job-shop-lib 0.5.1__tar.gz → 1.0.0a1__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. {job_shop_lib-0.5.1 → job_shop_lib-1.0.0a1}/PKG-INFO +68 -44
  2. {job_shop_lib-0.5.1 → job_shop_lib-1.0.0a1}/README.md +65 -42
  3. job_shop_lib-1.0.0a1/job_shop_lib/__init__.py +29 -0
  4. job_shop_lib-0.5.1/job_shop_lib/base_solver.py → job_shop_lib-1.0.0a1/job_shop_lib/_base_solver.py +1 -1
  5. job_shop_lib-0.5.1/job_shop_lib/job_shop_instance.py → job_shop_lib-1.0.0a1/job_shop_lib/_job_shop_instance.py +9 -4
  6. job_shop_lib-1.0.0a1/job_shop_lib/_operation.py +95 -0
  7. job_shop_lib-0.5.1/job_shop_lib/schedule.py → job_shop_lib-1.0.0a1/job_shop_lib/_schedule.py +73 -54
  8. job_shop_lib-0.5.1/job_shop_lib/scheduled_operation.py → job_shop_lib-1.0.0a1/job_shop_lib/_scheduled_operation.py +13 -37
  9. job_shop_lib-1.0.0a1/job_shop_lib/benchmarking/__init__.py +101 -0
  10. job_shop_lib-1.0.0a1/job_shop_lib/benchmarking/_load_benchmark.py +88 -0
  11. job_shop_lib-1.0.0a1/job_shop_lib/constraint_programming/__init__.py +13 -0
  12. job_shop_lib-0.5.1/job_shop_lib/cp_sat/ortools_solver.py → job_shop_lib-1.0.0a1/job_shop_lib/constraint_programming/_ortools_solver.py +57 -18
  13. job_shop_lib-1.0.0a1/job_shop_lib/dispatching/__init__.py +56 -0
  14. job_shop_lib-0.5.1/job_shop_lib/dispatching/dispatcher.py → job_shop_lib-1.0.0a1/job_shop_lib/dispatching/_dispatcher.py +153 -80
  15. job_shop_lib-1.0.0a1/job_shop_lib/dispatching/_dispatcher_observer_config.py +54 -0
  16. job_shop_lib-1.0.0a1/job_shop_lib/dispatching/_factories.py +125 -0
  17. job_shop_lib-0.5.1/job_shop_lib/dispatching/history_tracker.py → job_shop_lib-1.0.0a1/job_shop_lib/dispatching/_history_observer.py +4 -6
  18. job_shop_lib-0.5.1/job_shop_lib/dispatching/pruning_functions.py → job_shop_lib-1.0.0a1/job_shop_lib/dispatching/_ready_operation_filters.py +6 -35
  19. job_shop_lib-1.0.0a1/job_shop_lib/dispatching/_unscheduled_operations_observer.py +69 -0
  20. job_shop_lib-1.0.0a1/job_shop_lib/dispatching/feature_observers/__init__.py +34 -0
  21. job_shop_lib-0.5.1/job_shop_lib/dispatching/feature_observers/composite_feature_observer.py → job_shop_lib-1.0.0a1/job_shop_lib/dispatching/feature_observers/_composite_feature_observer.py +84 -2
  22. job_shop_lib-0.5.1/job_shop_lib/dispatching/feature_observers/duration_observer.py → job_shop_lib-1.0.0a1/job_shop_lib/dispatching/feature_observers/_duration_observer.py +6 -17
  23. job_shop_lib-0.5.1/job_shop_lib/dispatching/feature_observers/earliest_start_time_observer.py → job_shop_lib-1.0.0a1/job_shop_lib/dispatching/feature_observers/_earliest_start_time_observer.py +114 -35
  24. job_shop_lib-0.5.1/job_shop_lib/dispatching/feature_observers/factory.py → job_shop_lib-1.0.0a1/job_shop_lib/dispatching/feature_observers/_factory.py +31 -5
  25. job_shop_lib-0.5.1/job_shop_lib/dispatching/feature_observers/feature_observer.py → job_shop_lib-1.0.0a1/job_shop_lib/dispatching/feature_observers/_feature_observer.py +59 -16
  26. job_shop_lib-1.0.0a1/job_shop_lib/dispatching/feature_observers/_is_completed_observer.py +97 -0
  27. job_shop_lib-1.0.0a1/job_shop_lib/dispatching/feature_observers/_is_ready_observer.py +33 -0
  28. job_shop_lib-0.5.1/job_shop_lib/dispatching/feature_observers/position_in_job_observer.py → job_shop_lib-1.0.0a1/job_shop_lib/dispatching/feature_observers/_position_in_job_observer.py +1 -8
  29. job_shop_lib-0.5.1/job_shop_lib/dispatching/feature_observers/remaining_operations_observer.py → job_shop_lib-1.0.0a1/job_shop_lib/dispatching/feature_observers/_remaining_operations_observer.py +8 -26
  30. job_shop_lib-1.0.0a1/job_shop_lib/dispatching/rules/__init__.py +51 -0
  31. job_shop_lib-1.0.0a1/job_shop_lib/dispatching/rules/_dispatching_rule_factory.py +82 -0
  32. job_shop_lib-0.5.1/job_shop_lib/dispatching/dispatching_rule_solver.py → job_shop_lib-1.0.0a1/job_shop_lib/dispatching/rules/_dispatching_rule_solver.py +44 -15
  33. job_shop_lib-0.5.1/job_shop_lib/dispatching/dispatching_rules.py → job_shop_lib-1.0.0a1/job_shop_lib/dispatching/rules/_dispatching_rules_functions.py +74 -21
  34. job_shop_lib-1.0.0a1/job_shop_lib/dispatching/rules/_machine_chooser_factory.py +69 -0
  35. job_shop_lib-1.0.0a1/job_shop_lib/dispatching/rules/_utils.py +127 -0
  36. {job_shop_lib-0.5.1 → job_shop_lib-1.0.0a1}/job_shop_lib/exceptions.py +18 -0
  37. {job_shop_lib-0.5.1 → job_shop_lib-1.0.0a1}/job_shop_lib/generation/__init__.py +2 -2
  38. job_shop_lib-0.5.1/job_shop_lib/generation/general_instance_generator.py → job_shop_lib-1.0.0a1/job_shop_lib/generation/_general_instance_generator.py +26 -7
  39. job_shop_lib-0.5.1/job_shop_lib/generation/instance_generator.py → job_shop_lib-1.0.0a1/job_shop_lib/generation/_instance_generator.py +13 -3
  40. {job_shop_lib-0.5.1 → job_shop_lib-1.0.0a1}/job_shop_lib/graphs/__init__.py +17 -6
  41. job_shop_lib-0.5.1/job_shop_lib/graphs/job_shop_graph.py → job_shop_lib-1.0.0a1/job_shop_lib/graphs/_job_shop_graph.py +81 -2
  42. job_shop_lib-0.5.1/job_shop_lib/graphs/node.py → job_shop_lib-1.0.0a1/job_shop_lib/graphs/_node.py +18 -12
  43. job_shop_lib-1.0.0a1/job_shop_lib/graphs/graph_updaters/__init__.py +13 -0
  44. job_shop_lib-1.0.0a1/job_shop_lib/graphs/graph_updaters/_graph_updater.py +59 -0
  45. job_shop_lib-1.0.0a1/job_shop_lib/graphs/graph_updaters/_residual_graph_updater.py +154 -0
  46. job_shop_lib-1.0.0a1/job_shop_lib/graphs/graph_updaters/_utils.py +25 -0
  47. job_shop_lib-1.0.0a1/job_shop_lib/reinforcement_learning/__init__.py +41 -0
  48. job_shop_lib-1.0.0a1/job_shop_lib/reinforcement_learning/_multi_job_shop_graph_env.py +366 -0
  49. job_shop_lib-1.0.0a1/job_shop_lib/reinforcement_learning/_reward_observers.py +85 -0
  50. job_shop_lib-1.0.0a1/job_shop_lib/reinforcement_learning/_single_job_shop_graph_env.py +337 -0
  51. job_shop_lib-1.0.0a1/job_shop_lib/reinforcement_learning/_types_and_constants.py +61 -0
  52. job_shop_lib-1.0.0a1/job_shop_lib/reinforcement_learning/_utils.py +96 -0
  53. job_shop_lib-1.0.0a1/job_shop_lib/visualization/__init__.py +41 -0
  54. job_shop_lib-0.5.1/job_shop_lib/visualization/agent_task_graph.py → job_shop_lib-1.0.0a1/job_shop_lib/visualization/_agent_task_graph.py +28 -9
  55. job_shop_lib-1.0.0a1/job_shop_lib/visualization/_gantt_chart_creator.py +219 -0
  56. job_shop_lib-1.0.0a1/job_shop_lib/visualization/_gantt_chart_video_and_gif_creation.py +388 -0
  57. {job_shop_lib-0.5.1 → job_shop_lib-1.0.0a1}/pyproject.toml +12 -3
  58. job_shop_lib-0.5.1/job_shop_lib/__init__.py +0 -21
  59. job_shop_lib-0.5.1/job_shop_lib/benchmarking/__init__.py +0 -78
  60. job_shop_lib-0.5.1/job_shop_lib/benchmarking/load_benchmark.py +0 -142
  61. job_shop_lib-0.5.1/job_shop_lib/cp_sat/__init__.py +0 -5
  62. job_shop_lib-0.5.1/job_shop_lib/dispatching/__init__.py +0 -52
  63. job_shop_lib-0.5.1/job_shop_lib/dispatching/factories.py +0 -206
  64. job_shop_lib-0.5.1/job_shop_lib/dispatching/feature_observers/__init__.py +0 -28
  65. job_shop_lib-0.5.1/job_shop_lib/dispatching/feature_observers/is_completed_observer.py +0 -98
  66. job_shop_lib-0.5.1/job_shop_lib/dispatching/feature_observers/is_ready_observer.py +0 -40
  67. job_shop_lib-0.5.1/job_shop_lib/generators/__init__.py +0 -8
  68. job_shop_lib-0.5.1/job_shop_lib/generators/basic_generator.py +0 -200
  69. job_shop_lib-0.5.1/job_shop_lib/generators/transformations.py +0 -164
  70. job_shop_lib-0.5.1/job_shop_lib/operation.py +0 -122
  71. job_shop_lib-0.5.1/job_shop_lib/visualization/__init__.py +0 -25
  72. job_shop_lib-0.5.1/job_shop_lib/visualization/create_gif.py +0 -209
  73. {job_shop_lib-0.5.1 → job_shop_lib-1.0.0a1}/LICENSE +0 -0
  74. {job_shop_lib-0.5.1 → job_shop_lib-1.0.0a1}/job_shop_lib/benchmarking/benchmark_instances.json +0 -0
  75. /job_shop_lib-0.5.1/job_shop_lib/dispatching/feature_observers/is_scheduled_observer.py → /job_shop_lib-1.0.0a1/job_shop_lib/dispatching/feature_observers/_is_scheduled_observer.py +0 -0
  76. /job_shop_lib-0.5.1/job_shop_lib/generation/transformations.py → /job_shop_lib-1.0.0a1/job_shop_lib/generation/_transformations.py +0 -0
  77. /job_shop_lib-0.5.1/job_shop_lib/graphs/build_agent_task_graph.py → /job_shop_lib-1.0.0a1/job_shop_lib/graphs/_build_agent_task_graph.py +0 -0
  78. /job_shop_lib-0.5.1/job_shop_lib/graphs/build_disjunctive_graph.py → /job_shop_lib-1.0.0a1/job_shop_lib/graphs/_build_disjunctive_graph.py +0 -0
  79. /job_shop_lib-0.5.1/job_shop_lib/graphs/constants.py → /job_shop_lib-1.0.0a1/job_shop_lib/graphs/_constants.py +0 -0
  80. /job_shop_lib-0.5.1/job_shop_lib/visualization/disjunctive_graph.py → /job_shop_lib-1.0.0a1/job_shop_lib/visualization/_disjunctive_graph.py +0 -0
  81. /job_shop_lib-0.5.1/job_shop_lib/visualization/gantt_chart.py → /job_shop_lib-1.0.0a1/job_shop_lib/visualization/_gantt_chart.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: job-shop-lib
