{ "cells": [ { "cell_type": "markdown", "id": "5d2e69fd", "metadata": {}, "source": [ "# `profiles` — SimOpt-style progress curves and solvability profiles\n", "\n", "**What.** `tabench.experiments.profiles` is the diagnostics half of the SimOpt\n", "design (Eckman, Henderson & Shashaani 2023, `[eckman2023simopt]`,\n", "[docs/REFERENCES.md](../../docs/REFERENCES.md)): progress curves, α-solve-time\n", "cdf/quantile solvability profiles, and Moré-Wild data profiles, all as **pure\n", "post-hoc arithmetic over already-certified rows** — no solver, certifier, or\n", "the runner changes. See\n", "[docs/design/adr-032-simopt-profiles.md](../../docs/design/adr-032-simopt-profiles.md)\n", "for the full derivation, the ten disclosed deviations from a literal SimOpt\n", "port (D1-D10), and every closed-form anchor.\n", "\n", "**Why it is in the benchmark.** It redeems the last unshipped P5/P6 promise\n", "(`docs/ARCHITECTURE.md`: progress curves and solvability profiles for the\n", "deterministic/stochastic tracks). Because it reads certified CSV rows rather\n", "than touching a solver, there is no new trust surface — correctness is pinned\n", "by closed-form hand-derivations, not a new certifier.\n", "\n", "**Scope.** Running a real grid on Braess (mirroring `demos/demo_profiles.py`),\n", "the certified α-solve-time closed-form anchor, cdf-solvability and Moré-Wild\n", "data profiles, the honest censoring of a black-box surrogate, and TWO sharp\n", "API edges worth knowing before you reach for this module yourself: `load_run`\n", "takes the literal `{stem}.csv` **path**, and `write_profiles` needs\n", "`protocol=`/`provenance=` — neither is optional or defaulted." ] }, { "cell_type": "markdown", "id": "b466a01d", "metadata": {}, "source": [ "## How this notebook is graded\n", "\n", "**A notebook never claims a number it does not compute in that cell.** The\n", "closed-form α-solve-time anchor from adr-032 (`{msa: 5, fw: 24, bfw: 4}`) is\n", "asserted against a REAL grid run in this notebook, not quoted from the ADR.\n", "Profiles add no new certificate — every underlying metric was already\n", "certified by the P1 `Evaluator` inside `run_experiment`\n", "([README](../../README.md), *Certified, not self-reported*)." ] }, { "cell_type": "code", "execution_count": 1, "id": "bd0c185c", "metadata": { "execution": { "iopub.execute_input": "2026-07-21T13:56:56.813745Z", "iopub.status.busy": "2026-07-21T13:56:56.813595Z", "iopub.status.idle": "2026-07-21T13:56:58.882074Z", "shell.execute_reply": "2026-07-21T13:56:58.880741Z" } }, "outputs": [], "source": [ "# Setup. `experiments.profiles` is numpy/scipy core -- no optional extra, so no\n", "# guard cell. The inline backend is Agg-based: figures render headlessly into\n", "# the notebook, so CI can execute tutorials without a display. NEVER\n", "# matplotlib.use(\"Agg\") in-kernel -- it silently suppresses inline capture.\n", "%matplotlib inline\n", "import tempfile\n", "from pathlib import Path\n", "\n", "import numpy as np\n", "\n", "from tabench import (\n", " AllOrNothingModel,\n", " BiconjugateFrankWolfeModel,\n", " Budget,\n", " CallableModel,\n", " ConjugateFrankWolfeModel,\n", " FrankWolfeModel,\n", " MSAModel,\n", " braess_scenario,\n", " run_experiment,\n", ")\n", "from tabench.experiments.profiles import (\n", " Run,\n", " cdf_solvability,\n", " data_profile,\n", " load_run,\n", " progress_curves,\n", " read_profiles,\n", " run_provenance,\n", " solve_times,\n", " write_profiles,\n", ")\n", "\n", "ALPHA = 1e-4 # certified-gap solve target (Boyce et al. 2004 convergence target)\n", "TAU = 1e-3 # Moré-Wild convergence-test level" ] }, { "cell_type": "markdown", "id": "f464f604", "metadata": {}, "source": [ "## Running a real grid, to disk\n", "\n", "A five-solver Braess grid plus a `toy-surrogate` black box (a `CallableModel`\n", "that emits a noisy guess with no shortest-path work at all,\n", "`sp_calls=0`) — the honest-censoring story below needs a model that FAILS the\n", "audit. `run_experiment(..., out_dir=...)` writes the certified `{stem}.csv` +\n", "`{stem}.manifest.json` pair; the `stem` is auto-generated from the scenario\n", "hash + model names + budget + seed, so distinct runs can never silently\n", "overwrite each other — and, notably, so a caller can never *choose* the exact\n", "filename up front (the first sharp edge, made concrete below)." ] }, { "cell_type": "code", "execution_count": 2, "id": "16d09617", "metadata": { "execution": { "iopub.execute_input": "2026-07-21T13:56:58.887059Z", "iopub.status.busy": "2026-07-21T13:56:58.886623Z", "iopub.status.idle": "2026-07-21T13:56:58.965134Z", "shell.execute_reply": "2026-07-21T13:56:58.964052Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "scenario : braess (hash cf00f411cdccec88…)\n", "models : ['aon', 'msa', 'fw', 'cfw', 'bfw', 'toy-surrogate']\n", "written stem : braess-cf00f411_aon-msa-fw-cfw-bfw-toy-surrogate_it50_seed-0\n" ] } ], "source": [ "scenario = braess_scenario()\n", "\n", "\n", "def naive_surrogate(s, rng):\n", " base = s.demand.total / 2.0\n", " return np.abs(base + rng.normal(0.0, 0.5, s.network.n_links))\n", "\n", "\n", "models = [\n", " AllOrNothingModel(),\n", " MSAModel(),\n", " FrankWolfeModel(),\n", " ConjugateFrankWolfeModel(),\n", " BiconjugateFrankWolfeModel(),\n", " CallableModel(fn=naive_surrogate, name=\"toy-surrogate\", seedable=True),\n", "]\n", "\n", "out_dir = Path(tempfile.mkdtemp(prefix=\"tabench-profiles-\"))\n", "result = run_experiment(scenario, models, Budget(iterations=50), seed=0, out_dir=out_dir)\n", "csv_path = next(out_dir.glob(\"*.csv\"))\n", "print(f\"scenario : {scenario.name} (hash {scenario.content_hash()[:16]}…)\")\n", "print(f\"models : {[m.name for m in models]}\")\n", "print(f\"written stem : {csv_path.stem}\")" ] }, { "cell_type": "markdown", "id": "6db0aab1", "metadata": {}, "source": [ "## The closed-form anchor (adr-032): α-solve times `{msa: 5, fw: 24, bfw: 4}`\n", "\n", "`progress_curves` turns certified rows into per-`(model, macrorep)` step\n", "curves on the certified metric (`relative_gap` here, the manifest's default);\n", "`solve_times` reads the first work coordinate where the curve strictly\n", "crosses below `α` — SimOpt's strict-`<` crossing rule (D3). All three share\n", "the AON start; `msa`'s crossing at `sp_calls=5` is a genuine *first* crossing\n", "even though its trace ends unconverged — first-crossing, not sustained\n", "convergence." ] }, { "cell_type": "code", "execution_count": 3, "id": "d77b3959", "metadata": { "execution": { "iopub.execute_input": "2026-07-21T13:56:58.969120Z", "iopub.status.busy": "2026-07-21T13:56:58.968616Z", "iopub.status.idle": "2026-07-21T13:56:58.974737Z", "shell.execute_reply": "2026-07-21T13:56:58.973808Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " cfw 4\n", " bfw 4\n", " msa 5\n", " fw 24\n", " aon inf\n", " toy-surrogate inf\n" ] } ], "source": [ "curves = progress_curves(result, axis=\"sp_calls\") # accepts the in-memory ExperimentResult directly\n", "times = {model: t for (model, _macrorep), t in solve_times(curves, ALPHA).items()}\n", "for model in sorted(times, key=lambda m: times[m]):\n", " t = times[model]\n", " print(f\" {model:<14}{'inf' if t == float('inf') else int(t):>6}\")\n", "\n", "assert times[\"msa\"] == 5\n", "assert times[\"fw\"] == 24\n", "assert times[\"bfw\"] == 4\n", "assert times[\"toy-surrogate\"] == float(\"inf\") # censored: never crosses (see below)" ] }, { "cell_type": "markdown", "id": "b4fcc12d", "metadata": {}, "source": [ "## cdf-solvability and Moré-Wild data profiles\n", "\n", "`cdf_solvability` is the fraction of the run solved to `α` vs normalized\n", "budget fraction; `data_profile` is Moré & Wild's `d_s(κ)`, the fraction\n", "solved within `κ` all-or-nothing passes (κ = `sp_calls / n_origins`; Braess\n", "has one origin, so κ = raw `sp_calls` here). Both keep censored problems IN\n", "the denominator (D4) — a black box that never solves never inflates the\n", "profile by disappearing from it." ] }, { "cell_type": "code", "execution_count": 4, "id": "1a1c0c07", "metadata": { "execution": { "iopub.execute_input": "2026-07-21T13:56:58.978508Z", "iopub.status.busy": "2026-07-21T13:56:58.977940Z", "iopub.status.idle": "2026-07-21T13:56:58.985588Z", "shell.execute_reply": "2026-07-21T13:56:58.984666Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "cdf-solvability at budget fraction 1.0 (terminal):\n", " msa 1.000\n", " fw 1.000\n", " cfw 1.000\n", " bfw 1.000\n", " aon 0.000\n", " toy-surrogate 0.000\n", "\n", "data-profile fraction solved at κ=25:\n", " msa 1.000\n", " fw 1.000\n", " cfw 1.000\n", " bfw 1.000\n", " aon 0.000\n", " toy-surrogate 0.000\n" ] } ], "source": [ "run = Run.from_result(result)\n", "demand = scenario.demand\n", "n_origins = int((demand.matrix.sum(axis=1) > 0).sum())\n", "assert n_origins == 1 # Braess: a single origin\n", "\n", "cdf = cdf_solvability(run, ALPHA, axis=\"sp_calls\")\n", "data = data_profile(run, tau=TAU, axis=\"sp_calls\", work_unit=float(n_origins))\n", "\n", "print(\"cdf-solvability at budget fraction 1.0 (terminal):\")\n", "for model, curve in sorted(cdf.items(), key=lambda kv: -kv[1].lookup(1.0)):\n", " print(f\" {model:<14}{curve.lookup(1.0):.3f}\")\n", "\n", "print(\"\\ndata-profile fraction solved at κ=25:\")\n", "for model, curve in sorted(data.items(), key=lambda kv: -kv[1].lookup(25.0)):\n", " print(f\" {model:<14}{curve.lookup(25.0):.3f}\")\n", "\n", "assert cdf[\"bfw\"].lookup(1.0) == 1.0\n", "assert cdf[\"toy-surrogate\"].lookup(1.0) == 0.0 # censored -> never in the numerator" ] }, { "cell_type": "markdown", "id": "d8cd6317", "metadata": {}, "source": [ "## Two sharp API edges (this is why they are documented in-cell)\n", "\n", "Both refuse LOUDLY rather than doing something surprising:\n", "\n", "1. **`load_run` takes the literal `{stem}.csv` path, not a stem or a\n", " directory.** Pass the run's directory, or the stem without `.csv`, and it\n", " raises `ValueError` immediately — it never guesses.\n", "2. **`write_profiles(out_path, profiles, protocol, provenance)` has no\n", " defaults for `protocol`/`provenance`.** They are not optional metadata:\n", " the artifact's whole honesty story (adr-032 D8) is that a profile without\n", " its protocol constants and provenance is unauditable, so Python's own\n", " `TypeError` enforces it before a single byte is written." ] }, { "cell_type": "code", "execution_count": 5, "id": "8c784043", "metadata": { "execution": { "iopub.execute_input": "2026-07-21T13:56:58.989249Z", "iopub.status.busy": "2026-07-21T13:56:58.988929Z", "iopub.status.idle": "2026-07-21T13:56:58.998237Z", "shell.execute_reply": "2026-07-21T13:56:58.997342Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "load_run(directory) refused : expected a .csv run file, got 'tabench-profiles-'\n", "load_run(stem) refused : expected a .csv run file, got 'braess-cf00f411_aon-msa-fw-cfw-bfw-toy-surrogate_it50_seed-0'\n", "write_profiles(no protocol/provenance) refused : write_profiles() missing 2 required positional arguments: 'protocol' and 'provenance'\n", "\n", "artifact written and round-tripped: schema='tabench-profiles-v1', kinds=['cdf_solvability', 'data_profile']\n" ] } ], "source": [ "try:\n", " load_run(out_dir) # a directory, not the {stem}.csv file\n", " raise AssertionError(\"expected load_run(directory) to raise\")\n", "except ValueError as exc:\n", " print(f\"load_run(directory) refused : {str(exc).replace(out_dir.name, 'tabench-profiles-')}\")\n", "\n", "try:\n", " load_run(str(csv_path)[: -len(\".csv\")]) # the stem, without .csv\n", " raise AssertionError(\"expected load_run(stem) to raise\")\n", "except ValueError as exc:\n", " print(f\"load_run(stem) refused : {exc}\")\n", "\n", "try:\n", " write_profiles(out_dir / \"profiles.json\", {\"cdf_solvability\": cdf}) # missing protocol/provenance\n", " raise AssertionError(\"expected write_profiles(...) without protocol/provenance to raise\")\n", "except TypeError as exc:\n", " print(f\"write_profiles(no protocol/provenance) refused : {exc}\")\n", "\n", "# The CORRECT usage of both, round-tripped through the certified artifact.\n", "# (rows differ in TYPE -- csv.DictReader yields strings, the in-memory\n", "# ExperimentResult yields floats; _to_float collapses both, so it is the\n", "# CURVES that round-trip identically, not the raw row dicts -- adr-032 D8.)\n", "run_from_disk = load_run(csv_path)\n", "assert progress_curves(run_from_disk, axis=\"sp_calls\") == curves\n", "\n", "protocol = {\n", " \"metric\": \"relative_gap\", \"axis\": \"sp_calls\", \"alpha\": ALPHA, \"tau\": TAU,\n", " \"crossing\": \"strict-<\", \"censoring\": \"in-denominator\", \"aon_work_unit\": n_origins,\n", "}\n", "artifact_path = out_dir / \"profiles.json\"\n", "write_profiles(\n", " artifact_path, {\"cdf_solvability\": cdf, \"data_profile\": data},\n", " protocol, run_provenance(run_from_disk),\n", ")\n", "doc, profiles_back = read_profiles(artifact_path)\n", "print(f\"\\nartifact written and round-tripped: schema={doc['schema']!r}, \"\n", " f\"kinds={sorted(profiles_back)}\")\n", "assert doc[\"protocol\"] == protocol\n", "assert profiles_back[\"cdf_solvability\"][\"bfw\"].lookup(1.0) == 1.0" ] }, { "cell_type": "markdown", "id": "191da28f", "metadata": {}, "source": [ "## Visualize\n", "\n", "Profile curves (fraction-solved vs a normalized budget fraction / work\n", "units) are not road link flows, so the viz rule (adr-035) calls for plain\n", "matplotlib here, not `tabench.viz` — reasoned explicitly, not defaulted." ] }, { "cell_type": "code", "execution_count": 6, "id": "5097db39", "metadata": { "execution": { "iopub.execute_input": "2026-07-21T13:56:59.002524Z", "iopub.status.busy": "2026-07-21T13:56:59.001857Z", "iopub.status.idle": "2026-07-21T13:56:59.256475Z", "shell.execute_reply": "2026-07-21T13:56:59.255315Z" } }, "outputs": [ { "data": { "image/png": "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b180aNAALi4uCAwMRGJiIvr37w8A6NOnDypUqICAgAAAgI+PDxYtWoT69esrLlWbNGkSfHx8FImciIiI1K8w5WyJoSGqX73y2dukWJ5MlmV7REQEPDw8FO8//hKhfv362Lt3L+zt7fHw4UMcP34c7u7uaouJiIiKD60W3d26dUNcXBwmT56MmJgYODk54dChQ4qBWqKjo5US3MSJEyGRSDBx4kQ8fvwY5ubm8PHxwaxZs7S1CURERCVCYcrZEokEOtkUyurk6OiIY8eOoXPnzgA+nN3P4O7ujunTp2PatGmIiIjAkiVLsHnzZo3HRERERY/WB1Lz9fWFr69vltM+vS9KT08PU6ZMwZQpUwogMiIiIvpYScvZPj4+OHTokGIE9po1ayqmubm54fr163Bzc4O5uTkWLFiAGjVqaDFaIiIqrLRedBMREREVRhKJBCtXrsxyWrly5ZCWlgYAcHV1zTTIHBERUQYO901ERERERESkISy6iYiIiIiIiDSERTcRERERERGRhrDoJiIiIiIiItIQFt1EREREREREGsKim4iIiCgLoaGh8PPzU2rbsGEDXF1d8dtvv2kpKiIiKmr4yDAiIiIqUoQQSE1OV9vy9Ax0IJFI8tR369atOHToEMzMzNS2fiIiKt7yVHTXr18/z8no6tWrnxUQERER5V9JyNlpKXKs9z+ptuUNXuIBfalultNu3LgBHx8fxMTEoG3btrhw4QLatWsHHx8fpKWlYcKECahUqRJ+//132NnZYfLkydi0aZPaYiMioqIvT0V3hw4dFD+/f/8eK1euRM2aNdG4cWMAwPnz53Hr1i38+OOPGgmSiIiI8oY5W73evXuHw4cP459//oG/vz+cnJzw119/QQiBHj16ICoqCrVq1cLp06cRHR2NZs2aaTtkIiIqZPJUdE+ZMkXx83fffYfhw4djxowZmfo8fPhQvdERERGRSkpCztYz0MHgJR5qXV52Mq4ccHR0xNOnT1GqVCkAgImJCRITE3HixAn4+vri119/xYMHDzBmzBi1xUVERMWDygOpbd++HX369MnU3qtXL+zcuVMtQREREdHnK645WyKRQF+qq7ZXTpfjh4eHQwiByMhIWFtbK02rV68egoKC4O7uDolEgn/++QfVqlXT9OYTEVERo3LRLZPJEBYWlqk9LCwMhoaGagmKiIiIPh9z9ucrXbo0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V1cXsbGxSu2xsbGwsrLKcd4FCxZgzpw5OHbsGOrWravJMImIiEo05msiIqL80+rl5QYGBnB2dlYaVCVjkJXGjRtnO9+8efMwY8YMHDp0CA0aNCiIUImIiEos5msiIqL80/rl5aNHj0bfvn3RoEEDuLi4IDAwEImJiejfvz8AoE+fPqhQoQICAgIAAHPnzsXkyZOxZcsW2NvbK+4lMzY2hrGxsda2g4iIqDhjviYiIsofrRfd3bp1Q1xcHCZPnoyYmBg4OTnh0KFDisFaoqOjoaPzfyfkg4KCkJKSgs6dOystZ8qUKZg6dWpBhk5ERFRiMF8TERHlj9aLbgDw9fWFr69vltNCQ0OV3kdFRWk+ICIiIsqE+ZqIiEh1Wr2nm4iIiIiIiKg4Y9FNREREREREpCEsuomIiIiIiIg0hEU3ERERERERkYaw6CYiIiIiIiLSEBbdRERERERERBrCopuIiIiIiIhIQ1h0ExEREREREWkIi24iIiIiIiIiDWHRTURERERERKQhLLqJiIiIiIiINIRFNxEREREREZGGsOgmIiIiIiIi0hAW3UREREREREQawqKbiIiIiIiISENYdBMRERERERFpCItuIiIiIiIiIg1h0U1ERERERESkISy6iYiIiIiIiDSERTcRERERERGRhrDoJiIiIiIiItIQFt1EREREREREGsKim4iIiIiIiEhDWHQTERERERERaQiLbiIiIiIiIiINYdFNREREREREpCEsuomIiIiIiIg0hEU3ERERERERkYaw6CYiIiIiIiLSEBbdRERERERERBrCopuIiIiIiIhIQ1h0ExEREREREWlIoSi6V6xYAXt7exgaGsLV1RUXL17Msf/27dtRo0YNGBoaok6dOjhw4EABRUpERFRyMV8TERGpTk/bAQQHB2P06NFYtWoVXF1dERgYCG9vb0RGRsLCwiJT/7Nnz6J79+4ICAhA27ZtsWXLFnTo0AFXr15F7dq1CzT21JQUxD64W6DrBIDUhPcQIhUAEPf8IfRSSn3S4R1kQhcAkPTyOWDwrqBDpCLsfdp76KVJAAAJbxORqivXckRERYeJsRF0dArF99lqx3xNmpDrMY3aVsRjIyJSPs6VywvuGFcihBAFtrYsuLq6omHDhli+fDmADxtva2uLYcOGYdy4cZn6d+vWDYmJifjrr78UbY0aNYKTkxNWrVqV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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import matplotlib.pyplot as plt\n", "\n", "fig, axes = plt.subplots(1, 2, figsize=(10, 3.2))\n", "for ax, (title, profile, xlabel) in zip(\n", " axes,\n", " [\n", " (\"cdf-solvability\", cdf, \"normalized budget fraction\"),\n", " (\"Moré-Wild data profile\", data, f\"κ (sp_calls / {n_origins} AON-pass)\"),\n", " ],\n", "):\n", " for model, curve in profile.items():\n", " ax.step(curve.x, curve.y, where=\"post\", label=model)\n", " ax.set_xlabel(xlabel)\n", " ax.set_ylabel(\"fraction solved\")\n", " ax.set_ylim(-0.02, 1.02)\n", " ax.set_title(title)\n", " ax.legend(fontsize=6)\n", "fig.tight_layout()\n", "display(fig)\n", "plt.close(fig)" ] }, { "cell_type": "markdown", "id": "c530297b", "metadata": {}, "source": [ "## Takeaways & pointers\n", "\n", "- **No new trust surface.** Every curve here is a deterministic pure\n", " function of rows the P1 `Evaluator` already certified inside\n", " `run_experiment` — profiles add reporting, not scoring.\n", "- **Censoring stays in the denominator.** `toy-surrogate` never crosses `α`\n", " (`+inf`, `cdf=0.0` at budget fraction 1.0) but it never vanishes from a\n", " profile the way a solver that silently skipped a hard scenario would (D10,\n", " D4) — garbage is a first-class row, never dropped.\n", "- **Two sharp edges, now known.** `load_run` wants the exact `.csv` path;\n", " `write_profiles` wants its protocol and provenance every time — both\n", " refuse loudly rather than guessing.\n", "- **Where next.** The ten disclosed SimOpt deviations (D1-D10), the β-quantile\n", " parity fix, and the Moré-Wild work-unit convention in\n", " [docs/design/adr-032-simopt-profiles.md](../../docs/design/adr-032-simopt-profiles.md);\n", " a CLI-free runnable script at\n", " [demos/demo_profiles.py](https://github.com/UMN-Choi-Lab/TABenchmark/blob/main/demos/demo_profiles.py)." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.12" }, "tabench": { "covers": [], "requires_extra": null, "track": "experiments", "unit": "profiles" } }, "nbformat": 4, "nbformat_minor": 5 }