Contents Menu Expand Light mode Dark mode Auto light/dark, in light mode Auto light/dark, in dark mode Skip to content
TABenchmark
TABenchmark

Overview

  • TABenchmark
  • TABenchmark Architecture
  • The TABenchmark Model Compendium
  • Numerical Validation
  • Implementation Roadmap
  • The TABenchmark Reference Canon
  • Contributing to TABenchmark

Tutorials

  • TABenchmark tutorials
  • aon — All-or-nothing assignment on the Braess network
  • msa — Method of successive averages (MSA) on the Braess network
  • fw — Frank–Wolfe (LeBlanc et al. 1975) on the Braess network
  • cfw — Conjugate Frank–Wolfe (Mitradjieva & Lindberg 2013) on the Braess network
  • bfw — Bi-conjugate Frank–Wolfe on the Braess network
  • gp — Gradient projection (Jayakrishnan et al. 1994) on the Braess network
  • oba — Origin-based assignment (Bar-Gera 2002) on the Braess network
  • algb — Algorithm B (Dial 2006) on the Braess network
  • tapas — TAPAS — traffic assignment by paired alternative segments (Bar-Gera 2010) on the Braess network
  • sue-msa — Logit stochastic user equilibrium by MSA on the two-route network
  • sue-probit-msa — Probit SUE by MSA, certified by pinned Monte Carlo
  • so-bfw — System optimum by bi-conjugate Frank–Wolfe on the Braess network
  • fw-elastic — Elastic-demand user equilibrium (Florian & Nguyen 1974)
  • evans — Combined trip distribution + assignment (Evans 1976)
  • br-ue — Boundedly-rational user equilibrium (Mahmassani & Chang 1987)
  • sc-tap — Side-constrained (capacitated) user equilibrium (Larsson & Patriksson 1995)
  • vi-asym — Asymmetric variational-inequality UE (Dafermos 1980 / Smith 1979)
  • multiclass — Multiclass-user equilibrium (Dafermos 1972)
  • learned-surrogate — A learned UE surrogate, and how the harness CENSORS it
  • dtd-swap — Smith’s (1984) route-swap day-to-day dynamics
  • dtd-swap-sue — Smith & Watling’s (2016) route-swap SUE dynamics
  • dtd-link — He, Guo & Liu’s (2010) link-based day-to-day dynamics
  • dtd-friesz — Friesz et al.’s (1994) route-based projected dynamical system
  • dtd-horowitz — Horowitz’s (1984) cost-smoothing SUE dynamics
  • dtd-stochastic — Cascetta’s (1989) stochastic-process day-to-day model
  • dtd-unifying — Cantarella & Cascetta’s (1995) unifying day-to-day process
  • dtd-cumlog — Li, Wang & Nie’s (2024) cumulative-logit day-to-day dynamics
  • gls — Generalized Least Squares OD estimation (covers prior)
  • spiess — Spiess’s (1990) count-misfit-only OD estimation
  • vzw-entropy — Van Zuylen & Willumsen’s (1980) entropy-balancing OD estimation
  • od-congested — Yang, Sasaki, Iida & Asakura’s (1992) bilevel OD estimation
  • spsa — Spall’s (1992) simultaneous perturbation stochastic approximation
  • od-kalman — Davis & Nihan’s (1993) linear-Gaussian OD estimation
  • od-dynamic — Cascetta, Inaudi & Marquis’s (1993) within-day dynamic OD estimation
  • bo4mob-estimation — BO4Mob held-out-count OD estimation (D2 observational)
  • odme-dtalite — DTALite’s static ODME as one more guarded T2 estimator (Zhou & Taylor 2014)
  • transit-strategy — Spiess & Florian’s (1989) optimal strategies
  • ctm — Daganzo’s (1994, 1995) Cell Transmission Model
  • ltm — Yperman’s (2007) Link Transmission Model
  • godunov — Lebacque’s (1996) Godunov scheme + the Greenshields FD
  • node-model — Tampere et al.’s (2011) generic first-order node model
  • vickrey — Vickrey’s (1969) single-bottleneck departure-time equilibrium
  • vi-due — Friesz et al.’s (1993) variational-inequality dynamic user equilibrium
  • merchant-nemhauser — Merchant & Nemhauser’s (1978) exit-function SO-DTA
  • lp-so-dta — Ziliaskopoulos’s (2000) LP single-destination SO-DTA on CTM cells
  • pm-td — Peeta & Mahmassani’s (1995) time-dependent UE and SO
  • newell-3det — Newell’s (1993) interior kinematic-wave reconstruction
  • implicit-ue-nn — user equilibrium as an implicit layer (act two)
  • het-gnn — heterogeneous-GNN traffic assignment (act three)
  • sumo-marouter — SUMO’s macroscopic assignment as an external-simulator adapter
  • sumo-duaiterate — the first external-dynamic (EDOC-1) row
  • dtalite-tap — DTALite’s static Frank-Wolfe, an IDENTITY compile map
  • spsa-sumo — SPSA calibration against a production simulator (Balakrishna 2007)
  • matsim — the first agent-based, stochastic-track EDOC row
  • dtalite-simulation — the third EDOC row, the first DETERMINISTIC-track external engine
  • xu2024 — the 20-US-city cross-domain axis (Honolulu / San Francisco)
  • bo4mob — the BO4Mob San Jose freeway instances (stage 1: data + liveness)
  • profiles — SimOpt-style progress curves and solvability profiles

