taplite4mpo 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. taplite4mpo-0.2.0/LICENSE +21 -0
  2. taplite4mpo-0.2.0/MANIFEST.in +19 -0
  3. taplite4mpo-0.2.0/PKG-INFO +233 -0
  4. taplite4mpo-0.2.0/README.md +197 -0
  5. taplite4mpo-0.2.0/build.sh +23 -0
  6. taplite4mpo-0.2.0/docs/ARCHITECTURE.md +116 -0
  7. taplite4mpo-0.2.0/docs/GOLDEN_PATH_CHECKLIST.md +159 -0
  8. taplite4mpo-0.2.0/dtalite_qa/__init__.py +18 -0
  9. taplite4mpo-0.2.0/dtalite_qa/__main__.py +302 -0
  10. taplite4mpo-0.2.0/dtalite_qa/accessibility.py +187 -0
  11. taplite4mpo-0.2.0/dtalite_qa/adapt.py +173 -0
  12. taplite4mpo-0.2.0/dtalite_qa/agent_tools.py +132 -0
  13. taplite4mpo-0.2.0/dtalite_qa/calibrate.py +188 -0
  14. taplite4mpo-0.2.0/dtalite_qa/columns.py +303 -0
  15. taplite4mpo-0.2.0/dtalite_qa/control.py +115 -0
  16. taplite4mpo-0.2.0/dtalite_qa/convlog.py +91 -0
  17. taplite4mpo-0.2.0/dtalite_qa/csvio.py +44 -0
  18. taplite4mpo-0.2.0/dtalite_qa/demandbin.py +95 -0
  19. taplite4mpo-0.2.0/dtalite_qa/fill.py +113 -0
  20. taplite4mpo-0.2.0/dtalite_qa/forensics.py +310 -0
  21. taplite4mpo-0.2.0/dtalite_qa/guide.py +282 -0
  22. taplite4mpo-0.2.0/dtalite_qa/intake.py +376 -0
  23. taplite4mpo-0.2.0/dtalite_qa/inventory.py +79 -0
  24. taplite4mpo-0.2.0/dtalite_qa/lrs2gmns.py +157 -0
  25. taplite4mpo-0.2.0/dtalite_qa/mag_vdf.py +49 -0
  26. taplite4mpo-0.2.0/dtalite_qa/manifest.py +230 -0
  27. taplite4mpo-0.2.0/dtalite_qa/matrixio.py +190 -0
  28. taplite4mpo-0.2.0/dtalite_qa/multiperiod.py +116 -0
  29. taplite4mpo-0.2.0/dtalite_qa/net2gmns.py +298 -0
  30. taplite4mpo-0.2.0/dtalite_qa/nexta.py +243 -0
  31. taplite4mpo-0.2.0/dtalite_qa/plf.py +209 -0
  32. taplite4mpo-0.2.0/dtalite_qa/report.py +197 -0
  33. taplite4mpo-0.2.0/dtalite_qa/scenario.py +398 -0
  34. taplite4mpo-0.2.0/dtalite_qa/schema.py +106 -0
  35. taplite4mpo-0.2.0/dtalite_qa/skim.py +83 -0
  36. taplite4mpo-0.2.0/dtalite_qa/superzone.py +94 -0
  37. taplite4mpo-0.2.0/dtalite_qa/superzone_encoders.py +88 -0
  38. taplite4mpo-0.2.0/dtalite_qa/superzone_hier.py +185 -0
  39. taplite4mpo-0.2.0/dtalite_qa/templates/mpo_submission_template.yml +58 -0
  40. taplite4mpo-0.2.0/dtalite_qa/transcad_bin.py +128 -0
  41. taplite4mpo-0.2.0/dtalite_qa/validate.py +183 -0
  42. taplite4mpo-0.2.0/dtalite_qa/vizmap.py +119 -0
  43. taplite4mpo-0.2.0/dtalite_qa/workflow.py +511 -0
  44. taplite4mpo-0.2.0/kernel/CMakeLists.txt +44 -0
  45. taplite4mpo-0.2.0/kernel/python/CMakeLists.txt +32 -0
  46. taplite4mpo-0.2.0/kernel/python/binding.cpp +42 -0
  47. taplite4mpo-0.2.0/kernel/python/build_native.sh +29 -0
  48. taplite4mpo-0.2.0/kernel/python/build_shared.sh +28 -0
  49. taplite4mpo-0.2.0/kernel/src/TAPLite.cpp +8744 -0
  50. taplite4mpo-0.2.0/kernel/src/TAPLite.h +460 -0
  51. taplite4mpo-0.2.0/pyproject.toml +64 -0
  52. taplite4mpo-0.2.0/pytaplite/README.md +48 -0
  53. taplite4mpo-0.2.0/pytaplite/__init__.py +15 -0
  54. taplite4mpo-0.2.0/pytaplite/kernel.py +183 -0
  55. taplite4mpo-0.2.0/setup.cfg +4 -0
  56. taplite4mpo-0.2.0/setup.py +84 -0
  57. taplite4mpo-0.2.0/taplite4mpo.egg-info/PKG-INFO +233 -0
  58. taplite4mpo-0.2.0/taplite4mpo.egg-info/SOURCES.txt +60 -0
  59. taplite4mpo-0.2.0/taplite4mpo.egg-info/dependency_links.txt +1 -0
  60. taplite4mpo-0.2.0/taplite4mpo.egg-info/entry_points.txt +2 -0
  61. taplite4mpo-0.2.0/taplite4mpo.egg-info/requires.txt +17 -0
  62. taplite4mpo-0.2.0/taplite4mpo.egg-info/top_level.txt +2 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Xuesong (Simon) Zhou and the DTALite/TAPLite contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,19 @@