3
- Version: 0.5.1
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: imageio (>=2,<3)
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/logo_with_transparent_background.png" height="150px">
27
+ <img src="docs/source/images/jslib_minimalist_logo_no_background_fixed.png" height="150px">
27
28
 
28
- <h1>Job Shop Library</h1>
29
+ <h1>JobShopLib</h1>
29
30
 
30
31
  [![Tests](https://github.com/Pabloo22/job_shop_lib/actions/workflows/tests.yaml/badge.svg)](https://github.com/Pabloo22/job_shop_lib/actions/workflows/tests.yaml)
31
32
  ![Python versions](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12-blue)
@@ -34,25 +35,57 @@ Description-Content-Type: text/markdown
34
35
 
35
36
  </div>
36
37
 
37
- An easy-to-use and modular Python library for the Job Shop Scheduling Problem (JSSP) with a special focus on graph representations.
38
+ JobShopLib is a Python package for creating, solving, and visualizing Job Shop Scheduling Problems (JSSP).
38
39
 
39
- It provides intuitive data structures to represent instances and solutions, as well as solvers and visualization tools.
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 the [this](https://colab.research.google.com/drive/1XV_Rvq1F2ns6DFG8uNj66q_rcowwTZ4H?usp=sharing) Google Colab notebook for a quick start guide!
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
- You can install the library from PyPI:
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
- ## Quick Start :rocket:
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 Job Shop Instance by defining the jobs and operations. An operation is defined by the machine(s) it is processed on and the duration (processing time).
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 `benchmarks` contains functions to load the instances from the file and return them as `JobShopInstance` objects without having to download them
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 `BasicGenerator` class.
151
+ You can also generate a random instance with the `GeneralInstanceGenerator` class.
119
152
 
120
153
  ```python
121
- from job_shop_lib.generators import BasicGenerator
154
+ from job_shop_lib.generation import GeneralInstanceGenerator
122
155
 
123
- generator = BasicGenerator(
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 = BasicGenerator(iteration_limit=100, seed=42)
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.cp_sat import ORToolsSolver
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
- ![Example Gannt Chart](images/ft06_solution.png)
190
+ ![Example Gannt Chart](docs/source/images/ft06_solution.png)
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
- ![Example Gif](examples/ft06_optimized.gif)
226
+ ![Example Gif](docs/source/examples/output/ft06_optimized.gif)
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
- ![Example Disjunctive Graph](images/example_disjunctive_graph.png)
253
+ ![Example Disjunctive Graph](docs/source/images/example_disjunctive_graph.png)
221
254
 
222
255
 
223
- > [!WARNING]
224
- > This plot function requires having the optional dependency [PyGraphViz](https://pygraphviz.github.io/) installed.
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="examples/agent_task_graph.png" width="300">
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
- ### With Poetry
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
- poetry shell
327
+ git clone https://github.com/Pabloo22/job_shop_lib.git
328
+ cd job_shop_lib
300
329
  ```
301
- 4. Install dependencies:
330
+
331
+ 2. Install [poetry](https://python-poetry.org/docs/) if you don't have it already:
332
+
302
333
  ```bash
303
- poetry install --with notebooks --with test --with lint --all-extras
334
+ pip install poetry
304
335
  ```
305
- or equivalently:
336
+
337
+ 3. Install dependencies:
306
338
  ```bash
307
339
  make poetry_install_all
308
340
  ```
309
341
 
310
- ### With PyPI
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,
@@ -1,8 +1,8 @@
1
1
  <div align="center">
2
2
 
3
- <img src="images/logo_with_transparent_background.png" height="150px">
3
+ <img src="docs/source/images/jslib_minimalist_logo_no_background_fixed.png" height="150px">
4
4
 
5
- <h1>Job Shop Library</h1>
5
+ <h1>JobShopLib</h1>
6
6
 
7
7
  [![Tests](https://github.com/Pabloo22/job_shop_lib/actions/workflows/tests.yaml/badge.svg)](https://github.com/Pabloo22/job_shop_lib/actions/workflows/tests.yaml)
8
8
  ![Python versions](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12-blue)
@@ -11,25 +11,57 @@
11
11
 
12
12
  </div>
13
13
 
14
- An easy-to-use and modular Python library for the Job Shop Scheduling Problem (JSSP) with a special focus on graph representations.
14
+ JobShopLib is a Python package for creating, solving, and visualizing Job Shop Scheduling Problems (JSSP).
15
15
 
16
- It provides intuitive data structures to represent instances and solutions, as well as solvers and visualization tools.
16
+ It follows a modular design, allowing users to easily extend the library with new solvers, dispatching rules, visualization functions, etc.
17
17
 
18
- See the [this](https://colab.research.google.com/drive/1XV_Rvq1F2ns6DFG8uNj66q_rcowwTZ4H?usp=sharing) Google Colab notebook for a quick start guide!
18
+ See [this](https://colab.research.google.com/drive/1XV_Rvq1F2ns6DFG8uNj66q_rcowwTZ4H?usp=sharing) Google Colab notebook for a quick start guide!
19
19
 
20
- ## Installation
20
+ ## Installation :package:
21
21
 
22
- You can install the library from PyPI:
22
+ <!-- start installation -->
23
+
24
+ JobShopLib is distributed on [PyPI](https://pypi.org/project/job-shop-lib/) and it supports Python 3.10+.
25
+
26
+ You can install the latest version using `pip`:
23
27
 
24
28
  ```bash
25
29
  pip install job-shop-lib
26
30
  ```
27
31
 
28
- ## Quick Start :rocket:
32
+ <!-- end installation -->
33
+
34
+ <!-- key features -->
35
+
36
+ ## Key Features :star:
37
+
38
+ - **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).
39
+
40
+ - **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).
41
+
42
+ - **Random Instance Generation**: Create random instances with customizable sizes and properties or augment existing ones. See [`generation`](job_shop_lib/generation) package.
43
+
44
+ - **Multiple Solvers**:
45
+ - **Constraint Programming Solver**: OR-Tools' CP-SAT solver. See [Solving the Problem](docs/source/examples/02-Solving-the-Problem.ipynb).
46
+
47
+ - **Dispatching Rule Solvers**: Use any of the available dispatching rules or create custom ones. See [Dispatching Rules](docs/source/examples/03-Dispatching-Rules.ipynb).
48
+
49
+ - **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).
50
+
51
+ - **Graph Representations**:
52
+ - **Disjunctive Graphs**: Represent and visualize instances as disjunctive graphs. See [Disjunctive Graph](docs/source/examples/04-Disjunctive-Graph.ipynb).
53
+ - **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).
54
+ - Build your own custom graphs with the `JobShopGraph` class.
55
+
56
+ - **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).
57
+
58
+ <!-- end key features -->
59
+
60
+ ## Some Examples :rocket:
29
61
 
30
62
  ### Create a Job Shop Instance
31
63
 
32
- You can create a Job Shop Instance by defining the jobs and operations. An operation is defined by the machine(s) it is processed on and the duration (processing time).
64
+ 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).
33
65
 
34
66
  ```python
35
67
  from job_shop_lib import JobShopInstance, Operation
@@ -60,7 +92,7 @@ from job_shop_lib.benchmarking import load_benchmark_instance
60
92
  ft06 = load_benchmark_instance("ft06")
61
93
  ```
62
94
 
63
- The module `benchmarks` contains functions to load the instances from the file and return them as `JobShopInstance` objects without having to download them
95
+ The module `benchmarking` contains functions to load the instances from the file and return them as `JobShopInstance` objects without having to download them
64
96
  manually.
65
97
 
66
98
  The contributions to this benchmark dataset are as follows:
@@ -92,12 +124,12 @@ https://github.com/thomasWeise/jsspInstancesAndResults
92
124
 
93
125
  ### Generate a Random Instance
94
126
 
95
- You can also generate a random instance with the `BasicGenerator` class.
127
+ You can also generate a random instance with the `GeneralInstanceGenerator` class.
96
128
 
97
129
  ```python
98
- from job_shop_lib.generators import BasicGenerator
130
+ from job_shop_lib.generation import GeneralInstanceGenerator
99
131
 
100
- generator = BasicGenerator(
132
+ generator = GeneralInstanceGenerator(
101
133
  duration_range=(5, 10), seed=42, num_jobs=5, num_machines=5
102
134
  )
103
135
  random_instance = generator.generate()
@@ -106,7 +138,7 @@ random_instance = generator.generate()
106
138
  This class can also work as an iterator to generate multiple instances:
107
139
 
108
140
  ```python
109
- generator = BasicGenerator(iteration_limit=100, seed=42)
141
+ generator = GeneralInstanceGenerator(iteration_limit=100, seed=42)
110
142
  instances = []
111
143
  for instance in generator:
112
144
  instances.append(instance)
@@ -122,7 +154,7 @@ Every solver is a `Callable` that receives a `JobShopInstance` and returns a `Sc
122
154
  ```python
123
155
  import matplotlib.pyplot as plt
124
156
 
125
- from job_shop_lib.cp_sat import ORToolsSolver
157
+ from job_shop_lib.constraint_programming import ORToolsSolver
126
158
  from job_shop_lib.visualization import plot_gantt_chart
127
159
 
128
160
  solver = ORToolsSolver(max_time_in_seconds=10)
@@ -131,7 +163,7 @@ ft06_schedule = solver(ft06)
131
163
  fig, ax = plot_gantt_chart(ft06_schedule)
132
164
  plt.show()
133
165
  ```
134
- ![Example Gannt Chart](images/ft06_solution.png)
166
+ ![Example Gannt Chart](docs/source/images/ft06_solution.png)
135
167
 
136
168
  ### Solve an Instance with a Dispatching Rule Solver
137
169
 
@@ -167,7 +199,7 @@ create_gif(
167
199
  )
168
200
  ```
169
201
 
170
- ![Example Gif](examples/ft06_optimized.gif)
202
+ ![Example Gif](docs/source/examples/output/ft06_optimized.gif)
171
203
 
172
204
  The dashed red line represents the current time step, which is computed as the earliest time when the next operation can start.
173
205
 
@@ -194,11 +226,11 @@ fig = plot_disjunctive_graph(instance)
194
226
  plt.show()
195
227
  ```
196
228
 
197
- ![Example Disjunctive Graph](images/example_disjunctive_graph.png)
229
+ ![Example Disjunctive Graph](docs/source/images/example_disjunctive_graph.png)
198
230
 
199
231
 
200
- > [!WARNING]
201
- > This plot function requires having the optional dependency [PyGraphViz](https://pygraphviz.github.io/) installed.
232
+ > [!TIP]
233
+ > Installing the optional dependency [PyGraphViz](https://pygraphviz.github.io/) is recommended.
202
234
 
203
235
  The `JobShopGraph` class provides easy access to the nodes, for example, to get all the nodes of a specific type:
204
236
 
@@ -253,7 +285,7 @@ plt.show()
253
285
  ```
254
286
 
255
287
  <div align="center">
256
- <img src="examples/agent_task_graph.png" width="300">
288
+ <img src="docs/source/images/agent_task_graph.png" width="300">
257
289
  </div>
258
290
  <br>
259
291
 
@@ -263,43 +295,34 @@ For more details, check the [examples](examples) folder.
263
295
 
264
296
  ## Installation for development
265
297
 
266
- ### With Poetry
298
+ <!-- start installation development -->
267
299
 
268
300
  1. Clone the repository.
269
301
 
270
- 2. Install [poetry](https://python-poetry.org/docs/) if you don't have it already:
271
- ```bash
272
- pip install poetry==1.7
273
- ```
274
- 3. Create the virtual environment:
275
302
  ```bash
276
- poetry shell
303
+ git clone https://github.com/Pabloo22/job_shop_lib.git
304
+ cd job_shop_lib
277
305
  ```
278
- 4. Install dependencies:
306
+
307
+ 2. Install [poetry](https://python-poetry.org/docs/) if you don't have it already:
308
+
279
309
  ```bash
280
- poetry install --with notebooks --with test --with lint --all-extras
310
+ pip install poetry
281
311
  ```
282
- or equivalently:
312
+
313
+ 3. Install dependencies:
283
314
  ```bash
284
315
  make poetry_install_all
285
316
  ```
286
317
 
287
- ### With PyPI
288
-
289
- If you don't want to use Poetry, you can install the library directly from the source code:
290
-
291
- ```bash
292
- git clone https://github.com/Pabloo22/job_shop_lib.git
293
- cd job_shop_lib
294
- pip install -e .
295
- ```
318
+ <!-- end installation development -->
296
319
 
297
- ## License
320
+ ## License :scroll:
298
321
 
299
322
  This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
300
323
 
301
324
 
302
- ## References
325
+ ## References :books:
303
326
 
304
327
  - J. Adams, E. Balas, and D. Zawack, "The shifting bottleneck procedure
305
328
  for job shop scheduling," Management Science, vol. 34, no. 3,
@@ -0,0 +1,29 @@
1
+ """Contains the main data structures and base classes.
2
+
3
+ .. autosummary::
4
+ :nosignatures:
5
+
6
+ Operation
7
+ JobShopInstance
8
+ ScheduledOperation
9
+ Schedule
10
+ Solver
11
+ BaseSolver
12
+
13
+ """
14
+
15
+ from job_shop_lib._operation import Operation
16
+ from job_shop_lib._job_shop_instance import JobShopInstance
17
+ from job_shop_lib._scheduled_operation import ScheduledOperation
18
+ from job_shop_lib._schedule import Schedule
19
+ from job_shop_lib._base_solver import BaseSolver, Solver
20
+
21
+
22
+ __all__ = [
23
+ "Operation",
24
+ "JobShopInstance",
25
+ "ScheduledOperation",
26
+ "Schedule",
27
+ "Solver",
28
+ "BaseSolver",
29
+ ]
@@ -33,5 +33,5 @@ class BaseSolver(abc.ABC):
33
33
  schedule = self.solve(instance)
34
34
  elapsed_time = time_start - time.perf_counter()
35
35
  schedule.metadata["elapsed_time"] = elapsed_time
36
- schedule.metadata["solved_by"] = f"{self.__class__.__name__}"
36
+ schedule.metadata["solved_by"] = self.__class__.__name__
37
37
  return schedule
@@ -7,6 +7,7 @@ import functools
7
7
  from typing import Any
8
8
 
9
9
  import numpy as np
10
+ from numpy.typing import NDArray
10
11
 
11
12
  from job_shop_lib import Operation
12
13
 
@@ -267,7 +268,7 @@ class JobShopInstance:
267
268
  ]
268
269
 
269
270
  @functools.cached_property
270
- def durations_matrix_array(self) -> np.ndarray:
271
+ def durations_matrix_array(self) -> NDArray[np.float32]:
271
272
  """Returns the duration matrix of the instance as a numpy array.
272
273
 
273
274
  The returned array has shape (num_jobs, max_num_operations_per_job).
@@ -284,7 +285,7 @@ class JobShopInstance:
284
285
  return self._fill_matrix_with_nans_2d(duration_matrix)
285
286
 
286
287
  @functools.cached_property
287
- def machines_matrix_array(self) -> np.ndarray:
288
+ def machines_matrix_array(self) -> NDArray[np.float32]:
288
289
  """Returns the machines matrix of the instance as a numpy array.
289
290
 
290
291
  The returned array has shape (num_jobs, max_num_operations_per_job,
@@ -409,7 +410,9 @@ class JobShopInstance:
409
410
  return sum(self.job_durations)
410
411
 
411
412
  @staticmethod
412
- def _fill_matrix_with_nans_2d(matrix: list[list[int]]) -> np.ndarray:
413
+ def _fill_matrix_with_nans_2d(
414
+ matrix: list[list[int]],
415
+ ) -> NDArray[np.float32]:
413
416
  """Fills a matrix with np.nan values.
414
417
 
415
418
  Args:
@@ -429,7 +432,9 @@ class JobShopInstance:
429
432
  return squared_matrix
430
433
 
431
434
  @staticmethod
432
- def _fill_matrix_with_nans_3d(matrix: list[list[list[int]]]) -> np.ndarray:
435
+ def _fill_matrix_with_nans_3d(
436
+ matrix: list[list[list[int]]],
437
+ ) -> NDArray[np.float32]:
433
438
  """Fills a 3D matrix with np.nan values.
434
439
 
435
440
  Args:
@@ -0,0 +1,95 @@
1
+ """Home of the `Operation` class."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from job_shop_lib.exceptions import UninitializedAttributeError
6
+
7
+
8
+ class Operation:
9
+ """Stores machine and duration information for a job operation.
10
+
11
+ An operation is a task that must be performed on a machine. It is part of a
12
+ job and has a duration that represents the time it takes to complete the
13
+ task.
14
+
15
+ Tip:
16
+ To use custom attributes, such as due dates or priorities, subclass
17
+ this class and add the desired attributes.
18
+
19
+ Note:
20
+ To increase performance, some solvers such as the CP-SAT solver use
21
+ only integers to represent the operation's attributes. Should a
22
+ problem involve operations with non-integer durations, it would be
23
+ necessary to multiply all durations by a sufficiently large integer so
24
+ that every duration is an integer.
25
+
26
+ Attributes:
27
+ machines: A list of machine ids that can perform the operation.
28
+ duration: The time it takes to perform the operation.
29
+ """
30
+
31
+ __slots__ = (
32
+ "machines",
33
+ "duration",
34
+ "job_id",
35
+ "position_in_job",
36
+ "operation_id",
37
+ )
38
+
39
+ def __init__(self, machines: int | list[int], duration: int):
40
+ """Initializes the object with the given machines and duration.
41
+
42
+ Args:
43
+ machines:
44
+ A list of machine ids that can perform the operation. If
45
+ only one machine can perform the operation, it can be passed as
46
+ an integer.
47
+ duration:
48
+ The time it takes to perform the operation.
49
+ """
50
+ self.machines = [machines] if isinstance(machines, int) else machines
51
+ self.duration = duration
52
+
53
+ # Defined outside the class by the JobShopInstance class:
54
+ self.job_id: int = -1
55
+ self.position_in_job: int = -1
56
+ self.operation_id: int = -1
57
+
58
+ @property
59
+ def machine_id(self) -> int:
60
+ """Returns the id of the machine associated with the operation.
61
+
62
+ Raises:
63
+ UninitializedAttributeError: If the operation has multiple machines
64
+ in its list.
65
+ """
66
+ if len(self.machines) > 1:
67
+ raise UninitializedAttributeError(
68
+ "Operation has multiple machines."
69
+ )
70
+ return self.machines[0]
71
+
72
+ def is_initialized(self) -> bool:
73
+ """Returns whether the operation has been initialized."""
74
+ return (
75
+ self.job_id == -1
76
+ or self.position_in_job == -1
77
+ or self.operation_id == -1
78
+ )
79
+
80
+ def __hash__(self) -> int:
81
+ return hash(self.operation_id)
82
+
83
+ def __eq__(self, value: object) -> bool:
84
+ if not isinstance(value, Operation):
85
+ return False
86
+ return self.__slots__ == value.__slots__
87
+
88
+ def __repr__(self) -> str:
89
+ machines = (
90
+ self.machines[0] if len(self.machines) == 1 else self.machines
91
+ )
92
+ return (
93
+ f"O(m={machines}, d={self.duration}, "
94
+ f"j={self.job_id}, p={self.position_in_job})"
95
+ )