API reference

  • API reference
    • tabench.core
    • tabench.models
    • tabench.metrics
    • tabench.estimation
    • tabench.edoc

Design records (ADRs)

  • ADR-001 — Logit SUE: Dial’s STOCH loading, MSA-SUE, and the fixed-point certificate
  • ADR-002 — T2 estimation track: OD demand from link counts, and the pinned-assignment certificate
  • ADR-003 — Probit SUE: Monte Carlo fixed-point certificate with a pinned evaluation stream
  • ADR-004 — Route-flow proportionality: a diagnostic now, a scored certificate proposed
  • ADR-005 — Elastic (variable) demand: a new problem class with a P1-pure certificate
  • ADR-006 — Learned (black-box) models: certified by P1, gated by lineage
  • ADR-007 — Combined trip distribution + assignment (Evans 1976): a P1-pure certificate
  • ADR-008 — Boundedly-rational user equilibrium: a band-relaxed UE with a necessary link-flow certificate
  • ADR-009 — Side-constrained UE: hard link capacities with a link-visible feasibility certificate
  • ADR-010: dnl-core — generic supply/demand dynamic-network-loading foundation
  • ADR-011: vi-asym — asymmetric variational-inequality UE (non-separable costs)
  • ADR-012: od-kalman — Davis & Nihan (1993) linear-Gaussian OD estimation from a time series of link counts
  • ADR-013: multiclass — Dafermos (1972) multiclass-user equilibrium
  • ADR-014: transit-strategy — Spiess & Florian (1989) optimal-strategy transit assignment
  • ADR-015: ctm — Daganzo (1994/1995) cell transmission model link
  • ADR-016: ltm — Yperman (2007) link transmission model
  • ADR-017: node-model — Tampère et al. (2011) generic first-order node model
  • ADR-018: godunov — Lebacque (1996) Godunov scheme + the first non-triangular FD
  • ADR-019: vickrey — Vickrey (1969) single-bottleneck departure-time equilibrium
  • ADR-020: merchant-nemhauser — Merchant & Nemhauser (1978) exit-function SO-DTA
  • ADR-021: lp-so-dta — Ziliaskopoulos (2000) LP single-destination SO-DTA on CTM cells
  • ADR-022: vi-due — Friesz et al. (1993) VI dynamic user equilibrium
  • ADR-023: od-dynamic — Cascetta, Inaudi & Marquis (1993) within-day dynamic OD estimation
  • ADR-024: newell-3det — Newell (1993) three-detector interior reconstruction
  • ADR-025 — Implicit-NN user equilibrium: the first torch model, feasibility as architecture
  • ADR-026 — Heterogeneous-GNN traffic assignment: the third learned model, feasibility as a decode
  • ADR-027 — SUMO marouter: the first external-simulator adapter, and the simulator-to-benchmark model gap
  • ADR-028 — spsa-sumo: SPSA calibration against a production simulator, as one more estimator row
  • ADR-029 — DTALite assignment(): the second external engine, and the identity-map static-UE row
  • ADR-030 — MATSim / DynaMIT / DYNASMART adapters: measured deferral, and the ADR that unblocks them
  • ADR-031: pm-td-ue / pm-td-so — Peeta & Mahmassani (1995) time-dependent SO/UE
  • ADR-032: simopt-profiles — SimOpt-style progress curves and solvability profiles
  • ADR-033: xu2024-dataset — the Xu et al. (2024) 20-US-city cross-domain axis
  • ADR-034: bo4mob-scenarios — the BO4Mob San Jose freeway OD-estimation instances (stage 1)
  • ADR-035: tutorials-visualizer — the house visualizer and the per-unit tutorial notebooks
  • ADR-036: edoc-1 — the external-dynamic-engine observational certificate
  • ADR-037 — sumo-duaiterate: the first EDOC-1 row, and the shipped external-dynamic substrate
  • ADR-038 — Cumulative-logit day-to-day dynamics: boundedly-rational logit choice with an exact-Wardrop-UE limit
  • ADR-039 — matsim: the second EDOC-1 row, the first agent-based / first stochastic-track external engine
  • ADR-040 — dtalite-simulation: the third EDOC-1 row, the first deterministic-track external engine, closing the adr-029 honest-sourcing loop
  • ADR-041 — bo4mob-estimation: the BO4Mob held-out-count OD-estimation family (stage 2), a D2 observational T2 certificate
  • ADR-042 — odme-dtalite: DTALite’s static ODME as one more guarded T2 estimator row
  • ADR-043 — bo4mob-joint-estimation: the joint (demand, supply) estimand is under-identified from counts+speeds — a measured deferral
  • TABenchmark Angle A: A Scenario × Model Cross-Evaluation Matrix with SimOpt-Style Experiment Machinery
  • TABenchmark — Angle A: The Scenario × Model Matrix
  • TABenchmark: An Observability-First Benchmark for 50 Years of Traffic Assignment Models
  • TABenchmark — Angle B: Observability-First Design
  • TABenchmark Design Proposal — Contract/Plugin-First Extensibility (Angle C)
  • TABenchmark: Contract-First Design Proposal (Angle C)
