job-shop-lib 0.5.1__py3-none-any.whl → 1.0.0a1__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- job_shop_lib/__init__.py +16 -8
- job_shop_lib/{base_solver.py → _base_solver.py} +1 -1
- job_shop_lib/{job_shop_instance.py → _job_shop_instance.py} +9 -4
- job_shop_lib/_operation.py +95 -0
- job_shop_lib/{schedule.py → _schedule.py} +73 -54
- job_shop_lib/{scheduled_operation.py → _scheduled_operation.py} +13 -37
- job_shop_lib/benchmarking/__init__.py +66 -43
- job_shop_lib/benchmarking/_load_benchmark.py +88 -0
- job_shop_lib/constraint_programming/__init__.py +13 -0
- job_shop_lib/{cp_sat/ortools_solver.py → constraint_programming/_ortools_solver.py} +57 -18
- job_shop_lib/dispatching/__init__.py +45 -41
- job_shop_lib/dispatching/{dispatcher.py → _dispatcher.py} +153 -80
- job_shop_lib/dispatching/_dispatcher_observer_config.py +54 -0
- job_shop_lib/dispatching/_factories.py +125 -0
- job_shop_lib/dispatching/{history_tracker.py → _history_observer.py} +4 -6
- job_shop_lib/dispatching/{pruning_functions.py → _ready_operation_filters.py} +6 -35
- job_shop_lib/dispatching/_unscheduled_operations_observer.py +69 -0
- job_shop_lib/dispatching/feature_observers/__init__.py +16 -10
- job_shop_lib/dispatching/feature_observers/{composite_feature_observer.py → _composite_feature_observer.py} +84 -2
- job_shop_lib/dispatching/feature_observers/{duration_observer.py → _duration_observer.py} +6 -17
- job_shop_lib/dispatching/feature_observers/{earliest_start_time_observer.py → _earliest_start_time_observer.py} +114 -35
- job_shop_lib/dispatching/feature_observers/{factory.py → _factory.py} +31 -5
- job_shop_lib/dispatching/feature_observers/{feature_observer.py → _feature_observer.py} +59 -16
- job_shop_lib/dispatching/feature_observers/_is_completed_observer.py +97 -0
- job_shop_lib/dispatching/feature_observers/_is_ready_observer.py +33 -0
- job_shop_lib/dispatching/feature_observers/{position_in_job_observer.py → _position_in_job_observer.py} +1 -8
- job_shop_lib/dispatching/feature_observers/{remaining_operations_observer.py → _remaining_operations_observer.py} +8 -26
- job_shop_lib/dispatching/rules/__init__.py +51 -0
- job_shop_lib/dispatching/rules/_dispatching_rule_factory.py +82 -0
- job_shop_lib/dispatching/{dispatching_rule_solver.py → rules/_dispatching_rule_solver.py} +44 -15
- job_shop_lib/dispatching/{dispatching_rules.py → rules/_dispatching_rules_functions.py} +74 -21
- job_shop_lib/dispatching/rules/_machine_chooser_factory.py +69 -0
- job_shop_lib/dispatching/rules/_utils.py +127 -0
- job_shop_lib/exceptions.py +18 -0
- job_shop_lib/generation/__init__.py +2 -2
- job_shop_lib/generation/{general_instance_generator.py → _general_instance_generator.py} +26 -7
- job_shop_lib/generation/{instance_generator.py → _instance_generator.py} +13 -3
- job_shop_lib/graphs/__init__.py +17 -6
- job_shop_lib/graphs/{job_shop_graph.py → _job_shop_graph.py} +81 -2
- job_shop_lib/graphs/{node.py → _node.py} +18 -12
- job_shop_lib/graphs/graph_updaters/__init__.py +13 -0
- job_shop_lib/graphs/graph_updaters/_graph_updater.py +59 -0
- job_shop_lib/graphs/graph_updaters/_residual_graph_updater.py +154 -0
- job_shop_lib/graphs/graph_updaters/_utils.py +25 -0
- job_shop_lib/reinforcement_learning/__init__.py +41 -0
- job_shop_lib/reinforcement_learning/_multi_job_shop_graph_env.py +366 -0
- job_shop_lib/reinforcement_learning/_reward_observers.py +85 -0
- job_shop_lib/reinforcement_learning/_single_job_shop_graph_env.py +337 -0
- job_shop_lib/reinforcement_learning/_types_and_constants.py +61 -0
- job_shop_lib/reinforcement_learning/_utils.py +96 -0
- job_shop_lib/visualization/__init__.py +20 -4
- job_shop_lib/visualization/{agent_task_graph.py → _agent_task_graph.py} +28 -9
- job_shop_lib/visualization/_gantt_chart_creator.py +219 -0
- job_shop_lib/visualization/_gantt_chart_video_and_gif_creation.py +388 -0
- {job_shop_lib-0.5.1.dist-info → job_shop_lib-1.0.0a1.dist-info}/METADATA +68 -44
- job_shop_lib-1.0.0a1.dist-info/RECORD +66 -0
- job_shop_lib/benchmarking/load_benchmark.py +0 -142
- job_shop_lib/cp_sat/__init__.py +0 -5
- job_shop_lib/dispatching/factories.py +0 -206
- job_shop_lib/dispatching/feature_observers/is_completed_observer.py +0 -98
- job_shop_lib/dispatching/feature_observers/is_ready_observer.py +0 -40
- job_shop_lib/generators/__init__.py +0 -8
- job_shop_lib/generators/basic_generator.py +0 -200
- job_shop_lib/generators/transformations.py +0 -164
- job_shop_lib/operation.py +0 -122
- job_shop_lib/visualization/create_gif.py +0 -209
- job_shop_lib-0.5.1.dist-info/RECORD +0 -52
- /job_shop_lib/dispatching/feature_observers/{is_scheduled_observer.py → _is_scheduled_observer.py} +0 -0
- /job_shop_lib/generation/{transformations.py → _transformations.py} +0 -0
- /job_shop_lib/graphs/{build_agent_task_graph.py → _build_agent_task_graph.py} +0 -0
- /job_shop_lib/graphs/{build_disjunctive_graph.py → _build_disjunctive_graph.py} +0 -0
- /job_shop_lib/graphs/{constants.py → _constants.py} +0 -0
- /job_shop_lib/visualization/{disjunctive_graph.py → _disjunctive_graph.py} +0 -0
- /job_shop_lib/visualization/{gantt_chart.py → _gantt_chart.py} +0 -0
- {job_shop_lib-0.5.1.dist-info → job_shop_lib-1.0.0a1.dist-info}/LICENSE +0 -0
- {job_shop_lib-0.5.1.dist-info → job_shop_lib-1.0.0a1.dist-info}/WHEEL +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: job-shop-lib
|
3
|
-
Version: 0.
|
3
|
+
Version: 1.0.0a1
|
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,8 @@ 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:
|
15
|
+
Requires-Dist: gymnasium (>=0.29.1,<0.30.0)
|
16
|
+
Requires-Dist: imageio[ffmpeg] (>=2.34.1,<3.0.0)
|
16
17
|
Requires-Dist: matplotlib (>=3,<4)
|
17
18
|
Requires-Dist: networkx (>=3,<4)
|
18
19
|
Requires-Dist: numpy (>=1.26.4,<2.0.0)
|
@@ -23,9 +24,9 @@ Description-Content-Type: text/markdown
|
|
23
24
|
|
24
25
|
<div align="center">
|
25
26
|
|
26
|
-
<img src="images/
|
27
|
+
<img src="docs/source/images/jslib_minimalist_logo_no_background_fixed.png" height="150px">
|
27
28
|
|
28
|
-
<h1>
|
29
|
+
<h1>JobShopLib</h1>
|
29
30
|
|
30
31
|
[](https://github.com/Pabloo22/job_shop_lib/actions/workflows/tests.yaml)
|
31
32
|

|
@@ -34,25 +35,57 @@ Description-Content-Type: text/markdown
|
|
34
35
|
|
35
36
|
</div>
|
36
37
|
|
37
|
-
|
38
|
+
JobShopLib is a Python package for creating, solving, and visualizing Job Shop Scheduling Problems (JSSP).
|
38
39
|
|
39
|
-
It
|
40
|
+
It follows a modular design, allowing users to easily extend the library with new solvers, dispatching rules, visualization functions, etc.
|
40
41
|
|
41
|
-
See
|
42
|
+
See [this](https://colab.research.google.com/drive/1XV_Rvq1F2ns6DFG8uNj66q_rcowwTZ4H?usp=sharing) Google Colab notebook for a quick start guide!
|
42
43
|
|
43
|
-
## Installation
|
44
|
+
## Installation :package:
|
44
45
|
|
45
|
-
|
46
|
+
<!-- start installation -->
|
47
|
+
|
48
|
+
JobShopLib is distributed on [PyPI](https://pypi.org/project/job-shop-lib/) and it supports Python 3.10+.
|
49
|
+
|
50
|
+
You can install the latest version using `pip`:
|
46
51
|
|
47
52
|
```bash
|
48
53
|
pip install job-shop-lib
|
49
54
|
```
|
50
55
|
|
51
|
-
|
56
|
+
<!-- end installation -->
|
57
|
+
|
58
|
+
<!-- key features -->
|
59
|
+
|
60
|
+
## Key Features :star:
|
61
|
+
|
62
|
+
- **Data Structures**: Easily create, manage, and manipulate job shop instances and solutions with user-friendly data structures. See [Getting Started](docs/source/examples/00-Getting-Started.ipynb) and [How Solutions are Represented](docs/source/examples/01-How-Solutions-are-Represented.ipynb).
|
63
|
+
|
64
|
+
- **Benchmark Instances**: Load well-known benchmark instances directly from the library without manual downloading. See [Load Benchmark Instances](docs/source/examples/05-Load-Benchmark-Instances.ipynb).
|
65
|
+
|
66
|
+
- **Random Instance Generation**: Create random instances with customizable sizes and properties or augment existing ones. See [`generation`](job_shop_lib/generation) package.
|
67
|
+
|
68
|
+
- **Multiple Solvers**:
|
69
|
+
- **Constraint Programming Solver**: OR-Tools' CP-SAT solver. See [Solving the Problem](docs/source/examples/02-Solving-the-Problem.ipynb).
|
70
|
+
|
71
|
+
- **Dispatching Rule Solvers**: Use any of the available dispatching rules or create custom ones. See [Dispatching Rules](docs/source/examples/03-Dispatching-Rules.ipynb).
|
72
|
+
|
73
|
+
- **Gantt Charts**: Visualize final schedules and how are they created iteratively by dispatching rule solvers or sequences of scheduling decisions with GIFs or videos. See [Save Gif](docs/source/examples/06-Save-Gif.ipynb).
|
74
|
+
|
75
|
+
- **Graph Representations**:
|
76
|
+
- **Disjunctive Graphs**: Represent and visualize instances as disjunctive graphs. See [Disjunctive Graph](docs/source/examples/04-Disjunctive-Graph.ipynb).
|
77
|
+
- **Agent-Task Graphs**: Encode instances as agent-task graphs (introduced in [ScheduleNet paper](https://arxiv.org/abs/2106.03051)). See [Agent-Task Graph](docs/source/examples/07-Agent-Task-Graph.ipynb).
|
78
|
+
- Build your own custom graphs with the `JobShopGraph` class.
|
79
|
+
|
80
|
+
- **Gymnasium Environments**: Two environments for solving the problem with Graph Neural Networks (GNNs) or any other method, and Reinforcement Learning (RL). See [SingleJobShopGraphEnv](docs/source/examples/09-SingleJobShopGraphEnv.ipynb) and [MultiJobShopGraphEnv](examples/10-MultiJobShopGraphEnv.ipynb).
|
81
|
+
|
82
|
+
<!-- end key features -->
|
83
|
+
|
84
|
+
## Some Examples :rocket:
|
52
85
|
|
53
86
|
### Create a Job Shop Instance
|
54
87
|
|
55
|
-
You can create a
|
88
|
+
You can create a `JobShopInstance` by defining the jobs and operations. An operation is defined by the machine(s) it is processed on and the duration (processing time).
|
56
89
|
|
57
90
|
```python
|
58
91
|
from job_shop_lib import JobShopInstance, Operation
|
@@ -83,7 +116,7 @@ from job_shop_lib.benchmarking import load_benchmark_instance
|
|
83
116
|
ft06 = load_benchmark_instance("ft06")
|
84
117
|
```
|
85
118
|
|
86
|
-
The module `
|
119
|
+
The module `benchmarking` contains functions to load the instances from the file and return them as `JobShopInstance` objects without having to download them
|
87
120
|
manually.
|
88
121
|
|
89
122
|
The contributions to this benchmark dataset are as follows:
|
@@ -115,12 +148,12 @@ https://github.com/thomasWeise/jsspInstancesAndResults
|
|
115
148
|
|
116
149
|
### Generate a Random Instance
|
117
150
|
|
118
|
-
You can also generate a random instance with the `
|
151
|
+
You can also generate a random instance with the `GeneralInstanceGenerator` class.
|
119
152
|
|
120
153
|
```python
|
121
|
-
from job_shop_lib.
|
154
|
+
from job_shop_lib.generation import GeneralInstanceGenerator
|
122
155
|
|
123
|
-
generator =
|
156
|
+
generator = GeneralInstanceGenerator(
|
124
157
|
duration_range=(5, 10), seed=42, num_jobs=5, num_machines=5
|
125
158
|
)
|
126
159
|
random_instance = generator.generate()
|
@@ -129,7 +162,7 @@ random_instance = generator.generate()
|
|
129
162
|
This class can also work as an iterator to generate multiple instances:
|
130
163
|
|
131
164
|
```python
|
132
|
-
generator =
|
165
|
+
generator = GeneralInstanceGenerator(iteration_limit=100, seed=42)
|
133
166
|
instances = []
|
134
167
|
for instance in generator:
|
135
168
|
instances.append(instance)
|
@@ -145,7 +178,7 @@ Every solver is a `Callable` that receives a `JobShopInstance` and returns a `Sc
|
|
145
178
|
```python
|
146
179
|
import matplotlib.pyplot as plt
|
147
180
|
|
148
|
-
from job_shop_lib.
|
181
|
+
from job_shop_lib.constraint_programming import ORToolsSolver
|
149
182
|
from job_shop_lib.visualization import plot_gantt_chart
|
150
183
|
|
151
184
|
solver = ORToolsSolver(max_time_in_seconds=10)
|
@@ -154,7 +187,7 @@ ft06_schedule = solver(ft06)
|
|
154
187
|
fig, ax = plot_gantt_chart(ft06_schedule)
|
155
188
|
plt.show()
|
156
189
|
```
|
157
|
-

|
190
|
+

|
158
191
|
|
159
192
|
### Solve an Instance with a Dispatching Rule Solver
|
160
193
|
|
@@ -190,7 +223,7 @@ create_gif(
|
|
190
223
|
)
|
191
224
|
```
|
192
225
|
|
193
|
-

|
226
|
+

|
194
227
|
|
195
228
|
The dashed red line represents the current time step, which is computed as the earliest time when the next operation can start.
|
196
229
|
|
@@ -217,11 +250,11 @@ fig = plot_disjunctive_graph(instance)
|
|
217
250
|
plt.show()
|
218
251
|
```
|
219
252
|
|
220
|
-

|
253
|
+

|
221
254
|
|
222
255
|
|
223
|
-
> [!
|
224
|
-
>
|
256
|
+
> [!TIP]
|
257
|
+
> Installing the optional dependency [PyGraphViz](https://pygraphviz.github.io/) is recommended.
|
225
258
|
|
226
259
|
The `JobShopGraph` class provides easy access to the nodes, for example, to get all the nodes of a specific type:
|
227
260
|
|
@@ -276,7 +309,7 @@ plt.show()
|
|
276
309
|
```
|
277
310
|
|
278
311
|
<div align="center">
|
279
|
-
<img src="
|
312
|
+
<img src="docs/source/images/agent_task_graph.png" width="300">
|
280
313
|
</div>
|
281
314
|
<br>
|
282
315
|
|
@@ -286,43 +319,34 @@ For more details, check the [examples](examples) folder.
|
|
286
319
|
|
287
320
|
## Installation for development
|
288
321
|
|
289
|
-
|
322
|
+
<!-- start installation development -->
|
290
323
|
|
291
324
|
1. Clone the repository.
|
292
325
|
|
293
|
-
2. Install [poetry](https://python-poetry.org/docs/) if you don't have it already:
|
294
|
-
```bash
|
295
|
-
pip install poetry==1.7
|
296
|
-
```
|
297
|
-
3. Create the virtual environment:
|
298
326
|
```bash
|
299
|
-
|
327
|
+
git clone https://github.com/Pabloo22/job_shop_lib.git
|
328
|
+
cd job_shop_lib
|
300
329
|
```
|
301
|
-
|
330
|
+
|
331
|
+
2. Install [poetry](https://python-poetry.org/docs/) if you don't have it already:
|
332
|
+
|
302
333
|
```bash
|
303
|
-
|
334
|
+
pip install poetry
|
304
335
|
```
|
305
|
-
|
336
|
+
|
337
|
+
3. Install dependencies:
|
306
338
|
```bash
|
307
339
|
make poetry_install_all
|
308
340
|
```
|
309
341
|
|
310
|
-
|
311
|
-
|
312
|
-
If you don't want to use Poetry, you can install the library directly from the source code:
|
313
|
-
|
314
|
-
```bash
|
315
|
-
git clone https://github.com/Pabloo22/job_shop_lib.git
|
316
|
-
cd job_shop_lib
|
317
|
-
pip install -e .
|
318
|
-
```
|
342
|
+
<!-- end installation development -->
|
319
343
|
|
320
|
-
## License
|
344
|
+
## License :scroll:
|
321
345
|
|
322
346
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
323
347
|
|
324
348
|
|
325
|
-
## References
|
349
|
+
## References :books:
|
326
350
|
|
327
351
|
- J. Adams, E. Balas, and D. Zawack, "The shifting bottleneck procedure
|
328
352
|
for job shop scheduling," Management Science, vol. 34, no. 3,
|
@@ -0,0 +1,66 @@
|
|
1
|
+
job_shop_lib/__init__.py,sha256=Ci5ipn-zciO88C5aX5Wx-UN8iBTbpde3dSSg02ZcfwM,597
|
2
|
+
job_shop_lib/_base_solver.py,sha256=p17XmtufNc9Y481cqZUT45pEkUmmW1HWG53dfhIBJH8,1363
|
3
|
+
job_shop_lib/_job_shop_instance.py,sha256=Q0ml3C36tmcBskBo8MyaZWILJPbdvHjJcvXzD_YfLsU,16475
|
4
|
+
job_shop_lib/_operation.py,sha256=8Wj8ZLpxmHw4lJJbLCZoTpFhLaap9MSzwOA5VOJQ-DY,3099
|
5
|
+
job_shop_lib/_schedule.py,sha256=2QjhU21pZr7Gl6qEVJ9kXujx-bSrvaTdyZvjGbrQqzs,11193
|
6
|
+
job_shop_lib/_scheduled_operation.py,sha256=w7jKhgJ4dQycJ5wSItAd_B9gH5ipcoqy5KxtHFxWTP0,2775
|
7
|
+
job_shop_lib/benchmarking/__init__.py,sha256=BYCrJUNr_uk2c0xIbDt07OnUMhQx8Dudkukx3TFWxgw,3271
|
8
|
+
job_shop_lib/benchmarking/_load_benchmark.py,sha256=-cgyx0Kn6uAc3KdGFSQb6eUVQjQggmpVKOH9qusNkXI,2930
|
9
|
+
job_shop_lib/benchmarking/benchmark_instances.json,sha256=F9EvyzFwVxiKAN6rQTsrMhsKstmyUmroyWduM7a00KQ,464841
|
10
|
+
job_shop_lib/constraint_programming/__init__.py,sha256=kKQRUxxS_nVFUdXGnf4bQOD9mqrXxZZWElS753A4YiA,454
|
11
|
+
job_shop_lib/constraint_programming/_ortools_solver.py,sha256=U6kkk2pHsAgKLOhEjl6R1FFLy-i5_5sxBHaXezMR1tI,9860
|
12
|
+
job_shop_lib/dispatching/__init__.py,sha256=QV7qy-y0sSoKp_FslTm7sdqczYzpq0YctzKQ36l0ykg,1510
|
13
|
+
job_shop_lib/dispatching/_dispatcher.py,sha256=PCSBpYAF6QPXWrjwkBQXTxOdGdq6Y1Uqw8esQTW05TQ,21357
|
14
|
+
job_shop_lib/dispatching/_dispatcher_observer_config.py,sha256=l_lbaw9JJ5icVOmDAzAL6G5t6wG25bQLpRedN1bys8c,1932
|
15
|
+
job_shop_lib/dispatching/_factories.py,sha256=UAZLq7d_-puzMYteiAbbhkcW5ucKO-lo3bj8pCCEnOA,4229
|
16
|
+
job_shop_lib/dispatching/_history_observer.py,sha256=Vl8rQaxekUeEB-AyNxyC3c76zQakeh-rdri2iDnZvXw,610
|
17
|
+
job_shop_lib/dispatching/_ready_operation_filters.py,sha256=q8Xv4kp_2GsvEMC5mlTuJXivAz_b8bbrqo5sXaS3PJU,3110
|
18
|
+
job_shop_lib/dispatching/_unscheduled_operations_observer.py,sha256=LNEzqOWqEf6fvtkQrDmDWFEhCfA75OgEtzdomzbxYII,2683
|
19
|
+
job_shop_lib/dispatching/feature_observers/__init__.py,sha256=oPrhxw65znMhLugMqUD-1swNi8MufejQbHKiMxtgCU0,1103
|
20
|
+
job_shop_lib/dispatching/feature_observers/_composite_feature_observer.py,sha256=SqZ7Th97p1SkmHz2O_xdPCoqiPNwEs71n_iSkCO3FQM,6397
|
21
|
+
job_shop_lib/dispatching/feature_observers/_duration_observer.py,sha256=RfWXtxXvS4lakIRWPa1tD0I_UGgb7-h4-tTVvA_x4tA,3490
|
22
|
+
job_shop_lib/dispatching/feature_observers/_earliest_start_time_observer.py,sha256=iBkfGxG9-peO8shJKTl2P59YFq63aX_Z4XUvOL6m79g,8912
|
23
|
+
job_shop_lib/dispatching/feature_observers/_factory.py,sha256=3nlLDzdf_UJqmNO1Om69ygxj-9mF4kfPBp0rFFUC_a0,2773
|
24
|
+
job_shop_lib/dispatching/feature_observers/_feature_observer.py,sha256=N-UhOsw3VbasKucuZlAJyF-k0O7CiwtGFez39xOF66Q,5174
|
25
|
+
job_shop_lib/dispatching/feature_observers/_is_completed_observer.py,sha256=_ZSmHt1ZtLNXBipaeSOXwgY14WWN3tIm9sx8WY4-zBw,3448
|
26
|
+
job_shop_lib/dispatching/feature_observers/_is_ready_observer.py,sha256=iRr2MsCAglb6dO5fhHKSD7Z2ZHRjYqXK7E8bimAfpOY,1244
|
27
|
+
job_shop_lib/dispatching/feature_observers/_is_scheduled_observer.py,sha256=PeLxPVLJX_TP4TG8ViEQFR8WS43wIp6CqyuapM8lIt8,1477
|
28
|
+
job_shop_lib/dispatching/feature_observers/_position_in_job_observer.py,sha256=hvztjuajYRx-CnmflWqN4lG06pJelZIRZmarjPK9Afo,1107
|
29
|
+
job_shop_lib/dispatching/feature_observers/_remaining_operations_observer.py,sha256=kNvRVbxsx5SI2nMc9ZbmcPd5wDaxiljhkXpk6biV2rI,1442
|
30
|
+
job_shop_lib/dispatching/rules/__init__.py,sha256=p1rkqf66L62uvAOM1ZxNV8xHoh7SuYjHi_8ZNBvPIjg,1450
|
31
|
+
job_shop_lib/dispatching/rules/_dispatching_rule_factory.py,sha256=5fNpv90fAoR6rcE6NeJOWiB7ir-FVnoONIhHtKJ9H0E,2904
|
32
|
+
job_shop_lib/dispatching/rules/_dispatching_rule_solver.py,sha256=r-z3AHwbYNRRnrifoz1gmKASpWqxrUQoxvyfara92KM,5331
|
33
|
+
job_shop_lib/dispatching/rules/_dispatching_rules_functions.py,sha256=Wb9fQIfePvCJi4RqJ59UrRSnYufgQw5nQ_Am8M6-JOI,7569
|
34
|
+
job_shop_lib/dispatching/rules/_machine_chooser_factory.py,sha256=xsJ8nJwPDBi-sfLJRQF_BBQDbyXDfopD1U-efXffQAE,2331
|
35
|
+
job_shop_lib/dispatching/rules/_utils.py,sha256=X8vET2p1D3RyoB9mFfsfRgmilcTmxPssKYyJQ2zEt0Q,4605
|
36
|
+
job_shop_lib/exceptions.py,sha256=ARzpoZJCvRIvOesCiqqFSRxkv6w9WwEXx0aBP-l2IKA,1597
|
37
|
+
job_shop_lib/generation/__init__.py,sha256=hUqjnE0bEoknuUwFoLUWjBH26qTTCGsJAW4gscAbiQ8,294
|
38
|
+
job_shop_lib/generation/_general_instance_generator.py,sha256=8DG70qT2TUTyPp-3Q1DHWo3DhtUvyB4Yo_u0eAa5CIc,7431
|
39
|
+
job_shop_lib/generation/_instance_generator.py,sha256=fPcbNoyk0t1JtJpBMiwk3SlyPkWYNkYS7-Vs8qH_eDM,4642
|
40
|
+
job_shop_lib/generation/_transformations.py,sha256=FI2qHrETATJUrQP3-RYhZAQ5boyEZ0CF2StDbacBej8,5290
|
41
|
+
job_shop_lib/graphs/__init__.py,sha256=Kzw__atE5q_bbLf-vDwqya453RP-CfgV7RlURbdOfSc,1646
|
42
|
+
job_shop_lib/graphs/_build_agent_task_graph.py,sha256=ktj-oNLUPmWHfL81EVyaoF4hXClWYfnN7oG2Nn4pOsg,7128
|
43
|
+
job_shop_lib/graphs/_build_disjunctive_graph.py,sha256=z1jiuTTaWPJZj-vSZdo064quGx4LEDKjtZIb1FieZW4,3705
|
44
|
+
job_shop_lib/graphs/_constants.py,sha256=dqPF--okue5sF70Iv-YR14QKFx4pxPwT2dL1Rh5jylM,374
|
45
|
+
job_shop_lib/graphs/_job_shop_graph.py,sha256=QmYj-DptmV3Mca0JHplPa1YPt6D4zDSdIwclKK15Ib0,9938
|
46
|
+
job_shop_lib/graphs/_node.py,sha256=FcV92cH1RK6xv8qK3d4QaCRzB-C2kY0MtVeWNgsdi6U,5769
|
47
|
+
job_shop_lib/graphs/graph_updaters/__init__.py,sha256=utejVUdKNa3g_6HpfTKanv-9K9sVFlRnqhWpRPGxEHU,358
|
48
|
+
job_shop_lib/graphs/graph_updaters/_graph_updater.py,sha256=H8PtBj4gv6y5wQKOstF2CSnLsFjO1YeVHpzvYK3vMRM,2053
|
49
|
+
job_shop_lib/graphs/graph_updaters/_residual_graph_updater.py,sha256=kPuBmion70-GAQsyFal8gHylHvZSoBJae9eF8iGOkvA,6097
|
50
|
+
job_shop_lib/graphs/graph_updaters/_utils.py,sha256=X5YfwJA1CCgpm1r9C036Gal2CkDh2SSak7wl7TbdjHw,704
|
51
|
+
job_shop_lib/reinforcement_learning/__init__.py,sha256=QVFo9e1X-tpanZkGdcCPV_WobQ2EZ_y5uoYSJ36XrQI,957
|
52
|
+
job_shop_lib/reinforcement_learning/_multi_job_shop_graph_env.py,sha256=jKMcWYBvz1kwlw00Xe1x9HqhFkMMqlh-Y95NmeBL3-0,15129
|
53
|
+
job_shop_lib/reinforcement_learning/_reward_observers.py,sha256=4Kdyn9Jlp_1sBtVr6raF-ZFtcnKxwyCLykfX53TmuhU,2959
|
54
|
+
job_shop_lib/reinforcement_learning/_single_job_shop_graph_env.py,sha256=Kbd3N1rKcXm6IHTo99En-oX85vqVobv2bFBCyAht2mE,12949
|
55
|
+
job_shop_lib/reinforcement_learning/_types_and_constants.py,sha256=CY849lbv6UXy40KRcMJT3WxvGWrLqcfysu65LPkTfg8,1715
|
56
|
+
job_shop_lib/reinforcement_learning/_utils.py,sha256=ilI089Bs8CRlfRV_yH6XH8oypTDtRa7hS-H4iRCC5lU,2497
|
57
|
+
job_shop_lib/visualization/__init__.py,sha256=jXC188u5AnSWcO1lRZEzZAPZTXbqlYSPhYc7LMc0itU,1094
|
58
|
+
job_shop_lib/visualization/_agent_task_graph.py,sha256=AaBTD_S34WjrsZnL_iMAplR_f67RahZi7x58SOvp-q0,8834
|
59
|
+
job_shop_lib/visualization/_disjunctive_graph.py,sha256=pg4KG9BfQbnBPnXYgbyPGe0AuHSmhYqPeqWYAf_spWQ,5905
|
60
|
+
job_shop_lib/visualization/_gantt_chart.py,sha256=B9sn4XrEUqgQhRKju-1VUG5R67AZXRu7jbrtA8VcndU,4412
|
61
|
+
job_shop_lib/visualization/_gantt_chart_creator.py,sha256=qFhCfk3oC3uF7Mau3lrNhH-34sfHXvkqEXbsDzrIbBk,7721
|
62
|
+
job_shop_lib/visualization/_gantt_chart_video_and_gif_creation.py,sha256=XXRLpC05E3zY4SIytdFP2QuxmGA95VohUVmzoFzEt7Q,13206
|
63
|
+
job_shop_lib-1.0.0a1.dist-info/LICENSE,sha256=9mggivMGd5taAu3xbmBway-VQZMBzurBGHofFopvUsQ,1069
|
64
|
+
job_shop_lib-1.0.0a1.dist-info/METADATA,sha256=h5mdFHRaXbnL7F4lMjGNVE5-TSx35rvAG8SlzX3wWiU,14810
|
65
|
+
job_shop_lib-1.0.0a1.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
66
|
+
job_shop_lib-1.0.0a1.dist-info/RECORD,,
|
@@ -1,142 +0,0 @@
|
|
1
|
-
"""Module for loading benchmark instances.
|
2
|
-
|
3
|
-
All benchmark instances are stored in a single JSON file. This module provides
|
4
|
-
functions to load the instances from the file and return them as
|
5
|
-
JobShopInstance objects.
|
6
|
-
|
7
|
-
The contributions to this benchmark dataset are as follows:
|
8
|
-
|
9
|
-
abz5-9: This subset, comprising five instances, was introduced by Adams et
|
10
|
-
al. (1988).
|
11
|
-
ft06, ft10, ft20: These three instances are attributed to the work of
|
12
|
-
Fisher and Thompson, as detailed in their 1963 work.
|
13
|
-
la01-40: A collection of forty instances, this group was contributed by
|
14
|
-
Lawrence, as referenced in his 1984 report.
|
15
|
-
orb01-10: Ten instances in this category were provided by Applegate and
|
16
|
-
Cook, as seen in their 1991 study.
|
17
|
-
swb01-20: This segment, encompassing twenty instances, was contributed by
|
18
|
-
Storer et al., as per their 1992 article.
|
19
|
-
yn1-4: Yamada and Nakano are credited with the addition of four instances
|
20
|
-
in this group, as found in their 1992 paper.
|
21
|
-
ta01-80: The largest contribution, consisting of eighty instances, was
|
22
|
-
made by Taillard, as documented in his 1993 paper.
|
23
|
-
|
24
|
-
The metadata from these instances has been updated using data from:
|
25
|
-
|
26
|
-
Thomas Weise. jsspInstancesAndResults. Accessed in January 2024.
|
27
|
-
Available at: https://github.com/thomasWeise/jsspInstancesAndResults
|
28
|
-
|
29
|
-
It includes the following information:
|
30
|
-
- "optimum" (int | None): The optimal makespan for the instance.
|
31
|
-
- "lower_bound" (int): The lower bound for the makespan. If
|
32
|
-
optimality is known, it is equal to the optimum.
|
33
|
-
- "upper_bound" (int): The upper bound for the makespan. If
|
34
|
-
optimality is known, it is equal to the optimum.
|
35
|
-
- "reference" (str): The paper or source where the instance was first
|
36
|
-
introduced.
|
37
|
-
|
38
|
-
References:
|
39
|
-
- J. Adams, E. Balas, and D. Zawack, "The shifting bottleneck procedure
|
40
|
-
for job shop scheduling," Management Science, vol. 34, no. 3,
|
41
|
-
pp. 391–401, 1988.
|
42
|
-
|
43
|
-
- J.F. Muth and G.L. Thompson, Industrial scheduling. Englewood Cliffs,
|
44
|
-
NJ: Prentice-Hall, 1963.
|
45
|
-
|
46
|
-
- S. Lawrence, "Resource constrained project scheduling: An experimental
|
47
|
-
investigation of heuristic scheduling techniques (Supplement),"
|
48
|
-
Carnegie-Mellon University, Graduate School of Industrial
|
49
|
-
Administration, Pittsburgh, Pennsylvania, 1984.
|
50
|
-
|
51
|
-
- D. Applegate and W. Cook, "A computational study of job-shop
|
52
|
-
scheduling," ORSA Journal on Computer, vol. 3, no. 2, pp. 149–156,
|
53
|
-
1991.
|
54
|
-
|
55
|
-
- R.H. Storer, S.D. Wu, and R. Vaccari, "New search spaces for
|
56
|
-
sequencing problems with applications to job-shop scheduling,"
|
57
|
-
Management Science, vol. 38, no. 10, pp. 1495–1509, 1992.
|
58
|
-
|
59
|
-
- T. Yamada and R. Nakano, "A genetic algorithm applicable to
|
60
|
-
large-scale job-shop problems," in Proceedings of the Second
|
61
|
-
International Workshop on Parallel Problem Solving from Nature
|
62
|
-
(PPSN'2), Brussels, Belgium, pp. 281–290, 1992.
|
63
|
-
|
64
|
-
- E. Taillard, "Benchmarks for basic scheduling problems," European
|
65
|
-
Journal of Operational Research, vol. 64, no. 2, pp. 278–285, 1993.
|
66
|
-
"""
|
67
|
-
|
68
|
-
from typing import Any
|
69
|
-
|
70
|
-
import functools
|
71
|
-
import json
|
72
|
-
from importlib import resources
|
73
|
-
|
74
|
-
from job_shop_lib import JobShopInstance
|
75
|
-
|
76
|
-
|
77
|
-
@functools.cache
|
78
|
-
def load_all_benchmark_instances() -> dict[str, JobShopInstance]:
|
79
|
-
"""Loads all benchmark instances available.
|
80
|
-
|
81
|
-
Returns:
|
82
|
-
A dictionary containing the names of the benchmark instances as keys
|
83
|
-
and the corresponding JobShopInstance objects as values.
|
84
|
-
|
85
|
-
"""
|
86
|
-
benchmark_instances_dict = load_benchmark_json()
|
87
|
-
return {
|
88
|
-
name: load_benchmark_instance(name)
|
89
|
-
for name in benchmark_instances_dict
|
90
|
-
}
|
91
|
-
|
92
|
-
|
93
|
-
def load_benchmark_instance(name: str) -> JobShopInstance:
|
94
|
-
"""Loads a specific benchmark instance.
|
95
|
-
|
96
|
-
Calls to `load_benchmark_json` to load the benchmark instances from the
|
97
|
-
JSON file. The instance is then loaded from the dictionary using the
|
98
|
-
provided name. Since `load_benchmark_json` is cached, the file is only
|
99
|
-
read once.
|
100
|
-
|
101
|
-
Args:
|
102
|
-
name: The name of the benchmark instance to load. Can be one of the
|
103
|
-
following: "abz5-9", "ft06", "ft10", "ft20", "la01-40", "orb01-10",
|
104
|
-
"swb01-20", "yn1-4", or "ta01-80".
|
105
|
-
"""
|
106
|
-
benchmark_dict = load_benchmark_json()[name]
|
107
|
-
return JobShopInstance.from_matrices(
|
108
|
-
duration_matrix=benchmark_dict["duration_matrix"],
|
109
|
-
machines_matrix=benchmark_dict["machines_matrix"],
|
110
|
-
name=name,
|
111
|
-
metadata=benchmark_dict["metadata"],
|
112
|
-
)
|
113
|
-
|
114
|
-
|
115
|
-
@functools.cache
|
116
|
-
def load_benchmark_json() -> dict[str, dict[str, Any]]:
|
117
|
-
"""Loads the raw JSON file containing the benchmark instances.
|
118
|
-
|
119
|
-
Results are cached to avoid reading the file multiple times.
|
120
|
-
|
121
|
-
Each instance is represented as a dictionary with the following keys
|
122
|
-
and values:
|
123
|
-
- "name" (str): The name of the instance.
|
124
|
-
- "duration_matrix" (list[list[int]]): The matrix containing the
|
125
|
-
durations for each operation.
|
126
|
-
- "machines_matrix" (list[list[int]]): The matrix containing the
|
127
|
-
machines for each operation.
|
128
|
-
- "metadata" (dict[str, Any]): A dictionary containing metadata
|
129
|
-
about the instance. The keys are "optimum" (int | None),
|
130
|
-
"lower_bound" (int), "upper_bound" (int),
|
131
|
-
and "reference" (str).
|
132
|
-
|
133
|
-
Returns:
|
134
|
-
The dictionary containing the benchmark instances.
|
135
|
-
"""
|
136
|
-
benchmark_file = (
|
137
|
-
resources.files("job_shop_lib.benchmarking")
|
138
|
-
/ "benchmark_instances.json"
|
139
|
-
)
|
140
|
-
|
141
|
-
with benchmark_file.open("r", encoding="utf-8") as f:
|
142
|
-
return json.load(f)
|
job_shop_lib/cp_sat/__init__.py
DELETED
@@ -1,206 +0,0 @@
|
|
1
|
-
"""Contains factory functions for creating dispatching rules, machine choosers,
|
2
|
-
and pruning functions for the job shop scheduling problem.
|
3
|
-
|
4
|
-
The factory functions create and return the appropriate functions based on the
|
5
|
-
specified names or enums.
|
6
|
-
"""
|
7
|
-
|
8
|
-
from enum import Enum
|
9
|
-
|
10
|
-
from collections.abc import Callable, Sequence
|
11
|
-
import random
|
12
|
-
|
13
|
-
from job_shop_lib import Operation
|
14
|
-
from job_shop_lib.dispatching import (
|
15
|
-
shortest_processing_time_rule,
|
16
|
-
first_come_first_served_rule,
|
17
|
-
most_work_remaining_rule,
|
18
|
-
most_operations_remaining_rule,
|
19
|
-
random_operation_rule,
|
20
|
-
Dispatcher,
|
21
|
-
prune_dominated_operations,
|
22
|
-
prune_non_immediate_machines,
|
23
|
-
create_composite_pruning_function,
|
24
|
-
)
|
25
|
-
|
26
|
-
|
27
|
-
class DispatchingRule(str, Enum):
|
28
|
-
"""Enumeration of dispatching rules for the job shop scheduling problem."""
|
29
|
-
|
30
|
-
SHORTEST_PROCESSING_TIME = "shortest_processing_time"
|
31
|
-
FIRST_COME_FIRST_SERVED = "first_come_first_served"
|
32
|
-
MOST_WORK_REMAINING = "most_work_remaining"
|
33
|
-
MOST_OPERATIONS_REMAINING = "most_operations_remaining"
|
34
|
-
RANDOM = "random"
|
35
|
-
|
36
|
-
|
37
|
-
class MachineChooser(str, Enum):
|
38
|
-
"""Enumeration of machine chooser strategies for the job shop scheduling"""
|
39
|
-
|
40
|
-
FIRST = "first"
|
41
|
-
RANDOM = "random"
|
42
|
-
|
43
|
-
|
44
|
-
class PruningFunction(str, Enum):
|
45
|
-
"""Enumeration of pruning functions.
|
46
|
-
|
47
|
-
A pruning function is used by the `Dispatcher` class to reduce the
|
48
|
-
amount of available operations to choose from.
|
49
|
-
"""
|
50
|
-
|
51
|
-
DOMINATED_OPERATIONS = "dominated_operations"
|
52
|
-
NON_IMMEDIATE_MACHINES = "non_immediate_machines"
|
53
|
-
|
54
|
-
|
55
|
-
def dispatching_rule_factory(
|
56
|
-
dispatching_rule: str | DispatchingRule,
|
57
|
-
) -> Callable[[Dispatcher], Operation]:
|
58
|
-
"""Creates and returns a dispatching rule function based on the specified
|
59
|
-
dispatching rule name.
|
60
|
-
|
61
|
-
The dispatching rule function determines the order in which operations are
|
62
|
-
selected for execution based on certain criteria such as shortest
|
63
|
-
processing time, first come first served, etc.
|
64
|
-
|
65
|
-
Args:
|
66
|
-
dispatching_rule: The name of the dispatching rule to be used.
|
67
|
-
Supported values are 'shortest_processing_time',
|
68
|
-
'first_come_first_served', 'most_work_remaining',
|
69
|
-
and 'random'.
|
70
|
-
|
71
|
-
Returns:
|
72
|
-
A function that takes a Dispatcher instance as input and returns an
|
73
|
-
Operation based on the specified dispatching rule.
|
74
|
-
|
75
|
-
Raises:
|
76
|
-
ValueError: If the dispatching_rule argument is not recognized or is
|
77
|
-
not supported.
|
78
|
-
"""
|
79
|
-
dispatching_rules = {
|
80
|
-
DispatchingRule.SHORTEST_PROCESSING_TIME: (
|
81
|
-
shortest_processing_time_rule
|
82
|
-
),
|
83
|
-
DispatchingRule.FIRST_COME_FIRST_SERVED: first_come_first_served_rule,
|
84
|
-
DispatchingRule.MOST_WORK_REMAINING: most_work_remaining_rule,
|
85
|
-
DispatchingRule.MOST_OPERATIONS_REMAINING: (
|
86
|
-
most_operations_remaining_rule
|
87
|
-
),
|
88
|
-
DispatchingRule.RANDOM: random_operation_rule,
|
89
|
-
}
|
90
|
-
|
91
|
-
dispatching_rule = dispatching_rule.lower()
|
92
|
-
if dispatching_rule not in dispatching_rules:
|
93
|
-
raise ValueError(
|
94
|
-
f"Dispatching rule {dispatching_rule} not recognized. Available "
|
95
|
-
f"dispatching rules: {', '.join(dispatching_rules)}."
|
96
|
-
)
|
97
|
-
|
98
|
-
return dispatching_rules[dispatching_rule] # type: ignore[index]
|
99
|
-
|
100
|
-
|
101
|
-
def machine_chooser_factory(
|
102
|
-
machine_chooser: str,
|
103
|
-
) -> Callable[[Dispatcher, Operation], int]:
|
104
|
-
"""Creates and returns a machine chooser function based on the specified
|
105
|
-
machine chooser strategy name.
|
106
|
-
|
107
|
-
The machine chooser function determines which machine an operation should
|
108
|
-
be assigned to for execution. The selection can be based on different
|
109
|
-
strategies such as choosing the first available machine or selecting a
|
110
|
-
machine randomly.
|
111
|
-
|
112
|
-
Args:
|
113
|
-
machine_chooser (str): The name of the machine chooser strategy to be
|
114
|
-
used. Supported values are 'first' and 'random'.
|
115
|
-
|
116
|
-
Returns:
|
117
|
-
A function that takes a Dispatcher instance and an Operation as input
|
118
|
-
and returns the index of the selected machine based on the specified
|
119
|
-
machine chooser strategy.
|
120
|
-
|
121
|
-
Raises:
|
122
|
-
ValueError: If the machine_chooser argument is not recognized or is
|
123
|
-
not supported.
|
124
|
-
"""
|
125
|
-
machine_choosers: dict[str, Callable[[Dispatcher, Operation], int]] = {
|
126
|
-
MachineChooser.FIRST: lambda _, operation: operation.machines[0],
|
127
|
-
MachineChooser.RANDOM: lambda _, operation: random.choice(
|
128
|
-
operation.machines
|
129
|
-
),
|
130
|
-
}
|
131
|
-
|
132
|
-
machine_chooser = machine_chooser.lower()
|
133
|
-
if machine_chooser not in machine_choosers:
|
134
|
-
raise ValueError(
|
135
|
-
f"Machine chooser {machine_chooser} not recognized. Available "
|
136
|
-
f"machine choosers: {', '.join(machine_choosers)}."
|
137
|
-
)
|
138
|
-
|
139
|
-
return machine_choosers[machine_chooser]
|
140
|
-
|
141
|
-
|
142
|
-
def composite_pruning_function_factory(
|
143
|
-
pruning_function_names: Sequence[str | PruningFunction],
|
144
|
-
) -> Callable[[Dispatcher, list[Operation]], list[Operation]]:
|
145
|
-
"""Creates and returns a composite pruning function based on the
|
146
|
-
specified list of pruning strategies.
|
147
|
-
|
148
|
-
The composite pruning function filters out operations based on
|
149
|
-
the specified list of pruning strategies.
|
150
|
-
|
151
|
-
Args:
|
152
|
-
pruning_functions:
|
153
|
-
A list of pruning strategies to be used. Supported values are
|
154
|
-
'dominated_operations' and 'non_immediate_machines'.
|
155
|
-
|
156
|
-
Returns:
|
157
|
-
A function that takes a Dispatcher instance and a list of Operation
|
158
|
-
instances as input and returns a list of Operation instances based on
|
159
|
-
the specified list of pruning strategies.
|
160
|
-
|
161
|
-
Raises:
|
162
|
-
ValueError: If any of the pruning strategies in the list are not
|
163
|
-
recognized or are not supported.
|
164
|
-
"""
|
165
|
-
|
166
|
-
pruning_functions = [
|
167
|
-
pruning_function_factory(name) for name in pruning_function_names
|
168
|
-
]
|
169
|
-
return create_composite_pruning_function(pruning_functions)
|
170
|
-
|
171
|
-
|
172
|
-
def pruning_function_factory(
|
173
|
-
pruning_function_name: str | PruningFunction,
|
174
|
-
) -> Callable[[Dispatcher, list[Operation]], list[Operation]]:
|
175
|
-
"""Creates and returns a pruning function based on the specified
|
176
|
-
pruning strategy name.
|
177
|
-
|
178
|
-
The pruning function filters out operations based on certain
|
179
|
-
criteria such as dominated operations, non-immediate machines, etc.
|
180
|
-
|
181
|
-
Args:
|
182
|
-
pruning_function:
|
183
|
-
The name of the pruning function to be used. Supported values are
|
184
|
-
'dominated_operations' and 'non_immediate_machines'.
|
185
|
-
|
186
|
-
Returns:
|
187
|
-
A function that takes a Dispatcher instance and a list of Operation
|
188
|
-
instances as input and returns a list of Operation instances based on
|
189
|
-
the specified pruning function.
|
190
|
-
|
191
|
-
Raises:
|
192
|
-
ValueError: If the pruning_function argument is not recognized or is
|
193
|
-
not supported.
|
194
|
-
"""
|
195
|
-
pruning_strategies = {
|
196
|
-
PruningFunction.DOMINATED_OPERATIONS: prune_dominated_operations,
|
197
|
-
PruningFunction.NON_IMMEDIATE_MACHINES: prune_non_immediate_machines,
|
198
|
-
}
|
199
|
-
|
200
|
-
if pruning_function_name not in pruning_strategies:
|
201
|
-
raise ValueError(
|
202
|
-
f"Unsupported pruning function '{pruning_function_name}'. "
|
203
|
-
f"Supported values are {', '.join(pruning_strategies.keys())}."
|
204
|
-
)
|
205
|
-
|
206
|
-
return pruning_strategies[pruning_function_name] # type: ignore[index]
|