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

ltm — Yperman’s (2007) Link Transmission Model¶

What. ltm is the Newell-Daganzo cumulative-curve loading method as a LinkModel: sending reads Newell’s shifted UPSTREAM curve L/vf ahead (the point-queue look-ahead), and receiving adds a finite backward wave — storage freed by a downstream departure reappears at the upstream end L/w later. It is STATELESS beyond the base cumulative curves (no cells, _advance_state is a no-op): the whole link is evaluated by exact interpolation of piecewise-linear curves, not a grid of cell averages.

Why it is in the benchmark. It is ctm’s cumulative-curve twin — same sending/receiving interface, same physics, but no CFL = 1 cell-alignment requirement, only a wave-resolved grid dt <= min(L/vf, L/w). On any scenario where both are exact it must reproduce ctm’s boundary curves byte-for-byte; its concrete advantage is running on grids CTMLink rejects outright. See the model compendium (Yperman 2007) and docs/design/adr-016-ltm.md (P1).

Scope. This notebook loads the same built-in triangular_bottleneck_dynamic_scenario as ctm through LTMLink, certifies it, and cross-checks the two models’ cumulative curves. It also demonstrates LTM’s grid flexibility on a link CTMLink cannot load at all.

Canon. [yperman2007link], 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 DNLEvaluator from the cumulative link curves the loader emitted, in the cell where it is claimed. LTM has no self-report to diff — like ctm, NetworkLoader.run() is a deterministic, one-shot forward simulation (README, Certified, not self-reported).

# Setup. `ltm` is a core DNL link 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 (
    CTMLink,
    DNLEvaluator,
    DynamicDemand,
    DynamicScenario,
    LinkDynamics,
    LTMLink,
    NetworkLoader,
    TimeGrid,
    triangular_bottleneck_dynamic_scenario,
    viz,
)
from tabench.core.scenario import Network

The scenario¶

The same built-in triangular_bottleneck_dynamic_scenario ctm runs on (symmetric vf = w = 1, kappa = 4, capacities [2, 0.5], arrival rate 1.5) — both link models exact on this instance, so it is the fair cross-check anchor.

scenario = triangular_bottleneck_dynamic_scenario()
net = scenario.network
edges = scenario.grid.edges
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"grid          : dt={scenario.grid.dt}, n_steps={scenario.grid.n_steps}")
print("task          : deterministic DNL loading (feasibility + conservation + shock)")
scenario      : dnl-triangular-bottleneck
content hash  : d4148843c3292e42…
links         : 2  (tail→head: 1->3, 3->2)
grid          : dt=1.0, n_steps=12
task          : deterministic DNL loading (feasibility + conservation + shock)

Load the network¶

LTMLink needs only a finite jam density — no cell-alignment requirement — so the SAME NetworkLoader contract that ran ctm runs ltm unchanged.

out = NetworkLoader(scenario, LTMLink).run()
print(f"link model        : {LTMLink.__name__}")
print(f"emitted n_in[0]    : {np.round(out.n_in[0, ::4], 3)}  (every 4th edge)")
print(f"emitted n_out[0]   : {np.round(out.n_out[0, ::4], 3)}  (every 4th edge)")
print(f"storage at t={edges[-1]:.0f}      : {out.n_in[0, -1] - out.n_out[0, -1]:.3f}")
link model        : LTMLink
emitted n_in[0]    : [ 0.  6. 12. 18.]  (every 4th edge)
emitted n_out[0]   : [0. 0. 2. 4.]  (every 4th edge)
storage at t=12      : 14.000

Certify (P1) — feasibility, conservation, and byte-exact agreement with ctm¶

Both models are exact on this symmetric FD at CFL = 1, so LTM must reproduce CTM’s cumulative curves to machine precision — this is the distinctive LTM result, recomputed here by actually RUNNING ctm again in this cell (not quoting 01-ctm’s numbers) and diffing.

metrics = DNLEvaluator(scenario).evaluate(out)
print(f"dnl_feasible            : {metrics['dnl_feasible']:.0f}")
print(f"conservation_residual   : {metrics['conservation_residual']:.3e}")
print(f"storage_residual        : {metrics['storage_residual']:.3e}")
assert metrics["dnl_feasible"] == 1.0
assert metrics["conservation_residual"] <= 1e-9
assert metrics["storage_residual"] <= 1e-9

# The RH-shock boundary anchor, recomputed from the physical parameters exactly
# as in 01-ctm.ipynb (not quoted from it).
expected_n_in = 1.5 * edges
expected_n_out = np.maximum(0.0, 0.5 * (edges - 4.0))
np.testing.assert_allclose(out.n_in[0], expected_n_in, atol=1e-9)
np.testing.assert_allclose(out.n_out[0], expected_n_out, atol=1e-9)
print("boundary curves match the recomputed RH-shock anchor exactly (atol=1e-9)")