Back to top
View this page

dtd-link — He, Guo & Liu’s (2010) link-based day-to-day dynamics¶

What. The state is the aggregate LINK-flow vector, which moves each day toward the frozen-cost proximal target x*(v) = Proj_Ω(v − a t(v)) — a rational-behaviour adjustment that stays inside the OD-feasible polytope Ω. Its fixed point is Wardrop UE.

Why it is in the benchmark. Its distinctive signature is INVARIANCE: the emitted link flows never leave Ω (node balance ≈ 0 on every day), the He-Guo-Liu invariance principle — a different paradigm from route-swap (dtd-swap) that reaches the identical certified UE. See the model compendium and the certificate design in docs/ARCHITECTURE.md (P1).

Scope. Runs the process on a built-in scenario and certifies the result; it does not benchmark day-to-day models against each other. Reference: He, Guo & Liu (2010), Transportation Research Part B 44(4).

Canon. [he2010linkbased], docs/REFERENCES.md / docs/references.bib.

How this notebook is graded¶

A notebook never claims a number it does not compute in that cell. Every scored quantity below is recomputed live by the P1 Evaluator from the flows the model emitted, in the cell where it is claimed. Model self-reports (the per-day gap/residual, the Lyapunov value) are shown only as provenance and diffed against the certificate, exactly as the harness treats them (README, Certified, not self-reported).

# Setup. `dtd-link` is a core day-to-day model: a plain `pip install -e .` suffices —
# no optional extra, so no guard cell. The inline backend is Agg-based (headless CI
# renders into the notebook); NEVER matplotlib.use("Agg") in-kernel — it silently
# suppresses inline figure capture.
%matplotlib inline
import numpy as np

from tabench import (
    Budget,
    Evaluator,
    LinkBasedDTDModel,
    RngBundle,
    Trace,
    braess_scenario,
    viz,
)

The scenario¶

The built-in Braess network (4 nodes, 5 links, one OD pair 1→2, demand 6). Scenarios are frozen and content-hashed (P2) — the hash below is the benchmark instance’s identity.

scenario = braess_scenario()
net = scenario.network
print(f"scenario      : {scenario.name}")
print(f"content hash  : {scenario.content_hash()[:16]}…")
print(f"links         : {net.n_links}  (tail→head: "
      + ", ".join(f"{i}->{j}" for i, j in zip(net.init_node, net.term_node)) + ")")
print(f"total demand  : {scenario.demand.total}")
print("task          : Wardrop UE fixed point")
scenario      : braess
content hash  : cf00f411cdccec88…
links         : 5  (tail→head: 1->3, 1->4, 3->4, 3->2, 4->2)
total demand  : 6.0
task          : Wardrop UE fixed point

Run the adjustment process¶

The model contract (CONTRIBUTING.md): a model receives (scenario, budget, rng, trace) and records one checkpoint per day — here a budget iteration is a day. Everything the model writes into self_report (the per-day gap/residual, the Lyapunov value) is provenance, not a score.

bundle_trace = Trace()
model = LinkBasedDTDModel()
model.solve(scenario, Budget(iterations=800, target_relative_gap=1e-8),
            RngBundle(0), bundle_trace)
final = bundle_trace.final
print(f"model            : {model.name}")
print(f"days simulated   : {final.coords.iterations}  "
      f"({final.coords.sp_calls} shortest-path calls)")
print(f"emitted flows    : {np.round(final.link_flows, 6)}")
print(f"self-reported gap     : {final.self_report['relative_gap']:.3e}  (provenance only)")
model            : dtd-link
days simulated   : 43  (44 shortest-path calls)
emitted flows    : [4. 2. 2. 2. 4.]
self-reported gap     : 7.403e-09  (provenance only)

