{ "cells": [ { "cell_type": "markdown", "id": "033cc80b", "metadata": {}, "source": [ "# `bo4mob` — the BO4Mob San Jose freeway instances (stage 1: data + liveness)\n", "\n", "**What.** BO4Mob (Ryu, Kwon, Choi, Deshwal, Kang & Osorio 2025, NeurIPS 2025\n", "Datasets & Benchmarks, `[ryu2025bo4mob]`,\n", "[docs/REFERENCES.md](../../docs/REFERENCES.md)) poses five San Jose freeway\n", "networks as high-dimensional black-box OD-ESTIMATION problems: minimise the\n", "NRMSE between mesoscopic-SUMO link counts and real Caltrans PeMS sensor data.\n", "There is **no ground-truth OD** — truth is the real sensor panel. This\n", "notebook ships **stage 1 only**: data availability (a checksummed,\n", "download-on-demand registry of four small instances) and pipeline liveness (a\n", "mesoscopic-SUMO smoke run) — **no task family, no certificate, no estimator**.\n", "\n", "**Why it is in the benchmark, and the honesty contract that governs it.**\n", "BO4Mob is **the lab's own benchmark**\n", "(`github.com/UMN-Choi-Lab/BO4Mob`, MIT). Hosting a benchmark the lab authored\n", "inside a benchmark the lab authors is a standing honesty hazard — see\n", "[docs/design/adr-034-bo4mob-scenarios.md](../../docs/design/adr-034-bo4mob-scenarios.md)\n", "for the full dual-benchmark contract, reproduced verbatim below.\n", "\n", "**Scope.** The dual-benchmark honesty contract (in-artifact, not only in\n", "docs), the checksummed fetch of the four small instances (never\n", "`5fullRegion`, which refuses to fetch by design), and an optional sumo-gated\n", "pipeline-liveness cell reproducing the 1ramp smoke test." ] }, { "cell_type": "markdown", "id": "98a07593", "metadata": {}, "source": [ "## How this notebook is graded\n", "\n", "**A notebook never claims a number it does not compute in that cell.** This\n", "data notebook makes **no** certified-gap claim (stage 1 ships no certificate\n", "at all — see Stage 2 in the ADR). What IS recomputed live: the in-artifact\n", "disclosure strings, and — if `eclipse-sumo` is installed — the pipeline's\n", "NRMSE and seed-stability, exactly as the guarded smoke test does\n", "([README](../../README.md), *Certified, not self-reported*)." ] }, { "cell_type": "code", "execution_count": 1, "id": "443542b8", "metadata": { "execution": { "iopub.execute_input": "2026-07-21T13:56:50.817389Z", "iopub.status.busy": "2026-07-21T13:56:50.816829Z", "iopub.status.idle": "2026-07-21T13:56:52.856673Z", "shell.execute_reply": "2026-07-21T13:56:52.855688Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "registered instances : ['1ramp', '2corridor', '3junction', '4smallRegion', '5fullRegion']\n", "CI smoke instance : 1ramp\n" ] } ], "source": [ "# Setup. bo4mob's data layer is numpy/stdlib only — no package guard cell for\n", "# the notebook as a whole. ONE cell below (the pipeline-liveness demo) is\n", "# OPTIONALLY sumo-gated: it degrades gracefully, printing a clear notice\n", "# instead of raising, if `eclipse-sumo` is not installed — everything else in\n", "# this notebook (the fetch, the citation, the honesty contract) needs no\n", "# extra at all.\n", "#\n", "# The inline backend is Agg-based: figures render headlessly into the\n", "# 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", "from tabench.data.bo4mob import (\n", " BO4MOB_ORIGIN,\n", " BO4MOB_REGISTRY,\n", " BO4MOB_SMOKE,\n", " Bo4MobHpcOnlyError,\n", " bo4mob_citation,\n", " fetch_bo4mob,\n", ")\n", "\n", "print(f\"registered instances : {sorted(BO4MOB_REGISTRY)}\")\n", "print(f\"CI smoke instance : {BO4MOB_SMOKE}\")" ] }, { "cell_type": "markdown", "id": "9e2f8e0f", "metadata": {}, "source": [ "## The dual-benchmark honesty contract (in-artifact, not only in docs)\n", "\n", "The only honest claim shape (adr-034): TABenchmark hosts BO4Mob's instances\n", "as **scenarios/data only** — never as validation of TABench methods, never a\n", "claim to reproduce BO4Mob's published numbers (SUMO 1.12 in the paper vs the\n", "shipped 1.27.1 wheel here — a measured schema drift, below), and never an\n", "\"independent replication\" of BO4Mob's own BO leaderboard. Every registry\n", "entry's `notes` carries this disclosure; it is recomputed and printed here,\n", "not quoted from the ADR." ] }, { "cell_type": "code", "execution_count": 2, "id": "be39bb74", "metadata": { "execution": { "iopub.execute_input": "2026-07-21T13:56:52.859791Z", "iopub.status.busy": "2026-07-21T13:56:52.859386Z", "iopub.status.idle": "2026-07-21T13:56:52.864066Z", "shell.execute_reply": "2026-07-21T13:56:52.863321Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "BO4Mob (Ryu, Kwon, Choi, Deshwal, Kang & Osorio 2025, arXiv:2510.18824, NeurIPS 2025 Datasets & Benchmarks) is a UMN Choi Lab benchmark, MIT-licensed; ground truth is public Caltrans PeMS detector data. TABenchmark hosts its instances as scenarios/data only (adr-034) — never as validation of TABench methods — and does not reproduce BO4Mob's published numbers (engine drift SUMO 1.12 -> 1.27.1). Fetched from BO4Mob @ ef571e6819a6.\n", "\n", "Ryu, Kwon, Choi, Deshwal, Kang & Osorio (2025). BO4Mob: Bayesian Optimization Benchmarks for High-Dimensional Urban Mobility Problem. arXiv:2510.18824 (NeurIPS 2025 Datasets & Benchmarks). Data + engine: github.com/UMN-Choi-Lab/BO4Mob (commit ef571e6819a6, MIT). Ground truth: Caltrans PeMS detector data (public). BO4Mob is a UMN Choi Lab benchmark; TABenchmark hosts its instances as scenarios/data only (adr-034), not as validation of TABench methods, and does not reproduce BO4Mob's published numbers. Instance: 1ramp (3 OD pairs).\n" ] } ], "source": [ "print(BO4MOB_ORIGIN)\n", "assert \"scenarios/data only\" in BO4MOB_ORIGIN\n", "assert \"does not reproduce BO4Mob's published numbers\" in BO4MOB_ORIGIN\n", "for spec in BO4MOB_REGISTRY.values():\n", " assert spec.notes == BO4MOB_ORIGIN or spec.notes.startswith(BO4MOB_ORIGIN)\n", "print()\n", "print(bo4mob_citation(BO4MOB_REGISTRY[\"1ramp\"]))" ] }, { "cell_type": "markdown", "id": "7c310b1c", "metadata": {}, "source": [ "## The checksummed fetch: four small instances ship, `5fullRegion` refuses\n", "\n", "`1ramp`/`2corridor`/`3junction`/`4smallRegion` are single-evaluation bundles\n", "(< 1.2 MB total), fetched from a commit-pinned BO4Mob raw URL and verified\n", "against a pinned SHA-256 on every load — never vendored (P9). `5fullRegion`\n", "(10,100 OD pairs, 74 MB, ~11 h/eval) is registered metadata-only and **refuses\n", "to fetch** — a named refusal, not a silent omission." ] }, { "cell_type": "code", "execution_count": 3, "id": "a19649a6", "metadata": { "execution": { "iopub.execute_input": "2026-07-21T13:56:52.866283Z", "iopub.status.busy": "2026-07-21T13:56:52.866121Z", "iopub.status.idle": "2026-07-21T13:56:52.871340Z", "shell.execute_reply": "2026-07-21T13:56:52.870622Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1ramp bundle fetched and checksum-verified: ['additional', 'config', 'net', 'od', 'routes_single', 'sensor', 'single_od', 'taz']\n", "5fullRegion refused: bo4mob 5fullRegion is HPC-only (74 MB, ~11 h/eval) and is registered metadata-only; refusing to fet…\n" ] } ], "source": [ "paths = fetch_bo4mob(BO4MOB_REGISTRY[BO4MOB_SMOKE])\n", "print(f\"{BO4MOB_SMOKE} bundle fetched and checksum-verified: {sorted(paths)}\")\n", "assert set(paths) == {\"net\", \"taz\", \"od\", \"additional\", \"routes_single\", \"single_od\", \"config\", \"sensor\"}\n", "\n", "spec_full = BO4MOB_REGISTRY[\"5fullRegion\"]\n", "assert spec_full.hpc_only\n", "try:\n", " fetch_bo4mob(spec_full)\n", " raise AssertionError(\"expected 5fullRegion to refuse to fetch\")\n", "except Bo4MobHpcOnlyError as exc:\n", " print(f\"5fullRegion refused: {exc}\"[:120] + \"…\")" ] }, { "cell_type": "markdown", "id": "ef60663b", "metadata": {}, "source": [ "## Not a `load_scenario` scenario\n", "\n", "A BO4Mob instance is a mesoscopic-SUMO net with no BPR network and no true\n", "OD, so no `Scenario` (Network/Demand/ReferenceSolution) can be built — that\n", "is not a gap, it is the honest statement that these are data + an engine, not\n", "an equilibrium instance." ] }, { "cell_type": "code", "execution_count": 4, "id": "2d8dfffd", "metadata": { "execution": { "iopub.execute_input": "2026-07-21T13:56:52.873560Z", "iopub.status.busy": "2026-07-21T13:56:52.873264Z", "iopub.status.idle": "2026-07-21T13:56:52.877365Z", "shell.execute_reply": "2026-07-21T13:56:52.876653Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "load_scenario('1ramp') refused: \"Unknown scenario '1ramp'; available: braess, tworoute, elastic-twor…\n", "load_scenario('bo4mob-1ramp') refused: \"Unknown scenario 'bo4mob-1ramp'; available: braess, tworoute…\n" ] } ], "source": [ "from tabench import load_scenario\n", "\n", "for key in (\"1ramp\", \"bo4mob-1ramp\"):\n", " try:\n", " load_scenario(key)\n", " raise AssertionError(f\"expected load_scenario({key!r}) to raise\")\n", " except KeyError as exc:\n", " print(f\"load_scenario({key!r}) refused: {exc}\"[:100] + \"…\")" ] }, { "cell_type": "markdown", "id": "815f3214", "metadata": {}, "source": [ "## Pipeline liveness (optional, sumo-gated): the 1ramp smoke run\n", "\n", "BO4Mob's own pipeline — `od2trips` route-fixing, then a mesoscopic SUMO run —\n", "via the wheel binaries, reproducing the guarded smoke test\n", "(`tests/test_bo4mob.py`). The measured 1.12 -> 1.27.1 schema drift: the\n", "mesoscopic `edgeData` output carries no `nVehContrib` attribute, so the count\n", "convention here uses `arrived + left` (BO4Mob's own), which still exists. This\n", "cell degrades gracefully — no `eclipse-sumo` extra, no raise — since\n", "everything else in this notebook needs no extra at all." ] }, { "cell_type": "code", "execution_count": 5, "id": "39e7e0fb", "metadata": { "execution": { "iopub.execute_input": "2026-07-21T13:56:52.879848Z", "iopub.status.busy": "2026-07-21T13:56:52.879432Z", "iopub.status.idle": "2026-07-21T13:56:54.218114Z", "shell.execute_reply": "2026-07-21T13:56:54.216906Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "seed=0 nrmse=2.432471 edges=10 trips=3087 nVehContrib=False\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "seed=1 nrmse=2.432471 edges=10 trips=3087 nVehContrib=False\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "seed=2 nrmse=2.432471 edges=10 trips=3087 nVehContrib=False\n", "seed spread (max-min) : 0.00e+00\n" ] } ], "source": [ "try:\n", " import sumo\n", "except ModuleNotFoundError as exc:\n", " if exc.name != \"sumo\":\n", " raise\n", " print(\"eclipse-sumo not installed: skipping the pipeline-liveness demo \"\n", " \"(pip install tabench[sumo] to run it).\")\n", "else:\n", " import json\n", " import os\n", " import subprocess\n", " import tempfile\n", " import time\n", " from pathlib import Path\n", "\n", " from tabench.data import bo4mob as bo\n", "\n", " def _sbin(name):\n", " return os.path.join(sumo.SUMO_HOME, \"bin\", name)\n", "\n", " def _run(cmd, env, work, deadline):\n", " remaining = deadline - time.monotonic()\n", " if remaining <= 0:\n", " raise RuntimeError(\"bo4mob smoke exceeded the wall budget\")\n", " proc = subprocess.run(\n", " cmd, env=env, cwd=work, stdin=subprocess.DEVNULL,\n", " capture_output=True, text=True, timeout=remaining,\n", " )\n", " if proc.returncode != 0:\n", " raise RuntimeError(f\"{cmd[0]} failed (rc={proc.returncode}): {proc.stderr[-800:]}\")\n", "\n", " def _run_1ramp(paths, work, seed):\n", " cfg = json.loads(paths[\"config\"].read_text())\n", " sim_end = float(cfg[\"sim_end_time\"])\n", " od_end = int(cfg[\"od_end_time\"])\n", " s0, s1 = float(cfg[\"sensor_start_time\"]), float(cfg[\"sensor_end_time\"])\n", " env = {**os.environ, \"SUMO_HOME\": sumo.SUMO_HOME}\n", " deadline = time.monotonic() + 120.0\n", "\n", " od_filled = work / f\"od_filled_{seed}.xml\"\n", " bo.fill_single_od(paths[\"od\"], paths[\"single_od\"], od_filled, od_end)\n", " trips_before = work / f\"trips_before_{seed}.xml\"\n", " _run([\n", " _sbin(\"od2trips\"), \"--spread.uniform\", \"--taz-files\", str(paths[\"taz\"]),\n", " \"--tazrelation-files\", str(od_filled), \"-o\", str(trips_before),\n", " ], env, work, deadline)\n", " trips_fixed = work / f\"trips_fixed_{seed}.xml\"\n", " n_trips = bo.fix_routes_single(trips_before, paths[\"routes_single\"], trips_fixed)\n", " edge_data_name = f\"edge_data_{seed}.xml\"\n", " add_local = work / f\"additional_local_{seed}.xml\"\n", " bo.local_edgedata_additional(paths[\"additional\"], add_local, edge_data_name)\n", " _run([\n", " _sbin(\"sumo\"), \"--mesosim\", \"true\", \"--net-file\", str(paths[\"net\"]),\n", " \"--routes\", str(trips_fixed), \"-b\", \"0\", \"-e\", str(int(sim_end)),\n", " \"--additional-files\", str(add_local), \"--ignore-route-errors\", \"true\",\n", " \"--xml-validation\", \"never\", \"--no-warnings\", \"--seed\", str(seed),\n", " ], env, work, deadline)\n", " edge_data = work / edge_data_name\n", " counts = bo.edgedata_counts(edge_data, s0, s1)\n", " return bo.bo4mob_nrmse(paths[\"sensor\"], counts), len(counts), n_trips, bo.edgedata_has_nvehcontrib(edge_data)\n", "\n", " workdir = Path(tempfile.mkdtemp(prefix=\"tabench-bo4mob-\"))\n", " results, drift = [], []\n", " for seed in (0, 1, 2):\n", " nrmse, n_edges, n_trips, saw = _run_1ramp(paths, workdir, seed)\n", " results.append(nrmse)\n", " drift.append(saw)\n", " print(f\"seed={seed} nrmse={nrmse:.6f} edges={n_edges} trips={n_trips} nVehContrib={saw}\")\n", "\n", " print(f\"seed spread (max-min) : {max(results) - min(results):.2e}\")\n", " assert max(results) - min(results) < 1e-3 # uncongested + speedDev=0 -> deterministic\n", " assert 1.5 < results[0] < 3.5 # loose, version-robust band\n", " assert not any(drift) # the measured 1.12 -> 1.27.1 schema drift" ] }, { "cell_type": "markdown", "id": "48ca470d", "metadata": {}, "source": [ "## Visualize\n", "\n", "Stage 1 has no BPR network, no certified link-flow artifact, and no OD-fit\n", "diagram — nothing here is a road-link-flow object, so the viz rule (adr-035)\n", "calls for plain matplotlib, not `tabench.viz`. There is nothing to plot yet:\n", "the registry table below is the honest visual for a data-availability\n", "notebook." ] }, { "cell_type": "code", "execution_count": 6, "id": "664953af", "metadata": { "execution": { "iopub.execute_input": "2026-07-21T13:56:54.222353Z", "iopub.status.busy": "2026-07-21T13:56:54.222116Z", "iopub.status.idle": "2026-07-21T13:56:54.322236Z", "shell.execute_reply": "2026-07-21T13:56:54.321336Z" } }, "outputs": [ { "data": { "image/png": "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YWEqf61LUFAQZDKZ+KlevbpK109ERETlk9KJk4uLC6ZPn443b96IZa9fv8bMmTPh4uKissD++usvJCUloUaNGqhcuTIqV66MBw8eYMKECbC2tgYAWFhYICkpSW65nJwcJCcnw8LCoth1T5kyBampqeLn4cOHKoubiIiIyi+lb9UtXboU7u7uqFatGhwdHQEAV65cgba2Ng4dOqSywAYOHAg3Nze5Mnd3dwwcOBBDhgwB8DaJS0lJQXR0NJycnAAAx44dQ15eHlq0aFHsuqVSKaRSqcpiJSIioopB6cTJwcEBsbGx2LRpE27dugUA6NevH3x8fKCjo6PUutLT03H37l1xOi4uDjExMTAyMkKNGjVgbGwsV19TUxMWFhaoW7cuAKB+/fro3LkzRowYgVWrViE7Oxv+/v7w9vbmE3VERESkckonTgCgq6uLESNGfPTGL168iA4dOojT48ePBwD4+voiLCxMoXVs2rQJ/v7+6NixozgA5rJlyz46NiIiIqJ3KZQ47d27Fx4eHtDU1MTevXvfW7d79+4Kb9zV1VWplwXfv3+/UJmRkRE2b96s8DqIiIiISkqhxKlnz57io//FvRIFACQSCXJzc1UVGxEREZFaUShxyh8h/N2fiYiIiCqSEr+rrqCUlBRVrIaIiIhIrSmdOM2fPx/btm0Tp/v06QMjIyN89tlnuHLlikqDIyIiIlInSidOq1atEkfajoiIwJEjR3Dw4EF4eHhg4sSJKg+QiIiISF0oPRxBQkKCmDjt378fffv2RadOnWBtbf3eQSeJiIiI/uuUbnGqWrWq+IqSgwcPiqN7C4LAJ+qIiIioXFO6xal3797o378/7Ozs8Pz5c3h4eAAALl++jNq1a6s8QCIiIiJ1oXTiFBISAmtrazx8+BDBwcHQ09MDADx58gRjxoxReYBERERE6kLpxElTUxPffvttofJx48apJCAiIiIidVWid9XFxsYiMjISSUlJhQbEnDZtmkoCIyIiIlI3SidOa9euxejRo2FiYgILCwtIJBJxnkQiYeJERERE5ZbSidOcOXMwd+5cTJ48uTTiISIiIlJbSg9H8OLFC/Tp06c0YiEiIiJSa0onTn369MHhw4dLIxYiIiIitab0rbratWtj6tSpOHv2LBo2bAhNTU25+WPHjlVZcERERETqROnEac2aNdDT08OJEydw4sQJuXkS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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import matplotlib.pyplot as plt\n", "\n", "fig, ax = plt.subplots(figsize=(6, 3))\n", "keys = [k for k in BO4MOB_REGISTRY if not BO4MOB_REGISTRY[k].hpc_only]\n", "n_od = [BO4MOB_REGISTRY[k].n_od for k in keys]\n", "ax.bar(keys, n_od, color=\"#4c72b0\")\n", "ax.set_ylabel(\"OD pairs (problem dimension)\")\n", "ax.set_title(\"BO4Mob small instances — fetchable in stage 1\")\n", "fig.tight_layout()\n", "display(fig)\n", "plt.close(fig)" ] }, { "cell_type": "markdown", "id": "2b89e187", "metadata": {}, "source": [ "## Takeaways & pointers\n", "\n", "- **The dual-benchmark contract is in-artifact.** Every registry entry\n", " carries the affiliation, the license, and the \"scenarios/data only\" scope\n", " in its own `notes` — not just in this notebook or the ADR.\n", "- **No certificate here, on purpose.** Stage 1 ships data + liveness only;\n", " the pinned-engine held-out-date observational certificate is a named\n", " stage-2 follow-up with its own ADR.\n", "- **The engine numbers do not reproduce the paper's, and that is disclosed.**\n", " SUMO 1.12 (the paper) vs 1.27.1 (this wheel) is a measured schema drift,\n", " not a silent mismatch — `nVehContrib` is verifiably absent, checked above.\n", "- **Where next.** `xu2024` ([01-xu2024.ipynb](01-xu2024.ipynb)) for the OTHER\n", " data family (real cities, a full `Scenario`, a genuine cross-implementation\n", " agreement check); the stage-2 certificate design in\n", " [docs/design/adr-034-bo4mob-scenarios.md](../../docs/design/adr-034-bo4mob-scenarios.md)." ] } ], "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": "data", "unit": "bo4mob" } }, "nbformat": 4, "nbformat_minor": 5 }