# DISTINCTIVE: byte-exact agreement with ctm, RE-RUN here (not quoted).
ctm_out = NetworkLoader(scenario, CTMLink).run()
np.testing.assert_array_equal(out.n_in, ctm_out.n_in)
np.testing.assert_array_equal(out.n_out, ctm_out.n_out)
print("ltm reproduces ctm's cumulative curves byte-for-byte "
      f"(max diff {np.abs(out.n_in - ctm_out.n_in).max():.1f})")
dnl_feasible            : 1
conservation_residual   : 0.000e+00
storage_residual        : 0.000e+00
boundary curves match the recomputed RH-shock anchor exactly (atol=1e-9)
ltm reproduces ctm's cumulative curves byte-for-byte (max diff 0.0)

LTM’s advantage: grids ctm cannot load¶

CTMLink requires a cell-aligned length L = n * vf * dt; LTMLink only needs dt <= min(L/vf, L/w) (wave-resolved). A single link with L=3, vf=2, dt=1 gives L/vf = 1.5 — not an integer, so CTMLink refuses it outright, while LTMLink free-flow-translates it exactly via the exact cumulative-curve interpolation (recomputed here, not quoted).

unaligned_net = Network(
    name="ltm-unaligned", n_nodes=2, n_zones=2, first_thru_node=1,
    init_node=np.array([1], dtype=np.int64), term_node=np.array([2], dtype=np.int64),
    capacity=np.ones(1), length=np.zeros(1), free_flow_time=np.ones(1),
    b=np.zeros(1), power=np.ones(1), toll=np.zeros(1), link_type=np.ones(1, dtype=np.int64),
)
rates = np.zeros((1, 2, 2))
rates[0, 0, 1] = 1.0
unaligned = DynamicScenario(
    name="ltm-unaligned", network=unaligned_net,
    dynamics=LinkDynamics(
        length=np.array([3.0]), free_speed=np.array([2.0]), wave_speed=np.array([1.0]),
        jam_density=np.array([3.0]), capacity=np.array([2.0]),
    ),
    demand=DynamicDemand(breakpoints=np.array([0.0, 4.0]), rates=rates),
    grid=TimeGrid(dt=1.0, n_steps=10),
)

try:
    NetworkLoader(unaligned, CTMLink).run()
    raise AssertionError("expected CTMLink to reject the unaligned length")
except ValueError as exc:
    print(f"CTMLink refuses this link: {exc}")

u_out = NetworkLoader(unaligned, LTMLink).run()
u_edges = unaligned.grid.edges
u_expected = np.minimum(np.maximum(u_edges - 1.5, 0.0), 4.0)  # free-flow lag L/vf = 1.5
np.testing.assert_allclose(u_out.n_out[0], u_expected, atol=1e-12)
u_metrics = DNLEvaluator(unaligned).evaluate(u_out)
assert u_metrics["dnl_feasible"] == 1.0
print("LTM loads the unaligned link exactly (L/vf = 1.5 lag) where CTM cannot")
CTMLink refuses this link: CTMLink needs a cell-aligned length L = n*vf*dt (CFL = 1): L=3.0, vf*dt=2.0 give 1.5 cells, not an integer >= 1
LTM loads the unaligned link exactly (L/vf = 1.5 lag) where CTM cannot

Visualize¶

Both figures come from tabench.viz, the house visualizer. Left/top: the certified bottleneck network coloured by each link’s time-averaged flow. Right/bottom: LTM’s average flow against CTM’s — every point sits on y = x (the byte-exact agreement certified above).

T = float(edges[-1])
ltm_avg = out.n_out[:, -1] / T
ctm_avg = ctm_out.n_out[:, -1] / T

display(viz.plot_network_flows(net, ltm_avg))
display(viz.plot_flow_scatter(("ctm", ctm_avg), {"ltm": ltm_avg}))
../../_images/ddec8c84d2ac71fe5450a2b57c5ea4cd6be5ad8d1bfcd5fc47323297fa9da1de.png ../../_images/b43697177b03ac8be794d3bff44095efb4583eb53b573cccaef37732729a26e1.png

Takeaways & pointers¶

  • Certified, not self-reported. DNL link models have nothing to self-report — the boundary curves above ARE the emitted output, recertified from scratch by DNLEvaluator.

  • Exact where both are exact, flexible where ctm is not. LTM’s cumulative- curve evaluation carries no interior discretisation, so it needs no CFL = 1 cell alignment — the concrete win demonstrated above.

  • Where next. the cell-based twin ctm; the smooth non-triangular FD godunov (built on the same ctm cell update); merges/diverges node-model; the lineage in the model compendium.

Next
godunov — Lebacque’s (1996) Godunov scheme + the Greenshields FD
Previous
ctm — Daganzo’s (1994, 1995) Cell Transmission Model
Copyright © 2026, UMN Choi Lab
Made with Sphinx and @pradyunsg's Furo
On this page
  • ltm — Yperman’s (2007) Link Transmission Model
    • How this notebook is graded
    • The scenario
    • Load the network
    • Certify (P1) — feasibility, conservation, and byte-exact agreement with ctm
    • LTM’s advantage: grids ctm cannot load
    • Visualize
    • Takeaways & pointers