pytraf 0.3.1__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 (43) hide show
  1. pytraf-0.3.1/Cargo.lock +368 -0
  2. pytraf-0.3.1/Cargo.toml +9 -0
  3. pytraf-0.3.1/LICENSE +21 -0
  4. pytraf-0.3.1/PKG-INFO +239 -0
  5. pytraf-0.3.1/README.md +200 -0
  6. pytraf-0.3.1/crates/core/Cargo.toml +9 -0
  7. pytraf-0.3.1/crates/core/src/assignment.rs +337 -0
  8. pytraf-0.3.1/crates/core/src/frank_wolfe.rs +385 -0
  9. pytraf-0.3.1/crates/core/src/gradient_projection.rs +1727 -0
  10. pytraf-0.3.1/crates/core/src/lib.rs +41 -0
  11. pytraf-0.3.1/crates/core/src/network.rs +229 -0
  12. pytraf-0.3.1/crates/core/src/order.rs +184 -0
  13. pytraf-0.3.1/crates/core/src/path_store.rs +723 -0
  14. pytraf-0.3.1/crates/core/src/shortest_path.rs +435 -0
  15. pytraf-0.3.1/crates/core/src/turns.rs +389 -0
  16. pytraf-0.3.1/crates/core/src/vdf.rs +430 -0
  17. pytraf-0.3.1/crates/io/Cargo.toml +13 -0
  18. pytraf-0.3.1/crates/io/examples/gmns_assign.rs +113 -0
  19. pytraf-0.3.1/crates/io/examples/order_benchmark.rs +132 -0
  20. pytraf-0.3.1/crates/io/examples/scale_benchmark.rs +130 -0
  21. pytraf-0.3.1/crates/io/src/gmns.rs +1029 -0
  22. pytraf-0.3.1/crates/io/src/lib.rs +2 -0
  23. pytraf-0.3.1/crates/io/src/tntp.rs +548 -0
  24. pytraf-0.3.1/crates/io/tests/gmns_sioux_falls.rs +117 -0
  25. pytraf-0.3.1/crates/io/tests/larger_networks.rs +83 -0
  26. pytraf-0.3.1/crates/io/tests/parallel_sweeps.rs +114 -0
  27. pytraf-0.3.1/crates/io/tests/sioux_falls_all_or_nothing.rs +107 -0
  28. pytraf-0.3.1/crates/io/tests/sioux_falls_bpr.rs +45 -0
  29. pytraf-0.3.1/crates/io/tests/sioux_falls_frank_wolfe.rs +121 -0
  30. pytraf-0.3.1/crates/io/tests/sioux_falls_gradient_projection.rs +168 -0
  31. pytraf-0.3.1/crates/io/tests/sioux_falls_multiclass.rs +167 -0
  32. pytraf-0.3.1/crates/io/tests/sioux_falls_shortest_paths.rs +79 -0
  33. pytraf-0.3.1/crates/io/tests/sioux_falls_turn_shortest_paths.rs +108 -0
  34. pytraf-0.3.1/crates/io/tests/sioux_falls_turns.rs +42 -0
  35. pytraf-0.3.1/crates/io/tests/turn_costs_equivalence.rs +304 -0
  36. pytraf-0.3.1/crates/python/Cargo.toml +17 -0
  37. pytraf-0.3.1/crates/python/src/lib.rs +1169 -0
  38. pytraf-0.3.1/pyproject.toml +49 -0
  39. pytraf-0.3.1/python/pytraf/__init__.py +183 -0
  40. pytraf-0.3.1/python/pytraf/_pytraf.pyi +250 -0
  41. pytraf-0.3.1/python/pytraf/options.py +59 -0
  42. pytraf-0.3.1/python/pytraf/py.typed +0 -0
  43. pytraf-0.3.1/python/pytraf/results.py +448 -0
