{ "cells": [ { "cell_type": "markdown", "id": "odme01", "metadata": {}, "source": [ "# `odme-dtalite` — DTALite's static ODME as one more guarded T2 estimator (Zhou & Taylor 2014)\n", "\n", "**What.** `odme-dtalite` (T2, `ADR-042`) is the estimation track's second\n", "engine-in-the-loop estimator and its first ODME row. DTALite 0.8.1's PyPI wheel\n", "hides an Origin-Destination Matrix Estimation routine (`performODME`) *inside*\n", "the same static `assignment()` entry the `dtalite-tap` T1 adapter (adr-029)\n", "already wraps — it runs when `settings.csv` carries `odme_mode=1`. Given a seed\n", "OD, a target OD, and sensor link counts (`obs_volume`), it re-weights the\n", "route-flows the base Frank-Wolfe assignment discovered so the modeled link\n", "volumes approach the counts (`[zhou2014dtalite]`,\n", "[docs/REFERENCES.md](../../docs/REFERENCES.md)).\n", "\n", "**Why it is in the benchmark.** T2's whole thesis is that ANY OD-emitting method\n", "is scored by the SAME pinned-`bfw` certifier. `odme-dtalite` ships as a GUARDED\n", "STATIC estimator riding that UNCHANGED certifier (the adr-028 ideal: zero task,\n", "runner, or certifier changes) — the estimator emits an OD, the certifier\n", "re-assigns it under the declared BPR. It is a **row, not a new question**.\n" ] }, { "cell_type": "markdown", "id": "odme02", "metadata": {}, "source": [ "## How this notebook is graded\n", "\n", "**A notebook never claims a number it does not compute in that cell.** Every\n", "scored quantity below — `od_feasible`, `certificate_gap`, `obs_count_rmse`,\n", "`heldout_count_rmse` — comes from the SAME `ODCertifier` every other T2\n", "estimator here is scored by, re-assigning the emitted OD through its own pinned\n", "`bfw` reference, never from `odme-dtalite`'s self-report\n", "([README](../../README.md), *Certified, not self-reported*).\n" ] }, { "cell_type": "code", "execution_count": 1, "id": "odme03", "metadata": { "execution": { "iopub.execute_input": "2026-07-21T13:48:03.940394Z", "iopub.status.busy": "2026-07-21T13:48:03.939999Z", "iopub.status.idle": "2026-07-21T13:48:05.923994Z", "shell.execute_reply": "2026-07-21T13:48:05.922643Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "scenario: siouxfalls, 24 zones / 76 links, BPR power 4\n" ] } ], "source": [ "# Setup. `odme-dtalite` needs the optional `dtalite` extra\n", "# (`pip install tabench[dtalite]`). We probe it WITHOUT importing it: `import\n", "# DTALite` prints a banner and ctypes-loads an OpenMP engine into the host\n", "# (adr-029), so the estimator only ever runs it in a throwaway subprocess.\n", "#\n", "# The inline backend renders figures headlessly so CI can execute tutorials\n", "# without a display. NEVER matplotlib.use(\"Agg\") in-kernel -- it silently\n", "# suppresses inline capture.\n", "%matplotlib inline\n", "import importlib.util\n", "\n", "if importlib.util.find_spec(\"DTALite\") is None:\n", " raise ModuleNotFoundError(\n", " \"odme-dtalite needs the optional 'dtalite' extra: pip install tabench[dtalite]\",\n", " name=\"DTALite\",\n", " )\n", "\n", "import matplotlib.pyplot as plt\n", "\n", "from tabench import Budget, PriorBaseline, run_estimation_experiment\n", "from tabench.data import load_scenario\n", "from tabench.estimation import DtaliteODMEEstimator\n", "\n", "# THE marquee anchor (adr-042): siouxfalls UE (BPR power-4, 528 OD pairs), clean\n", "# counts, sensors random coverage 0.5, held-out coverage 0.2, stale prior cv=0.3.\n", "# Sioux-Falls scale is DELIBERATE: DTALite's ODME has a hardcoded ABSOLUTE\n", "# convergence floor (tol=1), so Braess-scale demand (~6) would no-op with \"0\n", "# iterations\". At this scale realistic deviations clear the floor.\n", "MARQUEE = {\n", " \"sensors\": {\"kind\": \"random\", \"coverage\": 0.5},\n", " \"heldout\": {\"kind\": \"random\", \"coverage\": 0.2},\n", " \"noise\": \"none\", \"n_periods\": 1, \"prior\": {\"kind\": \"stale\", \"cv\": 0.3},\n", "}\n", "SEED = 7\n", "scenario = load_scenario(\"siouxfalls\")\n", "print(f\"scenario: {scenario.name}, {scenario.network.n_zones} zones / \"\n", " f\"{scenario.network.n_links} links, BPR power {scenario.network.power[0]:.0f}\")\n" ] }, { "cell_type": "markdown", "id": "odme04", "metadata": {}, "source": [ "## The recovery anchor, certified through the UNCHANGED pinned-`bfw` certifier\n", "\n", "Zero changes to the task, runner, or certifier were needed for this row:\n", "`ODCertifier` re-assigns the emitted OD through its OWN pinned `bfw` reference\n", "regardless of which engine produced it — the whole point of T2. One non-obvious\n", "engine pin makes it work: `odme-dtalite` writes `route_output=1` so DTALite\n", "populates the route history its ODME reconstruction reads (with the lean\n", "`route_output=0`, the reconstruction collapses and the OD inflates ~40 %, a\n", "degenerate estimate — measured, adr-042).\n" ] }, { "cell_type": "code", "execution_count": 2, "id": "odme05", "metadata": { "execution": { "iopub.execute_input": "2026-07-21T13:48:05.928657Z", "iopub.status.busy": "2026-07-21T13:48:05.928333Z", "iopub.status.idle": "2026-07-21T13:48:12.791535Z", "shell.execute_reply": "2026-07-21T13:48:12.790245Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "certified od_feasible : 1\n", "certificate_converged : 1\n", "certificate_gap : 9.51e-07\n", "obs_count_rmse odme / prior : 365.3 / 994.8\n", "heldout_count_rmse odme / prior (rank): 556.6 / 816.5\n", "od_rmse odme / prior : 264.5 / 267.4\n" ] } ], "source": [ "res = run_estimation_experiment(\n", " scenario, [PriorBaseline(), DtaliteODMEEstimator()], Budget(iterations=100),\n", " seed=SEED, macroreps=1, estimation=MARQUEE,\n", ")\n", "last = {row[\"estimator\"]: row for row in res.rows}\n", "prior, odme = last[\"prior\"], last[\"odme-dtalite\"]\n", "\n", "print(f\"certified od_feasible : {odme['od_feasible']:.0f}\")\n", "print(f\"certificate_converged : {odme['certificate_converged']:.0f}\")\n", "print(f\"certificate_gap : {float(odme['certificate_gap']):.2e}\")\n", "print(f\"obs_count_rmse odme / prior : {float(odme['obs_count_rmse']):.1f} / \"\n", " f\"{float(prior['obs_count_rmse']):.1f}\")\n", "print(f\"heldout_count_rmse odme / prior (rank): {float(odme['heldout_count_rmse']):.1f} / \"\n", " f\"{float(prior['heldout_count_rmse']):.1f}\")\n", "print(f\"od_rmse odme / prior : {float(odme['od_rmse']):.1f} / \"\n", " f\"{float(prior['od_rmse']):.1f}\")\n", "\n", "# Certified, feasible, and a real improves-on-prior on the count fit it calibrates\n", "# AND the ranking held-out count fit (loose bounds; the .so can shift the decimals).\n", "assert odme[\"od_feasible\"] == 1.0 and odme[\"certificate_converged\"] == 1.0\n", "assert float(odme[\"obs_count_rmse\"]) < 0.6 * float(prior[\"obs_count_rmse\"])\n", "assert float(odme[\"heldout_count_rmse\"]) < 0.9 * float(prior[\"heldout_count_rmse\"])\n" ] }, { "cell_type": "markdown", "id": "odme06", "metadata": {}, "source": [ "## The disclosed envelope, and that the ODME descent actually fired\n", "\n", "DTALite's ODME is bounded by hardcoded, non-configurable engine constants (part\n", "of the pinned 0.8.1 identity, like marouter's linear vdf): a\n", "`[0.5·min, 1.5·max]`-of-`(seed,target)` recovery box, penalty weights\n", "`w_link=0.1 / w_od=0.01`, and the absolute `tol=1` convergence floor plus a fixed\n", "400-iteration descent. `demand_target_frac` (default 1.0) is the one documented\n", "dial — a **one-sided** widening of the box (`>1` raises the upper bound only).\n", "`od_rmse` barely moves because Sioux Falls OD is not linearly identifiable from\n", "these sensors (`od_identifiable = 0`, reported) — `odme-dtalite` is a\n", "count-matcher, honestly.\n" ] }, { "cell_type": "code", "execution_count": 3, "id": "odme07", "metadata": { "execution": { "iopub.execute_input": "2026-07-21T13:48:12.796730Z", "iopub.status.busy": "2026-07-21T13:48:12.796497Z", "iopub.status.idle": "2026-07-21T13:48:12.803656Z", "shell.execute_reply": "2026-07-21T13:48:12.802639Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ODME gradient iterations executed : 69 (>0: cleared the tol=1 floor)\n", "od_identifiable : 0 (0 -> od_rmse is descriptive, not ranked)\n", "demand_target_frac (hashed factor): 1.0\n" ] } ], "source": [ "bundle = res.bundles[(\"odme-dtalite\", \"m0\")]\n", "odme_iters = float(bundle.trace.final.self_report[\"engine_odme_iterations\"])\n", "print(f\"ODME gradient iterations executed : {odme_iters:.0f} (>0: cleared the tol=1 floor)\")\n", "print(f\"od_identifiable : {odme['od_identifiable']:.0f} \"\n", " \"(0 -> od_rmse is descriptive, not ranked)\")\n", "print(f\"demand_target_frac (hashed factor): \"\n", " f\"{DtaliteODMEEstimator().factor_values['demand_target_frac']}\")\n", "assert odme_iters > 0 # never a 'Convergence reached after 0 iterations' no-op\n" ] }, { "cell_type": "markdown", "id": "odme08", "metadata": {}, "source": [ "## Anti-laundering — the certifier scores the OD, never DTALite's self-report\n", "\n", "The sacred property: the ONLY channel from `odme-dtalite` to the harness is the\n", "emitted OD matrix. `ODCertifier` re-runs its own `bfw` and never reads DTALite's\n", "bookkeeping, so a buggy or adversarial run can at worst emit a *bad* OD that\n", "certifies honestly — it cannot forge a good certificate. DTALite reports a rosy\n", "count fit (its stalled-assignment, box-clamped predicted volumes); the certifier\n", "ignores it. That gap is the *measured engine-in-the-loop bias*, provenance only.\n" ] }, { "cell_type": "code", "execution_count": 4, "id": "odme09", "metadata": { "execution": { "iopub.execute_input": "2026-07-21T13:48:12.806990Z", "iopub.status.busy": "2026-07-21T13:48:12.806817Z", "iopub.status.idle": "2026-07-21T13:48:12.811346Z", "shell.execute_reply": "2026-07-21T13:48:12.810542Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "DTALite self-reported obs_count_rmse : 8.06 (its own optimistic view)\n", "pinned-bfw CERTIFIED obs_count_rmse : 365.3 (what the leaderboard sees)\n", "engine-in-the-loop bias (self << certified): True\n" ] } ], "source": [ "self_fit = float(bundle.trace.final.self_report[\"obs_count_rmse\"])\n", "certified = float(odme[\"obs_count_rmse\"])\n", "print(f\"DTALite self-reported obs_count_rmse : {self_fit:.2f} (its own optimistic view)\")\n", "print(f\"pinned-bfw CERTIFIED obs_count_rmse : {certified:.1f} (what the leaderboard sees)\")\n", "print(f\"engine-in-the-loop bias (self << certified): {self_fit < 0.5 * certified}\")\n", "assert self_fit < 0.5 * certified # the certifier did not trust the self-report\n" ] }, { "cell_type": "code", "execution_count": 5, "id": "odme10", "metadata": { "execution": { "iopub.execute_input": "2026-07-21T13:48:12.815079Z", "iopub.status.busy": "2026-07-21T13:48:12.814501Z", "iopub.status.idle": "2026-07-21T13:48:12.950839Z", "shell.execute_reply": "2026-07-21T13:48:12.949994Z" } }, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig, ax = plt.subplots(figsize=(5.2, 3.2))\n", "labels = [\"obs_count_rmse\", \"heldout_count_rmse\\n(ranking)\"]\n", "prior_vals = [float(prior[\"obs_count_rmse\"]), float(prior[\"heldout_count_rmse\"])]\n", "odme_vals = [float(odme[\"obs_count_rmse\"]), float(odme[\"heldout_count_rmse\"])]\n", "x = range(len(labels))\n", "ax.bar([i - 0.2 for i in x], prior_vals, width=0.4, label=\"prior baseline\")\n", "ax.bar([i + 0.2 for i in x], odme_vals, width=0.4, label=\"odme-dtalite\")\n", "ax.set_xticks(list(x)); ax.set_xticklabels(labels)\n", "ax.set_ylabel(\"certified count RMSE\"); ax.set_title(\"odme-dtalite vs prior (pinned-bfw certified)\")\n", "ax.legend(); fig.tight_layout()\n" ] }, { "cell_type": "markdown", "id": "odme11", "metadata": {}, "source": [ "## Takeaways\n", "\n", "* `odme-dtalite` is a **guarded static estimator** on the **UNCHANGED** pinned-`bfw`\n", " certifier — the adr-028 zero-certifier-change ideal, a second engine after\n", " `spsa-sumo`.\n", "* It measurably beats the prior on the certified count fit at the Sioux Falls\n", " marquee, with the ODME descent actually firing (>0 iterations) — the anchor is\n", " chosen to clear DTALite's hardcoded `tol=1` floor.\n", "* Its engine envelope (the `[0.5,1.5]×` box, the hardcoded weights/tol, the\n", " `route_output=1` requirement, the `link_performance.csv` corruption it routes\n", " around by reading `od_performance.csv` only) is disclosed as an honest scope\n", " boundary. Single-mode demand-only; multiclass ODME is a deferred follow-up.\n", "\n", "See [`docs/design/adr-042-odme-dtalite.md`](../../docs/design/adr-042-odme-dtalite.md).\n" ] } ], "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": "dtalite", "track": "estimation", "unit": "odme-dtalite" } }, "nbformat": 4, "nbformat_minor": 5 }