gmnsopt 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 (59) hide show
  1. gmnsopt-0.2.0/LICENSE +21 -0
  2. gmnsopt-0.2.0/PKG-INFO +149 -0
  3. gmnsopt-0.2.0/README.md +119 -0
  4. gmnsopt-0.2.0/pyproject.toml +36 -0
  5. gmnsopt-0.2.0/setup.cfg +4 -0
  6. gmnsopt-0.2.0/src/gmns_opt/__init__.py +17 -0
  7. gmnsopt-0.2.0/src/gmns_opt/applications/__init__.py +27 -0
  8. gmnsopt-0.2.0/src/gmns_opt/benchmark/__init__.py +4 -0
  9. gmnsopt-0.2.0/src/gmns_opt/benchmark/case.py +84 -0
  10. gmnsopt-0.2.0/src/gmns_opt/benchmark/registry.py +129 -0
  11. gmnsopt-0.2.0/src/gmns_opt/benchmark/report.py +44 -0
  12. gmnsopt-0.2.0/src/gmns_opt/cli.py +86 -0
  13. gmnsopt-0.2.0/src/gmns_opt/io/__init__.py +6 -0
  14. gmnsopt-0.2.0/src/gmns_opt/io/build_graph.py +36 -0
  15. gmnsopt-0.2.0/src/gmns_opt/io/read_gmns.py +88 -0
  16. gmnsopt-0.2.0/src/gmns_opt/io/validate_gmns.py +33 -0
  17. gmnsopt-0.2.0/src/gmns_opt/ml/__init__.py +8 -0
  18. gmnsopt-0.2.0/src/gmns_opt/ml/branching_dataset.py +29 -0
  19. gmnsopt-0.2.0/src/gmns_opt/ml/features.py +39 -0
  20. gmnsopt-0.2.0/src/gmns_opt/ml/warm_start.py +30 -0
  21. gmnsopt-0.2.0/src/gmns_opt/models/__init__.py +31 -0
  22. gmnsopt-0.2.0/src/gmns_opt/models/accessibility.py +43 -0
  23. gmnsopt-0.2.0/src/gmns_opt/models/facility_location.py +73 -0
  24. gmnsopt-0.2.0/src/gmns_opt/models/max_flow.py +36 -0
  25. gmnsopt-0.2.0/src/gmns_opt/models/min_cost_flow.py +46 -0
  26. gmnsopt-0.2.0/src/gmns_opt/models/multimodal_skeleton.py +40 -0
  27. gmnsopt-0.2.0/src/gmns_opt/models/network_design.py +66 -0
  28. gmnsopt-0.2.0/src/gmns_opt/models/odme.py +86 -0
  29. gmnsopt-0.2.0/src/gmns_opt/models/resilience.py +61 -0
  30. gmnsopt-0.2.0/src/gmns_opt/models/shortest_path.py +32 -0
  31. gmnsopt-0.2.0/src/gmns_opt/models/signal_timing.py +45 -0
  32. gmnsopt-0.2.0/src/gmns_opt/models/system_optimal.py +79 -0
  33. gmnsopt-0.2.0/src/gmns_opt/models/traffic_assignment.py +95 -0
  34. gmnsopt-0.2.0/src/gmns_opt/scenarios/__init__.py +3 -0
  35. gmnsopt-0.2.0/src/gmns_opt/scenarios/generator.py +50 -0
  36. gmnsopt-0.2.0/src/gmns_opt/solvers/__init__.py +19 -0
  37. gmnsopt-0.2.0/src/gmns_opt/solvers/base.py +20 -0
  38. gmnsopt-0.2.0/src/gmns_opt/solvers/commercial_placeholder.py +15 -0
  39. gmnsopt-0.2.0/src/gmns_opt/solvers/networkx_solver.py +13 -0
  40. gmnsopt-0.2.0/src/gmns_opt/solvers/neural_placeholder.py +15 -0
  41. gmnsopt-0.2.0/src/gmns_opt/solvers/ortools_adapter.py +13 -0
  42. gmnsopt-0.2.0/src/gmns_opt/solvers/scipy_highs.py +14 -0
  43. gmnsopt-0.2.0/src/gmns_opt/tensor/__init__.py +12 -0
  44. gmnsopt-0.2.0/src/gmns_opt/tensor/control_tensor.py +12 -0
  45. gmnsopt-0.2.0/src/gmns_opt/tensor/demand_tensor.py +44 -0
  46. gmnsopt-0.2.0/src/gmns_opt/tensor/scenario_tensor.py +37 -0
  47. gmnsopt-0.2.0/src/gmns_opt/tensor/schema.py +71 -0
  48. gmnsopt-0.2.0/src/gmns_opt/visualization/__init__.py +3 -0
  49. gmnsopt-0.2.0/src/gmns_opt/visualization/export_optimization_layers.py +54 -0
  50. gmnsopt-0.2.0/src/gmns_opt/viz/__init__.py +5 -0
  51. gmnsopt-0.2.0/src/gmns_opt/viz/export.py +27 -0
  52. gmnsopt-0.2.0/src/gmnsopt.egg-info/PKG-INFO +149 -0
  53. gmnsopt-0.2.0/src/gmnsopt.egg-info/SOURCES.txt +57 -0
  54. gmnsopt-0.2.0/src/gmnsopt.egg-info/dependency_links.txt +1 -0
  55. gmnsopt-0.2.0/src/gmnsopt.egg-info/entry_points.txt +2 -0
  56. gmnsopt-0.2.0/src/gmnsopt.egg-info/requires.txt +16 -0
  57. gmnsopt-0.2.0/src/gmnsopt.egg-info/top_level.txt +1 -0
  58. gmnsopt-0.2.0/tests/test_gmns_opt.py +86 -0
  59. gmnsopt-0.2.0/tests/test_scaffold.py +85 -0
