albones80 commited on
Commit
8993164
·
verified ·
1 Parent(s): 61acd54

Sync RouteOptimizer Hub snapshot (samples, format, license)

Browse files
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2018-2026 Alfonso Bonillas / alioit.com
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.
README.md ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ pretty_name: RouteOptimizer
4
+ tags:
5
+ - optimization
6
+ - operations-research
7
+ - mining
8
+ - fleet-dispatch
9
+ - milp
10
+ - pulp
11
+ - cbc
12
+ - routing
13
+ task_categories:
14
+ - other
15
+ ---
16
+
17
+ # RouteOptimizer
18
+
19
+ **This is an operations-research optimization solver, not a machine-learning model.**
20
+ There are **no trained weights**, no checkpoints, and no neural network to download.
21
+ The files here are **sample mine scenarios**, the **scenario file format**, and pointers
22
+ to install the solver itself.
23
+
24
+ Rights: Alfonso Bonillas / [alioit.com](http://www.alioit.com). License: **MIT**
25
+ ([`LICENSE`](LICENSE)).
26
+
27
+ ## What it does
28
+
29
+ - **Dispatch (A\*)** — builds a truck movement plan over a shift horizon from a
30
+ scenario file.
31
+ - **Shift plan (MILP)** — solves a mine-wide truck-flow plan with **PuLP + CBC**
32
+ (open-source; no commercial solver license).
33
+
34
+ Both tools read local JSON scenarios and write JSON results. They do **not** call
35
+ SQL Server or the network at run time.
36
+
37
+ ## What it does not do
38
+
39
+ - It does **not** train or serve ML models.
40
+ - It does **not** include production haul databases or live telematics.
41
+ - It does **not** require Gurobi, CPLEX, or other commercial solvers.
42
+ - A second anonymized haul-history sample is **not** published until the data
43
+ owner approves release.
44
+
45
+ ## Install
46
+
47
+ ### pip package
48
+
49
+ From the [GitHub repository](https://github.com/AlfonsoALIO/RouteOptimizer):
50
+
51
+ ```bash
52
+ pip install "PuLP>=2.7,<3"
53
+ pip install git+https://github.com/AlfonsoALIO/RouteOptimizer.git
54
+ ```
55
+
56
+ Or clone and install locally:
57
+
58
+ ```bash
59
+ git clone https://github.com/AlfonsoALIO/RouteOptimizer.git
60
+ cd RouteOptimizer
61
+ pip install .
62
+ ```
63
+
64
+ Console scripts: `route-optimizer`, `route-optimizer-dispatch`,
65
+ `route-optimizer-shift-plan`.
66
+
67
+ ### Docker image
68
+
69
+ Build from the same repository (image tag matches the package version in
70
+ `pyproject.toml`, currently `0.1.0`):
71
+
72
+ ```bash
73
+ git clone https://github.com/AlfonsoALIO/RouteOptimizer.git
74
+ cd RouteOptimizer
75
+ ./scripts/build_docker.sh
76
+ # → route-optimizer:0.1.0
77
+ ```
78
+
79
+ Run with a mounted folder and networking disabled:
80
+
81
+ ```bash
82
+ docker run --rm --network=none \
83
+ -v "$PWD/samples:/data/samples:ro" \
84
+ -v "$PWD/out:/data/out" \
85
+ route-optimizer:0.1.0 \
86
+ dispatch /data/samples/tiny_feasible.json -o /data/out/dispatch.json --segments 8 --trucks 2
87
+ ```
88
+
89
+ ## Scenario file format
90
+
91
+ See [`docs/scenario-format.md`](docs/scenario-format.md) (format version `"1"`).
92
+ Units: tons, hours, minutes.
93
+
94
+ ## Sample scenarios
95
+
96
+ | File | Role |
97
+ |------|------|
98
+ | [`samples/tiny_feasible.json`](samples/tiny_feasible.json) | Small mine; **dispatch and shift-plan** both succeed quickly |
99
+ | [`samples/toy_mine.json`](samples/toy_mine.json) | Larger synthetic toy mine used by the in-repo fixture (dispatch) |
100
+
101
+ ```bash
102
+ # pip — end-to-end on the small sample
103
+ route-optimizer dispatch samples/tiny_feasible.json -o out/dispatch.json --segments 8 --trucks 2
104
+ route-optimizer shift-plan samples/tiny_feasible.json -o out/shift_plan.json --segments 4
105
+
106
+ # optional wall-clock cap
107
+ route-optimizer dispatch samples/toy_mine.json -o out/toy_dispatch.json --segments 58 --trucks 21 --time-limit 60
108
+ ```
109
+
110
+ ## Links
111
+
112
+ | Resource | URL |
113
+ |----------|-----|
114
+ | Source / pip install | https://github.com/AlfonsoALIO/RouteOptimizer |
115
+ | Docker build script | https://github.com/AlfonsoALIO/RouteOptimizer/blob/master/scripts/build_docker.sh |
116
+ | Scenario format | [`docs/scenario-format.md`](docs/scenario-format.md) |
117
+ | License | [`LICENSE`](LICENSE) (MIT) |
118
+ | alioit.com | http://www.alioit.com |
119
+
120
+ ## Citation / credit
121
+
122
+ RouteOptimizer — Alfonso Bonillas / alioit.com — MIT License.
docs/scenario-format.md ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Mine scenario file format
2
+
3
+ Version: **1** (`format_version` field)
4
+
5
+ This JSON format describes one mine for both the A\* dispatcher and the MILP
6
+ shift planner. It matches the Story 2.1 scenario schema, with an explicit
7
+ format version for on-disk files.
8
+
9
+ ## Units
10
+
11
+ | Quantity | Unit |
12
+ |----------|------|
13
+ | Demand | tons |
14
+ | Truck capacity | tons |
15
+ | Shift length | hours |
16
+ | Arc travel time | minutes |
17
+
18
+ ## Top-level fields
19
+
20
+ | Name | Type | Unit | Required | Description |
21
+ |------|------|------|----------|-------------|
22
+ | `format_version` | string | — | **yes** (files) | Format version. Supported: `"1"`. |
23
+ | `locations` | array of objects | — | yes | Named places with queue capacity. |
24
+ | `arcs` | array of objects | — | yes | Directed travel links. |
25
+ | `demands` | array of objects | — | yes | Haul demand by source/destination. |
26
+ | `trucks` | array of objects | — | yes | Fleet members and capacities. |
27
+ | `shift_length_hours` | number | hours | yes | Shift horizon length. |
28
+ | `fleet_size` | integer | trucks | yes | Maximum trucks available. |
29
+
30
+ ## `locations[]`
31
+
32
+ | Name | Type | Unit | Required | Description |
33
+ |------|------|------|----------|-------------|
34
+ | `name` | string | — | yes | Unique location id (e.g. `garage`, `S1`). |
35
+ | `resident_capacity` | integer | trucks | yes | Max trucks that may queue here (≥ 0). |
36
+
37
+ ## `arcs[]`
38
+
39
+ | Name | Type | Unit | Required | Description |
40
+ |------|------|------|----------|-------------|
41
+ | `source` | string | — | yes | Must name a location. |
42
+ | `destination` | string | — | yes | Must name a location. |
43
+ | `travel_time_minutes` | number | minutes | yes | Positive travel time. |
44
+ | `distance` | number | (optional) | no | Optional distance; unused by solvers today. |
45
+
46
+ ## `demands[]`
47
+
48
+ | Name | Type | Unit | Required | Description |
49
+ |------|------|------|----------|-------------|
50
+ | `source` | string | — | yes | Must name a location. |
51
+ | `destination` | string | — | yes | Must name a location. |
52
+ | `tons` | number | tons | yes | Non-negative tonnage for the shift. |
53
+
54
+ ## `trucks[]`
55
+
56
+ | Name | Type | Unit | Required | Description |
57
+ |------|------|------|----------|-------------|
58
+ | `name` | string | — | yes | Unique truck id. |
59
+ | `tonnage_capacity` | number | tons | yes | Positive payload capacity. |
60
+
61
+ ## Validation
62
+
63
+ Loading a file through `core.scenario.load_scenario_file` rejects:
64
+
65
+ - a missing required field (error names the field)
66
+ - an unknown location on an arc or demand (error names the location)
67
+ - an unsupported `format_version` (error names the version)
68
+
69
+ ## Sample files
70
+
71
+ | File | Status |
72
+ |------|--------|
73
+ | [`samples/tiny_feasible.json`](../samples/tiny_feasible.json) | Small feasible mine (dispatch + shift plan) |
74
+ | [`samples/toy_mine.json`](../samples/toy_mine.json) | Published synthetic fixture (dispatch) |
75
+ | Haul-history anonymized sample | **Not published** until the data owner approves release |
76
+
77
+ ## Python API
78
+
79
+ ```python
80
+ from core.scenario import load_scenario_file, write_scenario_file
81
+
82
+ scenario = load_scenario_file("samples/toy_mine.json")
83
+ write_scenario_file(scenario, "out/copy.json")
84
+ ```
samples/README.md ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Sample scenarios
2
+
3
+ | File | Description |
4
+ |------|-------------|
5
+ | `toy_mine.json` | Published synthetic toy mine (format version 1). |
6
+ | `tiny_feasible.json` | Small feasible mine for fast CLI / solver checks. |
7
+
8
+ A second sample, exported from haul history and anonymized, will be published
9
+ **only after the data owner approves its release**. It is not included in this
10
+ repository yet.
11
+
12
+ See [docs/scenario-format.md](../docs/scenario-format.md) for the file format.
samples/tiny_feasible.json ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "arcs": [
3
+ {
4
+ "destination": "S",
5
+ "source": "garage",
6
+ "travel_time_minutes": 15.0
7
+ },
8
+ {
9
+ "destination": "garage",
10
+ "source": "S",
11
+ "travel_time_minutes": 15.0
12
+ },
13
+ {
14
+ "destination": "C",
15
+ "source": "S",
16
+ "travel_time_minutes": 15.0
17
+ },
18
+ {
19
+ "destination": "S",
20
+ "source": "C",
21
+ "travel_time_minutes": 15.0
22
+ },
23
+ {
24
+ "destination": "garage",
25
+ "source": "C",
26
+ "travel_time_minutes": 15.0
27
+ }
28
+ ],
29
+ "demands": [
30
+ {
31
+ "destination": "C",
32
+ "source": "S",
33
+ "tons": 100.0
34
+ }
35
+ ],
36
+ "fleet_size": 2,
37
+ "format_version": "1",
38
+ "locations": [
39
+ {
40
+ "name": "garage",
41
+ "resident_capacity": 4
42
+ },
43
+ {
44
+ "name": "S",
45
+ "resident_capacity": 2
46
+ },
47
+ {
48
+ "name": "C",
49
+ "resident_capacity": 2
50
+ }
51
+ ],
52
+ "shift_length_hours": 1.0,
53
+ "trucks": [
54
+ {
55
+ "name": "truck_1",
56
+ "tonnage_capacity": 100.0
57
+ },
58
+ {
59
+ "name": "truck_2",
60
+ "tonnage_capacity": 100.0
61
+ }
62
+ ]
63
+ }
samples/toy_mine.json ADDED
@@ -0,0 +1,270 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "arcs": [
3
+ {
4
+ "destination": "L1",
5
+ "source": "garage",
6
+ "travel_time_minutes": 15.0
7
+ },
8
+ {
9
+ "destination": "L2",
10
+ "source": "garage",
11
+ "travel_time_minutes": 15.0
12
+ },
13
+ {
14
+ "destination": "garage",
15
+ "source": "L1",
16
+ "travel_time_minutes": 15.0
17
+ },
18
+ {
19
+ "destination": "garage",
20
+ "source": "L2",
21
+ "travel_time_minutes": 15.0
22
+ },
23
+ {
24
+ "destination": "garage",
25
+ "source": "W",
26
+ "travel_time_minutes": 15.0
27
+ },
28
+ {
29
+ "destination": "S1",
30
+ "source": "garage",
31
+ "travel_time_minutes": 15.0
32
+ },
33
+ {
34
+ "destination": "S2",
35
+ "source": "garage",
36
+ "travel_time_minutes": 15.0
37
+ },
38
+ {
39
+ "destination": "garage",
40
+ "source": "S1",
41
+ "travel_time_minutes": 15.0
42
+ },
43
+ {
44
+ "destination": "garage",
45
+ "source": "S2",
46
+ "travel_time_minutes": 15.0
47
+ },
48
+ {
49
+ "destination": "garage",
50
+ "source": "C",
51
+ "travel_time_minutes": 15.0
52
+ },
53
+ {
54
+ "destination": "L1",
55
+ "source": "W",
56
+ "travel_time_minutes": 15.0
57
+ },
58
+ {
59
+ "destination": "W",
60
+ "source": "L1",
61
+ "travel_time_minutes": 15.0
62
+ },
63
+ {
64
+ "destination": "S1",
65
+ "source": "W",
66
+ "travel_time_minutes": 15.0
67
+ },
68
+ {
69
+ "destination": "W",
70
+ "source": "S1",
71
+ "travel_time_minutes": 15.0
72
+ },
73
+ {
74
+ "destination": "S2",
75
+ "source": "W",
76
+ "travel_time_minutes": 15.0
77
+ },
78
+ {
79
+ "destination": "W",
80
+ "source": "S2",
81
+ "travel_time_minutes": 15.0
82
+ },
83
+ {
84
+ "destination": "S1",
85
+ "source": "C",
86
+ "travel_time_minutes": 15.0
87
+ },
88
+ {
89
+ "destination": "C",
90
+ "source": "S1",
91
+ "travel_time_minutes": 15.0
92
+ },
93
+ {
94
+ "destination": "S2",
95
+ "source": "C",
96
+ "travel_time_minutes": 15.0
97
+ },
98
+ {
99
+ "destination": "C",
100
+ "source": "S2",
101
+ "travel_time_minutes": 15.0
102
+ },
103
+ {
104
+ "destination": "L2",
105
+ "source": "C",
106
+ "travel_time_minutes": 15.0
107
+ },
108
+ {
109
+ "destination": "C",
110
+ "source": "L2",
111
+ "travel_time_minutes": 15.0
112
+ },
113
+ {
114
+ "destination": "C",
115
+ "source": "L1",
116
+ "travel_time_minutes": 15.0
117
+ }
118
+ ],
119
+ "demands": [
120
+ {
121
+ "destination": "C",
122
+ "source": "S1",
123
+ "tons": 8000.0
124
+ },
125
+ {
126
+ "destination": "C",
127
+ "source": "S2",
128
+ "tons": 1200.0
129
+ },
130
+ {
131
+ "destination": "C",
132
+ "source": "L1",
133
+ "tons": 4000.0
134
+ },
135
+ {
136
+ "destination": "W",
137
+ "source": "S1",
138
+ "tons": 1600.0
139
+ },
140
+ {
141
+ "destination": "W",
142
+ "source": "S2",
143
+ "tons": 2000.0
144
+ },
145
+ {
146
+ "destination": "W",
147
+ "source": "L1",
148
+ "tons": 1000.0
149
+ }
150
+ ],
151
+ "fleet_size": 21,
152
+ "format_version": "1",
153
+ "locations": [
154
+ {
155
+ "name": "S1",
156
+ "resident_capacity": 2
157
+ },
158
+ {
159
+ "name": "S2",
160
+ "resident_capacity": 2
161
+ },
162
+ {
163
+ "name": "L1",
164
+ "resident_capacity": 2
165
+ },
166
+ {
167
+ "name": "L2",
168
+ "resident_capacity": 2
169
+ },
170
+ {
171
+ "name": "W",
172
+ "resident_capacity": 2
173
+ },
174
+ {
175
+ "name": "C",
176
+ "resident_capacity": 2
177
+ },
178
+ {
179
+ "name": "garage",
180
+ "resident_capacity": 21
181
+ }
182
+ ],
183
+ "shift_length_hours": 12.0,
184
+ "trucks": [
185
+ {
186
+ "name": "truck_1",
187
+ "tonnage_capacity": 100.0
188
+ },
189
+ {
190
+ "name": "truck_2",
191
+ "tonnage_capacity": 100.0
192
+ },
193
+ {
194
+ "name": "truck_3",
195
+ "tonnage_capacity": 100.0
196
+ },
197
+ {
198
+ "name": "truck_4",
199
+ "tonnage_capacity": 100.0
200
+ },
201
+ {
202
+ "name": "truck_5",
203
+ "tonnage_capacity": 100.0
204
+ },
205
+ {
206
+ "name": "truck_6",
207
+ "tonnage_capacity": 100.0
208
+ },
209
+ {
210
+ "name": "truck_7",
211
+ "tonnage_capacity": 100.0
212
+ },
213
+ {
214
+ "name": "truck_8",
215
+ "tonnage_capacity": 100.0
216
+ },
217
+ {
218
+ "name": "truck_9",
219
+ "tonnage_capacity": 100.0
220
+ },
221
+ {
222
+ "name": "truck_10",
223
+ "tonnage_capacity": 100.0
224
+ },
225
+ {
226
+ "name": "truck_11",
227
+ "tonnage_capacity": 100.0
228
+ },
229
+ {
230
+ "name": "truck_12",
231
+ "tonnage_capacity": 100.0
232
+ },
233
+ {
234
+ "name": "truck_13",
235
+ "tonnage_capacity": 100.0
236
+ },
237
+ {
238
+ "name": "truck_14",
239
+ "tonnage_capacity": 100.0
240
+ },
241
+ {
242
+ "name": "truck_15",
243
+ "tonnage_capacity": 100.0
244
+ },
245
+ {
246
+ "name": "truck_16",
247
+ "tonnage_capacity": 100.0
248
+ },
249
+ {
250
+ "name": "truck_17",
251
+ "tonnage_capacity": 100.0
252
+ },
253
+ {
254
+ "name": "truck_18",
255
+ "tonnage_capacity": 100.0
256
+ },
257
+ {
258
+ "name": "truck_19",
259
+ "tonnage_capacity": 100.0
260
+ },
261
+ {
262
+ "name": "truck_20",
263
+ "tonnage_capacity": 100.0
264
+ },
265
+ {
266
+ "name": "truck_21",
267
+ "tonnage_capacity": 100.0
268
+ }
269
+ ]
270
+ }