job-shop-lib 1.0.0b5__tar.gz → 1.0.2__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.0b5 → job_shop_lib-1.0.2}/PKG-INFO +19 -18
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/README.md +17 -16
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/__init__.py +1 -1
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/_job_shop_instance.py +2 -2
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/_operation.py +9 -3
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/_scheduled_operation.py +3 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/benchmarking/__init__.py +1 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/__init__.py +12 -10
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/_dispatcher.py +6 -13
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/_factories.py +3 -3
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/_optimal_operations_observer.py +0 -2
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/_ready_operation_filters.py +4 -4
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/feature_observers/_composite_feature_observer.py +11 -6
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/feature_observers/_factory.py +8 -3
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/feature_observers/_feature_observer.py +1 -1
- job_shop_lib-1.0.2/job_shop_lib/dispatching/feature_observers/_is_completed_observer.py +97 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/rules/__init__.py +11 -8
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/rules/_dispatching_rule_factory.py +1 -1
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/rules/_machine_chooser_factory.py +3 -2
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/generation/__init__.py +12 -1
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/graphs/__init__.py +42 -8
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/graphs/_build_resource_task_graphs.py +1 -1
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/graphs/_job_shop_graph.py +38 -19
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/graphs/graph_updaters/__init__.py +5 -1
- job_shop_lib-1.0.2/job_shop_lib/graphs/graph_updaters/_disjunctive_graph_updater.py +108 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/graphs/graph_updaters/_residual_graph_updater.py +3 -1
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/graphs/graph_updaters/_utils.py +2 -2
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/reinforcement_learning/__init__.py +13 -7
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/reinforcement_learning/_multi_job_shop_graph_env.py +1 -1
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/reinforcement_learning/_resource_task_graph_observation.py +102 -24
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/reinforcement_learning/_single_job_shop_graph_env.py +11 -2
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/reinforcement_learning/_types_and_constants.py +11 -10
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/reinforcement_learning/_utils.py +29 -0
- job_shop_lib-1.0.2/job_shop_lib/visualization/__init__.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/visualization/gantt/__init__.py +7 -3
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/visualization/gantt/_gantt_chart_video_and_gif_creation.py +5 -2
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/visualization/graphs/__init__.py +1 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/visualization/graphs/_plot_disjunctive_graph.py +53 -19
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/pyproject.toml +5 -12
- job_shop_lib-1.0.0b5/job_shop_lib/dispatching/feature_observers/_is_completed_observer.py +0 -129
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/LICENSE +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/_base_solver.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/_schedule.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/benchmarking/_load_benchmark.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/benchmarking/benchmark_instances.json +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/constraint_programming/__init__.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/constraint_programming/_ortools_solver.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/_dispatcher_observer_config.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/_history_observer.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/_unscheduled_operations_observer.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/feature_observers/__init__.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/feature_observers/_duration_observer.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/feature_observers/_earliest_start_time_observer.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/feature_observers/_is_ready_observer.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/feature_observers/_is_scheduled_observer.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/feature_observers/_position_in_job_observer.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/feature_observers/_remaining_operations_observer.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/rules/_dispatching_rule_solver.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/rules/_dispatching_rules_functions.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/rules/_utils.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/exceptions.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/generation/_general_instance_generator.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/generation/_instance_generator.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/generation/_transformations.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/generation/_utils.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/graphs/_build_disjunctive_graph.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/graphs/_constants.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/graphs/_node.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/graphs/graph_updaters/_graph_updater.py +0 -0
- /job_shop_lib-1.0.0b5/job_shop_lib/visualization/__init__.py → /job_shop_lib-1.0.2/job_shop_lib/py.typed +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/reinforcement_learning/_reward_observers.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/visualization/gantt/_gantt_chart_creator.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/visualization/gantt/_plot_gantt_chart.py +0 -0
- {job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/visualization/graphs/_plot_resource_task_graph.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.2
|
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
|
@@ -12,7 +12,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.11
|
13
13
|
Classifier: Programming Language :: Python :: 3.12
|
14
14
|
Provides-Extra: pygraphviz
|
15
|
-
Requires-Dist: gymnasium (>=0.
|
15
|
+
Requires-Dist: gymnasium (>=1.0.0,<2.0.0)
|
16
16
|
Requires-Dist: imageio[ffmpeg] (>=2.34.1,<3.0.0)
|
17
17
|
Requires-Dist: matplotlib (>=3,<4)
|
18
18
|
Requires-Dist: networkx (>=3,<4)
|
@@ -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
|
|
@@ -48,23 +52,12 @@ See the [documentation](https://job-shop-lib.readthedocs.io/en/latest/) for more
|
|
48
52
|
|
49
53
|
JobShopLib is distributed on [PyPI](https://pypi.org/project/job-shop-lib/) and it supports Python 3.10+.
|
50
54
|
|
51
|
-
You can install the latest stable version
|
55
|
+
You can install the latest stable version using `pip`:
|
52
56
|
|
53
57
|
```bash
|
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
|
-
Version 1.0.0 is currently in beta stage and can be installed with:
|
61
|
-
|
62
|
-
```bash
|
63
|
-
pip install job-shop-lib==1.0.0b5
|
64
|
-
```
|
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 familiarize yourself with new changes (see the [latest pull requests](https://github.com/Pabloo22/job_shop_lib/pulls?q=is%3Apr+is%3Aclosed)). There is a [documentation page](https://job-shop-lib.readthedocs.io/en/latest/) for versions 1.0.0a3 and onward.
|
67
|
-
|
68
61
|
<!-- end installation -->
|
69
62
|
|
70
63
|
<!-- key features -->
|
@@ -258,7 +251,15 @@ Additionally, the graph includes **disjunctive edges** between operations that u
|
|
258
251
|
```python
|
259
252
|
from job_shop_lib.visualization import plot_disjunctive_graph
|
260
253
|
|
261
|
-
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
|
+
)
|
262
263
|
plt.show()
|
263
264
|
```
|
264
265
|
|
@@ -314,9 +315,9 @@ from job_shop_lib.graphs import (
|
|
314
315
|
)
|
315
316
|
from job_shop_lib.visualization import plot_resource_task_graph
|
316
317
|
|
317
|
-
|
318
|
+
resource_task_graph = build_resource_task_graph(instance)
|
318
319
|
|
319
|
-
fig = plot_resource_task_graph(
|
320
|
+
fig = plot_resource_task_graph(resource_task_graph)
|
320
321
|
plt.show()
|
321
322
|
```
|
322
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
|
|
@@ -24,23 +28,12 @@ See the [documentation](https://job-shop-lib.readthedocs.io/en/latest/) for more
|
|
24
28
|
|
25
29
|
JobShopLib is distributed on [PyPI](https://pypi.org/project/job-shop-lib/) and it supports Python 3.10+.
|
26
30
|
|
27
|
-
You can install the latest stable version
|
31
|
+
You can install the latest stable version using `pip`:
|
28
32
|
|
29
33
|
```bash
|
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
|
-
Version 1.0.0 is currently in beta stage and can be installed with:
|
37
|
-
|
38
|
-
```bash
|
39
|
-
pip install job-shop-lib==1.0.0b5
|
40
|
-
```
|
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 familiarize yourself with new changes (see the [latest pull requests](https://github.com/Pabloo22/job_shop_lib/pulls?q=is%3Apr+is%3Aclosed)). There is a [documentation page](https://job-shop-lib.readthedocs.io/en/latest/) for versions 1.0.0a3 and onward.
|
43
|
-
|
44
37
|
<!-- end installation -->
|
45
38
|
|
46
39
|
<!-- key features -->
|
@@ -234,7 +227,15 @@ Additionally, the graph includes **disjunctive edges** between operations that u
|
|
234
227
|
```python
|
235
228
|
from job_shop_lib.visualization import plot_disjunctive_graph
|
236
229
|
|
237
|
-
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
|
+
)
|
238
239
|
plt.show()
|
239
240
|
```
|
240
241
|
|
@@ -290,9 +291,9 @@ from job_shop_lib.graphs import (
|
|
290
291
|
)
|
291
292
|
from job_shop_lib.visualization import plot_resource_task_graph
|
292
293
|
|
293
|
-
|
294
|
+
resource_task_graph = build_resource_task_graph(instance)
|
294
295
|
|
295
|
-
fig = plot_resource_task_graph(
|
296
|
+
fig = plot_resource_task_graph(resource_task_graph)
|
296
297
|
plt.show()
|
297
298
|
```
|
298
299
|
|
@@ -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
|
|
@@ -4,7 +4,7 @@ from __future__ import annotations
|
|
4
4
|
|
5
5
|
from typing import Union, List
|
6
6
|
|
7
|
-
from job_shop_lib.exceptions import
|
7
|
+
from job_shop_lib.exceptions import ValidationError
|
8
8
|
|
9
9
|
|
10
10
|
class Operation:
|
@@ -81,8 +81,14 @@ class Operation:
|
|
81
81
|
If the operation has multiple machines in its list.
|
82
82
|
"""
|
83
83
|
if len(self.machines) > 1:
|
84
|
-
raise
|
85
|
-
"Operation has multiple machines."
|
84
|
+
raise ValidationError(
|
85
|
+
"Operation has multiple machines. The `machine_id` property "
|
86
|
+
"should only be used when working with a classic JSSP "
|
87
|
+
"instance. This error prevents silent bugs. To handle "
|
88
|
+
"operations with more machines you have to use the machines "
|
89
|
+
"attribute. If you get this error using `job_shop_lib` "
|
90
|
+
"objects, it means that that object does not support "
|
91
|
+
"operations with multiple machines yet."
|
86
92
|
)
|
87
93
|
return self.machines[0]
|
88
94
|
|
@@ -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
|
]
|
@@ -336,8 +336,7 @@ class Dispatcher:
|
|
336
336
|
The operation to be scheduled.
|
337
337
|
machine_id:
|
338
338
|
The id of the machine on which the operation is to be
|
339
|
-
scheduled.
|
340
|
-
next available time for the operation on any machine.
|
339
|
+
scheduled.
|
341
340
|
"""
|
342
341
|
return max(
|
343
342
|
self._machine_next_available_time[machine_id],
|
@@ -459,12 +458,11 @@ class Dispatcher:
|
|
459
458
|
return unscheduled_operations
|
460
459
|
|
461
460
|
@_dispatcher_cache
|
462
|
-
def scheduled_operations(self) -> List[
|
461
|
+
def scheduled_operations(self) -> List[ScheduledOperation]:
|
463
462
|
"""Returns the list of operations that have been scheduled."""
|
464
463
|
scheduled_operations = []
|
465
|
-
for
|
466
|
-
|
467
|
-
scheduled_operations.extend(operations)
|
464
|
+
for machine_schedule in self.schedule.schedule:
|
465
|
+
scheduled_operations.extend(machine_schedule)
|
468
466
|
return scheduled_operations
|
469
467
|
|
470
468
|
@_dispatcher_cache
|
@@ -532,19 +530,14 @@ class Dispatcher:
|
|
532
530
|
return scheduled_operation.end_time - adjusted_start_time
|
533
531
|
|
534
532
|
@_dispatcher_cache
|
535
|
-
def completed_operations(self) -> Set[
|
533
|
+
def completed_operations(self) -> Set[ScheduledOperation]:
|
536
534
|
"""Returns the set of operations that have been completed.
|
537
535
|
|
538
536
|
This method returns the operations that have been scheduled and the
|
539
537
|
current time is greater than or equal to the end time of the operation.
|
540
538
|
"""
|
541
539
|
scheduled_operations = set(self.scheduled_operations())
|
542
|
-
ongoing_operations = set(
|
543
|
-
map(
|
544
|
-
lambda scheduled_op: scheduled_op.operation,
|
545
|
-
self.ongoing_operations(),
|
546
|
-
)
|
547
|
-
)
|
540
|
+
ongoing_operations = set(self.ongoing_operations())
|
548
541
|
completed_operations = scheduled_operations - ongoing_operations
|
549
542
|
return completed_operations
|
550
543
|
|
@@ -95,9 +95,9 @@ def ready_operations_filter_factory(
|
|
95
95
|
|
96
96
|
Args:
|
97
97
|
filter_name:
|
98
|
-
The name of the filter function to be used.
|
99
|
-
|
100
|
-
|
98
|
+
The name of the filter function to be used. See
|
99
|
+
:class:`ReadyOperationsFilterType` for supported values.
|
100
|
+
Alternatively, a custom filter function can be passed directly.
|
101
101
|
|
102
102
|
Returns:
|
103
103
|
A function that takes a :class:`~job_shop_lib.dispatching.Dispatcher`
|
{job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/_optimal_operations_observer.py
RENAMED
@@ -20,8 +20,6 @@ class OptimalOperationsObserver(DispatcherObserver):
|
|
20
20
|
based on the reference schedule.
|
21
21
|
reference_schedule: The reference schedule used to determine optimal
|
22
22
|
operations.
|
23
|
-
_operation_to_scheduled: Dictionary mapping operations to their
|
24
|
-
scheduled versions in the reference schedule.
|
25
23
|
|
26
24
|
Args:
|
27
25
|
dispatcher: The dispatcher instance to observe.
|
{job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/_ready_operation_filters.py
RENAMED
@@ -153,16 +153,16 @@ def _get_min_machine_end_times(
|
|
153
153
|
|
154
154
|
|
155
155
|
def _get_immediate_machines(
|
156
|
-
|
156
|
+
dispatcher: Dispatcher, available_operations: List[Operation]
|
157
157
|
) -> List[bool]:
|
158
158
|
"""Returns the machine ids of the machines that have at least one
|
159
159
|
operation with the lowest start time (i.e. the start time)."""
|
160
|
-
working_machines = [False] *
|
160
|
+
working_machines = [False] * dispatcher.instance.num_machines
|
161
161
|
# We can't use the current_time directly because it will cause
|
162
162
|
# an infinite loop.
|
163
|
-
current_time =
|
163
|
+
current_time = dispatcher.min_start_time(available_operations)
|
164
164
|
for op in available_operations:
|
165
165
|
for machine_id in op.machines:
|
166
|
-
if
|
166
|
+
if dispatcher.start_time(op, machine_id) == current_time:
|
167
167
|
working_machines[machine_id] = True
|
168
168
|
return working_machines
|
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
from collections import defaultdict
|
4
4
|
from collections.abc import Sequence
|
5
|
-
from typing import List, Dict, Union, Optional
|
5
|
+
from typing import List, Dict, Union, Optional, Type
|
6
6
|
# The Self type can be imported directly from Python’s typing module in
|
7
7
|
# version 3.11 and beyond. We use the typing_extensions module to support
|
8
|
-
# python >=3.
|
8
|
+
# python >=3.10
|
9
9
|
from typing_extensions import Self
|
10
10
|
import numpy as np
|
11
11
|
from numpy.typing import NDArray
|
@@ -18,6 +18,7 @@ from job_shop_lib.dispatching.feature_observers import (
|
|
18
18
|
FeatureType,
|
19
19
|
FeatureObserverConfig,
|
20
20
|
feature_observer_factory,
|
21
|
+
FeatureObserverType,
|
21
22
|
)
|
22
23
|
|
23
24
|
|
@@ -104,7 +105,14 @@ class CompositeFeatureObserver(FeatureObserver):
|
|
104
105
|
def from_feature_observer_configs(
|
105
106
|
cls,
|
106
107
|
dispatcher: Dispatcher,
|
107
|
-
feature_observer_configs: Sequence[
|
108
|
+
feature_observer_configs: Sequence[
|
109
|
+
Union[
|
110
|
+
str,
|
111
|
+
FeatureObserverType,
|
112
|
+
Type[FeatureObserver],
|
113
|
+
FeatureObserverConfig,
|
114
|
+
],
|
115
|
+
],
|
108
116
|
subscribe: bool = True,
|
109
117
|
) -> Self:
|
110
118
|
"""Creates the composite feature observer.
|
@@ -178,9 +186,6 @@ if __name__ == "__main__":
|
|
178
186
|
import time
|
179
187
|
from job_shop_lib.benchmarking import load_benchmark_instance
|
180
188
|
from job_shop_lib.dispatching.rules import DispatchingRuleSolver
|
181
|
-
from job_shop_lib.dispatching.feature_observers import (
|
182
|
-
FeatureObserverType,
|
183
|
-
)
|
184
189
|
|
185
190
|
ta80 = load_benchmark_instance("ta80")
|
186
191
|
|
{job_shop_lib-1.0.0b5 → job_shop_lib-1.0.2}/job_shop_lib/dispatching/feature_observers/_factory.py
RENAMED
@@ -39,9 +39,14 @@ class FeatureObserverType(str, Enum):
|
|
39
39
|
# FeatureObserverConfig = DispatcherObserverConfig[
|
40
40
|
# Type[FeatureObserver] | FeatureObserverType | str
|
41
41
|
# ]
|
42
|
-
FeatureObserverConfig = DispatcherObserverConfig[
|
43
|
-
|
44
|
-
]
|
42
|
+
# FeatureObserverConfig = DispatcherObserverConfig[
|
43
|
+
# Union[Type[FeatureObserver], FeatureObserverType, str]
|
44
|
+
# ]
|
45
|
+
FeatureObserverConfig = (
|
46
|
+
DispatcherObserverConfig[Type[FeatureObserver]]
|
47
|
+
| DispatcherObserverConfig[FeatureObserverType]
|
48
|
+
| DispatcherObserverConfig[str]
|
49
|
+
)
|
45
50
|
|
46
51
|
|
47
52
|
def feature_observer_factory(
|
@@ -36,7 +36,7 @@ class FeatureObserver(DispatcherObserver):
|
|
36
36
|
individually. Furthermore, machine learning models can be trained on these
|
37
37
|
arrays to predict the best dispatching decisions.
|
38
38
|
|
39
|
-
Arrays use the data type ``np.float32``.
|
39
|
+
Arrays use the data type ``np.float32``.
|
40
40
|
|
41
41
|
New :class:`FeatureObservers` must inherit from this class, and re-define
|
42
42
|
the class attributes ``_singleton`` (defualt ), ``_feature_size``
|
@@ -0,0 +1,97 @@
|
|
1
|
+
"""Home of the `IsCompletedObserver` class."""
|
2
|
+
|
3
|
+
from typing import Optional, Union, List
|
4
|
+
import numpy as np
|
5
|
+
|
6
|
+
from job_shop_lib import ScheduledOperation
|
7
|
+
from job_shop_lib.dispatching import Dispatcher
|
8
|
+
from job_shop_lib.dispatching.feature_observers import (
|
9
|
+
FeatureObserver,
|
10
|
+
FeatureType,
|
11
|
+
)
|
12
|
+
|
13
|
+
|
14
|
+
class IsCompletedObserver(FeatureObserver):
|
15
|
+
"""Adds a binary feature indicating whether each operation,
|
16
|
+
machine, or job has been completed.
|
17
|
+
|
18
|
+
An operation is considered completed if it has been scheduled and the
|
19
|
+
current time is greater than or equal to the sum of the operation's start
|
20
|
+
time and duration.
|
21
|
+
|
22
|
+
A machine or job is considered completed if all of its operations have been
|
23
|
+
completed.
|
24
|
+
|
25
|
+
Args:
|
26
|
+
dispatcher:
|
27
|
+
The :class:`~job_shop_lib.dispatching.Dispatcher` to observe.
|
28
|
+
feature_types:
|
29
|
+
A list of :class:`FeatureType` or a single :class:`FeatureType`
|
30
|
+
that specifies the types of features to observe. They must be a
|
31
|
+
subset of the class attribute :attr:`supported_feature_types`.
|
32
|
+
If ``None``, all supported feature types are tracked.
|
33
|
+
subscribe:
|
34
|
+
If ``True``, the observer is subscribed to the dispatcher upon
|
35
|
+
initialization. Otherwise, the observer must be subscribed later
|
36
|
+
or manually updated.
|
37
|
+
"""
|
38
|
+
|
39
|
+
def __init__(
|
40
|
+
self,
|
41
|
+
dispatcher: Dispatcher,
|
42
|
+
*,
|
43
|
+
feature_types: Optional[Union[List[FeatureType], FeatureType]] = None,
|
44
|
+
subscribe: bool = True,
|
45
|
+
):
|
46
|
+
feature_types = self._get_feature_types_list(feature_types)
|
47
|
+
self._num_of_operations_per_machine = np.array(
|
48
|
+
[
|
49
|
+
len(operations_by_machine)
|
50
|
+
for operations_by_machine in (
|
51
|
+
dispatcher.instance.operations_by_machine
|
52
|
+
)
|
53
|
+
]
|
54
|
+
)
|
55
|
+
self._num_of_operations_per_job = np.array(
|
56
|
+
[len(job) for job in dispatcher.instance.jobs]
|
57
|
+
)
|
58
|
+
super().__init__(
|
59
|
+
dispatcher,
|
60
|
+
feature_types=feature_types,
|
61
|
+
subscribe=subscribe,
|
62
|
+
)
|
63
|
+
|
64
|
+
def initialize_features(self):
|
65
|
+
if FeatureType.OPERATIONS in self.features:
|
66
|
+
completed_operations = [
|
67
|
+
op.operation.operation_id
|
68
|
+
for op in self.dispatcher.completed_operations()
|
69
|
+
]
|
70
|
+
self.features[FeatureType.OPERATIONS][completed_operations, 0] = 1
|
71
|
+
if FeatureType.MACHINES in self.features:
|
72
|
+
num_completed_ops_per_machine = np.zeros(
|
73
|
+
len(self._num_of_operations_per_machine)
|
74
|
+
)
|
75
|
+
for op in self.dispatcher.completed_operations():
|
76
|
+
for machine_id in op.operation.machines:
|
77
|
+
num_completed_ops_per_machine[machine_id] += 1
|
78
|
+
self.features[FeatureType.MACHINES][:, 0] = (
|
79
|
+
num_completed_ops_per_machine
|
80
|
+
== self._num_of_operations_per_machine
|
81
|
+
).astype(np.float32)
|
82
|
+
if FeatureType.JOBS in self.features:
|
83
|
+
num_completed_ops_per_job = np.zeros(
|
84
|
+
len(self._num_of_operations_per_job)
|
85
|
+
)
|
86
|
+
for op in self.dispatcher.completed_operations():
|
87
|
+
num_completed_ops_per_job[op.operation.job_id] += 1
|
88
|
+
self.features[FeatureType.JOBS][:, 0] = (
|
89
|
+
num_completed_ops_per_job
|
90
|
+
== self._num_of_operations_per_job
|
91
|
+
).astype(np.float32)
|
92
|
+
|
93
|
+
def reset(self):
|
94
|
+
self.set_features_to_zero()
|
95
|
+
|
96
|
+
def update(self, scheduled_operation: ScheduledOperation):
|
97
|
+
self.initialize_features()
|
@@ -3,17 +3,19 @@
|
|
3
3
|
Main objects:
|
4
4
|
|
5
5
|
.. autosummary::
|
6
|
+
:nosignatures:
|
6
7
|
|
7
8
|
DispatchingRuleSolver
|
8
|
-
dispatching_rule_factory
|
9
9
|
DispatchingRuleType
|
10
|
-
MachineChooserType
|
11
10
|
dispatching_rule_factory
|
11
|
+
MachineChooserType
|
12
12
|
machine_chooser_factory
|
13
|
+
MachineChooser
|
13
14
|
|
14
15
|
Dispatching rules:
|
15
16
|
|
16
17
|
.. autosummary::
|
18
|
+
:nosignatures:
|
17
19
|
|
18
20
|
shortest_processing_time_rule
|
19
21
|
first_come_first_served_rule
|
@@ -27,6 +29,7 @@ Dispatching rules:
|
|
27
29
|
Dispatching rule scorers:
|
28
30
|
|
29
31
|
.. autosummary::
|
32
|
+
:nosignatures:
|
30
33
|
|
31
34
|
shortest_processing_time_score
|
32
35
|
first_come_first_served_score
|
@@ -65,6 +68,11 @@ from ._dispatching_rule_solver import DispatchingRuleSolver
|
|
65
68
|
|
66
69
|
|
67
70
|
__all__ = [
|
71
|
+
"DispatchingRuleSolver",
|
72
|
+
"DispatchingRuleType",
|
73
|
+
"dispatching_rule_factory",
|
74
|
+
"MachineChooserType",
|
75
|
+
"machine_chooser_factory",
|
68
76
|
"shortest_processing_time_rule",
|
69
77
|
"first_come_first_served_rule",
|
70
78
|
"most_work_remaining_rule",
|
@@ -72,16 +80,11 @@ __all__ = [
|
|
72
80
|
"random_operation_rule",
|
73
81
|
"score_based_rule",
|
74
82
|
"score_based_rule_with_tie_breaker",
|
83
|
+
"observer_based_most_work_remaining_rule",
|
75
84
|
"shortest_processing_time_score",
|
76
85
|
"first_come_first_served_score",
|
77
86
|
"MostWorkRemainingScorer",
|
78
87
|
"most_operations_remaining_score",
|
79
88
|
"random_score",
|
80
|
-
"dispatching_rule_factory",
|
81
|
-
"DispatchingRuleType",
|
82
|
-
"MachineChooserType",
|
83
|
-
"machine_chooser_factory",
|
84
89
|
"MachineChooser",
|
85
|
-
"DispatchingRuleSolver",
|
86
|
-
"observer_based_most_work_remaining_rule",
|
87
90
|
]
|
@@ -33,7 +33,7 @@ class DispatchingRuleType(str, Enum):
|
|
33
33
|
|
34
34
|
|
35
35
|
def dispatching_rule_factory(
|
36
|
-
dispatching_rule: Union[str, DispatchingRuleType,
|
36
|
+
dispatching_rule: Union[str, DispatchingRuleType],
|
37
37
|
) -> Callable[[Dispatcher], Operation]:
|
38
38
|
"""Creates and returns a dispatching rule function based on the specified
|
39
39
|
dispatching rule name.
|
@@ -47,8 +47,9 @@ def machine_chooser_factory(
|
|
47
47
|
machine chooser strategy.
|
48
48
|
|
49
49
|
Raises:
|
50
|
-
|
51
|
-
not
|
50
|
+
ValidationError:
|
51
|
+
If the ``machine_chooser`` argument is not recognized or
|
52
|
+
is not supported.
|
52
53
|
"""
|
53
54
|
machine_choosers: Dict[str, Callable[[Dispatcher, Operation], int]] = {
|
54
55
|
MachineChooserType.FIRST: lambda _, operation: operation.machines[0],
|
@@ -1,4 +1,15 @@
|
|
1
|
-
"""Package for generating job shop instances.
|
1
|
+
"""Package for generating job shop instances.
|
2
|
+
|
3
|
+
.. autosummary::
|
4
|
+
:nosignatures:
|
5
|
+
|
6
|
+
InstanceGenerator
|
7
|
+
GeneralInstanceGenerator
|
8
|
+
generate_duration_matrix
|
9
|
+
generate_machine_matrix_with_recirculation
|
10
|
+
generate_machine_matrix_without_recirculation
|
11
|
+
|
12
|
+
"""
|
2
13
|
|
3
14
|
from job_shop_lib.generation._utils import (
|
4
15
|
generate_duration_matrix,
|