job-shop-lib 1.0.1__tar.gz → 1.0.3__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.
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/PKG-INFO +17 -10
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/README.md +16 -9
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/__init__.py +1 -1
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/_job_shop_instance.py +28 -28
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/_operation.py +2 -4
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/_schedule.py +11 -11
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/benchmarking/__init__.py +1 -0
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/benchmarking/_load_benchmark.py +3 -3
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/constraint_programming/_ortools_solver.py +6 -6
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/__init__.py +12 -10
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/_dispatcher.py +19 -19
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/_dispatcher_observer_config.py +3 -3
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/_factories.py +2 -3
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/_history_observer.py +1 -2
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/_optimal_operations_observer.py +3 -4
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/_ready_operation_filters.py +18 -19
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/_unscheduled_operations_observer.py +3 -2
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/feature_observers/_composite_feature_observer.py +11 -13
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/feature_observers/_earliest_start_time_observer.py +1 -3
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/feature_observers/_factory.py +11 -12
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/feature_observers/_feature_observer.py +8 -9
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/feature_observers/_is_completed_observer.py +2 -4
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/feature_observers/_is_ready_observer.py +2 -4
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/rules/__init__.py +11 -8
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/rules/_dispatching_rule_factory.py +2 -4
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/rules/_dispatching_rule_solver.py +15 -20
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/rules/_dispatching_rules_functions.py +9 -10
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/rules/_machine_chooser_factory.py +2 -3
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/rules/_utils.py +7 -8
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/generation/__init__.py +12 -1
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/generation/_general_instance_generator.py +22 -20
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/generation/_instance_generator.py +8 -8
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/generation/_transformations.py +4 -5
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/generation/_utils.py +16 -8
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/graphs/__init__.py +40 -8
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/graphs/_job_shop_graph.py +13 -14
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/graphs/_node.py +6 -12
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/graphs/graph_updaters/__init__.py +2 -1
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/graphs/graph_updaters/_residual_graph_updater.py +2 -4
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/reinforcement_learning/__init__.py +11 -8
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/reinforcement_learning/_multi_job_shop_graph_env.py +17 -17
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/reinforcement_learning/_resource_task_graph_observation.py +1 -1
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/reinforcement_learning/_reward_observers.py +1 -3
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/reinforcement_learning/_single_job_shop_graph_env.py +22 -24
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/reinforcement_learning/_utils.py +2 -2
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/visualization/gantt/__init__.py +7 -3
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/visualization/gantt/_gantt_chart_creator.py +11 -11
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/visualization/gantt/_gantt_chart_video_and_gif_creation.py +21 -21
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/visualization/gantt/_plot_gantt_chart.py +12 -14
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/visualization/graphs/__init__.py +1 -0
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/visualization/graphs/_plot_disjunctive_graph.py +15 -17
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/visualization/graphs/_plot_resource_task_graph.py +22 -24
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/pyproject.toml +3 -10
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/LICENSE +0 -0
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/_base_solver.py +0 -0
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/_scheduled_operation.py +0 -0
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/benchmarking/benchmark_instances.json +0 -0
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/constraint_programming/__init__.py +0 -0
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/feature_observers/__init__.py +0 -0
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/feature_observers/_duration_observer.py +0 -0
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/feature_observers/_is_scheduled_observer.py +0 -0
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/feature_observers/_position_in_job_observer.py +0 -0
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/dispatching/feature_observers/_remaining_operations_observer.py +0 -0
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/exceptions.py +0 -0
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/graphs/_build_disjunctive_graph.py +0 -0
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/graphs/_build_resource_task_graphs.py +0 -0
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/graphs/_constants.py +0 -0
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/graphs/graph_updaters/_disjunctive_graph_updater.py +0 -0
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/graphs/graph_updaters/_graph_updater.py +0 -0
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/graphs/graph_updaters/_utils.py +0 -0
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/py.typed +0 -0
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/reinforcement_learning/_types_and_constants.py +0 -0
- {job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/visualization/__init__.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: job-shop-lib
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.3
|
4
4
|
Summary: An easy-to-use and modular Python library for the Job Shop Scheduling Problem (JSSP)
|
5
5
|
License: MIT
|
6
6
|
Author: Pabloo22
|
@@ -40,7 +40,11 @@ JobShopLib is a Python package for creating, solving, and visualizing job shop s
|
|
40
40
|
|
41
41
|
It follows a modular design, allowing users to easily extend the library with new solvers, dispatching rules, visualization functions, etc.
|
42
42
|
|
43
|
-
|
43
|
+
There is a [documentation page](https://job-shop-lib.readthedocs.io/en/stable/) for versions 1.0.0a3 and onward. See the [latest pull requests](https://github.com/Pabloo22/job_shop_lib/pulls?q=is%3Apr+is%3Aclosed) for the latest changes.
|
44
|
+
|
45
|
+
See [`gnn_scheduler`](https://github.com/Pabloo22/gnn_scheduler/blob/main/gnn_scheduler/) for an example implementation of a graph neural network-based dispatcher trained with [PyTorch Geometric](https://pyg.org/).
|
46
|
+
|
47
|
+
See [this](https://colab.research.google.com/drive/1XV_Rvq1F2ns6DFG8uNj66q_rcowwTZ4H?usp=sharing) Google Colab notebook for a quick start guide! More advanced examples can be found [here](https://job-shop-lib.readthedocs.io/en/stable/examples.html).
|
44
48
|
|
45
49
|
## Installation :package:
|
46
50
|
|
@@ -54,11 +58,6 @@ You can install the latest stable version using `pip`:
|
|
54
58
|
pip install job-shop-lib
|
55
59
|
```
|
56
60
|
|
57
|
-
See [this](https://colab.research.google.com/drive/1XV_Rvq1F2ns6DFG8uNj66q_rcowwTZ4H?usp=sharing) Google Colab notebook for a quick start guide!
|
58
|
-
|
59
|
-
|
60
|
-
There is a [documentation page](https://job-shop-lib.readthedocs.io/en/latest/) for versions 1.0.0a3 and onward. See see the [latest pull requests](https://github.com/Pabloo22/job_shop_lib/pulls?q=is%3Apr+is%3Aclosed) for the latest changes.
|
61
|
-
|
62
61
|
<!-- end installation -->
|
63
62
|
|
64
63
|
<!-- key features -->
|
@@ -252,7 +251,15 @@ Additionally, the graph includes **disjunctive edges** between operations that u
|
|
252
251
|
```python
|
253
252
|
from job_shop_lib.visualization import plot_disjunctive_graph
|
254
253
|
|
255
|
-
fig = plot_disjunctive_graph(
|
254
|
+
fig = plot_disjunctive_graph(
|
255
|
+
instance,
|
256
|
+
figsize=(6, 4),
|
257
|
+
draw_disjunctive_edges="single_edge",
|
258
|
+
disjunctive_edges_additional_params={
|
259
|
+
"arrowstyle": "<|-|>",
|
260
|
+
"connectionstyle": "arc3,rad=0.15",
|
261
|
+
},
|
262
|
+
)
|
256
263
|
plt.show()
|
257
264
|
```
|
258
265
|
|
@@ -308,9 +315,9 @@ from job_shop_lib.graphs import (
|
|
308
315
|
)
|
309
316
|
from job_shop_lib.visualization import plot_resource_task_graph
|
310
317
|
|
311
|
-
|
318
|
+
resource_task_graph = build_resource_task_graph(instance)
|
312
319
|
|
313
|
-
fig = plot_resource_task_graph(
|
320
|
+
fig = plot_resource_task_graph(resource_task_graph)
|
314
321
|
plt.show()
|
315
322
|
```
|
316
323
|
|
@@ -16,7 +16,11 @@ JobShopLib is a Python package for creating, solving, and visualizing job shop s
|
|
16
16
|
|
17
17
|
It follows a modular design, allowing users to easily extend the library with new solvers, dispatching rules, visualization functions, etc.
|
18
18
|
|
19
|
-
|
19
|
+
There is a [documentation page](https://job-shop-lib.readthedocs.io/en/stable/) for versions 1.0.0a3 and onward. See the [latest pull requests](https://github.com/Pabloo22/job_shop_lib/pulls?q=is%3Apr+is%3Aclosed) for the latest changes.
|
20
|
+
|
21
|
+
See [`gnn_scheduler`](https://github.com/Pabloo22/gnn_scheduler/blob/main/gnn_scheduler/) for an example implementation of a graph neural network-based dispatcher trained with [PyTorch Geometric](https://pyg.org/).
|
22
|
+
|
23
|
+
See [this](https://colab.research.google.com/drive/1XV_Rvq1F2ns6DFG8uNj66q_rcowwTZ4H?usp=sharing) Google Colab notebook for a quick start guide! More advanced examples can be found [here](https://job-shop-lib.readthedocs.io/en/stable/examples.html).
|
20
24
|
|
21
25
|
## Installation :package:
|
22
26
|
|
@@ -30,11 +34,6 @@ You can install the latest stable version using `pip`:
|
|
30
34
|
pip install job-shop-lib
|
31
35
|
```
|
32
36
|
|
33
|
-
See [this](https://colab.research.google.com/drive/1XV_Rvq1F2ns6DFG8uNj66q_rcowwTZ4H?usp=sharing) Google Colab notebook for a quick start guide!
|
34
|
-
|
35
|
-
|
36
|
-
There is a [documentation page](https://job-shop-lib.readthedocs.io/en/latest/) for versions 1.0.0a3 and onward. See see the [latest pull requests](https://github.com/Pabloo22/job_shop_lib/pulls?q=is%3Apr+is%3Aclosed) for the latest changes.
|
37
|
-
|
38
37
|
<!-- end installation -->
|
39
38
|
|
40
39
|
<!-- key features -->
|
@@ -228,7 +227,15 @@ Additionally, the graph includes **disjunctive edges** between operations that u
|
|
228
227
|
```python
|
229
228
|
from job_shop_lib.visualization import plot_disjunctive_graph
|
230
229
|
|
231
|
-
fig = plot_disjunctive_graph(
|
230
|
+
fig = plot_disjunctive_graph(
|
231
|
+
instance,
|
232
|
+
figsize=(6, 4),
|
233
|
+
draw_disjunctive_edges="single_edge",
|
234
|
+
disjunctive_edges_additional_params={
|
235
|
+
"arrowstyle": "<|-|>",
|
236
|
+
"connectionstyle": "arc3,rad=0.15",
|
237
|
+
},
|
238
|
+
)
|
232
239
|
plt.show()
|
233
240
|
```
|
234
241
|
|
@@ -284,9 +291,9 @@ from job_shop_lib.graphs import (
|
|
284
291
|
)
|
285
292
|
from job_shop_lib.visualization import plot_resource_task_graph
|
286
293
|
|
287
|
-
|
294
|
+
resource_task_graph = build_resource_task_graph(instance)
|
288
295
|
|
289
|
-
fig = plot_resource_task_graph(
|
296
|
+
fig = plot_resource_task_graph(resource_task_graph)
|
290
297
|
plt.show()
|
291
298
|
```
|
292
299
|
|
@@ -4,7 +4,7 @@ from __future__ import annotations
|
|
4
4
|
|
5
5
|
import os
|
6
6
|
import functools
|
7
|
-
from typing import Any
|
7
|
+
from typing import Any
|
8
8
|
|
9
9
|
import numpy as np
|
10
10
|
from numpy.typing import NDArray
|
@@ -16,8 +16,8 @@ class JobShopInstance:
|
|
16
16
|
"""Data structure to store a Job Shop Scheduling Problem instance.
|
17
17
|
|
18
18
|
Additional attributes such as ``num_machines`` or ``durations_matrix`` can
|
19
|
-
be computed from the instance and are cached for performance
|
20
|
-
require expensive computations.
|
19
|
+
be computed from the instance and are cached for performance since they
|
20
|
+
might require expensive computations.
|
21
21
|
|
22
22
|
Methods:
|
23
23
|
|
@@ -51,14 +51,14 @@ class JobShopInstance:
|
|
51
51
|
total_duration
|
52
52
|
|
53
53
|
Attributes:
|
54
|
-
jobs (
|
54
|
+
jobs (list[list[Operation]]):
|
55
55
|
A list of lists of operations. Each list of operations represents
|
56
56
|
a job, and the operations are ordered by their position in the job.
|
57
57
|
The ``job_id``, ``position_in_job``, and ``operation_id``
|
58
58
|
attributes of the operations are set when the instance is created.
|
59
59
|
name (str):
|
60
60
|
A string with the name of the instance.
|
61
|
-
metadata (
|
61
|
+
metadata (dict[str, Any]):
|
62
62
|
A dictionary with additional information about the instance.
|
63
63
|
|
64
64
|
Args:
|
@@ -81,16 +81,16 @@ class JobShopInstance:
|
|
81
81
|
|
82
82
|
def __init__(
|
83
83
|
self,
|
84
|
-
jobs:
|
84
|
+
jobs: list[list[Operation]],
|
85
85
|
name: str = "JobShopInstance",
|
86
86
|
set_operation_attributes: bool = True,
|
87
87
|
**metadata: Any,
|
88
88
|
):
|
89
|
-
self.jobs:
|
89
|
+
self.jobs: list[list[Operation]] = jobs
|
90
90
|
if set_operation_attributes:
|
91
91
|
self.set_operation_attributes()
|
92
92
|
self.name: str = name
|
93
|
-
self.metadata:
|
93
|
+
self.metadata: dict[str, Any] = metadata
|
94
94
|
|
95
95
|
def set_operation_attributes(self):
|
96
96
|
"""Sets the ``job_id``, ``position_in_job``, and ``operation_id``
|
@@ -125,10 +125,10 @@ class JobShopInstance:
|
|
125
125
|
@classmethod
|
126
126
|
def from_taillard_file(
|
127
127
|
cls,
|
128
|
-
file_path:
|
128
|
+
file_path: os.PathLike | str | bytes,
|
129
129
|
encoding: str = "utf-8",
|
130
130
|
comment_symbol: str = "#",
|
131
|
-
name:
|
131
|
+
name: str | None = None,
|
132
132
|
**metadata: Any,
|
133
133
|
) -> JobShopInstance:
|
134
134
|
"""Creates a JobShopInstance from a file following Taillard's format.
|
@@ -178,7 +178,7 @@ class JobShopInstance:
|
|
178
178
|
name = name.split(".")[0]
|
179
179
|
return cls(jobs=jobs, name=name, **metadata)
|
180
180
|
|
181
|
-
def to_dict(self) ->
|
181
|
+
def to_dict(self) -> dict[str, Any]:
|
182
182
|
"""Returns a dictionary representation of the instance.
|
183
183
|
|
184
184
|
This representation is useful for saving the instance to a JSON file,
|
@@ -186,7 +186,7 @@ class JobShopInstance:
|
|
186
186
|
like Taillard's.
|
187
187
|
|
188
188
|
Returns:
|
189
|
-
|
189
|
+
dict[str, Any]: The returned dictionary has the following
|
190
190
|
structure:
|
191
191
|
|
192
192
|
.. code-block:: python
|
@@ -208,10 +208,10 @@ class JobShopInstance:
|
|
208
208
|
@classmethod
|
209
209
|
def from_matrices(
|
210
210
|
cls,
|
211
|
-
duration_matrix:
|
212
|
-
machines_matrix:
|
211
|
+
duration_matrix: list[list[int]],
|
212
|
+
machines_matrix: list[list[list[int]]] | list[list[int]],
|
213
213
|
name: str = "JobShopInstance",
|
214
|
-
metadata:
|
214
|
+
metadata: dict[str, Any] | None = None,
|
215
215
|
) -> JobShopInstance:
|
216
216
|
"""Creates a :class:`JobShopInstance` from duration and machines
|
217
217
|
matrices.
|
@@ -233,7 +233,7 @@ class JobShopInstance:
|
|
233
233
|
Returns:
|
234
234
|
A :class:`JobShopInstance` object.
|
235
235
|
"""
|
236
|
-
jobs:
|
236
|
+
jobs: list[list[Operation]] = [[] for _ in range(len(duration_matrix))]
|
237
237
|
|
238
238
|
num_jobs = len(duration_matrix)
|
239
239
|
for job_id in range(num_jobs):
|
@@ -290,7 +290,7 @@ class JobShopInstance:
|
|
290
290
|
)
|
291
291
|
|
292
292
|
@functools.cached_property
|
293
|
-
def durations_matrix(self) ->
|
293
|
+
def durations_matrix(self) -> list[list[int]]:
|
294
294
|
"""Returns the duration matrix of the instance.
|
295
295
|
|
296
296
|
The duration of the operation with ``job_id`` i and ``position_in_job``
|
@@ -305,7 +305,7 @@ class JobShopInstance:
|
|
305
305
|
return [[operation.duration for operation in job] for job in self.jobs]
|
306
306
|
|
307
307
|
@functools.cached_property
|
308
|
-
def machines_matrix(self) ->
|
308
|
+
def machines_matrix(self) -> list[list[list[int]]] | list[list[int]]:
|
309
309
|
"""Returns the machines matrix of the instance.
|
310
310
|
|
311
311
|
If the instance is flexible (i.e., if any operation has more than one
|
@@ -371,25 +371,25 @@ class JobShopInstance:
|
|
371
371
|
machines_matrix = self.machines_matrix
|
372
372
|
if self.is_flexible:
|
373
373
|
# False positive from mypy, the type of machines_matrix is
|
374
|
-
#
|
374
|
+
# list[list[list[int]]] here
|
375
375
|
return self._fill_matrix_with_nans_3d(
|
376
376
|
machines_matrix # type: ignore[arg-type]
|
377
377
|
)
|
378
378
|
|
379
379
|
# False positive from mypy, the type of machines_matrix is
|
380
|
-
#
|
380
|
+
# list[list[int]] here
|
381
381
|
return self._fill_matrix_with_nans_2d(
|
382
382
|
machines_matrix # type: ignore[arg-type]
|
383
383
|
)
|
384
384
|
|
385
385
|
@functools.cached_property
|
386
|
-
def operations_by_machine(self) ->
|
386
|
+
def operations_by_machine(self) -> list[list[Operation]]:
|
387
387
|
"""Returns a list of lists of operations.
|
388
388
|
|
389
389
|
The i-th list contains the operations that can be processed in the
|
390
390
|
machine with id i.
|
391
391
|
"""
|
392
|
-
operations_by_machine:
|
392
|
+
operations_by_machine: list[list[Operation]] = [
|
393
393
|
[] for _ in range(self.num_machines)
|
394
394
|
]
|
395
395
|
for job in self.jobs:
|
@@ -409,7 +409,7 @@ class JobShopInstance:
|
|
409
409
|
)
|
410
410
|
|
411
411
|
@functools.cached_property
|
412
|
-
def max_duration_per_job(self) ->
|
412
|
+
def max_duration_per_job(self) -> list[float]:
|
413
413
|
"""Returns the maximum duration of each job in the instance.
|
414
414
|
|
415
415
|
The maximum duration of the job with id i is stored in the i-th
|
@@ -420,7 +420,7 @@ class JobShopInstance:
|
|
420
420
|
return [max(op.duration for op in job) for job in self.jobs]
|
421
421
|
|
422
422
|
@functools.cached_property
|
423
|
-
def max_duration_per_machine(self) ->
|
423
|
+
def max_duration_per_machine(self) -> list[int]:
|
424
424
|
"""Returns the maximum duration of each machine in the instance.
|
425
425
|
|
426
426
|
The maximum duration of the machine with id i is stored in the i-th
|
@@ -439,7 +439,7 @@ class JobShopInstance:
|
|
439
439
|
return max_duration_per_machine
|
440
440
|
|
441
441
|
@functools.cached_property
|
442
|
-
def job_durations(self) ->
|
442
|
+
def job_durations(self) -> list[int]:
|
443
443
|
"""Returns a list with the duration of each job in the instance.
|
444
444
|
|
445
445
|
The duration of a job is the sum of the durations of its operations.
|
@@ -450,7 +450,7 @@ class JobShopInstance:
|
|
450
450
|
return [sum(op.duration for op in job) for job in self.jobs]
|
451
451
|
|
452
452
|
@functools.cached_property
|
453
|
-
def machine_loads(self) ->
|
453
|
+
def machine_loads(self) -> list[int]:
|
454
454
|
"""Returns the total machine load of each machine in the instance.
|
455
455
|
|
456
456
|
The total machine load of a machine is the sum of the durations of the
|
@@ -474,7 +474,7 @@ class JobShopInstance:
|
|
474
474
|
|
475
475
|
@staticmethod
|
476
476
|
def _fill_matrix_with_nans_2d(
|
477
|
-
matrix:
|
477
|
+
matrix: list[list[int]],
|
478
478
|
) -> NDArray[np.float32]:
|
479
479
|
"""Fills a matrix with ``np.nan`` values.
|
480
480
|
|
@@ -496,7 +496,7 @@ class JobShopInstance:
|
|
496
496
|
|
497
497
|
@staticmethod
|
498
498
|
def _fill_matrix_with_nans_3d(
|
499
|
-
matrix:
|
499
|
+
matrix: list[list[list[int]]],
|
500
500
|
) -> NDArray[np.float32]:
|
501
501
|
"""Fills a 3D matrix with ``np.nan`` values.
|
502
502
|
|
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
|
-
from typing import Union, List
|
6
|
-
|
7
5
|
from job_shop_lib.exceptions import ValidationError
|
8
6
|
|
9
7
|
|
@@ -61,8 +59,8 @@ class Operation:
|
|
61
59
|
),
|
62
60
|
}
|
63
61
|
|
64
|
-
def __init__(self, machines:
|
65
|
-
self.machines:
|
62
|
+
def __init__(self, machines: int | list[int], duration: int):
|
63
|
+
self.machines: list[int] = (
|
66
64
|
[machines] if isinstance(machines, int) else machines
|
67
65
|
)
|
68
66
|
self.duration: int = duration
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
|
-
from typing import Any
|
5
|
+
from typing import Any
|
6
6
|
from collections import deque
|
7
7
|
|
8
8
|
from job_shop_lib import ScheduledOperation, JobShopInstance
|
@@ -55,7 +55,7 @@ class Schedule:
|
|
55
55
|
def __init__(
|
56
56
|
self,
|
57
57
|
instance: JobShopInstance,
|
58
|
-
schedule:
|
58
|
+
schedule: list[list[ScheduledOperation]] | None = None,
|
59
59
|
**metadata: Any,
|
60
60
|
):
|
61
61
|
if schedule is None:
|
@@ -65,19 +65,19 @@ class Schedule:
|
|
65
65
|
|
66
66
|
self.instance: JobShopInstance = instance
|
67
67
|
self._schedule = schedule
|
68
|
-
self.metadata:
|
68
|
+
self.metadata: dict[str, Any] = metadata
|
69
69
|
|
70
70
|
def __repr__(self) -> str:
|
71
71
|
return str(self.schedule)
|
72
72
|
|
73
73
|
@property
|
74
|
-
def schedule(self) ->
|
74
|
+
def schedule(self) -> list[list[ScheduledOperation]]:
|
75
75
|
"""A list of lists of :class:`ScheduledOperation` objects. Each list
|
76
76
|
represents the order of operations on a machine."""
|
77
77
|
return self._schedule
|
78
78
|
|
79
79
|
@schedule.setter
|
80
|
-
def schedule(self, new_schedule:
|
80
|
+
def schedule(self, new_schedule: list[list[ScheduledOperation]]):
|
81
81
|
Schedule.check_schedule(new_schedule)
|
82
82
|
self._schedule = new_schedule
|
83
83
|
|
@@ -103,7 +103,7 @@ class Schedule:
|
|
103
103
|
- **"metadata"**: A dictionary with additional information
|
104
104
|
about the schedule.
|
105
105
|
"""
|
106
|
-
job_sequences:
|
106
|
+
job_sequences: list[list[int]] = []
|
107
107
|
for machine_schedule in self.schedule:
|
108
108
|
job_sequences.append(
|
109
109
|
[operation.job_id for operation in machine_schedule]
|
@@ -117,9 +117,9 @@ class Schedule:
|
|
117
117
|
|
118
118
|
@staticmethod
|
119
119
|
def from_dict(
|
120
|
-
instance:
|
121
|
-
job_sequences:
|
122
|
-
metadata:
|
120
|
+
instance: dict[str, Any] | JobShopInstance,
|
121
|
+
job_sequences: list[list[int]],
|
122
|
+
metadata: dict[str, Any] | None = None,
|
123
123
|
) -> Schedule:
|
124
124
|
"""Creates a schedule from a dictionary representation."""
|
125
125
|
if isinstance(instance, dict):
|
@@ -131,7 +131,7 @@ class Schedule:
|
|
131
131
|
@staticmethod
|
132
132
|
def from_job_sequences(
|
133
133
|
instance: JobShopInstance,
|
134
|
-
job_sequences:
|
134
|
+
job_sequences: list[list[int]],
|
135
135
|
) -> Schedule:
|
136
136
|
"""Creates an active schedule from a list of job sequences.
|
137
137
|
|
@@ -240,7 +240,7 @@ class Schedule:
|
|
240
240
|
return previous_operation.end_time <= scheduled_operation.start_time
|
241
241
|
|
242
242
|
@staticmethod
|
243
|
-
def check_schedule(schedule:
|
243
|
+
def check_schedule(schedule: list[list[ScheduledOperation]]):
|
244
244
|
"""Checks if a schedule is valid and raises a
|
245
245
|
:class:`~exceptions.ValidationError` if it is not.
|
246
246
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
"""Contains functions to load benchmark instances from a JSON file."""
|
2
2
|
|
3
|
-
from typing import Any
|
3
|
+
from typing import Any
|
4
4
|
|
5
5
|
import functools
|
6
6
|
import json
|
@@ -10,7 +10,7 @@ from job_shop_lib import JobShopInstance
|
|
10
10
|
|
11
11
|
|
12
12
|
@functools.cache
|
13
|
-
def load_all_benchmark_instances() ->
|
13
|
+
def load_all_benchmark_instances() -> dict[str, JobShopInstance]:
|
14
14
|
"""Loads all benchmark instances available.
|
15
15
|
|
16
16
|
Returns:
|
@@ -48,7 +48,7 @@ def load_benchmark_instance(name: str) -> JobShopInstance:
|
|
48
48
|
|
49
49
|
|
50
50
|
@functools.cache
|
51
|
-
def load_benchmark_json() ->
|
51
|
+
def load_benchmark_json() -> dict[str, dict[str, Any]]:
|
52
52
|
"""Loads the raw JSON file containing the benchmark instances.
|
53
53
|
|
54
54
|
Results are cached to avoid reading the file multiple times.
|
{job_shop_lib-1.0.1 → job_shop_lib-1.0.3}/job_shop_lib/constraint_programming/_ortools_solver.py
RENAMED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
|
-
from typing import Any
|
5
|
+
from typing import Any
|
6
6
|
import time
|
7
7
|
|
8
8
|
from ortools.sat.python import cp_model
|
@@ -62,7 +62,7 @@ class ORToolsSolver(BaseSolver):
|
|
62
62
|
self._makespan: cp_model.IntVar | None = None
|
63
63
|
self.model = cp_model.CpModel()
|
64
64
|
self.solver = cp_model.CpSolver()
|
65
|
-
self._operations_start:
|
65
|
+
self._operations_start: dict[Operation, tuple[IntVar, IntVar]] = {}
|
66
66
|
|
67
67
|
def __call__(self, instance: JobShopInstance) -> Schedule:
|
68
68
|
"""Equivalent to calling the :meth:`~ORToolsSolver.solve` method.
|
@@ -152,15 +152,15 @@ class ORToolsSolver(BaseSolver):
|
|
152
152
|
self._set_objective(instance)
|
153
153
|
|
154
154
|
def _create_schedule(
|
155
|
-
self, instance: JobShopInstance, metadata:
|
155
|
+
self, instance: JobShopInstance, metadata: dict[str, Any]
|
156
156
|
) -> Schedule:
|
157
157
|
"""Creates a Schedule object from the solution."""
|
158
|
-
operations_start:
|
158
|
+
operations_start: dict[Operation, int] = {
|
159
159
|
operation: self.solver.Value(start_var)
|
160
160
|
for operation, (start_var, _) in self._operations_start.items()
|
161
161
|
}
|
162
162
|
|
163
|
-
unsorted_schedule:
|
163
|
+
unsorted_schedule: list[list[ScheduledOperation]] = [
|
164
164
|
[] for _ in range(instance.num_machines)
|
165
165
|
]
|
166
166
|
for operation, start_time in operations_start.items():
|
@@ -235,7 +235,7 @@ class ORToolsSolver(BaseSolver):
|
|
235
235
|
each machine."""
|
236
236
|
|
237
237
|
# Create interval variables for each operation on each machine
|
238
|
-
machines_operations:
|
238
|
+
machines_operations: list[list[tuple[tuple[IntVar, IntVar], int]]] = [
|
239
239
|
[] for _ in range(instance.num_machines)
|
240
240
|
]
|
241
241
|
for job in instance.jobs:
|
@@ -9,13 +9,15 @@ Problem step-by-step.
|
|
9
9
|
HistoryObserver
|
10
10
|
UnscheduledOperationsObserver
|
11
11
|
OptimalOperationsObserver
|
12
|
-
ReadyOperationsFilter
|
13
12
|
DispatcherObserverConfig
|
13
|
+
ReadyOperationsFilter
|
14
|
+
ReadyOperationsFilterType
|
15
|
+
ready_operations_filter_factory
|
14
16
|
filter_dominated_operations
|
15
17
|
filter_non_immediate_machines
|
18
|
+
filter_non_idle_machines
|
19
|
+
filter_non_immediate_operations
|
16
20
|
create_composite_operation_filter
|
17
|
-
ReadyOperationsFilterType
|
18
|
-
ready_operations_filter_factory
|
19
21
|
|
20
22
|
Dispatching refers to the decision-making process of selecting which job
|
21
23
|
should be processed next on a particular machine when that machine becomes
|
@@ -45,17 +47,17 @@ from ._factories import (
|
|
45
47
|
|
46
48
|
__all__ = [
|
47
49
|
"Dispatcher",
|
48
|
-
"filter_dominated_operations",
|
49
|
-
"filter_non_immediate_machines",
|
50
|
-
"create_composite_operation_filter",
|
51
|
-
"ReadyOperationsFilterType",
|
52
|
-
"ready_operations_filter_factory",
|
53
50
|
"DispatcherObserver",
|
54
51
|
"HistoryObserver",
|
55
|
-
"DispatcherObserverConfig",
|
56
52
|
"UnscheduledOperationsObserver",
|
53
|
+
"OptimalOperationsObserver",
|
54
|
+
"DispatcherObserverConfig",
|
57
55
|
"ReadyOperationsFilter",
|
56
|
+
"ReadyOperationsFilterType",
|
57
|
+
"ready_operations_filter_factory",
|
58
|
+
"filter_dominated_operations",
|
59
|
+
"filter_non_immediate_machines",
|
58
60
|
"filter_non_idle_machines",
|
59
61
|
"filter_non_immediate_operations",
|
60
|
-
"
|
62
|
+
"create_composite_operation_filter",
|
61
63
|
]
|