gmnsopt-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 gmnsopt 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.
gmnsopt-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,149 @@
1
+ Metadata-Version: 2.4
2
+ Name: gmnsopt
3
+ Version: 0.2.0
4
+ Summary: GMNS-native transportation optimization testbed: reproducible, visual, data-grounded, progressively harder benchmark cases (shortest path -> assignment -> ODME -> signal -> resilience) for open-source & commercial solvers, ML-for-optimization, and RL/control.
5
+ Author: gmnsopt contributors
6
+ License: MIT
7
+ Project-URL: Source, https://github.com/asu-trans-ai-lab/gmnsopt
8
+ Keywords: GMNS,transportation,optimization,traffic-assignment,ODME,benchmark,operations-research,networkx,HiGHS
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Topic :: Scientific/Engineering
12
+ Classifier: Intended Audience :: Science/Research
13
+ Requires-Python: >=3.9
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Requires-Dist: numpy>=1.21
17
+ Requires-Dist: scipy>=1.7
18
+ Requires-Dist: networkx>=2.6
19
+ Requires-Dist: PyYAML>=5.4
20
+ Provides-Extra: viz
21
+ Requires-Dist: pandas>=1.3; extra == "viz"
22
+ Requires-Dist: matplotlib>=3.4; extra == "viz"
23
+ Provides-Extra: solvers
24
+ Requires-Dist: pyomo>=6.0; extra == "solvers"
25
+ Requires-Dist: highspy>=1.5; extra == "solvers"
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7.0; extra == "dev"
28
+ Requires-Dist: ruff>=0.1; extra == "dev"
29
+ Dynamic: license-file
30
+
31
+ # gmnsopt
32
+
33
+ [![CI](https://github.com/asu-trans-ai-lab/gmnsopt/actions/workflows/ci.yml/badge.svg)](https://github.com/asu-trans-ai-lab/gmnsopt/actions/workflows/ci.yml)
34
+ [![PyPI](https://img.shields.io/pypi/v/gmnsopt.svg)](https://pypi.org/project/gmnsopt/)
35
+ [![Python](https://img.shields.io/pypi/pyversions/gmnsopt.svg)](https://pypi.org/project/gmnsopt/)
36
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
37
+
38
+ **A GMNS-native transportation optimization testbed** — reproducible, visual, data-grounded, and
39
+ progressively harder. It turns standardized [GMNS](https://github.com/zephyr-data-specs/GMNS) networks +
40
+ demand + operations data into mathematical-programming and network-optimization cases:
41
+
42
+ ```
43
+ GMNS network + demand + operations data
44
+ → optimization model template
45
+ → solver / algorithm
46
+ → (dynamic simulation check)
47
+ → GUI4GMNS visualization
48
+ → reproducible benchmark report
49
+ ```
50
+
51
+ > **gmnsopt turns GMNS from a network data standard into a transportation optimization testbed
52
+ > for planning, operations, control, pricing, resilience, and multimodal decision-making** — where
53
+ > open-source solvers, commercial solvers, ML-for-optimization, and RL/control methods can all be tested on
54
+ > realistic, dynamic, stochastic, visually explainable mobility problems.
55
+
56
+ ## What ships in v0.1 (working, dependency-light)
57
+ Core kernel + **ten runnable cases** across the model families and formulation classes (LP / MILP / convex-NLP
58
+ / inverse), on the common **case contract** (`problem.yml` + GMNS `input/` → `output/solution.csv`,
59
+ `objective_trace.csv`, `constraint_status.csv`, `summary.md`):
60
+
61
+ | model | family | class | case | solver |
62
+ |---|---|---|---|---|
63
+ | `shortest_path` | A routing | LP | `cases/00_shortest_path_toy` | networkx Dijkstra |
64
+ | `min_cost_flow` | flow | LP | `cases/01_min_cost_flow_toy` | networkx |
65
+ | `traffic_assignment` (UE) | B assignment | convex-NLP | `cases/02_sioux_falls_assignment` | Frank-Wolfe + BPR |
66
+ | `system_optimal` (+ pricing) | B assignment | convex-NLP | `cases/03_system_optimal_pricing` | Frank-Wolfe (marginal cost) |
67
+ | `accessibility` | A routing | LP | `cases/04_accessibility` | networkx skims |
68
+ | `max_flow` (min-cut) | F resilience | LP | `cases/05_max_flow_evacuation` | networkx max-flow |
69
+ | `odme` (inverse) | C ODME | QP/NNLS | `cases/06_odme_sioux_falls` | scipy NNLS |
70
+ | `signal_timing` | D operations | LP | `cases/07_signal_timing_intersection` | scipy linprog (HiGHS) |
71
+ | `network_design` | E design | **MILP** | `cases/08_network_design_toy` | **scipy milp (HiGHS)** |
72
+ | `facility_location` (EV charging) | G siting | **MILP** | `cases/09_facility_location_charging` | **scipy milp (HiGHS)** |
73
+
74
+ Verified invariants: system-optimal total travel time **<** user-equilibrium; ODME count-RMSE 2720 → 185;
75
+ MILP network design respects the budget; p-median opens exactly K hubs. Only `numpy`, `scipy`, `networkx`,
76
+ `PyYAML` are required (MILP/LP use scipy's HiGHS backend — **no commercial solver needed**). Optional extras
77
+ add Pyomo/HiGHS bindings, pandas/matplotlib.
78
+
79
+ ## Install
80
+ ```bash
81
+ pip install -e . # core
82
+ pip install -e ".[viz,solvers,dev]" # + pandas/matplotlib, Pyomo/HiGHS, pytest/ruff
83
+ ```
84
+
85
+ ## Quick start
86
+ ```bash
87
+ gmns-opt run cases/02_sioux_falls_assignment # -> output/ (solution, trace, summary)
88
+ gmns-opt validate cases/02_sioux_falls_assignment
89
+ gmns-opt list-families # the 10-family taxonomy (maturity + classes)
90
+ gmns-opt describe-family signal_queue_control
91
+ gmns-opt solver-status # available solver tiers
92
+ gmns-opt generate-scenarios --case cases/11_resilience_capacity_drop_toy --type capacity_drop --links 1,2,3 --drop 0.5
93
+ ```
94
+
95
+ ## Broader benchmark scaffold
96
+ Beyond the runnable models, the package is an open-science **ecosystem scaffold**:
97
+ - **Application taxonomy** — 10 families (`gmns_opt.applications` / `benchmark.registry`), each with formulation
98
+ classes, required/optional GMNS files, outputs, solver tier, visualization, and **maturity**
99
+ (runnable / scaffold / planned). See [docs/application_taxonomy.md](docs/application_taxonomy.md).
100
+ - **Tensor framework** — `gmns_opt.tensor`: sparse `x[o,d,m,p,τ,s,a]` + companion tensors (D/F/Q/U/C/R/V),
101
+ GMNS→demand-tensor conversion, scenario expansion, CSV/JSON export. See [docs/tensor_framework.md](docs/tensor_framework.md).
102
+ - **Scenario generator** — `gmns_opt.scenarios`: deterministic normal / capacity_drop / demand_surge / work_zone
103
+ / weather / cav_penetration / uam_weather_restriction (fixed seeds).
104
+ - **Solver tiers** — `gmns_opt.solvers`: Tier 0 (networkx/scipy-HiGHS) → 1 (Pyomo) → 2 (commercial, optional) →
105
+ 3 (GPU/neural/RL). No commercial dependency. See [docs/solver_tiers.md](docs/solver_tiers.md).
106
+ - **ML-for-optimization readiness** — `gmns_opt.ml`: GMNS feature extraction (GNN-ready), learning-to-warm-start
107
+ interface, learning-to-branch dataset schema. See [docs/ml_for_optimization.md](docs/ml_for_optimization.md).
108
+ - **GUI4GMNS visualization** — `gmns_opt.visualization.export_optimization_layers` → GeoJSON + decision/constraint/
109
+ trace/scenario CSVs. See [docs/gui4gmns_integration.md](docs/gui4gmns_integration.md).
110
+ - **Case templates** — `case_templates/` (one per family) and 13 runnable/scaffold seed cases (`cases/00..12`).
111
+ ```python
112
+ from gmns_opt import run_case
113
+ res = run_case("cases/02_sioux_falls_assignment")
114
+ print(res["objective"], res["meta"]["final_relative_gap"]) # UE Beckmann + FW gap
115
+ ```
116
+
117
+ ## The benchmark ladder (design)
118
+ Not one benchmark — a **ladder** from transparent teaching cases to industrial-scale city cases:
119
+
120
+ | level | what | purpose |
121
+ |---|---|---|
122
+ | 0 | formulation micro-cases (5–20 nodes, 1 signal) | teach variables/constraints; debug solvers; validate LLM-generated models |
123
+ | 1 | classic research nets **as GMNS** (Sioux Falls, Anaheim, Chicago) | connect to the literature; algorithm comparison |
124
+ | 2 | open-city OSM2GMNS (Tempe, Phoenix, Atlanta, LA, Bay Area) | geographically meaningful; GIS/planning + GUI4GMNS outreach |
125
+ | 3 | dynamic corridor operations (signals, queues, work zones, incidents) | planning → operations (DTA/CBI/ODME) |
126
+ | 4 | stochastic / robust (demand, capacity, incident, weather, CAV/UAM uncertainty) | research-grade OR/AI |
127
+ | 5 | industrial-scale city (10⁴–10⁶ vars, multi-mode/period/scenario) | stress solvers + neural acceleration |
128
+
129
+ ## Model families (implemented → planned)
130
+ A. shortest path / accessibility ✅ · B. traffic assignment & system-optimal ✅ (UE) · C. **ODME / inverse
131
+ optimization** · D. signal timing & arterial control (MILP/MPC) · E. network design & capacity planning ·
132
+ F. resilience / work-zone / incident / extreme-heat · G. freight / EV charging / UAM / multimodal logistics ·
133
+ H. transit frequency & accessibility. See [docs/BENCHMARK_SPEC.md](docs/BENCHMARK_SPEC.md).
134
+
135
+ ## Solver tiers
136
+ `Tier 0` NetworkX / scipy / HiGHS / OR-Tools · `Tier 1` Pyomo + HiGHS/CBC/Ipopt · `Tier 2` Gurobi / CPLEX /
137
+ COPT / Mosek · `Tier 3` GPU / cuOpt / ADMM / RL / neural heuristics. Start license-free; scale up when needed.
138
+
139
+ ## Docs
140
+ [vision](docs/vision.md) · [application taxonomy](docs/application_taxonomy.md) ·
141
+ [tensor framework](docs/tensor_framework.md) · [benchmark ladder](docs/benchmark_ladder.md) ·
142
+ [solver tiers](docs/solver_tiers.md) · [ML for optimization](docs/ml_for_optimization.md) ·
143
+ [GUI4GMNS integration](docs/gui4gmns_integration.md) · [open-science test cases](docs/open_science_test_cases.md) ·
144
+ [benchmark spec](docs/BENCHMARK_SPEC.md) · [data contract](docs/data_contract.md) ·
145
+ [roadmap](../dev/ROADMAP.md) · [references](../references/README.md)
146
+
147
+ ## License
148
+ MIT — see [LICENSE](LICENSE). Bundled benchmark networks keep their own upstream licenses
149
+ (see [references](../references/README.md)); Sioux Falls is from the public Transportation Networks repo.
@@ -0,0 +1,119 @@
1
+ # gmnsopt
2
+
3
+ [![CI](https://github.com/asu-trans-ai-lab/gmnsopt/actions/workflows/ci.yml/badge.svg)](https://github.com/asu-trans-ai-lab/gmnsopt/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/gmnsopt.svg)](https://pypi.org/project/gmnsopt/)
5
+ [![Python](https://img.shields.io/pypi/pyversions/gmnsopt.svg)](https://pypi.org/project/gmnsopt/)
6
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
7
+
8
+ **A GMNS-native transportation optimization testbed** — reproducible, visual, data-grounded, and
9
+ progressively harder. It turns standardized [GMNS](https://github.com/zephyr-data-specs/GMNS) networks +
10
+ demand + operations data into mathematical-programming and network-optimization cases:
11
+
12
+ ```
13
+ GMNS network + demand + operations data
14
+ → optimization model template
15
+ → solver / algorithm
16
+ → (dynamic simulation check)
17
+ → GUI4GMNS visualization
18
+ → reproducible benchmark report
19
+ ```
20
+
21
+ > **gmnsopt turns GMNS from a network data standard into a transportation optimization testbed
22
+ > for planning, operations, control, pricing, resilience, and multimodal decision-making** — where
23
+ > open-source solvers, commercial solvers, ML-for-optimization, and RL/control methods can all be tested on
24
+ > realistic, dynamic, stochastic, visually explainable mobility problems.
25
+
26
+ ## What ships in v0.1 (working, dependency-light)
27
+ Core kernel + **ten runnable cases** across the model families and formulation classes (LP / MILP / convex-NLP
28
+ / inverse), on the common **case contract** (`problem.yml` + GMNS `input/` → `output/solution.csv`,
29
+ `objective_trace.csv`, `constraint_status.csv`, `summary.md`):
30
+
31
+ | model | family | class | case | solver |
32
+ |---|---|---|---|---|
33
+ | `shortest_path` | A routing | LP | `cases/00_shortest_path_toy` | networkx Dijkstra |
34
+ | `min_cost_flow` | flow | LP | `cases/01_min_cost_flow_toy` | networkx |
35
+ | `traffic_assignment` (UE) | B assignment | convex-NLP | `cases/02_sioux_falls_assignment` | Frank-Wolfe + BPR |
36
+ | `system_optimal` (+ pricing) | B assignment | convex-NLP | `cases/03_system_optimal_pricing` | Frank-Wolfe (marginal cost) |
37
+ | `accessibility` | A routing | LP | `cases/04_accessibility` | networkx skims |
38
+ | `max_flow` (min-cut) | F resilience | LP | `cases/05_max_flow_evacuation` | networkx max-flow |
39
+ | `odme` (inverse) | C ODME | QP/NNLS | `cases/06_odme_sioux_falls` | scipy NNLS |
40
+ | `signal_timing` | D operations | LP | `cases/07_signal_timing_intersection` | scipy linprog (HiGHS) |
41
+ | `network_design` | E design | **MILP** | `cases/08_network_design_toy` | **scipy milp (HiGHS)** |
42
+ | `facility_location` (EV charging) | G siting | **MILP** | `cases/09_facility_location_charging` | **scipy milp (HiGHS)** |
43
+
44
+ Verified invariants: system-optimal total travel time **<** user-equilibrium; ODME count-RMSE 2720 → 185;
45
+ MILP network design respects the budget; p-median opens exactly K hubs. Only `numpy`, `scipy`, `networkx`,
46
+ `PyYAML` are required (MILP/LP use scipy's HiGHS backend — **no commercial solver needed**). Optional extras
47
+ add Pyomo/HiGHS bindings, pandas/matplotlib.
48
+
49
+ ## Install
50
+ ```bash
51
+ pip install -e . # core
52
+ pip install -e ".[viz,solvers,dev]" # + pandas/matplotlib, Pyomo/HiGHS, pytest/ruff
53
+ ```
54
+
55
+ ## Quick start
56
+ ```bash
57
+ gmns-opt run cases/02_sioux_falls_assignment # -> output/ (solution, trace, summary)
58
+ gmns-opt validate cases/02_sioux_falls_assignment
59
+ gmns-opt list-families # the 10-family taxonomy (maturity + classes)
60
+ gmns-opt describe-family signal_queue_control
61
+ gmns-opt solver-status # available solver tiers
62
+ gmns-opt generate-scenarios --case cases/11_resilience_capacity_drop_toy --type capacity_drop --links 1,2,3 --drop 0.5
63
+ ```
64
+
65
+ ## Broader benchmark scaffold
66
+ Beyond the runnable models, the package is an open-science **ecosystem scaffold**:
67
+ - **Application taxonomy** — 10 families (`gmns_opt.applications` / `benchmark.registry`), each with formulation
68
+ classes, required/optional GMNS files, outputs, solver tier, visualization, and **maturity**
69
+ (runnable / scaffold / planned). See [docs/application_taxonomy.md](docs/application_taxonomy.md).
70
+ - **Tensor framework** — `gmns_opt.tensor`: sparse `x[o,d,m,p,τ,s,a]` + companion tensors (D/F/Q/U/C/R/V),
71
+ GMNS→demand-tensor conversion, scenario expansion, CSV/JSON export. See [docs/tensor_framework.md](docs/tensor_framework.md).
72
+ - **Scenario generator** — `gmns_opt.scenarios`: deterministic normal / capacity_drop / demand_surge / work_zone
73
+ / weather / cav_penetration / uam_weather_restriction (fixed seeds).
74
+ - **Solver tiers** — `gmns_opt.solvers`: Tier 0 (networkx/scipy-HiGHS) → 1 (Pyomo) → 2 (commercial, optional) →
75
+ 3 (GPU/neural/RL). No commercial dependency. See [docs/solver_tiers.md](docs/solver_tiers.md).
76
+ - **ML-for-optimization readiness** — `gmns_opt.ml`: GMNS feature extraction (GNN-ready), learning-to-warm-start
77
+ interface, learning-to-branch dataset schema. See [docs/ml_for_optimization.md](docs/ml_for_optimization.md).
78
+ - **GUI4GMNS visualization** — `gmns_opt.visualization.export_optimization_layers` → GeoJSON + decision/constraint/
79
+ trace/scenario CSVs. See [docs/gui4gmns_integration.md](docs/gui4gmns_integration.md).
80
+ - **Case templates** — `case_templates/` (one per family) and 13 runnable/scaffold seed cases (`cases/00..12`).
81
+ ```python
82
+ from gmns_opt import run_case
83
+ res = run_case("cases/02_sioux_falls_assignment")
84
+ print(res["objective"], res["meta"]["final_relative_gap"]) # UE Beckmann + FW gap
85
+ ```
86
+
87
+ ## The benchmark ladder (design)
88
+ Not one benchmark — a **ladder** from transparent teaching cases to industrial-scale city cases:
89
+
90
+ | level | what | purpose |
91
+ |---|---|---|
92
+ | 0 | formulation micro-cases (5–20 nodes, 1 signal) | teach variables/constraints; debug solvers; validate LLM-generated models |
93
+ | 1 | classic research nets **as GMNS** (Sioux Falls, Anaheim, Chicago) | connect to the literature; algorithm comparison |
94
+ | 2 | open-city OSM2GMNS (Tempe, Phoenix, Atlanta, LA, Bay Area) | geographically meaningful; GIS/planning + GUI4GMNS outreach |
95
+ | 3 | dynamic corridor operations (signals, queues, work zones, incidents) | planning → operations (DTA/CBI/ODME) |
96
+ | 4 | stochastic / robust (demand, capacity, incident, weather, CAV/UAM uncertainty) | research-grade OR/AI |
97
+ | 5 | industrial-scale city (10⁴–10⁶ vars, multi-mode/period/scenario) | stress solvers + neural acceleration |
98
+
99
+ ## Model families (implemented → planned)
100
+ A. shortest path / accessibility ✅ · B. traffic assignment & system-optimal ✅ (UE) · C. **ODME / inverse
101
+ optimization** · D. signal timing & arterial control (MILP/MPC) · E. network design & capacity planning ·
102
+ F. resilience / work-zone / incident / extreme-heat · G. freight / EV charging / UAM / multimodal logistics ·
103
+ H. transit frequency & accessibility. See [docs/BENCHMARK_SPEC.md](docs/BENCHMARK_SPEC.md).
104
+
105
+ ## Solver tiers
106
+ `Tier 0` NetworkX / scipy / HiGHS / OR-Tools · `Tier 1` Pyomo + HiGHS/CBC/Ipopt · `Tier 2` Gurobi / CPLEX /
107
+ COPT / Mosek · `Tier 3` GPU / cuOpt / ADMM / RL / neural heuristics. Start license-free; scale up when needed.
108
+
109
+ ## Docs
110
+ [vision](docs/vision.md) · [application taxonomy](docs/application_taxonomy.md) ·
111
+ [tensor framework](docs/tensor_framework.md) · [benchmark ladder](docs/benchmark_ladder.md) ·
112
+ [solver tiers](docs/solver_tiers.md) · [ML for optimization](docs/ml_for_optimization.md) ·
113
+ [GUI4GMNS integration](docs/gui4gmns_integration.md) · [open-science test cases](docs/open_science_test_cases.md) ·
114
+ [benchmark spec](docs/BENCHMARK_SPEC.md) · [data contract](docs/data_contract.md) ·
115
+ [roadmap](../dev/ROADMAP.md) · [references](../references/README.md)
116
+
117
+ ## License
118
+ MIT — see [LICENSE](LICENSE). Bundled benchmark networks keep their own upstream licenses
119
+ (see [references](../references/README.md)); Sioux Falls is from the public Transportation Networks repo.
@@ -0,0 +1,36 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "gmnsopt"
7
+ version = "0.2.0"
8
+ description = "GMNS-native transportation optimization testbed: reproducible, visual, data-grounded, progressively harder benchmark cases (shortest path -> assignment -> ODME -> signal -> resilience) for open-source & commercial solvers, ML-for-optimization, and RL/control."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "gmnsopt contributors" }]
13
+ keywords = ["GMNS", "transportation", "optimization", "traffic-assignment", "ODME",
14
+ "benchmark", "operations-research", "networkx", "HiGHS"]
15
+ classifiers = [
16
+ "Programming Language :: Python :: 3",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Topic :: Scientific/Engineering",
19
+ "Intended Audience :: Science/Research",
20
+ ]
21
+ dependencies = ["numpy>=1.21", "scipy>=1.7", "networkx>=2.6", "PyYAML>=5.4"]
22
+
23
+ [project.optional-dependencies]
24
+ viz = ["pandas>=1.3", "matplotlib>=3.4"]
25
+ solvers = ["pyomo>=6.0", "highspy>=1.5"] # optional Tier-1 modeling + HiGHS bindings
26
+ dev = ["pytest>=7.0", "ruff>=0.1"]
27
+
28
+ [project.scripts]
29
+ gmns-opt = "gmns_opt.cli:main"
30
+
31
+ [project.urls]
32
+ Source = "https://github.com/asu-trans-ai-lab/gmnsopt"
33
+
34
+ [tool.setuptools.packages.find]
35
+ where = ["src"]
36
+ include = ["gmns_opt*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,17 @@
1
+ """gmnsopt — a GMNS-native transportation optimization testbed.
2
+
3
+ Turns standardized GMNS networks + demand + operations data into reproducible optimization cases:
4
+ GMNS network + demand -> optimization model -> solver -> (simulation check) -> report.
5
+
6
+ Public API:
7
+ read_gmns, build_graph, validate_gmns (io)
8
+ shortest_path, min_cost_flow, traffic_assignment (models)
9
+ run_case (benchmark case runner)
10
+ """
11
+ from .io import read_gmns, build_graph, validate_gmns
12
+ from .models import shortest_path, min_cost_flow, traffic_assignment
13
+ from .benchmark import run_case
14
+
15
+ __version__ = "0.2.0"
16
+ __all__ = ["read_gmns", "build_graph", "validate_gmns",
17
+ "shortest_path", "min_cost_flow", "traffic_assignment", "run_case"]
@@ -0,0 +1,27 @@
1
+ """Application taxonomy — the ten transportation optimization families.
2
+
3
+ Thin, registry-backed surface: the authoritative metadata lives in `gmns_opt.benchmark.registry`; this package
4
+ exposes it for discovery and groups families by maturity. See docs/application_taxonomy.md.
5
+ """
6
+ from __future__ import annotations
7
+ from ..benchmark.registry import FAMILIES, list_families, get_family, ProblemFamily
8
+
9
+ BY_ID = {f.id: f for f in FAMILIES}
10
+ FAMILY_IDS = [f.id for f in FAMILIES]
11
+
12
+
13
+ def by_maturity(maturity: str):
14
+ """Families at a given maturity: 'runnable' | 'scaffold' | 'planned'."""
15
+ return [f for f in FAMILIES if f.maturity == maturity]
16
+
17
+
18
+ def runnable_models():
19
+ """All registered runnable problem_type ids across families."""
20
+ out = []
21
+ for f in FAMILIES:
22
+ out.extend(f.runnable_models)
23
+ return sorted(set(out))
24
+
25
+
26
+ __all__ = ["FAMILIES", "FAMILY_IDS", "BY_ID", "list_families", "get_family", "ProblemFamily",
27
+ "by_maturity", "runnable_models"]
@@ -0,0 +1,4 @@
1
+ """Benchmark harness: run a case folder (problem.yml + GMNS input) and write the standard output set."""
2
+ from .case import run_case
3
+
4
+ __all__ = ["run_case"]
@@ -0,0 +1,84 @@
1
+ """Run a benchmark case: read `problem.yml` + GMNS `input/`, dispatch to a model, write `output/`.
2
+
3
+ Output set (the open-science case contract):
4
+ output/solution.csv per-link (or per-path) solution
5
+ output/objective_trace.csv iteration, objective, gap, ... (convergence)
6
+ output/constraint_status.csv constraint, status (feasibility)
7
+ output/summary.md human-readable headline + KPIs
8
+ """
9
+ from __future__ import annotations
10
+ import os
11
+ import yaml
12
+ from ..io import read_gmns, validate_gmns
13
+ from ..models import (shortest_path, accessibility, min_cost_flow, max_flow, traffic_assignment,
14
+ system_optimal, odme, signal_timing, network_design, facility_location,
15
+ resilience_scenario, multimodal_skeleton)
16
+ from .report import write_outputs
17
+
18
+
19
+ def _ml_features(net, p, cd):
20
+ from ..ml import extract_features
21
+ feat = extract_features(net, scenario=p.get("scenario", "normal"))
22
+ return {"objective": feat["stats"]["n_links"], "solution": [], "objective_trace": [],
23
+ "constraint_status": [{"constraint": "feature_extraction", "status": "ok"}],
24
+ "meta": {"feasible": True, "maturity": "scaffold", **feat["stats"],
25
+ "note": "GMNS feature blocks for ML-for-optimization (see docs/ml_for_optimization.md)"},
26
+ "features": feat}
27
+
28
+ # each entry: (net, params, case_dir) -> result dict
29
+ DISPATCH = {
30
+ "shortest_path": lambda net, p, cd: shortest_path(net, p["origin"], p["destination"],
31
+ weight=p.get("weight", "fftt_min"),
32
+ by_zone=p.get("by_zone", True)),
33
+ "accessibility": lambda net, p, cd: accessibility(net, threshold_min=p.get("threshold_min", 30.0),
34
+ weight=p.get("weight", "fftt_min"),
35
+ decay=p.get("decay", 0.0)),
36
+ "min_cost_flow": lambda net, p, cd: min_cost_flow(net, p["supplies"], weight=p.get("weight", "fftt_min"),
37
+ by_zone=p.get("by_zone", True), scale=p.get("scale", 1)),
38
+ "max_flow": lambda net, p, cd: max_flow(net, p["source"], p["sink"], by_zone=p.get("by_zone", True)),
39
+ "traffic_assignment": lambda net, p, cd: traffic_assignment(net, max_iter=p.get("max_iter", 60),
40
+ gap_tol=p.get("gap_tol", 1e-4),
41
+ by_zone=p.get("by_zone", True)),
42
+ "system_optimal": lambda net, p, cd: system_optimal(net, max_iter=p.get("max_iter", 80),
43
+ gap_tol=p.get("gap_tol", 1e-4),
44
+ by_zone=p.get("by_zone", True)),
45
+ "odme": lambda net, p, cd: odme(net, case_dir=cd, reg=p.get("reg", 0.1), by_zone=p.get("by_zone", True)),
46
+ "signal_timing": lambda net, p, cd: signal_timing(net, p["phases"], cycle=p.get("cycle", 90.0),
47
+ lost_time_per_phase=p.get("lost_time_per_phase", 4.0),
48
+ min_green=p.get("min_green", 7.0)),
49
+ "network_design": lambda net, p, cd: network_design(net, p["source"], p["sink"], p["flow"], p["budget"],
50
+ by_zone=p.get("by_zone", True),
51
+ candidate_link_ids=p.get("candidate_link_ids")),
52
+ "facility_location": lambda net, p, cd: facility_location(net, p["k"], candidates=p.get("candidates"),
53
+ weight=p.get("weight", "fftt_min")),
54
+ "resilience_scenario": lambda net, p, cd: resilience_scenario(net, drop_link_ids=p.get("drop_link_ids"),
55
+ drop=p.get("drop", 0.5), case_dir=cd,
56
+ by_zone=p.get("by_zone", True)),
57
+ "multimodal_skeleton": lambda net, p, cd: multimodal_skeleton(net, modes=p.get("modes"),
58
+ time_stages=p.get("time_stages", 4),
59
+ scenarios=p.get("scenarios")),
60
+ "ml_features": _ml_features,
61
+ }
62
+
63
+
64
+ def run_case(case_dir: str, write: bool = True) -> dict:
65
+ """Run the case in `case_dir`. Returns the result dict; writes output/ when `write` is True."""
66
+ with open(os.path.join(case_dir, "problem.yml"), encoding="utf-8") as f:
67
+ problem = yaml.safe_load(f)
68
+ ptype = problem["problem_type"]
69
+ if ptype not in DISPATCH:
70
+ raise ValueError(f"unknown problem_type '{ptype}'. Available: {sorted(DISPATCH)}")
71
+
72
+ net = read_gmns(case_dir)
73
+ report = validate_gmns(net)
74
+ if not report["ok"]:
75
+ raise ValueError(f"GMNS validation failed for {case_dir}: {report['errors'][:5]}")
76
+
77
+ result = DISPATCH[ptype](net, problem.get("params", {}) or {}, case_dir)
78
+ result["problem"] = problem
79
+ result["network_stats"] = report["stats"]
80
+ if write:
81
+ out = os.path.join(case_dir, "output")
82
+ write_outputs(out, problem, result, report)
83
+ result["output_dir"] = out
84
+ return result
@@ -0,0 +1,129 @@
1
+ """Benchmark category registry — the machine-readable taxonomy of transportation optimization families.
2
+
3
+ Each `ProblemFamily` records its formulation classes, required/optional GMNS files, required outputs, default
4
+ solver tier, visualization type, and maturity (runnable | scaffold | planned) plus the implemented model
5
+ templates (`problem_type` ids usable in a case `problem.yml`). This is the single source of truth surfaced by
6
+ `gmns-opt list-families` / `describe-family` and by `gmns_opt.applications`.
7
+ """
8
+ from __future__ import annotations
9
+ from dataclasses import dataclass, field
10
+ from typing import List
11
+
12
+
13
+ @dataclass(frozen=True)
14
+ class ProblemFamily:
15
+ id: str
16
+ name: str
17
+ formulation_classes: List[str]
18
+ required_files: List[str]
19
+ optional_files: List[str] = field(default_factory=list)
20
+ outputs: List[str] = field(default_factory=lambda: ["solution.csv", "objective_trace.csv",
21
+ "constraint_status.csv", "summary.md"])
22
+ default_solver_tier: int = 0
23
+ visualization: str = "link_flow"
24
+ maturity: str = "planned" # runnable | scaffold | planned
25
+ runnable_models: List[str] = field(default_factory=list) # registered problem_type ids
26
+ subtypes: List[str] = field(default_factory=list)
27
+
28
+
29
+ FAMILIES: List[ProblemFamily] = [
30
+ ProblemFamily(
31
+ id="routing_accessibility", name="Routing & Accessibility",
32
+ formulation_classes=["LP", "network_flow"],
33
+ required_files=["node.csv", "link.csv"], optional_files=["zone.csv", "demand.csv", "transit_route.csv"],
34
+ default_solver_tier=0, visualization="path_highlight", maturity="runnable",
35
+ runnable_models=["shortest_path", "accessibility", "min_cost_flow"],
36
+ subtypes=["shortest_path", "multimodal_path", "accessibility", "equity_aware_access"]),
37
+ ProblemFamily(
38
+ id="traffic_assignment_pricing", name="Traffic Assignment & Pricing",
39
+ formulation_classes=["convex_NLP", "MIP", "dynamic", "stochastic"],
40
+ required_files=["node.csv", "link.csv", "demand.csv"], optional_files=["toll.csv", "scenario.csv"],
41
+ default_solver_tier=0, visualization="flow_height_speed_color", maturity="runnable",
42
+ runnable_models=["traffic_assignment", "system_optimal"],
43
+ subtypes=["user_equilibrium", "system_optimal", "dynamic_assignment", "congestion_pricing",
44
+ "managed_lane_control"]),
45
+ ProblemFamily(
46
+ id="odme_inverse_optimization", name="ODME & Inverse Optimization",
47
+ formulation_classes=["LP", "QP", "NLP", "stochastic", "inverse"],
48
+ required_files=["node.csv", "link.csv", "demand.csv"],
49
+ optional_files=["counts.csv", "detector.csv", "trajectory.csv", "scenario.csv"],
50
+ default_solver_tier=0, visualization="desire_line_delta", maturity="runnable",
51
+ runnable_models=["odme"],
52
+ subtypes=["od_matrix_estimation", "path_flow_correction", "sensor_residual_min", "demand_tensor_calibration"]),
53
+ ProblemFamily(
54
+ id="signal_queue_control", name="Signal & Queue Spillback Control",
55
+ formulation_classes=["MIP", "dynamic", "stochastic", "RL_ready"],
56
+ required_files=["node.csv", "link.csv", "demand.csv"],
57
+ optional_files=["movement.csv", "signal_timing.csv", "detector.csv", "scenario.csv"],
58
+ outputs=["solution_signal.csv", "queue_profile.csv", "constraint_status.csv", "objective_trace.csv"],
59
+ default_solver_tier=0, visualization="phase_clock_queue_ribbon", maturity="runnable",
60
+ runnable_models=["signal_timing"],
61
+ subtypes=["signal_timing", "green_split_offset_phase", "queue_spillback", "corridor_mpc_milp_rl"]),
62
+ ProblemFamily(
63
+ id="resilience_workzone_incident", name="Resilience, Work-Zone & Incident",
64
+ formulation_classes=["MIP", "stochastic", "dynamic", "robust"],
65
+ required_files=["node.csv", "link.csv", "demand.csv"], optional_files=["scenario.csv", "resource.csv"],
66
+ outputs=["scenario_summary.csv", "solution.csv", "constraint_status.csv", "objective_trace.csv"],
67
+ default_solver_tier=0, visualization="warning_layer_before_after", maturity="runnable",
68
+ runnable_models=["resilience_scenario", "max_flow"],
69
+ subtypes=["incident_response", "work_zone_scheduling", "extreme_heat_weather_flood",
70
+ "evacuation_recovery"]),
71
+ ProblemFamily(
72
+ id="cav_control", name="CAV Mixed-Traffic Control",
73
+ formulation_classes=["MIP", "QP", "NLP", "stochastic", "dynamic", "RL"],
74
+ required_files=["node.csv", "link.csv", "demand.csv"],
75
+ optional_files=["scenario.csv", "penetration.csv", "control_zone.csv"],
76
+ outputs=["decision_variable.csv", "constraint_status.csv", "objective_trace.csv", "summary.md"],
77
+ default_solver_tier=2, visualization="control_zone_speed", maturity="scaffold",
78
+ runnable_models=["multimodal_skeleton"],
79
+ subtypes=["mixed_traffic", "speed_advisory", "platooning", "lane_use_control", "ramp_metering",
80
+ "communication_failure"]),
81
+ ProblemFamily(
82
+ id="uam_air_ground_coordination", name="UAM Air–Ground Coordination",
83
+ formulation_classes=["MIP", "stochastic", "dynamic", "RL"],
84
+ required_files=["node.csv", "link.csv", "demand.csv"],
85
+ optional_files=["vertiport.csv", "air_link.csv", "weather_scenario.csv", "charging_station.csv"],
86
+ outputs=["decision_variable.csv", "constraint_status.csv", "objective_trace.csv", "summary.md"],
87
+ default_solver_tier=2, visualization="vertiport_queue_3d", maturity="scaffold",
88
+ runnable_models=["multimodal_skeleton"],
89
+ subtypes=["vertiport_capacity", "dispatch_repositioning", "weather_uncertainty", "battery_charging",
90
+ "ground_access_integration"]),
91
+ ProblemFamily(
92
+ id="freight_ev_logistics", name="Freight, EV & Logistics Routing",
93
+ formulation_classes=["MIP", "stochastic", "dynamic"],
94
+ required_files=["node.csv", "link.csv"],
95
+ optional_files=["vehicle.csv", "charging_station.csv", "delivery_demand.csv", "scenario.csv"],
96
+ default_solver_tier=1, visualization="route_energy", maturity="scaffold",
97
+ runnable_models=["facility_location"],
98
+ subtypes=["vrp", "ev_routing_charging", "time_windows", "curb_depot_fleet", "truck_drone_uam"]),
99
+ ProblemFamily(
100
+ id="transit_frequency_accessibility", name="Transit Frequency & Accessibility",
101
+ formulation_classes=["MIP", "LP", "stochastic"],
102
+ required_files=["node.csv", "link.csv", "demand.csv"],
103
+ optional_files=["transit_route.csv", "fleet.csv", "scenario.csv"],
104
+ default_solver_tier=1, visualization="frequency_accessibility", maturity="planned",
105
+ runnable_models=[],
106
+ subtypes=["bus_frequency", "fleet_allocation", "first_last_mile", "transfer_coordination",
107
+ "equity_service"]),
108
+ ProblemFamily(
109
+ id="solver_learning_and_neural_optimization", name="Solver Learning & Neural Optimization",
110
+ formulation_classes=["ML", "RL", "surrogate"],
111
+ required_files=["node.csv", "link.csv", "demand.csv"], optional_files=["scenario.csv"],
112
+ outputs=["features.json", "warm_start.csv", "objective_trace.csv", "summary.md"],
113
+ default_solver_tier=3, visualization="convergence_panel", maturity="scaffold",
114
+ runnable_models=["ml_features"],
115
+ subtypes=["learning_to_warm_start", "learning_to_branch", "graph_neural_features", "neural_surrogate",
116
+ "rl_policy_interface", "train_val_test_city_split"]),
117
+ ]
118
+
119
+ _BY_ID = {f.id: f for f in FAMILIES}
120
+
121
+
122
+ def list_families() -> List[ProblemFamily]:
123
+ return list(FAMILIES)
124
+
125
+
126
+ def get_family(family_id: str) -> ProblemFamily:
127
+ if family_id not in _BY_ID:
128
+ raise KeyError(f"unknown family '{family_id}'. Known: {sorted(_BY_ID)}")
129
+ return _BY_ID[family_id]