nextroute 1.8.0.dev24__cp312-cp312-macosx_13_0_x86_64.whl → 1.12.3__cp312-cp312-macosx_13_0_x86_64.whl
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.
- nextroute/__about__.py +1 -1
- nextroute/__init__.py +1 -3
- nextroute/bin/nextroute.exe +0 -0
- nextroute/check/__init__.py +0 -2
- nextroute/options.py +177 -68
- nextroute/schema/input.py +35 -4
- nextroute/solve.py +5 -14
- nextroute/version.py +2 -0
- {nextroute-1.8.0.dev24.dist-info → nextroute-1.12.3.dist-info}/METADATA +6 -9
- nextroute-1.12.3.dist-info/RECORD +26 -0
- {nextroute-1.8.0.dev24.dist-info → nextroute-1.12.3.dist-info}/WHEEL +1 -1
- tests/solve_golden/main.py +50 -0
- nextroute/check/options.py +0 -31
- nextroute/factory/__init__.py +0 -16
- nextroute/factory/options.py +0 -146
- nextroute-1.8.0.dev24.dist-info/RECORD +0 -29
- tests/nextroute_python/test_options.py +0 -141
- {nextroute-1.8.0.dev24.dist-info → nextroute-1.12.3.dist-info/licenses}/LICENSE +0 -0
- {nextroute-1.8.0.dev24.dist-info → nextroute-1.12.3.dist-info}/top_level.txt +0 -0
- /tests/{nextroute_python → schema}/__init__.py +0 -0
- /tests/{nextroute_python/schema → schema}/test_input.py +0 -0
- /tests/{nextroute_python/schema → schema}/test_output.py +0 -0
- /tests/{nextroute_python/schema → solve_golden}/__init__.py +0 -0
nextroute/__about__.py
CHANGED
nextroute/__init__.py
CHANGED
|
@@ -9,10 +9,8 @@ to it.
|
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
11
|
from .__about__ import __version__
|
|
12
|
-
from .options import DisableFormatOptions as DisableFormatOptions
|
|
13
|
-
from .options import FormatOptions as FormatOptions
|
|
14
12
|
from .options import Options as Options
|
|
15
|
-
from .options import
|
|
13
|
+
from .options import Verbosity as Verbosity
|
|
16
14
|
from .solve import solve as solve
|
|
17
15
|
from .version import nextroute_version as nextroute_version
|
|
18
16
|
|
nextroute/bin/nextroute.exe
CHANGED
|
Binary file
|
nextroute/check/__init__.py
CHANGED
|
@@ -19,8 +19,6 @@ solution. If the check is invoked on a solution, it is executed on the
|
|
|
19
19
|
unplanned plan units of the solution.
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
-
from .options import Options as Options
|
|
23
|
-
from .options import Verbosity as Verbosity
|
|
24
22
|
from .schema import Objective as Objective
|
|
25
23
|
from .schema import ObjectiveTerm as ObjectiveTerm
|
|
26
24
|
from .schema import Output as Output
|
nextroute/options.py
CHANGED
|
@@ -5,69 +5,181 @@ Options for working with the Nextroute engine.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import json
|
|
8
|
+
from enum import Enum
|
|
8
9
|
from typing import Any, Dict, List
|
|
9
10
|
|
|
10
11
|
from pydantic import Field
|
|
11
12
|
|
|
12
13
|
from nextroute.base_model import BaseModel
|
|
13
|
-
from nextroute.check.options import Options as CheckOptions
|
|
14
|
-
from nextroute.factory.options import Options as FactoryOptions
|
|
15
14
|
|
|
15
|
+
# Arguments that require a duration suffix.
|
|
16
16
|
_DURATIONS_ARGS = [
|
|
17
17
|
"-check.duration",
|
|
18
18
|
"-solve.duration",
|
|
19
|
+
"-solve.plateau.duration",
|
|
20
|
+
"-solve.plateau.delay",
|
|
19
21
|
]
|
|
20
22
|
|
|
23
|
+
# Arguments that require a string enum.
|
|
24
|
+
_STR_ENUM_ARGS = [
|
|
25
|
+
"CHECK_VERBOSITY",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class Verbosity(str, Enum):
|
|
30
|
+
"""Format of an `Input`."""
|
|
21
31
|
|
|
22
|
-
|
|
23
|
-
"""
|
|
32
|
+
OFF = "off"
|
|
33
|
+
"""The check engine is not run."""
|
|
34
|
+
LOW = "low"
|
|
35
|
+
"""Low verbosity for the check engine."""
|
|
36
|
+
MEDIUM = "medium"
|
|
37
|
+
"""Medium verbosity for the check engine."""
|
|
38
|
+
HIGH = "high"
|
|
39
|
+
"""High verbosity for the check engine."""
|
|
24
40
|
|
|
25
|
-
|
|
41
|
+
|
|
42
|
+
class Options(BaseModel):
|
|
43
|
+
"""Options for using Nextroute."""
|
|
44
|
+
|
|
45
|
+
CHECK_DURATION: float = 30
|
|
46
|
+
"""Maximum duration of the check, in seconds."""
|
|
47
|
+
CHECK_VERBOSITY: Verbosity = Verbosity.OFF
|
|
48
|
+
"""Verbosity of the check engine."""
|
|
49
|
+
FORMAT_DISABLE_PROGRESSION: bool = False
|
|
50
|
+
"""Whether to disable the progression series."""
|
|
51
|
+
MODEL_CONSTRAINTS_DISABLE_ATTRIBUTES: bool = False
|
|
52
|
+
"""Ignore the compatibility attributes constraint."""
|
|
53
|
+
MODEL_CONSTRAINTS_DISABLE_CAPACITIES: List[str] = Field(default_factory=list)
|
|
54
|
+
"""Ignore the capacity constraint for the given resource names."""
|
|
55
|
+
MODEL_CONSTRAINTS_DISABLE_CAPACITY: bool = False
|
|
56
|
+
"""Ignore the capacity constraint for all resources."""
|
|
57
|
+
MODEL_CONSTRAINTS_DISABLE_DISTANCELIMIT: bool = False
|
|
58
|
+
"""Ignore the distance limit constraint."""
|
|
59
|
+
MODEL_CONSTRAINTS_DISABLE_GROUPS: bool = False
|
|
60
|
+
"""Ignore the groups constraint."""
|
|
61
|
+
MODEL_CONSTRAINTS_DISABLE_MAXIMUMDURATION: bool = False
|
|
62
|
+
"""Ignore the maximum duration constraint."""
|
|
63
|
+
MODEL_CONSTRAINTS_DISABLE_MAXIMUMSTOPS: bool = False
|
|
64
|
+
"""Ignore the maximum stops constraint."""
|
|
65
|
+
MODEL_CONSTRAINTS_DISABLE_MAXIMUMWAITSTOP: bool = False
|
|
66
|
+
"""Ignore the maximum stop wait constraint."""
|
|
67
|
+
MODEL_CONSTRAINTS_DISABLE_MAXIMUMWAITVEHICLE: bool = False
|
|
68
|
+
"""Ignore the maximum vehicle wait constraint."""
|
|
69
|
+
MODEL_CONSTRAINTS_DISABLE_MIXINGITEMS: bool = False
|
|
70
|
+
"""Ignore the do not mix items constraint."""
|
|
71
|
+
MODEL_CONSTRAINTS_DISABLE_PRECEDENCE: bool = False
|
|
72
|
+
"""Ignore the precedence (pickups & deliveries) constraint."""
|
|
73
|
+
MODEL_CONSTRAINTS_DISABLE_STARTTIMEWINDOWS: bool = False
|
|
74
|
+
"""Ignore the start time windows constraint."""
|
|
75
|
+
MODEL_CONSTRAINTS_DISABLE_VEHICLEENDTIME: bool = False
|
|
76
|
+
"""Ignore the vehicle end time constraint."""
|
|
77
|
+
MODEL_CONSTRAINTS_DISABLE_VEHICLESTARTTIME: bool = False
|
|
78
|
+
"""Ignore the vehicle start time constraint."""
|
|
79
|
+
MODEL_CONSTRAINTS_ENABLE_CLUSTER: bool = False
|
|
80
|
+
"""Enable the cluster constraint."""
|
|
81
|
+
MODEL_OBJECTIVES_CAPACITIES: str = ""
|
|
82
|
+
"""
|
|
83
|
+
Capacity objective, provide triple for each resource
|
|
84
|
+
`name=default;factor=1.0;offset=0.0`.
|
|
85
|
+
"""
|
|
86
|
+
MODEL_OBJECTIVES_CLUSTER: float = 0.0
|
|
87
|
+
"""Factor to weigh the cluster objective."""
|
|
88
|
+
MODEL_OBJECTIVES_DISTANCE: float = 0.0
|
|
89
|
+
"""Factor to weigh the distance objective."""
|
|
90
|
+
MODEL_OBJECTIVES_EARLYARRIVALPENALTY: float = 1.0
|
|
91
|
+
"""Factor to weigh the early arrival objective."""
|
|
92
|
+
MODEL_OBJECTIVES_LATEARRIVALPENALTY: float = 1.0
|
|
93
|
+
"""Factor to weigh the late arrival objective."""
|
|
94
|
+
MODEL_OBJECTIVES_MINSTOPS: float = 1.0
|
|
95
|
+
"""Factor to weigh the min stops objective."""
|
|
96
|
+
MODEL_OBJECTIVES_STOPBALANCE: float = 0.0
|
|
97
|
+
"""Factor to weigh the stop balance objective."""
|
|
98
|
+
MODEL_OBJECTIVES_TRAVELDURATION: float = 0.0
|
|
99
|
+
"""Factor to weigh the travel duration objective."""
|
|
100
|
+
MODEL_OBJECTIVES_UNPLANNEDPENALTY: float = 1.0
|
|
101
|
+
"""Factor to weigh the unplanned objective."""
|
|
102
|
+
MODEL_OBJECTIVES_VEHICLEACTIVATIONPENALTY: float = 1.0
|
|
103
|
+
"""Factor to weigh the vehicle activation objective."""
|
|
104
|
+
MODEL_OBJECTIVES_VEHICLESDURATION: float = 1.0
|
|
105
|
+
"""Factor to weigh the vehicles duration objective."""
|
|
106
|
+
MODEL_PROPERTIES_DISABLE_DURATIONGROUPS: bool = False
|
|
107
|
+
"""Ignore the durations groups of stops."""
|
|
108
|
+
MODEL_PROPERTIES_DISABLE_DURATIONS: bool = False
|
|
109
|
+
"""Ignore the durations of stops."""
|
|
110
|
+
MODEL_PROPERTIES_DISABLE_INITIALSOLUTION: bool = False
|
|
111
|
+
"""Ignore the initial solution."""
|
|
112
|
+
MODEL_PROPERTIES_DISABLE_STOPDURATIONMULTIPLIERS: bool = False
|
|
113
|
+
"""Ignore the stop duration multipliers defined on vehicles."""
|
|
114
|
+
MODEL_PROPERTIES_MAXIMUMTIMEHORIZON: int = 15552000
|
|
115
|
+
"""Maximum time horizon for the model in seconds."""
|
|
116
|
+
MODEL_VALIDATE_DISABLE_RESOURCES: bool = False
|
|
117
|
+
"""Disable the resources validation."""
|
|
118
|
+
MODEL_VALIDATE_DISABLE_STARTTIME: bool = False
|
|
119
|
+
"""Disable the start time validation."""
|
|
120
|
+
MODEL_VALIDATE_ENABLE_MATRIX: bool = False
|
|
121
|
+
"""Enable matrix validation."""
|
|
122
|
+
MODEL_VALIDATE_ENABLE_MATRIXASYMMETRYTOLERANCE: int = 20
|
|
123
|
+
"""Percentage of acceptable matrix asymmetry, requires matrix validation enabled."""
|
|
124
|
+
SOLVE_DURATION: float = 5
|
|
125
|
+
"""Maximum duration, in seconds, of the solver."""
|
|
126
|
+
SOLVE_ITERATIONS: int = -1
|
|
26
127
|
"""
|
|
27
128
|
Maximum number of iterations, -1 assumes no limit; iterations are counted
|
|
28
129
|
after start solutions are generated.
|
|
29
130
|
"""
|
|
30
|
-
|
|
31
|
-
"""Maximum duration, in seconds, of the solver."""
|
|
32
|
-
parallel_runs: int = -1
|
|
131
|
+
SOLVE_PARALLELRUNS: int = -1
|
|
33
132
|
"""
|
|
34
133
|
Maximum number of parallel runs, -1 results in using all available
|
|
35
134
|
resources.
|
|
36
135
|
"""
|
|
37
|
-
|
|
136
|
+
SOLVE_PLATEAU_DELAY: float = 0.0
|
|
137
|
+
"""Delay before starting to monitor for a plateau."""
|
|
138
|
+
SOLVE_PLATEAU_ABSOLUTETHRESHOLD: float = -1
|
|
139
|
+
"""Absolute threshold for significant improvement."""
|
|
140
|
+
SOLVE_PLATEAU_DURATION: float = 0.0
|
|
141
|
+
"""Maximum duration, in seconds, without (significant) improvement."""
|
|
142
|
+
SOLVE_PLATEAU_ITERATIONS: int = 0
|
|
143
|
+
"""Maximum number of iterations without (significant) improvement."""
|
|
144
|
+
SOLVE_PLATEAU_RELATIVETHRESHOLD: float = 0.0
|
|
145
|
+
"""Relative threshold for significant improvement."""
|
|
146
|
+
SOLVE_RUNDETERMINISTICALLY: bool = False
|
|
147
|
+
"""Run the parallel solver deterministically."""
|
|
148
|
+
SOLVE_SOLVER_PLANGROUPSIZE_DELTA: int = 0
|
|
149
|
+
"""Delta for the plan group size parameter."""
|
|
150
|
+
SOLVE_SOLVER_PLANGROUPSIZE_DELTAAFTERITERATIONS: int = 1000000000
|
|
151
|
+
"""Delta after each iteration for the plan group size parameter."""
|
|
152
|
+
SOLVE_SOLVER_PLANGROUPSIZE_MAXVALUE: int = 2
|
|
153
|
+
"""Maximum value for the plan group size parameter."""
|
|
154
|
+
SOLVE_SOLVER_PLANGROUPSIZE_MINVALUE: int = 2
|
|
155
|
+
"""Minimum value for the plan group size parameter."""
|
|
156
|
+
SOLVE_SOLVER_PLANGROUPSIZE_SNAPBACKAFTERIMPROVEMENT: bool = True
|
|
157
|
+
"""Snap back to start value after improvement of best solution for the plan group size parameter."""
|
|
158
|
+
SOLVE_SOLVER_PLANGROUPSIZE_STARTVALUE: int = 2
|
|
159
|
+
"""Start value for the plan group size parameter."""
|
|
160
|
+
SOLVE_SOLVER_PLANGROUPSIZE_ZIGZAG: bool = True
|
|
161
|
+
"""Zigzag between min and max value like a jig saw for the plan group size parameter."""
|
|
162
|
+
SOLVE_SOLVER_UNPLANUNITS_DELTA: int = 2
|
|
163
|
+
"""Delta for the unplan units parameter."""
|
|
164
|
+
SOLVE_SOLVER_UNPLANUNITS_DELTAAFTERITERATIONS: int = 125
|
|
165
|
+
"""Delta after each iteration for the unplan units parameter."""
|
|
166
|
+
SOLVE_SOLVER_UNPLANUNITS_MAXVALUE: int = -1
|
|
167
|
+
"""Maximum value for the unplan units parameter."""
|
|
168
|
+
SOLVE_SOLVER_UNPLANUNITS_MINVALUE: int = 2
|
|
169
|
+
"""Minimum value for the unplan units parameter."""
|
|
170
|
+
SOLVE_SOLVER_UNPLANUNITS_SNAPBACKAFTERIMPROVEMENT: bool = True
|
|
171
|
+
"""Snap back to start value after improvement of best solution for the unplan units parameter."""
|
|
172
|
+
SOLVE_SOLVER_UNPLANUNITS_STARTVALUE: int = 2
|
|
173
|
+
"""Start value for the unplan units parameter."""
|
|
174
|
+
SOLVE_SOLVER_UNPLANUNITS_ZIGZAG: bool = True
|
|
175
|
+
"""Zigzag between min and max value like a jig saw for the unplan units parameter."""
|
|
176
|
+
SOLVE_SOLVER_UNPLANWEIGHTS: str = "Vehicle:3,Island:1,Location:293"
|
|
177
|
+
"""Unplan heuristic weights parameter."""
|
|
178
|
+
SOLVE_STARTSOLUTIONS: int = -1
|
|
38
179
|
"""
|
|
39
180
|
Number of solutions to generate on top of those passed in; one solution
|
|
40
181
|
generated with sweep algorithm, the rest generated randomly.
|
|
41
182
|
"""
|
|
42
|
-
run_deterministically: bool = False
|
|
43
|
-
"""Run the parallel solver deterministically."""
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
class DisableFormatOptions(BaseModel):
|
|
47
|
-
"""Options for disabling/enabling the progression series."""
|
|
48
|
-
|
|
49
|
-
progression: bool = False
|
|
50
|
-
"""Whether to disable the progression series."""
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
class FormatOptions(BaseModel):
|
|
54
|
-
"""Options for formatting the output of the solver."""
|
|
55
|
-
|
|
56
|
-
disable: DisableFormatOptions = Field(default_factory=DisableFormatOptions)
|
|
57
|
-
"""Options for disabling/enabling the progression series."""
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
class Options(BaseModel):
|
|
61
|
-
"""Options for using Nextroute."""
|
|
62
|
-
|
|
63
|
-
check: CheckOptions = Field(default_factory=CheckOptions)
|
|
64
|
-
"""Options for enabling the check engine."""
|
|
65
|
-
format: FormatOptions = Field(default_factory=FormatOptions)
|
|
66
|
-
"""Options for the output format."""
|
|
67
|
-
model: FactoryOptions = Field(default_factory=FactoryOptions)
|
|
68
|
-
"""Options for the ready-to-go model."""
|
|
69
|
-
solve: ParallelSolveOptions = Field(default_factory=ParallelSolveOptions)
|
|
70
|
-
"""Options for the parallel solver."""
|
|
71
183
|
|
|
72
184
|
def to_args(self) -> List[str]:
|
|
73
185
|
"""
|
|
@@ -80,20 +192,18 @@ class Options(BaseModel):
|
|
|
80
192
|
"""
|
|
81
193
|
|
|
82
194
|
opt_dict = self.to_dict()
|
|
83
|
-
flattened = _flatten(opt_dict)
|
|
84
195
|
|
|
85
196
|
default_options = Options()
|
|
86
197
|
default_options_dict = default_options.to_dict()
|
|
87
|
-
default_flattened = _flatten(default_options_dict)
|
|
88
198
|
|
|
89
199
|
args = []
|
|
90
|
-
for key, value in
|
|
200
|
+
for key, value in opt_dict.items():
|
|
91
201
|
# We only care about custom options, so we skip the default ones.
|
|
92
|
-
default_value =
|
|
202
|
+
default_value = default_options_dict.get(key)
|
|
93
203
|
if value == default_value:
|
|
94
204
|
continue
|
|
95
205
|
|
|
96
|
-
key = key.replace(
|
|
206
|
+
key = f"-{key.replace('_', '.').lower()}"
|
|
97
207
|
|
|
98
208
|
str_value = json.dumps(value)
|
|
99
209
|
if key in _DURATIONS_ARGS:
|
|
@@ -118,34 +228,33 @@ class Options(BaseModel):
|
|
|
118
228
|
|
|
119
229
|
return args
|
|
120
230
|
|
|
231
|
+
@classmethod
|
|
232
|
+
def extract_from_dict(cls, data: Dict[str, Any]) -> "Options":
|
|
233
|
+
"""
|
|
234
|
+
Extracts options from a dictionary. This dictionary may contain more
|
|
235
|
+
keys that are not part of the Nextroute options.
|
|
121
236
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
for child_key, child_value in nested.items():
|
|
127
|
-
root_key = f"-{child_key}"
|
|
128
|
-
__set_children(flattened, root_key, child_value)
|
|
129
|
-
|
|
130
|
-
return flattened
|
|
131
|
-
|
|
237
|
+
Parameters
|
|
238
|
+
----------
|
|
239
|
+
data : Dict[str, Any]
|
|
240
|
+
The dictionary to extract options from.
|
|
132
241
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
242
|
+
Returns
|
|
243
|
+
----------
|
|
244
|
+
Options
|
|
245
|
+
The Nextroute options.
|
|
246
|
+
"""
|
|
138
247
|
|
|
139
|
-
|
|
248
|
+
options = cls()
|
|
249
|
+
for key, value in data.items():
|
|
250
|
+
key = key.upper()
|
|
251
|
+
if not hasattr(options, key):
|
|
252
|
+
continue
|
|
140
253
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
254
|
+
# Enums need to be handled manually.
|
|
255
|
+
if key == "CHECK_VERBOSITY":
|
|
256
|
+
value = Verbosity(value)
|
|
144
257
|
|
|
145
|
-
|
|
146
|
-
for child_key, child_value in parent_value.items():
|
|
147
|
-
new_key = f"{parent_key}.{child_key}"
|
|
148
|
-
__set_children(flattened, new_key, child_value)
|
|
149
|
-
return
|
|
258
|
+
setattr(options, key, value)
|
|
150
259
|
|
|
151
|
-
|
|
260
|
+
return options
|
nextroute/schema/input.py
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
Defines the input class.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
from
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from typing import Any, List, Optional, Union
|
|
8
9
|
|
|
9
10
|
from nextroute.base_model import BaseModel
|
|
10
11
|
from nextroute.schema.stop import AlternateStop, Stop, StopDefaults
|
|
@@ -30,6 +31,30 @@ class DurationGroup(BaseModel):
|
|
|
30
31
|
"""Stop IDs contained in the group."""
|
|
31
32
|
|
|
32
33
|
|
|
34
|
+
class MatrixTimeFrame(BaseModel):
|
|
35
|
+
"""Represents a time-dependent duration matrix or scaling factor."""
|
|
36
|
+
|
|
37
|
+
start_time: datetime
|
|
38
|
+
"""Start time of the time frame."""
|
|
39
|
+
end_time: datetime
|
|
40
|
+
"""End time of the time frame."""
|
|
41
|
+
matrix: Optional[List[List[float]]] = None
|
|
42
|
+
"""Duration matrix for the time frame."""
|
|
43
|
+
scaling_factor: Optional[float] = None
|
|
44
|
+
"""Scaling factor for the time frame."""
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class TimeDependentMatrix(BaseModel):
|
|
48
|
+
"""Represents time-dependent duration matrices."""
|
|
49
|
+
|
|
50
|
+
vehicle_ids: Optional[List[str]] = None
|
|
51
|
+
"""Vehicle IDs for which the duration matrix is defined."""
|
|
52
|
+
default_matrix: List[List[float]]
|
|
53
|
+
"""Default duration matrix."""
|
|
54
|
+
matrix_time_frames: Optional[List[MatrixTimeFrame]] = None
|
|
55
|
+
"""Time-dependent duration matrices."""
|
|
56
|
+
|
|
57
|
+
|
|
33
58
|
class Input(BaseModel):
|
|
34
59
|
"""Input schema for Nextroute."""
|
|
35
60
|
|
|
@@ -46,10 +71,16 @@ class Input(BaseModel):
|
|
|
46
71
|
"""Default values for vehicles and stops."""
|
|
47
72
|
distance_matrix: Optional[List[List[float]]] = None
|
|
48
73
|
"""Matrix of travel distances in meters between stops."""
|
|
49
|
-
|
|
74
|
+
duration_groups: Optional[List[DurationGroup]] = None
|
|
50
75
|
"""Duration in seconds added when approaching the group."""
|
|
51
|
-
duration_matrix: Optional[
|
|
52
|
-
|
|
76
|
+
duration_matrix: Optional[
|
|
77
|
+
Union[
|
|
78
|
+
List[List[float]],
|
|
79
|
+
TimeDependentMatrix,
|
|
80
|
+
List[TimeDependentMatrix],
|
|
81
|
+
]
|
|
82
|
+
] = None
|
|
83
|
+
"""Matrix of travel durations in seconds between stops as a single matrix or duration matrices."""
|
|
53
84
|
options: Optional[Any] = None
|
|
54
85
|
"""Arbitrary options."""
|
|
55
86
|
stop_groups: Optional[List[List[str]]] = None
|
nextroute/solve.py
CHANGED
|
@@ -6,6 +6,7 @@ Methods for solving a Vehicle Routing Problem with Nextroute.
|
|
|
6
6
|
|
|
7
7
|
import json
|
|
8
8
|
import os
|
|
9
|
+
import platform
|
|
9
10
|
import subprocess
|
|
10
11
|
from typing import Any, Dict, Union
|
|
11
12
|
|
|
@@ -15,15 +16,9 @@ from nextroute.schema.output import Output
|
|
|
15
16
|
|
|
16
17
|
SUPPORTED_OS = ["linux", "windows", "darwin"]
|
|
17
18
|
"""The operating systems supported by the Nextroute engine."""
|
|
18
|
-
SUPPORTED_ARCHITECTURES = ["x86_64", "arm64", "aarch64"]
|
|
19
|
+
SUPPORTED_ARCHITECTURES = ["amd64", "x86_64", "arm64", "aarch64"]
|
|
19
20
|
"""The architectures supported by the Nextroute engine."""
|
|
20
21
|
|
|
21
|
-
_ARCHITECTURE_TRANSLATION = {
|
|
22
|
-
"x86_64": "amd64",
|
|
23
|
-
"arm64": "arm64",
|
|
24
|
-
"aarch64": "arm64",
|
|
25
|
-
}
|
|
26
|
-
|
|
27
22
|
|
|
28
23
|
def solve(
|
|
29
24
|
input: Union[Input, Dict[str, Any]],
|
|
@@ -114,21 +109,17 @@ def solve(
|
|
|
114
109
|
if isinstance(options, dict):
|
|
115
110
|
options = Options.from_dict(options)
|
|
116
111
|
|
|
117
|
-
os_name =
|
|
112
|
+
os_name = platform.system().lower()
|
|
118
113
|
if os_name not in SUPPORTED_OS:
|
|
119
114
|
raise Exception(f'unsupported operating system: "{os_name}", supported os are: {", ".join(SUPPORTED_OS)}')
|
|
120
115
|
|
|
121
|
-
architecture =
|
|
116
|
+
architecture = platform.machine().lower()
|
|
122
117
|
if architecture not in SUPPORTED_ARCHITECTURES:
|
|
123
118
|
raise Exception(
|
|
124
119
|
f'unsupported architecture: "{architecture}", supported arch are: {", ".join(SUPPORTED_ARCHITECTURES)}'
|
|
125
120
|
)
|
|
126
121
|
|
|
127
|
-
|
|
128
|
-
if os_name == "windows":
|
|
129
|
-
binary_name += ".exe"
|
|
130
|
-
|
|
131
|
-
executable = os.path.join(os.path.dirname(__file__), "bin", binary_name)
|
|
122
|
+
executable = os.path.join(os.path.dirname(__file__), "bin", "nextroute.exe")
|
|
132
123
|
if not os.path.exists(executable):
|
|
133
124
|
raise Exception(f"missing Nextroute binary: {executable}")
|
|
134
125
|
|
nextroute/version.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: nextroute
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.12.3
|
|
4
4
|
Summary: Nextroute is an engine for solving Vehicle Routing Problems (VRPs).
|
|
5
5
|
Author-email: Nextmv <tech@nextmv.io>
|
|
6
6
|
Maintainer-email: Nextmv <tech@nextmv.io>
|
|
@@ -104,10 +104,12 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
104
104
|
Classifier: Programming Language :: Python :: 3.10
|
|
105
105
|
Classifier: Programming Language :: Python :: 3.11
|
|
106
106
|
Classifier: Programming Language :: Python :: 3.12
|
|
107
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
107
108
|
Requires-Python: >=3.8
|
|
108
109
|
Description-Content-Type: text/markdown
|
|
109
110
|
License-File: LICENSE
|
|
110
111
|
Requires-Dist: pydantic>=2.5.2
|
|
112
|
+
Dynamic: license-file
|
|
111
113
|
|
|
112
114
|
# Nextroute
|
|
113
115
|
|
|
@@ -197,7 +199,7 @@ file.
|
|
|
197
199
|
|
|
198
200
|
For further information on how to get started, features, deployment, etc.,
|
|
199
201
|
please refer to the [official
|
|
200
|
-
documentation](https://www.nextmv.io/docs/vehicle-routing).
|
|
202
|
+
documentation](https://www.nextmv.io/docs/vehicle-routing/get-started).
|
|
201
203
|
|
|
202
204
|
### Go
|
|
203
205
|
|
|
@@ -233,12 +235,7 @@ with open("cmd/input.json") as f:
|
|
|
233
235
|
data = json.load(f)
|
|
234
236
|
|
|
235
237
|
input = nextroute.schema.Input.from_dict(data)
|
|
236
|
-
options = nextroute.Options(
|
|
237
|
-
solve=nextroute.ParallelSolveOptions(
|
|
238
|
-
duration=5,
|
|
239
|
-
),
|
|
240
|
-
)
|
|
241
|
-
|
|
238
|
+
options = nextroute.Options(SOLVE_DURATION=5)
|
|
242
239
|
output = nextroute.solve(input, options)
|
|
243
240
|
print(json.dumps(output.to_dict(), indent=2))
|
|
244
241
|
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
nextroute-1.12.3.dist-info/RECORD,,
|
|
2
|
+
nextroute-1.12.3.dist-info/WHEEL,sha256=entZNN85s-JxqcmXHTt39Ax198pJrOYoKFOQaLspAVk,110
|
|
3
|
+
nextroute-1.12.3.dist-info/top_level.txt,sha256=KNsuo1j7tr-QvBFS_ELmo68OmJ-orEZiOXqstGLJDXA,16
|
|
4
|
+
nextroute-1.12.3.dist-info/METADATA,sha256=IWx8wIDz9Eq2z-3bNW431o7hYu2q3HX0iJLH6A1MOn4,15612
|
|
5
|
+
nextroute-1.12.3.dist-info/licenses/LICENSE,sha256=ElKAl6B15yj4LTFL_Dh1hje431kMHut2urxo5nheRWs,4107
|
|
6
|
+
tests/solve_golden/__init__.py,sha256=MRZbyX5fYnxsXV0YP6lf32c5YYMo3NsEFqPwdwf5W18,32
|
|
7
|
+
tests/solve_golden/main.py,sha256=VScx0kPD8ihGR5bSIpLrPTIxRh7mkk9YQ9g0eg8XZMc,1738
|
|
8
|
+
tests/schema/test_input.py,sha256=kNIlUFqCkvvQieuJIo7-6C_NB9PZqZ72NpGwUWtDZcA,1851
|
|
9
|
+
tests/schema/__init__.py,sha256=MRZbyX5fYnxsXV0YP6lf32c5YYMo3NsEFqPwdwf5W18,32
|
|
10
|
+
tests/schema/test_output.py,sha256=i0VreVBXamC-Pk-z7X3W9APjmjfG8iOPAt2jxP4hDQA,11579
|
|
11
|
+
nextroute/options.py,sha256=tZcTLIjsx-6fq9Q9Y-Z8syKbPqGyR3GV6vfpWvVmzLQ,10280
|
|
12
|
+
nextroute/version.py,sha256=aA_wmIifNRCzxBigX4cSz1Y2CdXvuBNIiY7Nem5UqRA,325
|
|
13
|
+
nextroute/__init__.py,sha256=wBHS73T_Mm2MfcEx4chZCI1QMbV-a1D7bw7megFLgb4,529
|
|
14
|
+
nextroute/base_model.py,sha256=Jl205oJZvndkY8rIomZD2k5YhlGgRBn_2I1BKwQ8Vkk,541
|
|
15
|
+
nextroute/__about__.py,sha256=H71OIfyHAXJOiG4wuGcoP506V3in6aScHaOMWCJknuM,57
|
|
16
|
+
nextroute/solve.py,sha256=It1kDEdFk_AXX-gEUjvQbc7C-0ma9bEPRbnC_bHMsUU,4192
|
|
17
|
+
nextroute/bin/nextroute.exe,sha256=uqL63K4vXMiKLTpZqa8APeh7kmutF7frc4EGSCMm4Eo,14990208
|
|
18
|
+
nextroute/schema/stop.py,sha256=leKhNC0rcEo64NMNofDuVYnfDNLaqfLZ-mSxUEAwoZk,2199
|
|
19
|
+
nextroute/schema/vehicle.py,sha256=0W3q-upCn5yEUDX2BBeq5TkOCsrlLsk3Wao-T74nDmU,2535
|
|
20
|
+
nextroute/schema/__init__.py,sha256=KSlnpJQMnCDq5IXyiltt9CiafcxUH40B3FdE1fc5wdI,1167
|
|
21
|
+
nextroute/schema/location.py,sha256=hihllMU3IXxQHugGC4Wn_TzDPr5zm4xqVqRsKanwrmA,301
|
|
22
|
+
nextroute/schema/input.py,sha256=uidXX_hpv1KpiIUCc_XhiiQf69vxiav9DsXfiLtpD2s,2856
|
|
23
|
+
nextroute/schema/statistics.py,sha256=lNlb1mcpR6xWQclG-fkDMnFoy-sEKpXKk80zU1TKrpQ,3600
|
|
24
|
+
nextroute/schema/output.py,sha256=rJv_PpP0X0MdLTRa2tbDsLLbGhTRi43hGmMNmzvNZEw,4810
|
|
25
|
+
nextroute/check/__init__.py,sha256=Hrw5LUqdMeaBEsoIrJmWDhmAKAzGuzDnoBExwNWJvlU,1303
|
|
26
|
+
nextroute/check/schema.py,sha256=hBC0Usw4_rEJHsWDxDtIi0-d6byXt8f9eYqBE9hqiCc,5853
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# This script is copied to the `src` root so that the `nextroute` import is
|
|
2
|
+
# resolved. It is fed an input via stdin and is meant to write the output to
|
|
3
|
+
# stdout.
|
|
4
|
+
import nextmv
|
|
5
|
+
|
|
6
|
+
import nextroute
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def main() -> None:
|
|
10
|
+
"""Entry point for the program."""
|
|
11
|
+
|
|
12
|
+
parameters = [
|
|
13
|
+
nextmv.Parameter("input", str, "", "Path to input file. Default is stdin.", False),
|
|
14
|
+
nextmv.Parameter("output", str, "", "Path to output file. Default is stdout.", False),
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
default_options = nextroute.Options()
|
|
18
|
+
for name, default_value in default_options.to_dict().items():
|
|
19
|
+
parameters.append(nextmv.Parameter(name.lower(), type(default_value), default_value, name, False))
|
|
20
|
+
|
|
21
|
+
options = nextmv.Options(*parameters)
|
|
22
|
+
|
|
23
|
+
input = nextmv.load_local(options=options, path=options.input)
|
|
24
|
+
|
|
25
|
+
nextmv.log("Solving vehicle routing problem:")
|
|
26
|
+
nextmv.log(f" - stops: {len(input.data.get('stops', []))}")
|
|
27
|
+
nextmv.log(f" - vehicles: {len(input.data.get('vehicles', []))}")
|
|
28
|
+
|
|
29
|
+
model = DecisionModel()
|
|
30
|
+
output = model.solve(input)
|
|
31
|
+
nextmv.write_local(output, path=options.output)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class DecisionModel(nextmv.Model):
|
|
35
|
+
def solve(self, input: nextmv.Input) -> nextmv.Output:
|
|
36
|
+
"""Solves the given problem and returns the solution."""
|
|
37
|
+
|
|
38
|
+
nextroute_input = nextroute.schema.Input.from_dict(input.data)
|
|
39
|
+
nextroute_options = nextroute.Options.extract_from_dict(input.options.to_dict())
|
|
40
|
+
nextroute_output = nextroute.solve(nextroute_input, nextroute_options)
|
|
41
|
+
|
|
42
|
+
return nextmv.Output(
|
|
43
|
+
options=input.options,
|
|
44
|
+
solution=nextroute_output.solutions[0].to_dict(),
|
|
45
|
+
statistics=nextroute_output.statistics.to_dict(),
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
if __name__ == "__main__":
|
|
50
|
+
main()
|
nextroute/check/options.py
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# © 2019-present nextmv.io inc
|
|
2
|
-
|
|
3
|
-
"""
|
|
4
|
-
Options for the Nextroute check engine.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from enum import Enum
|
|
8
|
-
|
|
9
|
-
from nextroute.base_model import BaseModel
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class Verbosity(str, Enum):
|
|
13
|
-
"""Format of an `Input`."""
|
|
14
|
-
|
|
15
|
-
OFF = "off"
|
|
16
|
-
"""The check engine is not run."""
|
|
17
|
-
LOW = "low"
|
|
18
|
-
"""Low verbosity for the check engine."""
|
|
19
|
-
MEDIUM = "medium"
|
|
20
|
-
"""Medium verbosity for the check engine."""
|
|
21
|
-
HIGH = "high"
|
|
22
|
-
"""High verbosity for the check engine."""
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class Options(BaseModel):
|
|
26
|
-
"""Options for the Nextroute check engine."""
|
|
27
|
-
|
|
28
|
-
duration: float = 30
|
|
29
|
-
"""Maximum duration of the check, in seconds."""
|
|
30
|
-
verbosity: Verbosity = Verbosity.OFF
|
|
31
|
-
"""Verbosity of the check engine."""
|
nextroute/factory/__init__.py
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# © 2019-present nextmv.io inc
|
|
2
|
-
|
|
3
|
-
"""
|
|
4
|
-
Functionality for creating a ready-to-go Nextroute model.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from .options import Constraints as Constraints
|
|
8
|
-
from .options import DisableConstraints as DisableConstraints
|
|
9
|
-
from .options import DisableProperties as DisableProperties
|
|
10
|
-
from .options import DisableValidate as DisableValidate
|
|
11
|
-
from .options import EnableConstraints as EnableConstraints
|
|
12
|
-
from .options import EnableValidate as EnableValidate
|
|
13
|
-
from .options import Objectives as Objectives
|
|
14
|
-
from .options import Options as Options
|
|
15
|
-
from .options import Properties as Properties
|
|
16
|
-
from .options import Validate as Validate
|
nextroute/factory/options.py
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
# © 2019-present nextmv.io inc
|
|
2
|
-
|
|
3
|
-
"""
|
|
4
|
-
Options for the Nextroute factory.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from typing import List
|
|
8
|
-
|
|
9
|
-
from pydantic import Field
|
|
10
|
-
|
|
11
|
-
from nextroute.base_model import BaseModel
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class DisableConstraints(BaseModel):
|
|
15
|
-
"""Options for disabling specific constraints."""
|
|
16
|
-
|
|
17
|
-
attributes: bool = False
|
|
18
|
-
"""Ignore the compatibility attributes constraint."""
|
|
19
|
-
capacity: bool = False
|
|
20
|
-
"""Ignore the capacity constraint for all resources."""
|
|
21
|
-
capacities: List[str] = Field(default_factory=list)
|
|
22
|
-
"""Ignore the capacity constraint for the given resource names."""
|
|
23
|
-
distance_limit: bool = False
|
|
24
|
-
"""Ignore the distance limit constraint."""
|
|
25
|
-
groups: bool = False
|
|
26
|
-
"""Ignore the groups constraint."""
|
|
27
|
-
maximum_duration: bool = False
|
|
28
|
-
"""Ignore the maximum duration constraint."""
|
|
29
|
-
maximum_stops: bool = False
|
|
30
|
-
"""Ignore the maximum stops constraint."""
|
|
31
|
-
maximum_wait_stop: bool = False
|
|
32
|
-
"""Ignore the maximum stop wait constraint."""
|
|
33
|
-
maximum_wait_vehicle: bool = False
|
|
34
|
-
"""Ignore the maximum vehicle wait constraint."""
|
|
35
|
-
mixing_items: bool = False
|
|
36
|
-
"""Ignore the do not mix items constraint."""
|
|
37
|
-
precedence: bool = False
|
|
38
|
-
"""Ignore the precedence (pickups & deliveries) constraint."""
|
|
39
|
-
vehicle_start_time: bool = False
|
|
40
|
-
"""Ignore the vehicle start time constraint."""
|
|
41
|
-
vehicle_end_time: bool = False
|
|
42
|
-
"""Ignore the vehicle end time constraint."""
|
|
43
|
-
start_time_windows: bool = False
|
|
44
|
-
"""Ignore the start time windows constraint."""
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
class EnableConstraints(BaseModel):
|
|
48
|
-
"""Options for enabling specific constraints."""
|
|
49
|
-
|
|
50
|
-
cluster: bool = False
|
|
51
|
-
"""Enable the cluster constraint."""
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
class Constraints(BaseModel):
|
|
55
|
-
"""Options for configuring constraints."""
|
|
56
|
-
|
|
57
|
-
disable: DisableConstraints = Field(default_factory=DisableConstraints)
|
|
58
|
-
"""Options for disabling specific constraints."""
|
|
59
|
-
enable: EnableConstraints = Field(default_factory=EnableConstraints)
|
|
60
|
-
"""Options for enabling specific constraints."""
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
class Objectives(BaseModel):
|
|
64
|
-
"""Options for configuring objectives."""
|
|
65
|
-
|
|
66
|
-
capacities: str = ""
|
|
67
|
-
"""
|
|
68
|
-
Capacity objective, provide triple for each resource
|
|
69
|
-
`name:default;factor:1.0;offset;0.0`.
|
|
70
|
-
"""
|
|
71
|
-
min_stops: float = 1.0
|
|
72
|
-
"""Factor to weigh the min stops objective."""
|
|
73
|
-
early_arrival_penalty: float = 1.0
|
|
74
|
-
"""Factor to weigh the early arrival objective."""
|
|
75
|
-
late_arrival_penalty: float = 1.0
|
|
76
|
-
"""Factor to weigh the late arrival objective."""
|
|
77
|
-
vehicle_activation_penalty: float = 1.0
|
|
78
|
-
"""Factor to weigh the vehicle activation objective."""
|
|
79
|
-
travel_duration: float = 0.0
|
|
80
|
-
"""Factor to weigh the travel duration objective."""
|
|
81
|
-
vehicles_duration: float = 1.0
|
|
82
|
-
"""Factor to weigh the vehicles duration objective."""
|
|
83
|
-
unplanned_penalty: float = 1.0
|
|
84
|
-
"""Factor to weigh the unplanned objective."""
|
|
85
|
-
cluster: float = 0.0
|
|
86
|
-
"""Factor to weigh the cluster objective."""
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
class DisableProperties(BaseModel):
|
|
90
|
-
"""Options for disabling specific properties."""
|
|
91
|
-
|
|
92
|
-
durations: bool = False
|
|
93
|
-
"""Ignore the durations of stops."""
|
|
94
|
-
stop_duration_multipliers: bool = False
|
|
95
|
-
"""Ignore the stop duration multipliers defined on vehicles."""
|
|
96
|
-
duration_groups: bool = False
|
|
97
|
-
"""Ignore the durations groups of stops."""
|
|
98
|
-
initial_solution: bool = False
|
|
99
|
-
"""Ignore the initial solution."""
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
class Properties(BaseModel):
|
|
103
|
-
"""Options for configuring properties."""
|
|
104
|
-
|
|
105
|
-
disable: DisableProperties = Field(default_factory=DisableProperties)
|
|
106
|
-
"""Options for disabling specific properties."""
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
class DisableValidate(BaseModel):
|
|
110
|
-
"""Options for disabling specific validations."""
|
|
111
|
-
|
|
112
|
-
start_time: bool = False
|
|
113
|
-
"""Disable the start time validation."""
|
|
114
|
-
resources: bool = False
|
|
115
|
-
"""Disable the resources validation."""
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
class EnableValidate(BaseModel):
|
|
119
|
-
"""Options for enabling specific validations."""
|
|
120
|
-
|
|
121
|
-
matrix: bool = False
|
|
122
|
-
"""Enable matrix validation."""
|
|
123
|
-
matrix_asymmetry_tolerance: int = 20
|
|
124
|
-
"""Percentage of acceptable matrix asymmetry, requires matrix validation enabled."""
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
class Validate(BaseModel):
|
|
128
|
-
"""Options for configuring validations."""
|
|
129
|
-
|
|
130
|
-
disable: DisableValidate = Field(default_factory=DisableValidate)
|
|
131
|
-
"""Options for disabling specific validations"""
|
|
132
|
-
enable: EnableValidate = Field(default_factory=EnableValidate)
|
|
133
|
-
"""Options for enabling specific validations"""
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
class Options(BaseModel):
|
|
137
|
-
"""Options that configure how a Nextroute model is built."""
|
|
138
|
-
|
|
139
|
-
constraints: Constraints = Field(default_factory=Constraints)
|
|
140
|
-
"""Options for configuring constraints."""
|
|
141
|
-
objectives: Objectives = Field(default_factory=Objectives)
|
|
142
|
-
"""Options for configuring objectives."""
|
|
143
|
-
properties: Properties = Field(default_factory=Properties)
|
|
144
|
-
"""Options for configuring properties."""
|
|
145
|
-
validate_options: Validate = Field(default_factory=Validate, alias="validate")
|
|
146
|
-
"""Options for configuring validations."""
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
tests/nextroute_python/test_options.py,sha256=8MJM05tF12M2kUjasA0kStrMFoIC1m9jDlydybpSUmI,4960
|
|
2
|
-
tests/nextroute_python/__init__.py,sha256=MRZbyX5fYnxsXV0YP6lf32c5YYMo3NsEFqPwdwf5W18,32
|
|
3
|
-
tests/nextroute_python/schema/test_input.py,sha256=kNIlUFqCkvvQieuJIo7-6C_NB9PZqZ72NpGwUWtDZcA,1851
|
|
4
|
-
tests/nextroute_python/schema/__init__.py,sha256=MRZbyX5fYnxsXV0YP6lf32c5YYMo3NsEFqPwdwf5W18,32
|
|
5
|
-
tests/nextroute_python/schema/test_output.py,sha256=i0VreVBXamC-Pk-z7X3W9APjmjfG8iOPAt2jxP4hDQA,11579
|
|
6
|
-
nextroute/options.py,sha256=swxZjQxkZ1-YbZ4RodaVsxZLc-6Ii5N6dp6veCPPl28,4647
|
|
7
|
-
nextroute/version.py,sha256=LIMuiAulNxiYKzNKUC6Qc6R67OgxI-54dtlvVHBFto8,292
|
|
8
|
-
nextroute/__init__.py,sha256=1NRMAxEvJKZ6JRwPGRK2C7LbfDH7SFqjSCGGLeqdFlM,669
|
|
9
|
-
nextroute/base_model.py,sha256=Jl205oJZvndkY8rIomZD2k5YhlGgRBn_2I1BKwQ8Vkk,541
|
|
10
|
-
nextroute/__about__.py,sha256=OdrvvA4KQR6CdtHBxVgVsNdTuVWgCqdn-eK4jSa7GJk,62
|
|
11
|
-
nextroute/solve.py,sha256=Fdo35yPnz_54CyqVUy46uGQ6WjTBZy3alJKz8yI6Iok,4409
|
|
12
|
-
nextroute/bin/nextroute.exe,sha256=U5ohy1yYxPwUmct_Pd6SuO78Tg_7kybZDsbxfgsySDk,13296048
|
|
13
|
-
nextroute/schema/stop.py,sha256=leKhNC0rcEo64NMNofDuVYnfDNLaqfLZ-mSxUEAwoZk,2199
|
|
14
|
-
nextroute/schema/vehicle.py,sha256=0W3q-upCn5yEUDX2BBeq5TkOCsrlLsk3Wao-T74nDmU,2535
|
|
15
|
-
nextroute/schema/__init__.py,sha256=KSlnpJQMnCDq5IXyiltt9CiafcxUH40B3FdE1fc5wdI,1167
|
|
16
|
-
nextroute/schema/location.py,sha256=hihllMU3IXxQHugGC4Wn_TzDPr5zm4xqVqRsKanwrmA,301
|
|
17
|
-
nextroute/schema/input.py,sha256=8_-xi-P2t-A6mObLscKavT-Ro0td9VECp2pZOQ1dWmo,1863
|
|
18
|
-
nextroute/schema/statistics.py,sha256=lNlb1mcpR6xWQclG-fkDMnFoy-sEKpXKk80zU1TKrpQ,3600
|
|
19
|
-
nextroute/schema/output.py,sha256=rJv_PpP0X0MdLTRa2tbDsLLbGhTRi43hGmMNmzvNZEw,4810
|
|
20
|
-
nextroute/check/options.py,sha256=6fMFJvnd84OPmpGiFtSZmtVJmn0FdmX0PH71dZeQdt4,703
|
|
21
|
-
nextroute/check/__init__.py,sha256=cYCx73rR1gOysg1XHvothsdsN6sP-1jAiVIjxtNzaVg,1387
|
|
22
|
-
nextroute/check/schema.py,sha256=hBC0Usw4_rEJHsWDxDtIi0-d6byXt8f9eYqBE9hqiCc,5853
|
|
23
|
-
nextroute/factory/options.py,sha256=XMvfev4K5RGclMxkX5tCu5JhV5GchBWeOpptn3cdL9I,4948
|
|
24
|
-
nextroute/factory/__init__.py,sha256=kqi5fdunYqwBP3uOsBu-m0vHQANjOiyJpnKZ1xluER4,614
|
|
25
|
-
nextroute-1.8.0.dev24.dist-info/RECORD,,
|
|
26
|
-
nextroute-1.8.0.dev24.dist-info/LICENSE,sha256=ElKAl6B15yj4LTFL_Dh1hje431kMHut2urxo5nheRWs,4107
|
|
27
|
-
nextroute-1.8.0.dev24.dist-info/WHEEL,sha256=kEDwEAybh1yMTwMF4usCWe2WGZj5bJzouP4ddPUefKc,111
|
|
28
|
-
nextroute-1.8.0.dev24.dist-info/top_level.txt,sha256=KNsuo1j7tr-QvBFS_ELmo68OmJ-orEZiOXqstGLJDXA,16
|
|
29
|
-
nextroute-1.8.0.dev24.dist-info/METADATA,sha256=5wRe6kY7cqQuvwgGortFEhJ0Uj_VRe0uy7D5EnKj2hY,15587
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import unittest
|
|
2
|
-
|
|
3
|
-
import nextroute
|
|
4
|
-
import nextroute.check
|
|
5
|
-
import nextroute.factory
|
|
6
|
-
from nextroute import options
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class TestOptions(unittest.TestCase):
|
|
10
|
-
def test_options_default_values(self):
|
|
11
|
-
opt = nextroute.Options()
|
|
12
|
-
options_dict = opt.to_dict()
|
|
13
|
-
self.assertDictEqual(
|
|
14
|
-
options_dict,
|
|
15
|
-
{
|
|
16
|
-
"check": {"duration": 30.0, "verbosity": "off"},
|
|
17
|
-
"format": {"disable": {"progression": False}},
|
|
18
|
-
"model": {
|
|
19
|
-
"constraints": {
|
|
20
|
-
"disable": {
|
|
21
|
-
"attributes": False,
|
|
22
|
-
"capacity": False,
|
|
23
|
-
"capacities": [],
|
|
24
|
-
"distance_limit": False,
|
|
25
|
-
"groups": False,
|
|
26
|
-
"maximum_duration": False,
|
|
27
|
-
"maximum_stops": False,
|
|
28
|
-
"maximum_wait_stop": False,
|
|
29
|
-
"maximum_wait_vehicle": False,
|
|
30
|
-
"mixing_items": False,
|
|
31
|
-
"precedence": False,
|
|
32
|
-
"vehicle_start_time": False,
|
|
33
|
-
"vehicle_end_time": False,
|
|
34
|
-
"start_time_windows": False,
|
|
35
|
-
},
|
|
36
|
-
"enable": {"cluster": False},
|
|
37
|
-
},
|
|
38
|
-
"objectives": {
|
|
39
|
-
"capacities": "",
|
|
40
|
-
"min_stops": 1.0,
|
|
41
|
-
"early_arrival_penalty": 1.0,
|
|
42
|
-
"late_arrival_penalty": 1.0,
|
|
43
|
-
"vehicle_activation_penalty": 1.0,
|
|
44
|
-
"travel_duration": 0.0,
|
|
45
|
-
"vehicles_duration": 1.0,
|
|
46
|
-
"unplanned_penalty": 1.0,
|
|
47
|
-
"cluster": 0.0,
|
|
48
|
-
},
|
|
49
|
-
"properties": {
|
|
50
|
-
"disable": {
|
|
51
|
-
"durations": False,
|
|
52
|
-
"stop_duration_multipliers": False,
|
|
53
|
-
"duration_groups": False,
|
|
54
|
-
"initial_solution": False,
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
|
-
"validate": {
|
|
58
|
-
"disable": {"start_time": False, "resources": False},
|
|
59
|
-
"enable": {"matrix": False, "matrix_asymmetry_tolerance": 20},
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
"solve": {
|
|
63
|
-
"iterations": -1,
|
|
64
|
-
"duration": 5.0,
|
|
65
|
-
"parallel_runs": -1,
|
|
66
|
-
"start_solutions": -1,
|
|
67
|
-
"run_deterministically": False,
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
def test_flatten(self):
|
|
73
|
-
nested = {
|
|
74
|
-
"foo": {
|
|
75
|
-
"bar": False,
|
|
76
|
-
"baz": 1,
|
|
77
|
-
"roh": "doh",
|
|
78
|
-
},
|
|
79
|
-
"bar": {
|
|
80
|
-
"baz": {
|
|
81
|
-
"bah": "roh",
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
"baz": False,
|
|
85
|
-
"bah": 1,
|
|
86
|
-
}
|
|
87
|
-
flat = options._flatten(nested)
|
|
88
|
-
self.assertDictEqual(
|
|
89
|
-
flat,
|
|
90
|
-
{
|
|
91
|
-
"-foo.bar": False,
|
|
92
|
-
"-foo.baz": 1,
|
|
93
|
-
"-foo.roh": "doh",
|
|
94
|
-
"-bar.baz.bah": "roh",
|
|
95
|
-
"-baz": False,
|
|
96
|
-
"-bah": 1,
|
|
97
|
-
},
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
def test_options_to_args(self):
|
|
101
|
-
# Default options should not produce any arguments.
|
|
102
|
-
opt = nextroute.Options()
|
|
103
|
-
args = opt.to_args()
|
|
104
|
-
self.assertListEqual(args, [])
|
|
105
|
-
|
|
106
|
-
# Only options that are not default should produce arguments.
|
|
107
|
-
opt2 = nextroute.Options(
|
|
108
|
-
check=nextroute.check.Options(
|
|
109
|
-
duration=4,
|
|
110
|
-
verbosity=nextroute.check.Verbosity.MEDIUM,
|
|
111
|
-
),
|
|
112
|
-
solve=nextroute.ParallelSolveOptions(
|
|
113
|
-
duration=4,
|
|
114
|
-
iterations=-1, # Default value should be skipped.
|
|
115
|
-
),
|
|
116
|
-
model=nextroute.factory.Options(
|
|
117
|
-
constraints=nextroute.factory.Constraints(
|
|
118
|
-
disable=nextroute.factory.DisableConstraints(
|
|
119
|
-
attributes=True,
|
|
120
|
-
),
|
|
121
|
-
),
|
|
122
|
-
validate=nextroute.factory.Validate(
|
|
123
|
-
enable=nextroute.factory.EnableValidate(
|
|
124
|
-
matrix=False, # This option should be skipped because it is bool False.
|
|
125
|
-
),
|
|
126
|
-
),
|
|
127
|
-
),
|
|
128
|
-
)
|
|
129
|
-
args2 = opt2.to_args()
|
|
130
|
-
self.assertListEqual(
|
|
131
|
-
args2,
|
|
132
|
-
[
|
|
133
|
-
"-check.duration",
|
|
134
|
-
"4.0s",
|
|
135
|
-
"-check.verbosity",
|
|
136
|
-
"medium",
|
|
137
|
-
"-model.constraints.disable.attributes", # Bool flags do not have values.
|
|
138
|
-
"-solve.duration",
|
|
139
|
-
"4.0s",
|
|
140
|
-
],
|
|
141
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|