job-shop-lib 1.0.0a3__tar.gz → 1.0.0a4__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/PKG-INFO +5 -5
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/README.md +4 -4
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/_job_shop_instance.py +104 -38
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/_operation.py +12 -3
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/_schedule.py +10 -12
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/_scheduled_operation.py +15 -16
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/_dispatcher.py +12 -15
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/_dispatcher_observer_config.py +15 -2
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/_factories.py +2 -2
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/feature_observers/_composite_feature_observer.py +0 -1
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/feature_observers/_factory.py +21 -18
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/feature_observers/_is_completed_observer.py +1 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/rules/_dispatching_rule_solver.py +1 -1
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/generation/_general_instance_generator.py +33 -34
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/generation/_instance_generator.py +14 -17
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/generation/_transformations.py +11 -8
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/graphs/__init__.py +3 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/graphs/_build_disjunctive_graph.py +41 -3
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/graphs/graph_updaters/_graph_updater.py +11 -13
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/graphs/graph_updaters/_residual_graph_updater.py +17 -20
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/reinforcement_learning/__init__.py +16 -7
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/reinforcement_learning/_multi_job_shop_graph_env.py +69 -57
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/reinforcement_learning/_single_job_shop_graph_env.py +42 -31
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/reinforcement_learning/_types_and_constants.py +2 -2
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/visualization/__init__.py +24 -5
- job_shop_lib-1.0.0a4/job_shop_lib/visualization/_gantt_chart_creator.py +257 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/visualization/_gantt_chart_video_and_gif_creation.py +15 -11
- job_shop_lib-1.0.0a4/job_shop_lib/visualization/_plot_disjunctive_graph.py +382 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/pyproject.toml +2 -1
- job_shop_lib-1.0.0a3/job_shop_lib/visualization/_disjunctive_graph.py +0 -210
- job_shop_lib-1.0.0a3/job_shop_lib/visualization/_gantt_chart_creator.py +0 -219
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/LICENSE +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/__init__.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/_base_solver.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/benchmarking/__init__.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/benchmarking/_load_benchmark.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/benchmarking/benchmark_instances.json +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/constraint_programming/__init__.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/constraint_programming/_ortools_solver.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/__init__.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/_history_observer.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/_ready_operation_filters.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/_unscheduled_operations_observer.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/feature_observers/__init__.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/feature_observers/_duration_observer.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/feature_observers/_earliest_start_time_observer.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/feature_observers/_feature_observer.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/feature_observers/_is_ready_observer.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/feature_observers/_is_scheduled_observer.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/feature_observers/_position_in_job_observer.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/feature_observers/_remaining_operations_observer.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/rules/__init__.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/rules/_dispatching_rule_factory.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/rules/_dispatching_rules_functions.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/rules/_machine_chooser_factory.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/rules/_utils.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/exceptions.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/generation/__init__.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/graphs/_build_agent_task_graph.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/graphs/_constants.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/graphs/_job_shop_graph.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/graphs/_node.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/graphs/graph_updaters/__init__.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/graphs/graph_updaters/_utils.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/reinforcement_learning/_reward_observers.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/reinforcement_learning/_utils.py +0 -0
- /job_shop_lib-1.0.0a3/job_shop_lib/visualization/_agent_task_graph.py → /job_shop_lib-1.0.0a4/job_shop_lib/visualization/_plot_agent_task_graph.py +0 -0
- {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/visualization/_plot_gantt_chart.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.0a4
|
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,7 @@ 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
|
-
See the [documentation](https://job-shop-lib.readthedocs.io/en/latest/) for more details about the latest version
|
43
|
+
See the [documentation](https://job-shop-lib.readthedocs.io/en/latest/) for more details about the latest version.
|
44
44
|
|
45
45
|
## Installation :package:
|
46
46
|
|
@@ -57,13 +57,13 @@ pip install job-shop-lib
|
|
57
57
|
See [this](https://colab.research.google.com/drive/1XV_Rvq1F2ns6DFG8uNj66q_rcowwTZ4H?usp=sharing) Google Colab notebook for a quick start guide!
|
58
58
|
|
59
59
|
|
60
|
-
Version 1.0.0 is currently in
|
60
|
+
Version 1.0.0 is currently in alpha stage and can be installed with:
|
61
61
|
|
62
62
|
```bash
|
63
|
-
pip install job-shop-lib==1.0.
|
63
|
+
pip install job-shop-lib==1.0.0a4
|
64
64
|
```
|
65
65
|
|
66
|
-
Although this version is not stable and may contain breaking changes in subsequent releases, it is recommended to install it to access the new reinforcement learning environments and
|
66
|
+
Although this version is not stable and may contain breaking changes in subsequent releases, it is recommended to install it to access the new reinforcement learning environments and familiarize yourself with new changes (see the [latest pull requests](https://github.com/Pabloo22/job_shop_lib/pulls?q=is%3Apr+is%3Aclosed)). This version is the first one with a [documentation page](https://job-shop-lib.readthedocs.io/en/latest/).
|
67
67
|
|
68
68
|
<!-- end installation -->
|
69
69
|
|
@@ -16,7 +16,7 @@ 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
|
-
See the [documentation](https://job-shop-lib.readthedocs.io/en/latest/) for more details about the latest version
|
19
|
+
See the [documentation](https://job-shop-lib.readthedocs.io/en/latest/) for more details about the latest version.
|
20
20
|
|
21
21
|
## Installation :package:
|
22
22
|
|
@@ -33,13 +33,13 @@ pip install job-shop-lib
|
|
33
33
|
See [this](https://colab.research.google.com/drive/1XV_Rvq1F2ns6DFG8uNj66q_rcowwTZ4H?usp=sharing) Google Colab notebook for a quick start guide!
|
34
34
|
|
35
35
|
|
36
|
-
Version 1.0.0 is currently in
|
36
|
+
Version 1.0.0 is currently in alpha stage and can be installed with:
|
37
37
|
|
38
38
|
```bash
|
39
|
-
pip install job-shop-lib==1.0.
|
39
|
+
pip install job-shop-lib==1.0.0a4
|
40
40
|
```
|
41
41
|
|
42
|
-
Although this version is not stable and may contain breaking changes in subsequent releases, it is recommended to install it to access the new reinforcement learning environments and
|
42
|
+
Although this version is not stable and may contain breaking changes in subsequent releases, it is recommended to install it to access the new reinforcement learning environments and familiarize yourself with new changes (see the [latest pull requests](https://github.com/Pabloo22/job_shop_lib/pulls?q=is%3Apr+is%3Aclosed)). This version is the first one with a [documentation page](https://job-shop-lib.readthedocs.io/en/latest/).
|
43
43
|
|
44
44
|
<!-- end installation -->
|
45
45
|
|
@@ -15,16 +15,47 @@ from job_shop_lib import Operation
|
|
15
15
|
class JobShopInstance:
|
16
16
|
"""Data structure to store a Job Shop Scheduling Problem instance.
|
17
17
|
|
18
|
-
Additional attributes such as
|
19
|
-
from the instance and are cached for performance if they
|
20
|
-
computations.
|
18
|
+
Additional attributes such as ``num_machines`` or ``durations_matrix`` can
|
19
|
+
be computed from the instance and are cached for performance if they
|
20
|
+
require expensive computations.
|
21
|
+
|
22
|
+
Methods:
|
23
|
+
|
24
|
+
.. autosummary::
|
25
|
+
:nosignatures:
|
26
|
+
|
27
|
+
from_taillard_file
|
28
|
+
to_dict
|
29
|
+
from_matrices
|
30
|
+
set_operation_attributes
|
31
|
+
|
32
|
+
Properties:
|
33
|
+
|
34
|
+
.. autosummary::
|
35
|
+
:nosignatures:
|
36
|
+
|
37
|
+
num_jobs
|
38
|
+
num_machines
|
39
|
+
num_operations
|
40
|
+
is_flexible
|
41
|
+
durations_matrix
|
42
|
+
machines_matrix
|
43
|
+
durations_matrix_array
|
44
|
+
machines_matrix_array
|
45
|
+
operations_by_machine
|
46
|
+
max_duration
|
47
|
+
max_duration_per_job
|
48
|
+
max_duration_per_machine
|
49
|
+
job_durations
|
50
|
+
machine_loads
|
51
|
+
total_duration
|
21
52
|
|
22
53
|
Attributes:
|
23
54
|
jobs (list[list[Operation]]):
|
24
55
|
A list of lists of operations. Each list of operations represents
|
25
56
|
a job, and the operations are ordered by their position in the job.
|
26
|
-
The
|
27
|
-
the operations are set when the instance is created.
|
57
|
+
The ``job_id``, ``position_in_job``, and `operation_id` attributes
|
58
|
+
of the operations are set when the instance is created.
|
28
59
|
name (str):
|
29
60
|
A string with the name of the instance.
|
30
61
|
metadata (dict[str, Any]):
|
@@ -34,11 +65,16 @@ class JobShopInstance:
|
|
34
65
|
jobs:
|
35
66
|
A list of lists of operations. Each list of operations
|
36
67
|
represents a job, and the operations are ordered by their
|
37
|
-
position in the job. The
|
38
|
-
|
68
|
+
position in the job. The ``job_id``, ``position_in_job``, and
|
69
|
+
``operation_id`` attributes of the operations are set when the
|
39
70
|
instance is created.
|
40
71
|
name:
|
41
72
|
A string with the name of the instance.
|
73
|
+
set_operation_attributes:
|
74
|
+
If True, the ``job_id``, ``position_in_job``, and ``operation_id``
|
75
|
+
attributes of the operations are set when the instance is created.
|
76
|
+
See :meth:`set_operation_attributes` for more information. Defaults
|
77
|
+
to True.
|
42
78
|
**metadata:
|
43
79
|
Additional information about the instance.
|
44
80
|
"""
|
@@ -47,15 +83,37 @@ class JobShopInstance:
|
|
47
83
|
self,
|
48
84
|
jobs: list[list[Operation]],
|
49
85
|
name: str = "JobShopInstance",
|
86
|
+
set_operation_attributes: bool = True,
|
50
87
|
**metadata: Any,
|
51
88
|
):
|
52
89
|
self.jobs: list[list[Operation]] = jobs
|
53
|
-
|
90
|
+
if set_operation_attributes:
|
91
|
+
self.set_operation_attributes()
|
54
92
|
self.name: str = name
|
55
93
|
self.metadata: dict[str, Any] = metadata
|
56
94
|
|
57
95
|
def set_operation_attributes(self):
|
58
|
-
"""Sets the job_id and
|
96
|
+
"""Sets the ``job_id``, ``position_in_job``, and ``operation_id``
|
97
|
+
attributes for each operation in the instance.
|
98
|
+
|
99
|
+
The ``job_id`` attribute is set to the id of the job to which the
|
100
|
+
operation belongs.
|
101
|
+
|
102
|
+
The ``position_in_job`` attribute is set to the
|
103
|
+
position of the operation in the job (starts from 0).
|
104
|
+
|
105
|
+
The ``operation_id`` attribute is set to a unique identifier for the
|
106
|
+
operation (starting from 0).
|
107
|
+
|
108
|
+
The formula to compute the ``operation_id`` in a job shop instance with
|
109
|
+
a fixed number of operations per job is:
|
110
|
+
|
111
|
+
.. code-block:: python
|
112
|
+
|
113
|
+
operation_id = job_id * num_operations_per_job + position_in_job
|
114
|
+
|
115
|
+
"""
|
116
|
+
|
59
117
|
operation_id = 0
|
60
118
|
for job_id, job in enumerate(self.jobs):
|
61
119
|
for position, operation in enumerate(job):
|
@@ -90,8 +148,8 @@ class JobShopInstance:
|
|
90
148
|
Additional information about the instance.
|
91
149
|
|
92
150
|
Returns:
|
93
|
-
A JobShopInstance object with the operations read from the
|
94
|
-
and the name and metadata provided.
|
151
|
+
A :class:`JobShopInstance` object with the operations read from the
|
152
|
+
file, and the name and metadata provided.
|
95
153
|
"""
|
96
154
|
with open(file_path, "r", encoding=encoding) as file:
|
97
155
|
lines = file.readlines()
|
@@ -128,13 +186,17 @@ class JobShopInstance:
|
|
128
186
|
like Taillard's.
|
129
187
|
|
130
188
|
Returns:
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
189
|
+
dict[str, Any]: The returned dictionary has the following
|
190
|
+
structure:
|
191
|
+
|
192
|
+
.. code-block:: python
|
193
|
+
|
194
|
+
{
|
195
|
+
"name": self.name,
|
196
|
+
"duration_matrix": self.durations_matrix,
|
197
|
+
"machines_matrix": self.machines_matrix,
|
198
|
+
"metadata": self.metadata,
|
199
|
+
}
|
138
200
|
"""
|
139
201
|
return {
|
140
202
|
"name": self.name,
|
@@ -151,7 +213,8 @@ class JobShopInstance:
|
|
151
213
|
name: str = "JobShopInstance",
|
152
214
|
metadata: dict[str, Any] | None = None,
|
153
215
|
) -> JobShopInstance:
|
154
|
-
"""Creates a JobShopInstance from duration and machines
|
216
|
+
"""Creates a :class:`JobShopInstance` from duration and machines
|
217
|
+
matrices.
|
155
218
|
|
156
219
|
Args:
|
157
220
|
duration_matrix:
|
@@ -168,7 +231,7 @@ class JobShopInstance:
|
|
168
231
|
A dictionary with additional information about the instance.
|
169
232
|
|
170
233
|
Returns:
|
171
|
-
A JobShopInstance object.
|
234
|
+
A :class:`JobShopInstance` object.
|
172
235
|
"""
|
173
236
|
jobs: list[list[Operation]] = [[] for _ in range(len(duration_matrix))]
|
174
237
|
|
@@ -220,7 +283,7 @@ class JobShopInstance:
|
|
220
283
|
|
221
284
|
@functools.cached_property
|
222
285
|
def is_flexible(self) -> bool:
|
223
|
-
"""Returns True if any operation has more than one machine."""
|
286
|
+
"""Returns ``True`` if any operation has more than one machine."""
|
224
287
|
return any(
|
225
288
|
any(len(operation.machines) > 1 for operation in job)
|
226
289
|
for job in self.jobs
|
@@ -230,12 +293,14 @@ class JobShopInstance:
|
|
230
293
|
def durations_matrix(self) -> list[list[int]]:
|
231
294
|
"""Returns the duration matrix of the instance.
|
232
295
|
|
233
|
-
The duration of the operation with
|
234
|
-
is stored in the i-th position of the j-th list of the returned
|
296
|
+
The duration of the operation with ``job_id`` i and ``position_in_job``
|
297
|
+
j is stored in the i-th position of the j-th list of the returned
|
298
|
+
matrix:
|
299
|
+
|
300
|
+
.. code-block:: python
|
301
|
+
|
302
|
+
duration = instance.durations_matrix[i][j]
|
235
303
|
|
236
|
-
```python
|
237
|
-
duration = instance.durations_matrix[i][j]
|
238
|
-
```
|
239
304
|
"""
|
240
305
|
return [[operation.duration for operation in job] for job in self.jobs]
|
241
306
|
|
@@ -252,9 +317,9 @@ class JobShopInstance:
|
|
252
317
|
To access the machines of the operation with position i in the job
|
253
318
|
with id j, the following code must be used:
|
254
319
|
|
255
|
-
|
256
|
-
|
257
|
-
|
320
|
+
.. code-block:: python
|
321
|
+
|
322
|
+
machines = instance.machines_matrix[j][i]
|
258
323
|
|
259
324
|
"""
|
260
325
|
if self.is_flexible:
|
@@ -269,8 +334,9 @@ class JobShopInstance:
|
|
269
334
|
def durations_matrix_array(self) -> NDArray[np.float32]:
|
270
335
|
"""Returns the duration matrix of the instance as a numpy array.
|
271
336
|
|
272
|
-
The returned array has shape (num_jobs
|
273
|
-
|
337
|
+
The returned array has shape (``num_jobs``,
|
338
|
+
``max_num_operations_per_job``).
|
339
|
+
Non-existing operations are filled with ``np.nan``.
|
274
340
|
|
275
341
|
Example:
|
276
342
|
>>> jobs = [[Operation(0, 2), Operation(1, 3)], [Operation(0, 4)]]
|
@@ -286,9 +352,9 @@ class JobShopInstance:
|
|
286
352
|
def machines_matrix_array(self) -> NDArray[np.float32]:
|
287
353
|
"""Returns the machines matrix of the instance as a numpy array.
|
288
354
|
|
289
|
-
The returned array has shape (num_jobs
|
290
|
-
max_num_machines_per_operation).
|
291
|
-
np.nan
|
355
|
+
The returned array has shape (``num_jobs``,
|
356
|
+
``max_num_operations_per_job``, ``max_num_machines_per_operation``).
|
357
|
+
Non-existing machines are filled with ``np.nan``.
|
292
358
|
|
293
359
|
Example:
|
294
360
|
>>> jobs = [
|
@@ -411,7 +477,7 @@ class JobShopInstance:
|
|
411
477
|
def _fill_matrix_with_nans_2d(
|
412
478
|
matrix: list[list[int]],
|
413
479
|
) -> NDArray[np.float32]:
|
414
|
-
"""Fills a matrix with np.nan values.
|
480
|
+
"""Fills a matrix with ``np.nan`` values.
|
415
481
|
|
416
482
|
Args:
|
417
483
|
matrix:
|
@@ -419,7 +485,7 @@ class JobShopInstance:
|
|
419
485
|
|
420
486
|
Returns:
|
421
487
|
A numpy array with the same shape as the input matrix, filled with
|
422
|
-
np.nan values.
|
488
|
+
``np.nan`` values.
|
423
489
|
"""
|
424
490
|
max_length = max(len(row) for row in matrix)
|
425
491
|
squared_matrix = np.full(
|
@@ -433,7 +499,7 @@ class JobShopInstance:
|
|
433
499
|
def _fill_matrix_with_nans_3d(
|
434
500
|
matrix: list[list[list[int]]],
|
435
501
|
) -> NDArray[np.float32]:
|
436
|
-
"""Fills a 3D matrix with np.nan values.
|
502
|
+
"""Fills a 3D matrix with ``np.nan`` values.
|
437
503
|
|
438
504
|
Args:
|
439
505
|
matrix:
|
@@ -441,7 +507,7 @@ class JobShopInstance:
|
|
441
507
|
|
442
508
|
Returns:
|
443
509
|
A numpy array with the same shape as the input matrix, filled with
|
444
|
-
np.nan values.
|
510
|
+
``np.nan`` values.
|
445
511
|
"""
|
446
512
|
max_length = max(len(row) for row in matrix)
|
447
513
|
max_inner_length = len(matrix[0][0])
|
@@ -42,11 +42,20 @@ class Operation:
|
|
42
42
|
"The time it takes to perform the operation. Often referred"
|
43
43
|
" to as the processing time."
|
44
44
|
),
|
45
|
-
"job_id":
|
46
|
-
|
45
|
+
"job_id": (
|
46
|
+
"The id of the job the operation belongs to. Defaults to -1. "
|
47
|
+
"It is usually set by the :class:`JobShopInstance` class after "
|
48
|
+
"initialization."
|
49
|
+
),
|
50
|
+
"position_in_job": (
|
51
|
+
"The index of the operation in the job. Defaults to -1. "
|
52
|
+
"It is usually set by the :class:`JobShopInstance` class after "
|
53
|
+
"initialization."
|
54
|
+
),
|
47
55
|
"operation_id": (
|
48
56
|
"The id of the operation. This is unique within a "
|
49
|
-
":class:`JobShopInstance`."
|
57
|
+
":class:`JobShopInstance`. Defaults to -1. It is usually set by "
|
58
|
+
"the :class:`JobShopInstance` class after initialization."
|
50
59
|
),
|
51
60
|
}
|
52
61
|
|
@@ -25,6 +25,16 @@ class Schedule:
|
|
25
25
|
is_complete
|
26
26
|
add
|
27
27
|
reset
|
28
|
+
|
29
|
+
Args:
|
30
|
+
instance:
|
31
|
+
The :class:`JobShopInstance` object that the schedule is for.
|
32
|
+
schedule:
|
33
|
+
A list of lists of :class:`ScheduledOperation` objects. Each
|
34
|
+
list represents the order of operations on a machine. If
|
35
|
+
not provided, the schedule is initialized as an empty schedule.
|
36
|
+
**metadata:
|
37
|
+
Additional information about the schedule.
|
28
38
|
"""
|
29
39
|
|
30
40
|
__slots__ = {
|
@@ -48,18 +58,6 @@ class Schedule:
|
|
48
58
|
schedule: list[list[ScheduledOperation]] | None = None,
|
49
59
|
**metadata: Any,
|
50
60
|
):
|
51
|
-
"""Initializes the object with the given instance and schedule.
|
52
|
-
|
53
|
-
Args:
|
54
|
-
instance:
|
55
|
-
The :class:`JobShopInstance` object that the schedule is for.
|
56
|
-
schedule:
|
57
|
-
A list of lists of :class:`ScheduledOperation` objects. Each
|
58
|
-
list represents the order of operations on a machine. If
|
59
|
-
not provided, the schedule is initialized as an empty schedule.
|
60
|
-
**metadata:
|
61
|
-
Additional information about the schedule.
|
62
|
-
"""
|
63
61
|
if schedule is None:
|
64
62
|
schedule = [[] for _ in range(instance.num_machines)]
|
65
63
|
|
@@ -5,7 +5,21 @@ from job_shop_lib.exceptions import ValidationError
|
|
5
5
|
|
6
6
|
|
7
7
|
class ScheduledOperation:
|
8
|
-
"""Data structure to store a scheduled operation.
|
8
|
+
"""Data structure to store a scheduled operation.
|
9
|
+
|
10
|
+
Args:
|
11
|
+
operation:
|
12
|
+
The :class:`Operation` object that is scheduled.
|
13
|
+
start_time:
|
14
|
+
The time at which the operation is scheduled to start.
|
15
|
+
machine_id:
|
16
|
+
The id of the machine on which the operation is scheduled.
|
17
|
+
|
18
|
+
Raises:
|
19
|
+
ValidationError:
|
20
|
+
If the given machine_id is not in the list of valid machines
|
21
|
+
for the operation.
|
22
|
+
"""
|
9
23
|
|
10
24
|
__slots__ = {
|
11
25
|
"operation": "The :class:`Operation` object that is scheduled.",
|
@@ -16,21 +30,6 @@ class ScheduledOperation:
|
|
16
30
|
}
|
17
31
|
|
18
32
|
def __init__(self, operation: Operation, start_time: int, machine_id: int):
|
19
|
-
"""Initializes a new instance of the :class:`ScheduledOperation` class.
|
20
|
-
|
21
|
-
Args:
|
22
|
-
operation:
|
23
|
-
The :class:`Operation` object that is scheduled.
|
24
|
-
start_time:
|
25
|
-
The time at which the operation is scheduled to start.
|
26
|
-
machine_id:
|
27
|
-
The id of the machine on which the operation is scheduled.
|
28
|
-
|
29
|
-
Raises:
|
30
|
-
ValidationError:
|
31
|
-
If the given machine_id is not in the list of valid machines
|
32
|
-
for the operation.
|
33
|
-
"""
|
34
33
|
self.operation: Operation = operation
|
35
34
|
self.start_time: int = start_time
|
36
35
|
self._machine_id = machine_id
|
@@ -29,6 +29,18 @@ class DispatcherObserver(abc.ABC):
|
|
29
29
|
dispatcher:
|
30
30
|
The :class:`Dispatcher` instance to observe.
|
31
31
|
|
32
|
+
Args:
|
33
|
+
dispatcher:
|
34
|
+
The :class:`Dispatcher` instance to observe.
|
35
|
+
subscribe:
|
36
|
+
If ``True``, automatically subscribes the observer to the
|
37
|
+
dispatcher when it is initialized. Defaults to ``True``.
|
38
|
+
|
39
|
+
Raises:
|
40
|
+
ValidationError: If ``is_singleton`` is ``True`` and an observer of the
|
41
|
+
same type already exists in the dispatcher's list of
|
42
|
+
subscribers.
|
43
|
+
|
32
44
|
Example:
|
33
45
|
|
34
46
|
.. code-block:: python
|
@@ -61,21 +73,6 @@ class DispatcherObserver(abc.ABC):
|
|
61
73
|
*,
|
62
74
|
subscribe: bool = True,
|
63
75
|
):
|
64
|
-
"""Initializes the observer with the :class:`Dispatcher` and subscribes
|
65
|
-
to it.
|
66
|
-
|
67
|
-
Args:
|
68
|
-
dispatcher:
|
69
|
-
The `Dispatcher` instance to observe.
|
70
|
-
subscribe:
|
71
|
-
If True, automatically subscribes the observer to the
|
72
|
-
dispatcher.
|
73
|
-
|
74
|
-
Raises:
|
75
|
-
ValidationError: If ``is_singleton`` is True and an observer of the
|
76
|
-
same type already exists in the dispatcher's list of
|
77
|
-
subscribers.
|
78
|
-
"""
|
79
76
|
if self._is_singleton and any(
|
80
77
|
isinstance(observer, self.__class__)
|
81
78
|
for observer in dispatcher.subscribers
|
@@ -26,14 +26,21 @@ class DispatcherObserverConfig(Generic[T]):
|
|
26
26
|
keyword arguments to pass to the dispatcher observer constructor while
|
27
27
|
not containing the ``dispatcher`` argument.
|
28
28
|
|
29
|
-
|
29
|
+
Args:
|
30
30
|
class_type:
|
31
31
|
Type of the class to be initialized. It can be the class type, an
|
32
32
|
enum value, or a string. This is useful for the creation of
|
33
|
-
DispatcherObserver instances
|
33
|
+
:class:`~job_shop_lib.dispatching.DispatcherObserver` instances
|
34
|
+
from the factory functions.
|
34
35
|
kwargs:
|
35
36
|
Keyword arguments needed to initialize the class. It must not
|
36
37
|
contain the ``dispatcher`` argument.
|
38
|
+
|
39
|
+
.. seealso::
|
40
|
+
|
41
|
+
- :class:`~job_shop_lib.dispatching.DispatcherObserver`
|
42
|
+
- :func:`job_shop_lib.dispatching.feature_observers.\\
|
43
|
+
feature_observer_factory`
|
37
44
|
"""
|
38
45
|
|
39
46
|
# We use the type hint T, instead of ObserverType, to allow for string or
|
@@ -44,7 +51,13 @@ class DispatcherObserverConfig(Generic[T]):
|
|
44
51
|
# This allows for the creation of a FeatureObserver instance
|
45
52
|
# from the factory function.
|
46
53
|
class_type: T
|
54
|
+
"""Type of the class to be initialized. It can be the class type, an
|
55
|
+
enum value, or a string. This is useful for the creation of
|
56
|
+
:class:`DispatcherObserver` instances from the factory functions."""
|
57
|
+
|
47
58
|
kwargs: dict[str, Any] = field(default_factory=dict)
|
59
|
+
"""Keyword arguments needed to initialize the class. It must not
|
60
|
+
contain the ``dispatcher`` argument."""
|
48
61
|
|
49
62
|
def __post_init__(self):
|
50
63
|
if "dispatcher" in self.kwargs:
|
@@ -51,13 +51,13 @@ def create_composite_operation_filter(
|
|
51
51
|
'non_immediate_machines' or any Callable that takes a
|
52
52
|
:class:`~job_shop_lib.dispatching.Dispatcher` instance and a list
|
53
53
|
of :class:`~job_shop_lib.Operation` instances as input
|
54
|
-
and returns a list of :class:`~job_shop_lib.Operation`instances.
|
54
|
+
and returns a list of :class:`~job_shop_lib.Operation` instances.
|
55
55
|
|
56
56
|
Returns:
|
57
57
|
A function that takes a :class:`~job_shop_lib.dispatching.Dispatcher`
|
58
58
|
instance and a list of :class:`~job_shop_lib.Operation`
|
59
59
|
instances as input and returns a list of
|
60
|
-
:class:`~job_shop_lib.Operation`instances based on
|
60
|
+
:class:`~job_shop_lib.Operation` instances based on
|
61
61
|
the specified list of filter strategies.
|
62
62
|
|
63
63
|
Raises:
|
@@ -193,7 +193,6 @@ if __name__ == "__main__":
|
|
193
193
|
dispatcher=dispatcher_,
|
194
194
|
)
|
195
195
|
for observer_type in feature_observer_types_
|
196
|
-
if not observer_type == FeatureObserverType.COMPOSITE
|
197
196
|
# and not FeatureObserverType.EARLIEST_START_TIME
|
198
197
|
]
|
199
198
|
composite_observer_ = CompositeFeatureObserver(
|
{job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/feature_observers/_factory.py
RENAMED
@@ -1,4 +1,4 @@
|
|
1
|
-
"""Contains factory functions for creating
|
1
|
+
"""Contains factory functions for creating :class:`FeatureObserver`s."""
|
2
2
|
|
3
3
|
from enum import Enum
|
4
4
|
|
@@ -18,8 +18,12 @@ from job_shop_lib.dispatching.feature_observers import (
|
|
18
18
|
class FeatureObserverType(str, Enum):
|
19
19
|
"""Enumeration of the different feature observers.
|
20
20
|
|
21
|
-
Each
|
22
|
-
to create the
|
21
|
+
Each :class:`FeatureObserver` is associated with a string value that can be
|
22
|
+
used to create the :class:`FeatureObserver` using the factory function.
|
23
|
+
|
24
|
+
It does not include the :class:`CompositeFeatureObserver` class since this
|
25
|
+
observer is often managed separately from the others. For example, a
|
26
|
+
common use case is to create a list of feature observers and pass them to
|
23
27
|
"""
|
24
28
|
|
25
29
|
IS_READY = "is_ready"
|
@@ -29,7 +33,6 @@ class FeatureObserverType(str, Enum):
|
|
29
33
|
POSITION_IN_JOB = "position_in_job"
|
30
34
|
REMAINING_OPERATIONS = "remaining_operations"
|
31
35
|
IS_COMPLETED = "is_completed"
|
32
|
-
COMPOSITE = "composite"
|
33
36
|
|
34
37
|
|
35
38
|
# FeatureObserverConfig = DispatcherObserverConfig[
|
@@ -43,7 +46,7 @@ FeatureObserverConfig = (
|
|
43
46
|
|
44
47
|
|
45
48
|
def feature_observer_factory(
|
46
|
-
|
49
|
+
feature_observer_type: (
|
47
50
|
str
|
48
51
|
| FeatureObserverType
|
49
52
|
| type[FeatureObserver]
|
@@ -51,29 +54,29 @@ def feature_observer_factory(
|
|
51
54
|
),
|
52
55
|
**kwargs,
|
53
56
|
) -> FeatureObserver:
|
54
|
-
"""Creates and returns a
|
55
|
-
|
57
|
+
"""Creates and returns a :class:`FeatureObserver` based on the specified
|
58
|
+
:class:`FeatureObserver` type.
|
56
59
|
|
57
60
|
Args:
|
58
61
|
feature_creator_type:
|
59
|
-
The type of
|
62
|
+
The type of :class:`FeatureObserver` to create.
|
60
63
|
**kwargs:
|
61
|
-
Additional keyword arguments to pass to the
|
62
|
-
|
64
|
+
Additional keyword arguments to pass to the
|
65
|
+
:class:`FeatureObserver` constructor.
|
63
66
|
|
64
67
|
Returns:
|
65
|
-
A
|
68
|
+
A :class:`FeatureObserver` instance.
|
66
69
|
"""
|
67
|
-
if isinstance(
|
70
|
+
if isinstance(feature_observer_type, DispatcherObserverConfig):
|
68
71
|
return feature_observer_factory(
|
69
|
-
|
70
|
-
**
|
72
|
+
feature_observer_type.class_type,
|
73
|
+
**feature_observer_type.kwargs,
|
71
74
|
**kwargs,
|
72
75
|
)
|
73
76
|
# if the instance is of type type[FeatureObserver] we can just
|
74
77
|
# call the object constructor with the keyword arguments
|
75
|
-
if isinstance(
|
76
|
-
return
|
78
|
+
if isinstance(feature_observer_type, type):
|
79
|
+
return feature_observer_type(**kwargs)
|
77
80
|
|
78
81
|
mapping: dict[FeatureObserverType, type[FeatureObserver]] = {
|
79
82
|
FeatureObserverType.IS_READY: IsReadyObserver,
|
@@ -84,5 +87,5 @@ def feature_observer_factory(
|
|
84
87
|
FeatureObserverType.REMAINING_OPERATIONS: RemainingOperationsObserver,
|
85
88
|
FeatureObserverType.IS_COMPLETED: IsCompletedObserver,
|
86
89
|
}
|
87
|
-
|
88
|
-
return
|
90
|
+
feature_observer = mapping[feature_observer_type] # type: ignore[index]
|
91
|
+
return feature_observer(**kwargs)
|
@@ -55,7 +55,7 @@ class DispatchingRuleSolver(BaseSolver):
|
|
55
55
|
- a list with names or actual ready operations filters to be used.
|
56
56
|
If a list is provided, a composite filter will be created
|
57
57
|
using the specified filters.
|
58
|
-
|
58
|
+
|
59
59
|
.. seealso::
|
60
60
|
- :func:`job_shop_lib.dispatching.rules.dispatching_rule_factory`
|
61
61
|
- :func:`job_shop_lib.dispatching.rules.machine_chooser_factory`
|