1
+ # Files needed to BUILD the package from an sdist (the C++ kernel source + binding).
2
+ include README.md LICENSE pyproject.toml setup.py
3
+ include kernel/src/TAPLite.cpp kernel/src/TAPLite.h
4
+ include kernel/python/binding.cpp kernel/python/CMakeLists.txt
5
+ include kernel/python/build_native.sh kernel/python/build_shared.sh
6
+ include kernel/CMakeLists.txt build.sh
7
+ recursive-include dtalite_qa *.yml
8
+ include docs/ARCHITECTURE.md docs/GOLDEN_PATH_CHECKLIST.md pytaplite/README.md
9
+
10
+ # Keep the sdist small — exclude the large example / benchmark / agency data.
11
+ prune examples
12
+ prune test_networks
13
+ prune kernel/data_sets
14
+ prune nvta_run
15
+ prune private
16
+ prune .github
17
+ global-exclude *.pyc
18
+ global-exclude __pycache__/*
19
+ global-exclude *.pyd *.so *.dll *.dylib *.egg-info
@@ -0,0 +1,233 @@
1
+ Metadata-Version: 2.4
2
+ Name: taplite4mpo
3
+ Version: 0.2.0
4
+ Summary: Open C++ static traffic-assignment kernel (GMNS) for MPO/DOT models, with a Python QA/orchestration layer (dtalite_qa) and a kernel driver (pytaplite).
5
+ Author: ASU Trans-AI Lab
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/asu-trans-ai-lab/TAPLite4MPO
8
+ Project-URL: Repository, https://github.com/asu-trans-ai-lab/TAPLite4MPO
9
+ Project-URL: Documentation, https://github.com/asu-trans-ai-lab/TAPLite4MPO/blob/main/docs/ARCHITECTURE.md
10
+ Project-URL: Issues, https://github.com/asu-trans-ai-lab/TAPLite4MPO/issues
11
+ Keywords: traffic-assignment,transportation,user-equilibrium,frank-wolfe,gmns,dtalite,taplite,mpo,travel-demand-model,vdf,qvdf
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: C++
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Topic :: Scientific/Engineering
19
+ Requires-Python: >=3.8
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Provides-Extra: data
23
+ Requires-Dist: pandas; extra == "data"
24
+ Provides-Extra: science
25
+ Requires-Dist: numpy; extra == "science"
26
+ Requires-Dist: scipy; extra == "science"
27
+ Provides-Extra: gis
28
+ Requires-Dist: pyshp; extra == "gis"
29
+ Requires-Dist: pandas; extra == "gis"
30
+ Provides-Extra: all
31
+ Requires-Dist: pandas; extra == "all"
32
+ Requires-Dist: numpy; extra == "all"
33
+ Requires-Dist: scipy; extra == "all"
34
+ Requires-Dist: pyshp; extra == "all"
35
+ Dynamic: license-file
36
+
37
+ # TAPLite4MPO — open C++ static traffic assignment for MPOs
38
+
39
+ [![build-and-test](../../actions/workflows/ci.yml/badge.svg)](../../actions/workflows/ci.yml)
40
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
41
+
42
+ A single-file, reproducible **C++ (CMake) static user-equilibrium traffic-assignment
43
+ kernel** (Frank–Wolfe) for GMNS networks — with the VDF library, generalized cost,
44
+ peak-load-factor, and solver options that **MPO/DOT static highway assignments** need —
45
+ plus a Python QA/automation package, open benchmark networks, and a two-volume user
46
+ guide. Built for teaching and for reproducing agency assignments (ARC, SERPM, TRPA,
47
+ MTC, SANDAG, MWCOG, VDOT, ODOT).
48
+
49
+ ![TAPLite4MPO at a glance — the Golden Path (collect → GMNS → declare → run → validate → advanced), the three gates (can I run / trust / improve), why a shapefile is not yet a model, the dataset ladder (Sketch → Regional → ARC Atlanta → OSM), super-zone compression (~2× faster), and recovering the original-resolution zone-to-zone skim (R²=0.99).](workflow_diagram.png)
50
+
51
+ > The whole pipeline at a glance. Start with **[docs/GOLDEN_PATH_CHECKLIST.md](docs/GOLDEN_PATH_CHECKLIST.md)**.
52
+ > (Figure generated from `docs/IMAGE_PROMPTS.md`.)
53
+
54
+ > ### ⚙️ Which part solves the assignment?
55
+ > The **C++ kernel** (`bin/DTALite.exe`, `kernel/src/TAPLite.cpp`) is the **solver** —
56
+ > Frank–Wolfe equilibrium, the VDF library, OpenMP, the scale. The **`dtalite_qa` Python
57
+ > package is QA/orchestration only**: it validates inputs, builds scenarios, and *invokes* the
58
+ > kernel — **it does not compute the assignment.** So you **must build the kernel**
59
+ > (`bash build.sh`); running only Python assigns nothing. This is not a pure-Python solver.
60
+ > Full explanation, environment matrix, and how to call the kernel from Python:
61
+ > **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)**.
62
+
63
+ **Features**
64
+ - Frank–Wolfe with an exact cost-based line search; **conjugate / bi-conjugate FW**
65
+ (`assignment_method`) for faster convergence on congested networks.
66
+ - **VDF library:** BPR, modified-BPR (linear term), conical (Spiess), QVDF (queue),
67
+ BPR2, INRETS, Akcelik, SANDAG signal-delay, SCAG piecewise-BPR, SCAG ramp-meter
68
+ (`vdf_type` 0–8).
69
+ - **QVDF congestion duration** — a D/C-consistent queue output (`P`, severe-congestion
70
+ duration, queue speeds), calibrated from corridor speeds by the **CBI sister project**.
71
+ - Multiclass: per-mode demand, **VOT**, **PCE**, occupancy, per-mode toll + distance
72
+ operating cost (generalized cost), `allowed_use` (HOV/truck/managed lanes).
73
+ - **Peak-Load-Factor / period-capacity** convention (`vdf_plf = φ/L`).
74
+ - Relative-gap stop (N consecutive iters), binary demand fast-load, OpenMP parallel.
75
+
76
+ > **Start with the flagship example → [`examples/arc_atlanta/`](examples/arc_atlanta/):**
77
+ > a complete end-to-end MPO run — reproduce the Atlanta Regional Commission's AM highway
78
+ > assignment and **validate it against ARC's own count benchmark** (region %RMSE 22 %,
79
+ > target ~38 %; re-baselined 2026-07 from 23 % after the Dijkstra-default and gap-metric
80
+ > kernel updates). It shows every MPO feature wired up, with a clean ARC-requirement →
81
+ > kernel-setting mapping. Background: [`docs/mpo_spec/`](docs/mpo_spec/) (the design spec
82
+ > + multi-agency survey).
83
+
84
+ ---
85
+
86
+ ## 1. Build the kernel (the solver — required)
87
+
88
+ `bin/DTALite.exe` is the C++ engine that actually runs the assignment; the Python tools just
89
+ drive it. Build it first:
90
+ ```bash
91
+ bash build.sh # -> bin/DTALite.exe (CMake + g++/MinGW, OpenMP, Release)
92
+ ```
93
+ Requires CMake, a C++17 compiler (g++/clang/MSVC), and OpenMP. Output: `bin/DTALite.exe`.
94
+ (See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for why this is mandatory.)
95
+
96
+ ### Install the Python packages
97
+ ```bash
98
+ pip install . # installs dtalite_qa + pytaplite; compiles the in-process kernel binding
99
+ ```
100
+ This builds `pytaplite._native` from the bundled kernel source (falls back to subprocess if no
101
+ compiler). Multi-platform PyPI wheels (`pip install taplite4mpo`) are produced by cibuildwheel
102
+ on a version tag — see **[RELEASE.md](RELEASE.md)**.
103
+
104
+ Then call the kernel from Python:
105
+ ```python
106
+ import pytaplite
107
+ r = pytaplite.assign("kernel/data_sets/02_Sioux_Falls") # runs the C++ kernel
108
+ print(r.summary()) # links, VMT, VHT, returncode
109
+ ```
110
+ Runnable demo: **[`examples/pytaplite_quickstart.py`](examples/pytaplite_quickstart.py)**
111
+ (`python examples/pytaplite_quickstart.py`).
112
+
113
+ ## 2. Reproduce a run (open benchmark networks — no extra data needed)
114
+
115
+ ```bash
116
+ cd kernel/data_sets/02_Sioux_Falls # or 03_chicago_sketch, 04_chicago_regional
117
+ cp ../../../bin/DTALite.exe .
118
+ ./DTALite.exe # reads node/link/demand/settings, writes link_performance.csv
119
+ ```
120
+
121
+ Or via the Python QA wrapper (validates inputs first, then runs):
122
+ ```bash
123
+ pip install -e .
124
+ python -m dtalite_qa run kernel/data_sets/02_Sioux_Falls --exe bin/DTALite.exe
125
+ ```
126
+
127
+ ## 3. Regression / self-test
128
+
129
+ ```bash
130
+ python test_networks/run_regression.py # builds & checks BPR/conic/QVDF, multimodal, turn restrictions
131
+ ```
132
+
133
+ ---
134
+
135
+ ## 4. Documentation
136
+ - **[HANDOFF/](HANDOFF/)** — ⭐ **new engineer? start here.** The onboarding & handoff folder:
137
+ the ordered reading path, the runs to reproduce, the "which agency taught us this" issue
138
+ index, a **[BPR/VDF/PLF config-rules card](HANDOFF/BPR_AND_VDF_CONFIG_RULES.md)**, and a
139
+ **[hands-on lab](HANDOFF/REPRODUCE_THE_ISSUES.md)** that trips each classic conversion error
140
+ on the open networks so you learn to recognize it.
141
+ - **[docs/CONVERSION_ERRORS_CATALOG.md](docs/CONVERSION_ERRORS_CATALOG.md)** — the
142
+ **lessons-learned / error-source** reference: every way an MPO hand-off goes wrong
143
+ (capacity, PLF, units, demand, zones, VDF, truncation, allowed-use, count basis, build),
144
+ symptom → cause → fix → *which agency*.
145
+ - **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)** — **the C++ kernel solves; the Python
146
+ package orchestrates.** Which part runs what, the environment matrix, and how to call the
147
+ kernel from Python. Read it if you're unsure what's doing the assignment.
148
+ - **[docs/GOLDEN_PATH_CHECKLIST.md](docs/GOLDEN_PATH_CHECKLIST.md)** — ⭐ **READ THIS FIRST.**
149
+ The Golden Path: from agency files to a trusted assignment, in 6 stages, framed by three
150
+ questions — *can I run? can I trust it? can I improve it?* Simple first, advanced later.
151
+ - **[docs/DATASET_LADDER.md](docs/DATASET_LADDER.md)** — which example to start with
152
+ (Chicago Sketch → Chicago Regional → ARC Atlanta → OSM quick start).
153
+ - **[docs/onboarding_guide.html](docs/onboarding_guide.html)** — **the visual onboarding guide**:
154
+ open in a browser for the staged journey (GIS field-map → declare → convert → intake →
155
+ quality → run → traceable workflow), each with its gate and a progress tracker. Generate
156
+ it anytime with `python -m dtalite_qa guide`.
157
+ - **[docs/MPO_ONBOARDING_GUIDE.md](docs/MPO_ONBOARDING_GUIDE.md)** — **start here for a new
158
+ agency model.** The process to turn a raw hand-off (shapefile + matrix + "alpha/beta")
159
+ into a trustworthy run: declare → convert → **intake audit** → resolve → validate. The
160
+ intake (`dtalite_qa intake`) never guesses a convention — it blocks on anything the MPO
161
+ didn't declare (capacity basis/period, PLF, units, trip kind) and produces an issue
162
+ report + conversion log + a guided HTML dashboard. The MPO fills
163
+ [`submission.yml`](dtalite_qa/templates/mpo_submission_template.yml) (the README for the
164
+ data; ARC's is in `examples/arc_atlanta/gmns/`).
165
+ - **[USER_GUIDE.md](USER_GUIDE.md)** — Volume 1: kernel reference (input schema, settings,
166
+ VDFs, outputs).
167
+ - **[USER_GUIDE_VOL2_MPO.md](USER_GUIDE_VOL2_MPO.md)** — Volume 2: static highway assignment
168
+ for MPOs (period capacity / PLF, generalized cost, convergence/solver, validation,
169
+ per-agency recipes).
170
+ - `examples/arc_atlanta/` — **complete worked MPO example** (ARC AM assignment, calibrate
171
+ → run → validate vs the agency benchmark) with the ARC→kernel mapping.
172
+ - `docs/mpo_spec/` — design spec + **multi-agency survey/conformance** (ARC, SERPM, TRPA,
173
+ MTC, SANDAG, MWCOG, VDOT, ODOT): requirement → kernel feature → how to verify.
174
+ - `docs/qvdf_congestion_duration.md` — QVDF as the D/C-consistent congestion-**duration**
175
+ output, and the **CBI sister-project pipeline** (corridor speeds → QVDF params → kernel).
176
+ - `docs/` — methodology notes (peak load factor, super-zone aggregation, 4-step
177
+ integration, OD-compression operators).
178
+ - `docs/IMAGE_PROMPTS.md` — copy-paste prompts for GPT image tools to generate the
179
+ easy-to-follow figures (Golden Path, the 3 gates, super-zones, the skim advantage).
180
+ - `.claude/skills/taplite4mpo-pipeline/` — a Claude Code **skill** encoding the whole
181
+ pipeline (gates, stages, conventions, the ARC loop) for agent-assisted work in this repo.
182
+ - `dtalite_qa/` — Python package: `guide`, `intake`, `workflow`, `validate`, `fill`, `inventory`,
183
+ `accessibility`, `report`, `demand-bin`, `plf`, `adapt`, `run` (see `python -m dtalite_qa -h`).
184
+ - **[`pytaplite/`](pytaplite/)** — Python interface that **drives the C++ kernel**:
185
+ `pytaplite.assign(scenario)` → runs `DTALite.exe`, returns `link_performance` (subprocess, or
186
+ the in-process `_native` binding from [`kernel/python/`](kernel/python/) if built).
187
+
188
+ ## 5. Folder map
189
+ ```
190
+ TAPLite4MPO/
191
+ ├── kernel/ C++ kernel (src/TAPLite.cpp, CMakeLists.txt) + open data_sets/
192
+ ├── examples/
193
+ │ └── arc_atlanta/ complete end-to-end MPO example (ARC AM, validated)
194
+ ├── dtalite_qa/ Python QA / control package
195
+ ├── test_networks/ open test/benchmark networks + regression harness
196
+ ├── schemas/ GMNS field schema (JSON)
197
+ ├── docs/ methodology docs
198
+ │ └── mpo_spec/ design spec + multi-agency survey & conformance mapping
199
+ ├── nvta_run/ NVTA run-configs + helper scripts (bring-your-own-data, §6)
200
+ ├── USER_GUIDE.md Volume 1 (kernel)
201
+ ├── USER_GUIDE_VOL2_MPO.md Volume 2 (MPOs)
202
+ └── build.sh
203
+ ```
204
+
205
+ ## 6. NVTA reproduction (bring-your-own-data)
206
+
207
+ The **NVTA dataset is agency-restricted and is NOT included** in this repository.
208
+ `nvta_run/` ships the run-configs and helper scripts (network prep, settings, conic/QVDF
209
+ staging). To run it, point the scripts at your own copy of the data:
210
+
211
+ ```bash
212
+ # option A: environment variable
213
+ export DTALITE_NVTA_INTERNAL=/path/to/nvta/_internal
214
+ # option B: nvta_run/local_config.json -> {"internal": "...", "subarea": "..."}
215
+ # option C: place the data in data/nvta_internal/
216
+ python nvta_run/run_nvta.py
217
+ ```
218
+ If unconfigured, the runner prints a clear message. **All of §2–§3 reproduces fully
219
+ without it** using the open benchmark networks.
220
+
221
+ > Course note: instructors distribute the NVTA data to students through a separate
222
+ > channel (not this public repo); students set one of the options above.
223
+
224
+ ---
225
+
226
+ ## Continuous integration
227
+ `.github/workflows/ci.yml` builds the kernel (CMake + MSVC on `windows-latest`) and runs
228
+ the full regression suite on every push / pull request.
229
+
230
+ ## License & citation
231
+ **MIT** — see `LICENSE`. If you use this kernel in research or coursework, please cite the
232
+ DTALite / TAPLite project. (Some `docs/` notes reference internal companion files that are
233
+ not part of this public release.)
@@ -0,0 +1,197 @@
1
+ # TAPLite4MPO — open C++ static traffic assignment for MPOs
2
+
3
+ [![build-and-test](../../actions/workflows/ci.yml/badge.svg)](../../actions/workflows/ci.yml)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
5
+
6
+ A single-file, reproducible **C++ (CMake) static user-equilibrium traffic-assignment
7
+ kernel** (Frank–Wolfe) for GMNS networks — with the VDF library, generalized cost,
8
+ peak-load-factor, and solver options that **MPO/DOT static highway assignments** need —
9
+ plus a Python QA/automation package, open benchmark networks, and a two-volume user
10
+ guide. Built for teaching and for reproducing agency assignments (ARC, SERPM, TRPA,
11
+ MTC, SANDAG, MWCOG, VDOT, ODOT).
12
+
13
+ ![TAPLite4MPO at a glance — the Golden Path (collect → GMNS → declare → run → validate → advanced), the three gates (can I run / trust / improve), why a shapefile is not yet a model, the dataset ladder (Sketch → Regional → ARC Atlanta → OSM), super-zone compression (~2× faster), and recovering the original-resolution zone-to-zone skim (R²=0.99).](workflow_diagram.png)
14
+
15
+ > The whole pipeline at a glance. Start with **[docs/GOLDEN_PATH_CHECKLIST.md](docs/GOLDEN_PATH_CHECKLIST.md)**.
16
+ > (Figure generated from `docs/IMAGE_PROMPTS.md`.)
17
+
18
+ > ### ⚙️ Which part solves the assignment?
19
+ > The **C++ kernel** (`bin/DTALite.exe`, `kernel/src/TAPLite.cpp`) is the **solver** —
20
+ > Frank–Wolfe equilibrium, the VDF library, OpenMP, the scale. The **`dtalite_qa` Python
21
+ > package is QA/orchestration only**: it validates inputs, builds scenarios, and *invokes* the
22
+ > kernel — **it does not compute the assignment.** So you **must build the kernel**
23
+ > (`bash build.sh`); running only Python assigns nothing. This is not a pure-Python solver.
24
+ > Full explanation, environment matrix, and how to call the kernel from Python:
25
+ > **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)**.
26
+
27
+ **Features**
28
+ - Frank–Wolfe with an exact cost-based line search; **conjugate / bi-conjugate FW**
29
+ (`assignment_method`) for faster convergence on congested networks.
30
+ - **VDF library:** BPR, modified-BPR (linear term), conical (Spiess), QVDF (queue),
31
+ BPR2, INRETS, Akcelik, SANDAG signal-delay, SCAG piecewise-BPR, SCAG ramp-meter
32
+ (`vdf_type` 0–8).
33
+ - **QVDF congestion duration** — a D/C-consistent queue output (`P`, severe-congestion
34
+ duration, queue speeds), calibrated from corridor speeds by the **CBI sister project**.
35
+ - Multiclass: per-mode demand, **VOT**, **PCE**, occupancy, per-mode toll + distance
36
+ operating cost (generalized cost), `allowed_use` (HOV/truck/managed lanes).
37
+ - **Peak-Load-Factor / period-capacity** convention (`vdf_plf = φ/L`).
38
+ - Relative-gap stop (N consecutive iters), binary demand fast-load, OpenMP parallel.
39
+
40
+ > **Start with the flagship example → [`examples/arc_atlanta/`](examples/arc_atlanta/):**
41
+ > a complete end-to-end MPO run — reproduce the Atlanta Regional Commission's AM highway
42
+ > assignment and **validate it against ARC's own count benchmark** (region %RMSE 22 %,
43
+ > target ~38 %; re-baselined 2026-07 from 23 % after the Dijkstra-default and gap-metric
44
+ > kernel updates). It shows every MPO feature wired up, with a clean ARC-requirement →
45
+ > kernel-setting mapping. Background: [`docs/mpo_spec/`](docs/mpo_spec/) (the design spec
46
+ > + multi-agency survey).
47
+
48
+ ---
49
+
50
+ ## 1. Build the kernel (the solver — required)
51
+
52
+ `bin/DTALite.exe` is the C++ engine that actually runs the assignment; the Python tools just
53
+ drive it. Build it first:
54
+ ```bash
55
+ bash build.sh # -> bin/DTALite.exe (CMake + g++/MinGW, OpenMP, Release)
56
+ ```
57
+ Requires CMake, a C++17 compiler (g++/clang/MSVC), and OpenMP. Output: `bin/DTALite.exe`.
58
+ (See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for why this is mandatory.)
59
+
60
+ ### Install the Python packages
61
+ ```bash
62
+ pip install . # installs dtalite_qa + pytaplite; compiles the in-process kernel binding
63
+ ```
64
+ This builds `pytaplite._native` from the bundled kernel source (falls back to subprocess if no
65
+ compiler). Multi-platform PyPI wheels (`pip install taplite4mpo`) are produced by cibuildwheel
66
+ on a version tag — see **[RELEASE.md](RELEASE.md)**.
67
+
68
+ Then call the kernel from Python:
69
+ ```python
70
+ import pytaplite
71
+ r = pytaplite.assign("kernel/data_sets/02_Sioux_Falls") # runs the C++ kernel
72
+ print(r.summary()) # links, VMT, VHT, returncode
73
+ ```
74
+ Runnable demo: **[`examples/pytaplite_quickstart.py`](examples/pytaplite_quickstart.py)**
75
+ (`python examples/pytaplite_quickstart.py`).
76
+
77
+ ## 2. Reproduce a run (open benchmark networks — no extra data needed)
78
+
79
+ ```bash
80
+ cd kernel/data_sets/02_Sioux_Falls # or 03_chicago_sketch, 04_chicago_regional
81
+ cp ../../../bin/DTALite.exe .
82
+ ./DTALite.exe # reads node/link/demand/settings, writes link_performance.csv
83
+ ```
84
+
85
+ Or via the Python QA wrapper (validates inputs first, then runs):
86
+ ```bash
87
+ pip install -e .
88
+ python -m dtalite_qa run kernel/data_sets/02_Sioux_Falls --exe bin/DTALite.exe
89
+ ```
90
+
91
+ ## 3. Regression / self-test
92
+
93
+ ```bash
94
+ python test_networks/run_regression.py # builds & checks BPR/conic/QVDF, multimodal, turn restrictions
95
+ ```
96
+
97
+ ---
98
+
99
+ ## 4. Documentation
100
+ - **[HANDOFF/](HANDOFF/)** — ⭐ **new engineer? start here.** The onboarding & handoff folder:
101
+ the ordered reading path, the runs to reproduce, the "which agency taught us this" issue
102
+ index, a **[BPR/VDF/PLF config-rules card](HANDOFF/BPR_AND_VDF_CONFIG_RULES.md)**, and a
103
+ **[hands-on lab](HANDOFF/REPRODUCE_THE_ISSUES.md)** that trips each classic conversion error
104
+ on the open networks so you learn to recognize it.
105
+ - **[docs/CONVERSION_ERRORS_CATALOG.md](docs/CONVERSION_ERRORS_CATALOG.md)** — the
106
+ **lessons-learned / error-source** reference: every way an MPO hand-off goes wrong
107
+ (capacity, PLF, units, demand, zones, VDF, truncation, allowed-use, count basis, build),
108
+ symptom → cause → fix → *which agency*.
109
+ - **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)** — **the C++ kernel solves; the Python
110
+ package orchestrates.** Which part runs what, the environment matrix, and how to call the
111
+ kernel from Python. Read it if you're unsure what's doing the assignment.
112
+ - **[docs/GOLDEN_PATH_CHECKLIST.md](docs/GOLDEN_PATH_CHECKLIST.md)** — ⭐ **READ THIS FIRST.**
113
+ The Golden Path: from agency files to a trusted assignment, in 6 stages, framed by three
114
+ questions — *can I run? can I trust it? can I improve it?* Simple first, advanced later.
115
+ - **[docs/DATASET_LADDER.md](docs/DATASET_LADDER.md)** — which example to start with
116
+ (Chicago Sketch → Chicago Regional → ARC Atlanta → OSM quick start).
117
+ - **[docs/onboarding_guide.html](docs/onboarding_guide.html)** — **the visual onboarding guide**:
118
+ open in a browser for the staged journey (GIS field-map → declare → convert → intake →
119
+ quality → run → traceable workflow), each with its gate and a progress tracker. Generate
120
+ it anytime with `python -m dtalite_qa guide`.
121
+ - **[docs/MPO_ONBOARDING_GUIDE.md](docs/MPO_ONBOARDING_GUIDE.md)** — **start here for a new
122
+ agency model.** The process to turn a raw hand-off (shapefile + matrix + "alpha/beta")
123
+ into a trustworthy run: declare → convert → **intake audit** → resolve → validate. The
124
+ intake (`dtalite_qa intake`) never guesses a convention — it blocks on anything the MPO
125
+ didn't declare (capacity basis/period, PLF, units, trip kind) and produces an issue
126
+ report + conversion log + a guided HTML dashboard. The MPO fills
127
+ [`submission.yml`](dtalite_qa/templates/mpo_submission_template.yml) (the README for the
128
+ data; ARC's is in `examples/arc_atlanta/gmns/`).
129
+ - **[USER_GUIDE.md](USER_GUIDE.md)** — Volume 1: kernel reference (input schema, settings,
130
+ VDFs, outputs).
131
+ - **[USER_GUIDE_VOL2_MPO.md](USER_GUIDE_VOL2_MPO.md)** — Volume 2: static highway assignment
132
+ for MPOs (period capacity / PLF, generalized cost, convergence/solver, validation,
133
+ per-agency recipes).
134
+ - `examples/arc_atlanta/` — **complete worked MPO example** (ARC AM assignment, calibrate
135
+ → run → validate vs the agency benchmark) with the ARC→kernel mapping.
136
+ - `docs/mpo_spec/` — design spec + **multi-agency survey/conformance** (ARC, SERPM, TRPA,
137
+ MTC, SANDAG, MWCOG, VDOT, ODOT): requirement → kernel feature → how to verify.
138
+ - `docs/qvdf_congestion_duration.md` — QVDF as the D/C-consistent congestion-**duration**
139
+ output, and the **CBI sister-project pipeline** (corridor speeds → QVDF params → kernel).
140
+ - `docs/` — methodology notes (peak load factor, super-zone aggregation, 4-step
141
+ integration, OD-compression operators).
142
+ - `docs/IMAGE_PROMPTS.md` — copy-paste prompts for GPT image tools to generate the
143
+ easy-to-follow figures (Golden Path, the 3 gates, super-zones, the skim advantage).
144
+ - `.claude/skills/taplite4mpo-pipeline/` — a Claude Code **skill** encoding the whole
145
+ pipeline (gates, stages, conventions, the ARC loop) for agent-assisted work in this repo.
146
+ - `dtalite_qa/` — Python package: `guide`, `intake`, `workflow`, `validate`, `fill`, `inventory`,
147
+ `accessibility`, `report`, `demand-bin`, `plf`, `adapt`, `run` (see `python -m dtalite_qa -h`).
148
+ - **[`pytaplite/`](pytaplite/)** — Python interface that **drives the C++ kernel**:
149
+ `pytaplite.assign(scenario)` → runs `DTALite.exe`, returns `link_performance` (subprocess, or
150
+ the in-process `_native` binding from [`kernel/python/`](kernel/python/) if built).
151
+
152
+ ## 5. Folder map
153
+ ```
154
+ TAPLite4MPO/
155
+ ├── kernel/ C++ kernel (src/TAPLite.cpp, CMakeLists.txt) + open data_sets/
156
+ ├── examples/
157
+ │ └── arc_atlanta/ complete end-to-end MPO example (ARC AM, validated)
158
+ ├── dtalite_qa/ Python QA / control package
159
+ ├── test_networks/ open test/benchmark networks + regression harness
160
+ ├── schemas/ GMNS field schema (JSON)
161
+ ├── docs/ methodology docs
162
+ │ └── mpo_spec/ design spec + multi-agency survey & conformance mapping
163
+ ├── nvta_run/ NVTA run-configs + helper scripts (bring-your-own-data, §6)
164
+ ├── USER_GUIDE.md Volume 1 (kernel)
165
+ ├── USER_GUIDE_VOL2_MPO.md Volume 2 (MPOs)
166
+ └── build.sh
167
+ ```
168
+
169
+ ## 6. NVTA reproduction (bring-your-own-data)
170
+
171
+ The **NVTA dataset is agency-restricted and is NOT included** in this repository.
172
+ `nvta_run/` ships the run-configs and helper scripts (network prep, settings, conic/QVDF
173
+ staging). To run it, point the scripts at your own copy of the data:
174
+
175
+ ```bash
176
+ # option A: environment variable
177
+ export DTALITE_NVTA_INTERNAL=/path/to/nvta/_internal
178
+ # option B: nvta_run/local_config.json -> {"internal": "...", "subarea": "..."}
179
+ # option C: place the data in data/nvta_internal/
180
+ python nvta_run/run_nvta.py
181
+ ```
182
+ If unconfigured, the runner prints a clear message. **All of §2–§3 reproduces fully
183
+ without it** using the open benchmark networks.
184
+
185
+ > Course note: instructors distribute the NVTA data to students through a separate
186
+ > channel (not this public repo); students set one of the options above.
187
+
188
+ ---
189
+
190
+ ## Continuous integration
191
+ `.github/workflows/ci.yml` builds the kernel (CMake + MSVC on `windows-latest`) and runs
192
+ the full regression suite on every push / pull request.
193
+
194
+ ## License & citation
195
+ **MIT** — see `LICENSE`. If you use this kernel in research or coursework, please cite the
196
+ DTALite / TAPLite project. (Some `docs/` notes reference internal companion files that are
197
+ not part of this public release.)
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env bash
2
+ # Canonical build for the consolidated DTALite/TAPLite C++ kernel.
3
+ # Self-contained: builds kernel/src/TAPLite.cpp -> bin/DTALite.exe via CMake.
4
+ #
5
+ # Output: a stripped Release standalone executable (App-Control-clean, ~1.5 MB).
6
+ # For gdb source debugging, turn OFF Windows Smart App Control, then build with
7
+ # -DCMAKE_BUILD_TYPE=RelWithDebInfo (larger binary, App Control may block it).
8
+ set -e
9
+ export PATH="/c/Users/xzhou/AppData/Local/Microsoft/WinGet/Packages/BrechtSanders.WinLibs.POSIX.UCRT_Microsoft.Winget.Source_8wekyb3d8bbwe/mingw64/bin:$PATH"
10
+ HERE="$(cd "$(dirname "$0")" && pwd)"
11
+ SRC="$HERE/kernel"
12
+ BUILD="$HERE/cmake_build_rel"
13
+ mkdir -p "$HERE/bin"
14
+ echo "[build] configure (Release, stripped, exe target)"
15
+ cmake -S "$SRC" -B "$BUILD" -G Ninja \
16
+ -DCMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++.exe \
17
+ -DCMAKE_BUILD_TYPE=Release \
18
+ -DCMAKE_CXX_FLAGS="-fopenmp -O2 -DNDEBUG" \
19
+ -DCMAKE_EXE_LINKER_FLAGS="-s" >/dev/null
20
+ echo "[build] build DTALite_exe"
21
+ cmake --build "$BUILD" --target DTALite_exe
22
+ cp "$BUILD/DTALite_exe.exe" "$HERE/bin/DTALite.exe"
23
+ echo "[build] kernel -> $HERE/bin/DTALite.exe ($(stat -c%s "$HERE/bin/DTALite.exe") bytes)"
@@ -0,0 +1,116 @@
1
+ # Architecture — what actually solves the assignment
2
+
3
+ **Read this if you're unsure which part does the work.** TAPLite4MPO is **two layers**, and it
4
+ matters which one you're using:
5
+
6
+ ```
7
+ ┌──────────────────────────────────────────────────────────────────┐
8
+ │ dtalite_qa (Python package) — QA / orchestration ONLY │
9
+ │ validates inputs · fills defaults · intake audit · builds │
10
+ │ scenarios · runs the R1-R6 workflow · super-zones · skims │
11
+ │ >>> it does NOT solve the assignment <<< │
12
+ └───────────────────────────────┬──────────────────────────────────┘
13
+ │ prepares CSVs, then invokes ↓ (subprocess)
14
+ ┌───────────────────────────────▼──────────────────────────────────┐
15
+ │ THE KERNEL (C++17, bin/DTALite.exe) — the SOLVER / engine │
16
+ │ reads node/link/demand/settings CSV → Frank-Wolfe / conjugate / │
17
+ │ bi-conjugate user equilibrium (OpenMP, scalable) → writes │
18
+ │ link_performance.csv (volumes, V/C, speed, VMT/VHT, QVDF) │
19
+ └──────────────────────────────────────────────────────────────────┘
20
+ ```
21
+
22
+ **The C++ kernel is the engine.** All assignment math, the VDF library, the line search, the
23
+ parallelism, and the scale live in `kernel/src/TAPLite.cpp`. The Python package is a
24
+ *controller*: it never computes an equilibrium — it prepares the inputs the kernel reads and
25
+ then **shells out to `DTALite.exe`** (`dtalite_qa/control.py` → `subprocess.run`). If you run
26
+ only Python and never build the kernel, **nothing is assigned.** This is also why
27
+ `python -m dtalite_qa run` **requires `--exe`**, and why it now fails loudly with a pointer
28
+ here if the kernel binary is missing.
29
+
30
+ > Not the same as a pure-Python solver. Some traffic-assignment tools are entirely Python; this
31
+ > one is not. Python is the convenience/QA layer; the **C++ kernel does the assignment** and is
32
+ > what makes it scalable to a 145k-link / 6k-zone network in minutes.
33
+
34
+ ---
35
+
36
+ ## Two ways to run — and which environment each needs
37
+
38
+ | Path | What runs | You need |
39
+ |---|---|---|
40
+ | **A. Kernel directly** | the C++ solver only | a built `DTALite.exe`; nothing else |
41
+ | **B. Python-orchestrated** (recommended) | Python validates/builds, then calls the kernel | Python 3.8+ **and** a built `DTALite.exe` |
42
+
43
+ **A — run the kernel directly** (no Python at all):
44
+ ```bash
45
+ cd kernel/data_sets/03_chicago_sketch
46
+ cp ../../../bin/DTALite.exe .
47
+ ./DTALite.exe # reads the CSVs here, writes link_performance.csv
48
+ ```
49
+
50
+ **B — Python orchestrates the kernel** (QA gate first, then the same kernel):
51
+ ```bash
52
+ pip install -e .
53
+ python -m dtalite_qa run <scenario> --exe bin/DTALite.exe
54
+ # = validate inputs → fill defaults → invoke DTALite.exe → check outputs
55
+ ```
56
+ Either way **the C++ kernel does the assignment.** Path B just wraps it with validation and
57
+ reporting.
58
+
59
+ ## Environment requirements
60
+
61
+ | To do this | You need |
62
+ |---|---|
63
+ | **Build the kernel** (once) | a C++17 compiler (g++/clang/MSVC) + CMake + OpenMP — `bash build.sh` → `bin/DTALite.exe` |
64
+ | Run the kernel | the built `DTALite.exe` (Windows/Linux/macOS); no runtime deps |
65
+ | Use `dtalite_qa` (intake/check/run/workflow/guide) | Python 3.8+ (standard library only) |
66
+ | Drive the kernel from Python (`pytaplite`) | Python 3.8+ (+ `pandas` for `to_pandas`) + a built `DTALite.exe` |
67
+ | Build the **native in-process binding** (optional) | `pybind11` + the C++ toolchain — `bash kernel/python/build_native.sh` |
68
+ | Super-zone encoders / skim recovery | Python + `numpy`, `scipy` (and `scikit-learn` for `demand_kmeans`) |
69
+ | Read agency shapefiles in the example converters | `pyshp` / `pyogrio` / `pandas` (provenance scripts only) |
70
+
71
+ CI (`.github/workflows/ci.yml`) builds the kernel with MSVC on `windows-latest` and runs the
72
+ regression — proof the C++ layer is the thing under test.
73
+
74
+ ## Calling the C++ kernel from Python — two ways, both shipped
75
+
76
+ **1. `pytaplite` — the clean Python interface (recommended).**
77
+ ```python
78
+ import pytaplite
79
+ r = pytaplite.assign("examples/arc_atlanta/gmns_calibrated") # runs the C++ kernel
80
+ print(r.summary()) # {'links': ..., 'total_VMT': ..., 'returncode': 0}
81
+ df = r.to_pandas() # link_performance as a DataFrame
82
+ ```
83
+ It locates the binary, runs the assignment, and loads `link_performance.csv` back. It picks
84
+ the fastest of three execution paths automatically (all call the same C++ kernel):
85
+
86
+ **2. ctypes shared library — the Path4GMNS / DTALite pattern (in-process, no pybind11).**
87
+ The kernel exports the C-ABI symbols `DTA_AssignmentAPI()` / `DTA_SimulationAPI()`
88
+ (`extern "C"` in `kernel/src/TAPLite.h`), so it builds as a shared library that Python loads
89
+ with stdlib **`ctypes`** — exactly how [Path4GMNS](https://github.com/jdlph/Path4GMNS) ships
90
+ the `DTALite` engine:
91
+ ```bash
92
+ bash kernel/python/build_shared.sh # -> pytaplite/DTALite.dll | libDTALite.so | libDTALite.dylib
93
+ ```
94
+ `pytaplite.assign(...)` then loads it and calls `DTA_AssignmentAPI()` **in-process**. (CMake's
95
+ `add_library(DTALite SHARED ...)` target builds the same library.)
96
+
97
+ **3. pybind11 binding — `pytaplite._native` (alternative in-process; releases the GIL).**
98
+ `pip install pybind11 && bash kernel/python/build_native.sh`.
99
+
100
+ **Caveat (both in-process paths):** the kernel keeps global state, so run **one assignment
101
+ per process**; for many runs use a fresh `work_dir` per call, `multiprocessing`, or
102
+ `prefer_inproc=False` to use the subprocess path. The shared lib / native module are optional
103
+ and git-ignored; **subprocess works with no library build.**
104
+
105
+ Lowest level — just launch the binary yourself (any language can):
106
+ ```python
107
+ import subprocess
108
+ subprocess.run(["bin/DTALite.exe"], cwd="my_scenario") # the solver, in that folder
109
+ ```
110
+
111
+ The kernel is a **self-contained binary**, deliberately: it stays fast and dependency-free,
112
+
113
+ ## Where each part lives
114
+ - `kernel/src/TAPLite.cpp`, `kernel/CMakeLists.txt`, `build.sh` — **the solver**.
115
+ - `dtalite_qa/` — the Python controller (`control.py` is where it invokes the kernel).
116
+ - `examples/`, `test_networks/`, `kernel/data_sets/` — inputs the kernel reads.