Certify (P1) — the fixed point AND the descent¶

The harness, never the model, computes every scored metric. Certified here: (1) the terminal flows are the Wardrop UE — relative gap → 0 with the analytic Braess anchor recomputed in-cell; (2) the day-to-day signature — Beckmann descends monotonically to 386 — plus this model’s distinctive provenance measure.

evaluator = Evaluator(scenario)
metrics = evaluator.evaluate(final.link_flows)
gap = metrics["relative_gap"]
print(f"certified relative gap : {gap:.3e}")
print(f"feasible               : {metrics['feasible']:.0f}")
assert metrics["feasible"] == 1.0
assert gap < 1e-6
# Analytic Braess UE anchor, recomputed in-cell (flows (4,2,2,2,4), every route costs 92).
ref_flows = np.array([4.0, 2.0, 2.0, 2.0, 4.0])
assert evaluator.evaluate(ref_flows)["relative_gap"] < 1e-6
assert np.allclose(final.link_flows, ref_flows, atol=1e-4)
route_time = metrics["tstt"] / scenario.demand.total
print(f"route time (TSTT/D)    : {route_time:.4f}  (analytic UE: 92)")
assert abs(route_time - 92.0) < 1e-2
# Beckmann is a Lyapunov function: monotone non-increasing to the UE value 386.
beckmann = [s.self_report["beckmann"] for s in bundle_trace]
assert all(beckmann[i] >= beckmann[i + 1] - 1e-9 for i in range(len(beckmann) - 1))
assert abs(beckmann[-1] - 386.0) < 1e-2
print(f"Beckmann descent       : {beckmann[0]:.2f} → {beckmann[-1]:.2f}  (monotone ✓)")
# Honesty diff (P1): the terminal self-reported Beckmann value against the SAME
# quantity the certificate itself computes from final.link_flows -- the Lyapunov
# claim is not backed by self-report alone.
assert np.isclose(beckmann[-1], metrics["beckmann_objective"], atol=1e-6)
# INVARIANCE (He, Guo & Liu 2010): the LINK-flow state never leaves the OD-feasible set
# Ω — node balance is at the noise floor on EVERY recorded day, not only at convergence.
worst_balance = max(
    evaluator.evaluate(s.link_flows)["node_balance_residual"] for s in bundle_trace
)
print(f"worst node-balance/day : {worst_balance:.2e}  (stays inside Ω every day)")
assert worst_balance <= 1e-6 * scenario.demand.total
certified relative gap : 7.403e-09
feasible               : 1
route time (TSTT/D)    : 92.0000  (analytic UE: 92)
Beckmann descent       : 438.00 → 386.00  (monotone ✓)
worst node-balance/day : 3.55e-15  (stays inside Ω every day)

Visualize¶

Both figures come from tabench.viz, the house visualizer — every plotted number is one certified above. Left/top: the certified terminal link flows on the network. Right/bottom: the emitted flows against the fixed point recomputed in the certify cell — points on the y = x guide mean the day-to-day process settled on it link-for-link.

# Certified terminal flows on the network (house style via tabench.viz).
display(viz.plot_network_flows(net, final.link_flows))

# Emitted flows vs the Wardrop UE recomputed above (off-diagonal == not settled).
display(viz.plot_flow_scatter(("Wardrop UE", ref_flows), {"dtd-link": final.link_flows}))
../../_images/2b71de868ec10a6ef62b7d86214034ecb6108182a42d57e782c3dd5b2580f5b2.png ../../_images/2e669cb1d024f097386c255d2c152951bfb7e79e6b7260958f12434defe4ccc3.png

Takeaways & pointers¶

  • Certified, not self-reported. The gap came from Evaluator; the per-day node-balance invariance was certified from the emitted flows, not the self-report.

  • The day-to-day signature is the point. A UE/SUE solver gives you the fixed point; a day-to-day model gives you the adjustment path to it.

  • Where next. the route-swap paradigm dtd-swap; the route-space projected gradient dtd-friesz; the lineage in the model compendium.

Next
dtd-friesz — Friesz et al.’s (1994) route-based projected dynamical system
Previous
dtd-swap-sue — Smith & Watling’s (2016) route-swap SUE dynamics
Copyright © 2026, UMN Choi Lab
Made with Sphinx and @pradyunsg's Furo
On this page
  • dtd-link — He, Guo & Liu’s (2010) link-based day-to-day dynamics
    • How this notebook is graded
    • The scenario
    • Run the adjustment process
    • Certify (P1) — the fixed point AND the descent
    • Visualize
    • Takeaways & pointers