@@ -0,0 +1,368 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
5
+ [[package]]
6
+ name = "autocfg"
7
+ version = "1.5.1"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
10
+
11
+ [[package]]
12
+ name = "crossbeam-deque"
13
+ version = "0.8.8"
14
+ source = "registry+https://github.com/rust-lang/crates.io-index"
15
+ checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a"
16
+ dependencies = [
17
+ "crossbeam-epoch",
18
+ "crossbeam-utils",
19
+ ]
20
+
21
+ [[package]]
22
+ name = "crossbeam-epoch"
23
+ version = "0.9.21"
24
+ source = "registry+https://github.com/rust-lang/crates.io-index"
25
+ checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d"
26
+ dependencies = [
27
+ "crossbeam-utils",
28
+ ]
29
+
30
+ [[package]]
31
+ name = "crossbeam-utils"
32
+ version = "0.8.23"
33
+ source = "registry+https://github.com/rust-lang/crates.io-index"
34
+ checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6"
35
+
36
+ [[package]]
37
+ name = "csv"
38
+ version = "1.4.0"
39
+ source = "registry+https://github.com/rust-lang/crates.io-index"
40
+ checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938"
41
+ dependencies = [
42
+ "csv-core",
43
+ "itoa",
44
+ "ryu",
45
+ "serde_core",
46
+ ]
47
+
48
+ [[package]]
49
+ name = "csv-core"
50
+ version = "0.1.13"
51
+ source = "registry+https://github.com/rust-lang/crates.io-index"
52
+ checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782"
53
+ dependencies = [
54
+ "memchr",
55
+ ]
56
+
57
+ [[package]]
58
+ name = "either"
59
+ version = "1.19.0"
60
+ source = "registry+https://github.com/rust-lang/crates.io-index"
61
+ checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be"
62
+
63
+ [[package]]
64
+ name = "heck"
65
+ version = "0.5.0"
66
+ source = "registry+https://github.com/rust-lang/crates.io-index"
67
+ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
68
+
69
+ [[package]]
70
+ name = "itoa"
71
+ version = "1.0.18"
72
+ source = "registry+https://github.com/rust-lang/crates.io-index"
73
+ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
74
+
75
+ [[package]]
76
+ name = "libc"
77
+ version = "0.2.190"
78
+ source = "registry+https://github.com/rust-lang/crates.io-index"
79
+ checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78"
80
+
81
+ [[package]]
82
+ name = "matrixmultiply"
83
+ version = "0.3.11"
84
+ source = "registry+https://github.com/rust-lang/crates.io-index"
85
+ checksum = "3f607c237553f086e7043417a51df26b2eb899d3caff94e6a67592ff992fedc7"
86
+ dependencies = [
87
+ "autocfg",
88
+ "rawpointer",
89
+ ]
90
+
91
+ [[package]]
92
+ name = "memchr"
93
+ version = "2.8.3"
94
+ source = "registry+https://github.com/rust-lang/crates.io-index"
95
+ checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
96
+
97
+ [[package]]
98
+ name = "ndarray"
99
+ version = "0.17.2"
100
+ source = "registry+https://github.com/rust-lang/crates.io-index"
101
+ checksum = "520080814a7a6b4a6e9070823bb24b4531daac8c4627e08ba5de8c5ef2f2752d"
102
+ dependencies = [
103
+ "matrixmultiply",
104
+ "num-complex",
105
+ "num-integer",
106
+ "num-traits",
107
+ "portable-atomic",
108
+ "portable-atomic-util",
109
+ "rawpointer",
110
+ ]
111
+
112
+ [[package]]
113
+ name = "num-complex"
114
+ version = "0.4.6"
115
+ source = "registry+https://github.com/rust-lang/crates.io-index"
116
+ checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
117
+ dependencies = [
118
+ "num-traits",
119
+ ]
120
+
121
+ [[package]]
122
+ name = "num-integer"
123
+ version = "0.1.47"
124
+ source = "registry+https://github.com/rust-lang/crates.io-index"
125
+ checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b"
126
+ dependencies = [
127
+ "num-traits",
128
+ ]
129
+
130
+ [[package]]
131
+ name = "num-traits"
132
+ version = "0.2.19"
133
+ source = "registry+https://github.com/rust-lang/crates.io-index"
134
+ checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
135
+ dependencies = [
136
+ "autocfg",
137
+ ]
138
+
139
+ [[package]]
140
+ name = "numpy"
141
+ version = "0.29.0"
142
+ source = "registry+https://github.com/rust-lang/crates.io-index"
143
+ checksum = "6a5b15d63a5ff39e378daed0e1340d3a5964703ea9712eb09a0dc66fade996f4"
144
+ dependencies = [
145
+ "libc",
146
+ "ndarray",
147
+ "num-complex",
148
+ "num-integer",
149
+ "num-traits",
150
+ "pyo3",
151
+ "pyo3-build-config",
152
+ "rustc-hash",
153
+ ]
154
+
155
+ [[package]]
156
+ name = "once_cell"
157
+ version = "1.21.4"
158
+ source = "registry+https://github.com/rust-lang/crates.io-index"
159
+ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
160
+
161
+ [[package]]
162
+ name = "portable-atomic"
163
+ version = "1.15.0"
164
+ source = "registry+https://github.com/rust-lang/crates.io-index"
165
+ checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
166
+
167
+ [[package]]
168
+ name = "portable-atomic-util"
169
+ version = "0.2.8"
170
+ source = "registry+https://github.com/rust-lang/crates.io-index"
171
+ checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715"
172
+ dependencies = [
173
+ "portable-atomic",
174
+ ]
175
+
176
+ [[package]]
177
+ name = "proc-macro2"
178
+ version = "1.0.107"
179
+ source = "registry+https://github.com/rust-lang/crates.io-index"
180
+ checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
181
+ dependencies = [
182
+ "unicode-ident",
183
+ ]
184
+
185
+ [[package]]
186
+ name = "pyo3"
187
+ version = "0.29.3"
188
+ source = "registry+https://github.com/rust-lang/crates.io-index"
189
+ checksum = "700d18fa267b73b9b521fd7e13580e2f446916f176cacee1ab63fcc8191f1655"
190
+ dependencies = [
191
+ "libc",
192
+ "once_cell",
193
+ "portable-atomic",
194
+ "pyo3-build-config",
195
+ "pyo3-ffi",
196
+ "pyo3-macros",
197
+ ]
198
+
199
+ [[package]]
200
+ name = "pyo3-build-config"
201
+ version = "0.29.3"
202
+ source = "registry+https://github.com/rust-lang/crates.io-index"
203
+ checksum = "7b3fc0c4d08f6bb10e71fe39dfb9e2f59c6eb6854e22ec8092f50c69a4499adb"
204
+ dependencies = [
205
+ "target-lexicon",
206
+ ]
207
+
208
+ [[package]]
209
+ name = "pyo3-ffi"
210
+ version = "0.29.3"
211
+ source = "registry+https://github.com/rust-lang/crates.io-index"
212
+ checksum = "dfc0b8e19df29aad7086cf977bb0c2a2f143e30567eb113e9cf72b62ca698330"
213
+ dependencies = [
214
+ "libc",
215
+ "pyo3-build-config",
216
+ ]
217
+
218
+ [[package]]
219
+ name = "pyo3-macros"
220
+ version = "0.29.3"
221
+ source = "registry+https://github.com/rust-lang/crates.io-index"
222
+ checksum = "6100e8a4b5eba53afaa5ed078364851a0b2499c553a44c31026b929049b49dc6"
223
+ dependencies = [
224
+ "proc-macro2",
225
+ "pyo3-macros-backend",
226
+ "quote",
227
+ "syn 2.0.119",
228
+ ]
229
+
230
+ [[package]]
231
+ name = "pyo3-macros-backend"
232
+ version = "0.29.3"
233
+ source = "registry+https://github.com/rust-lang/crates.io-index"
234
+ checksum = "6143877a16e82b5a727b7127ff4cd86858a24a28d745d72f43e6f227c7b1bdb3"
235
+ dependencies = [
236
+ "heck",
237
+ "proc-macro2",
238
+ "quote",
239
+ "syn 2.0.119",
240
+ ]
241
+
242
+ [[package]]
243
+ name = "pytraf-core"
244
+ version = "0.3.1"
245
+ dependencies = [
246
+ "rayon",
247
+ ]
248
+
249
+ [[package]]
250
+ name = "pytraf-io"
251
+ version = "0.3.1"
252
+ dependencies = [
253
+ "csv",
254
+ "pytraf-core",
255
+ "rayon",
256
+ ]
257
+
258
+ [[package]]
259
+ name = "pytraf-py"
260
+ version = "0.3.1"
261
+ dependencies = [
262
+ "numpy",
263
+ "pyo3",
264
+ "pytraf-core",
265
+ "pytraf-io",
266
+ "rayon",
267
+ ]
268
+
269
+ [[package]]
270
+ name = "quote"
271
+ version = "1.0.47"
272
+ source = "registry+https://github.com/rust-lang/crates.io-index"
273
+ checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
274
+ dependencies = [
275
+ "proc-macro2",
276
+ ]
277
+
278
+ [[package]]
279
+ name = "rawpointer"
280
+ version = "0.2.1"
281
+ source = "registry+https://github.com/rust-lang/crates.io-index"
282
+ checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
283
+
284
+ [[package]]
285
+ name = "rayon"
286
+ version = "1.12.0"
287
+ source = "registry+https://github.com/rust-lang/crates.io-index"
288
+ checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d"
289
+ dependencies = [
290
+ "either",
291
+ "rayon-core",
292
+ ]
293
+
294
+ [[package]]
295
+ name = "rayon-core"
296
+ version = "1.13.0"
297
+ source = "registry+https://github.com/rust-lang/crates.io-index"
298
+ checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
299
+ dependencies = [
300
+ "crossbeam-deque",
301
+ "crossbeam-utils",
302
+ ]
303
+
304
+ [[package]]
305
+ name = "rustc-hash"
306
+ version = "2.1.3"
307
+ source = "registry+https://github.com/rust-lang/crates.io-index"
308
+ checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
309
+
310
+ [[package]]
311
+ name = "ryu"
312
+ version = "1.0.23"
313
+ source = "registry+https://github.com/rust-lang/crates.io-index"
314
+ checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
315
+
316
+ [[package]]
317
+ name = "serde_core"
318
+ version = "1.0.229"
319
+ source = "registry+https://github.com/rust-lang/crates.io-index"
320
+ checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
321
+ dependencies = [
322
+ "serde_derive",
323
+ ]
324
+
325
+ [[package]]
326
+ name = "serde_derive"
327
+ version = "1.0.229"
328
+ source = "registry+https://github.com/rust-lang/crates.io-index"
329
+ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
330
+ dependencies = [
331
+ "proc-macro2",
332
+ "quote",
333
+ "syn 3.0.9",
334
+ ]
335
+
336
+ [[package]]
337
+ name = "syn"
338
+ version = "2.0.119"
339
+ source = "registry+https://github.com/rust-lang/crates.io-index"
340
+ checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
341
+ dependencies = [
342
+ "proc-macro2",
343
+ "quote",
344
+ "unicode-ident",
345
+ ]
346
+
347
+ [[package]]
348
+ name = "syn"
349
+ version = "3.0.9"
350
+ source = "registry+https://github.com/rust-lang/crates.io-index"
351
+ checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b"
352
+ dependencies = [
353
+ "proc-macro2",
354
+ "quote",
355
+ "unicode-ident",
356
+ ]
357
+
358
+ [[package]]
359
+ name = "target-lexicon"
360
+ version = "0.13.5"
361
+ source = "registry+https://github.com/rust-lang/crates.io-index"
362
+ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
363
+
364
+ [[package]]
365
+ name = "unicode-ident"
366
+ version = "1.0.27"
367
+ source = "registry+https://github.com/rust-lang/crates.io-index"
368
+ checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563"
@@ -0,0 +1,9 @@
1
+ [workspace]
2
+ members = ["crates/core", "crates/io", "crates/python"]
3
+ resolver = "2"
4
+
5
+ [workspace.package]
6
+ version = "0.3.1"
7
+ edition = "2024"
8
+ license = "MIT"
9
+ repository = "https://github.com/harisbal/pytraf"
pytraf-0.3.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Haris Ballis
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.
pytraf-0.3.1/PKG-INFO ADDED
@@ -0,0 +1,239 @@
1
+ Metadata-Version: 2.4
2
+ Name: pytraf
3
+ Version: 0.3.1
4
+ Classifier: Development Status :: 3 - Alpha
5
+ Classifier: Intended Audience :: Science/Research
6
+ Classifier: License :: OSI Approved :: MIT License
7
+ Classifier: Operating System :: OS Independent
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.9
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Rust
15
+ Classifier: Topic :: Scientific/Engineering
16
+ Requires-Dist: numpy>=1.23
17
+ Requires-Dist: mkdocs>=1.6,<2 ; extra == 'docs'
18
+ Requires-Dist: mkdocs-material>=9.7,<10 ; extra == 'docs'
19
+ Requires-Dist: mkdocstrings[python]>=0.26 ; extra == 'docs'
20
+ Requires-Dist: ruff ; extra == 'docs'
21
+ Requires-Dist: pandas>=1.5 ; extra == 'pandas'
22
+ Requires-Dist: pytest>=7 ; extra == 'test'
23
+ Requires-Dist: pandas>=1.5 ; extra == 'test'
24
+ Provides-Extra: docs
25
+ Provides-Extra: pandas
26
+ Provides-Extra: test
27
+ License-File: LICENSE
28
+ Summary: Path-based traffic assignment with turn delays and multiple vehicle classes.
29
+ Keywords: traffic assignment,user equilibrium,transportation,gradient projection,GMNS
30
+ Author: Haris Ballis
31
+ License: MIT
32
+ Requires-Python: >=3.9
33
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
34
+ Project-URL: Changelog, https://harisbal.github.io/pytraf/changelog/
35
+ Project-URL: Documentation, https://harisbal.github.io/pytraf/
36
+ Project-URL: Issues, https://github.com/harisbal/pytraf/issues
37
+ Project-URL: Repository, https://github.com/harisbal/pytraf
38
+
39
+ # PyTraf
40
+
41
+ [![Release](https://img.shields.io/github/v/release/harisbal/pytraf)](https://github.com/harisbal/pytraf/releases)
42
+ [![Docs](https://img.shields.io/badge/docs-harisbal.github.io%2Fpytraf-blue)](https://harisbal.github.io/pytraf/)
43
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)](https://github.com/harisbal/pytraf/blob/main/LICENSE)
44
+
45
+ Path-based traffic assignment with turn delays and multiple vehicle classes.
46
+
47
+ **Documentation: <https://harisbal.github.io/pytraf/>**
48
+
49
+ PyTraf is an open-source package for **static user-equilibrium traffic assignment** on road networks.
50
+ Given a network and an origin–destination demand matrix, it computes the link and path flows that
51
+ satisfy Wardrop's first principle, solving the problem in path space with gradient projection.
52
+
53
+ Its main features are:
54
+
55
+ - **Path-based equilibration** by gradient projection, with Frank-Wolfe as a reference method. Path
56
+ flows are retained, so select-link and route-level analyses need no post-processing.
57
+ - **Turn-aware routing**: turn prohibitions, fixed turn penalties and flow-dependent turn delays, handled
58
+ exactly by labelling links rather than nodes in the shortest-path search.
59
+ - **Multi-class assignment**, with class-specific demand, passenger-car equivalents, generalised link
60
+ costs (e.g. tolls) and link restrictions.
61
+ - **Background traffic**: fixed preloads on links and turns, such as buses or through traffic.
62
+ - **Tabular results**: link, turn and path results as pandas DataFrames, or as NumPy arrays.
63
+ - **Standard input formats**: TNTP benchmark files, GMNS datasets, or plain tables (pandas DataFrames,
64
+ NumPy arrays).
65
+ - **Validation** against published equilibrium solutions of the standard test networks.
66
+ - **Performance**: a multi-threaded Rust core, usable from Python or directly from Rust.
67
+
68
+ ## Install
69
+
70
+ ```sh
71
+ pip install pytraf
72
+ pip install pandas # optional: for the DataFrame inputs and tables
73
+ ```
74
+
75
+ Wheels for Linux, macOS and Windows need Python 3.9 or newer and nothing else. To build from source you need
76
+ Rust ([rustup](https://rustup.rs)) and [maturin](https://www.maturin.rs):
77
+
78
+ ```sh
79
+ uv venv .venv && source .venv/bin/activate # or python -m venv
80
+ uv pip install numpy pandas pytest maturin
81
+ maturin develop --release # builds and installs `pytraf`
82
+ pytest # optional: run the Python tests
83
+ ```
84
+
85
+ ## Python quick start
86
+
87
+ ```python
88
+ import pytraf
89
+
90
+ net = pytraf.Network.from_tntp("data/tntp/SiouxFalls/SiouxFalls_net.tntp")
91
+ demand = pytraf.Demand.from_tntp(net, "data/tntp/SiouxFalls/SiouxFalls_trips.tntp")
92
+
93
+ result = net.assign(demand, gap=1e-6)
94
+ result.converged, result.iterations, result.relative_gap
95
+ result.links.flow # numpy array, one entry per link
96
+ result.diagnostics.objective # Beckmann objective (single class, PCE 1)
97
+ result.links.table() # DataFrame: flow, volume/capacity and time per link
98
+ result.paths.table() # DataFrame: every path with its flow, time and links
99
+ print(result.summary()) # a short account of the run
100
+ ```
101
+
102
+ From your own tables (DataFrames or dicts of arrays):
103
+
104
+ ```python
105
+ net = pytraf.Network.from_tables(links_df, turns_df) # see docs/guide/python.md for columns
106
+ demand = pytraf.Demand.from_table(net, trips_df)
107
+ result = net.assign(demand, gap=1e-6)
108
+ ```
109
+
110
+ Several classes:
111
+
112
+ ```python
113
+ cars = pytraf.TrafficClass(car_demand)
114
+ trucks = pytraf.TrafficClass(truck_demand, pce=2.5,
115
+ extra_link_cost=toll_in_minutes, # per link, same units as time
116
+ allowed_links=~truck_banned) # bool per link
117
+ result = net.assign([cars, trucks], gap=1e-6)
118
+ result.links.by_class["trucks"] # vehicles of one class, by name or position
119
+ result.links.volume # PCE-weighted volume that drives travel times
120
+ ```
121
+
122
+ A worked example is in [Getting started](https://harisbal.github.io/pytraf/getting-started/); every table column is in
123
+ [the Python guide](https://harisbal.github.io/pytraf/guide/python/).
124
+
125
+ ## Rust quick start
126
+
127
+ ```rust
128
+ use pytraf_core::*;
129
+ use pytraf_io::tntp::{read_net, read_trips};
130
+
131
+ let net = read_net("data/tntp/SiouxFalls/SiouxFalls_net.tntp")?;
132
+ let trips = read_trips("data/tntp/SiouxFalls/SiouxFalls_trips.tntp")?;
133
+ let demand = OdDemand::from_triples(
134
+ net.network.num_nodes(), &trips.origins, &trips.destinations, &trips.flows)?;
135
+ let turns = TurnTable::build(&net.network, &net.is_endpoint, &[], TurnOptions::default())?;
136
+ let vdf = Bpr::new(net.free_flow_time, net.capacity, net.b, net.power)?;
137
+
138
+ let result = gradient_projection(&net.network, &turns, &vdf, &demand,
139
+ GradientProjectionOptions::default())?;
140
+ println!("{} sweeps, gap {:.2e}", result.iterations, result.relative_gap);
141
+ ```
142
+
143
+ `gradient_projection_multiclass` takes a slice of `ClassSpec`s and a turn delay function.
144
+ The core crate does no file IO: it takes typed arrays, so Rust and Python users call the same code.
145
+
146
+ ## Does it get the right answer?
147
+
148
+ It reproduces the published solutions of the standard benchmark networks (Sioux Falls, Anaheim) and is
149
+ checked against independent models; see [docs/benchmarks.md](https://harisbal.github.io/pytraf/benchmarks/).
150
+
151
+ ## Layout
152
+
153
+ ```
154
+ crates/core algorithms, no IO: network, turns, shortest paths, solvers, path store
155
+ crates/io TNTP reader (and the benchmark example)
156
+ crates/python PyO3 bindings (the `pytraf._pytraf` extension)
157
+ python/pytraf Python package: DataFrame helpers and type stubs
158
+ python/tests pytest suite
159
+ data/tntp benchmark networks from github.com/bstabler/TransportationNetworks
160
+ docs the documentation site source (MkDocs): guides, concepts, design, benchmarks
161
+ ```
162
+
163
+ ## Documentation
164
+
165
+ The full documentation is a MkDocs site built from `docs/`:
166
+
167
+ ```sh
168
+ uv pip install -e ".[docs]"
169
+ mkdocs serve # live preview at http://127.0.0.1:8000
170
+ mkdocs build --strict # static site in site/
171
+ cargo doc --workspace --no-deps --open # Rust API reference
172
+ ```
173
+
174
+ ## Limitations
175
+
176
+ PyTraf solves the static problem: no queue spillback, and delays depend only on a link's or turn's own
177
+ traffic. See [the roadmap](https://harisbal.github.io/pytraf/design/roadmap/).
178
+
179
+ ## Next steps
180
+
181
+ Planned extensions, roughly in order:
182
+
183
+ - **Larger networks**: lower path memory and faster flow updates, for models with several thousand zones.
184
+ - **OpenStreetMap networks**, converted to GMNS or flat tables in the Python layer.
185
+ - **Link-direction optimisation**, built on the assignment engine.
186
+ - **Interacting junction models** for signalised and priority junctions.
187
+
188
+ **Stochastic user equilibrium** is deliberately deferred: PyTraf keeps the deterministic equilibrium for
189
+ now. When it is added, path-based logit SUE fits the existing solver best. The full list, with the
190
+ current limitations, is in the [roadmap](https://harisbal.github.io/pytraf/design/roadmap/).
191
+
192
+ ## Contributing
193
+
194
+ Bug reports, questions and pull requests are welcome on
195
+ [GitHub](https://github.com/harisbal/pytraf/issues). For larger changes, please open an issue first to
196
+ discuss the approach.
197
+
198
+ - **Tests.** Check new solver features against something independent of the code: a published solution,
199
+ a closed-form equilibrium or an equivalent model.
200
+ - **Design decisions** are recorded in [docs/design/decisions](https://github.com/harisbal/pytraf/tree/main/docs/design/decisions); add one for any change to the model or the API.
201
+ - **Before opening a pull request**, run:
202
+
203
+ ```sh
204
+ cargo fmt --check && cargo clippy --workspace --all-targets
205
+ cargo test --workspace
206
+ maturin develop --release && pytest
207
+ mkdocs build --strict
208
+ ```
209
+
210
+ Benchmarks: `cargo run --release -p pytraf-io --example order_benchmark -- Anaheim 1e-4 1e-6`.
211
+
212
+ **Releases.** The version lives in one place, `[workspace.package]` in `Cargo.toml`; the crates, the
213
+ Python package (`pytraf.__version__`) and the docs read it from there. To release, bump it, update
214
+ `version` and `date-released` in `CITATION.cff` and the citation in this README, then tag `vX.Y.Z` and
215
+ publish a GitHub release.
216
+
217
+ ## Citing PyTraf
218
+
219
+ If you use PyTraf in your research, please cite it as below (GitHub's "Cite this repository" button gives
220
+ the same from [`CITATION.cff`](https://github.com/harisbal/pytraf/blob/main/CITATION.cff)):
221
+
222
+ > Ballis, H. (2026). *PyTraf: Path-based static traffic assignment* (Version 0.3.1)
223
+ > [Computer software]. https://github.com/harisbal/pytraf
224
+
225
+ ```bibtex
226
+ @software{ballis_pytraf_2026,
227
+ author = {Ballis, Haris},
228
+ title = {{PyTraf}: Path-based static traffic assignment},
229
+ year = {2026},
230
+ version = {0.3.1},
231
+ url = {https://github.com/harisbal/pytraf}
232
+ }
233
+ ```
234
+
235
+ ## License
236
+
237
+ MIT. The benchmark networks in `data/tntp` come from
238
+ [TransportationNetworks](https://github.com/bstabler/TransportationNetworks) and keep their own terms.
239
+