job-shop-lib 1.0.0a4__tar.gz → 1.0.0b1__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/PKG-INFO +26 -24
  2. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/README.md +24 -22
  3. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/__init__.py +3 -0
  4. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/_job_shop_instance.py +36 -31
  5. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/_operation.py +4 -2
  6. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/_schedule.py +11 -11
  7. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/benchmarking/_load_benchmark.py +3 -3
  8. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/constraint_programming/_ortools_solver.py +6 -5
  9. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/_dispatcher.py +58 -20
  10. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/_dispatcher_observer_config.py +4 -4
  11. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/_factories.py +8 -6
  12. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/_history_observer.py +2 -1
  13. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/_ready_operation_filters.py +19 -18
  14. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/_unscheduled_operations_observer.py +4 -3
  15. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/feature_observers/_composite_feature_observer.py +7 -8
  16. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/feature_observers/_earliest_start_time_observer.py +3 -1
  17. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/feature_observers/_factory.py +13 -14
  18. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/feature_observers/_feature_observer.py +9 -8
  19. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/feature_observers/_is_completed_observer.py +2 -1
  20. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/feature_observers/_is_ready_observer.py +4 -2
  21. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/rules/_dispatching_rule_factory.py +4 -2
  22. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/rules/_dispatching_rule_solver.py +23 -15
  23. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/rules/_dispatching_rules_functions.py +9 -8
  24. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/rules/_machine_chooser_factory.py +4 -3
  25. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/rules/_utils.py +9 -8
  26. job_shop_lib-1.0.0b1/job_shop_lib/generation/__init__.py +19 -0
  27. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/generation/_general_instance_generator.py +42 -64
  28. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/generation/_instance_generator.py +11 -7
  29. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/generation/_transformations.py +5 -4
  30. job_shop_lib-1.0.0b1/job_shop_lib/generation/_utils.py +124 -0
  31. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/graphs/__init__.py +7 -7
  32. job_shop_lib-1.0.0a4/job_shop_lib/graphs/_build_agent_task_graph.py → job_shop_lib-1.0.0b1/job_shop_lib/graphs/_build_resource_task_graphs.py +26 -24
  33. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/graphs/_job_shop_graph.py +17 -13
  34. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/graphs/_node.py +6 -4
  35. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/graphs/graph_updaters/_residual_graph_updater.py +4 -2
  36. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/reinforcement_learning/_multi_job_shop_graph_env.py +40 -20
  37. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/reinforcement_learning/_reward_observers.py +3 -1
  38. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/reinforcement_learning/_single_job_shop_graph_env.py +89 -22
  39. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/reinforcement_learning/_types_and_constants.py +1 -1
  40. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/reinforcement_learning/_utils.py +3 -3
  41. job_shop_lib-1.0.0b1/job_shop_lib/visualization/__init__.py +0 -0
  42. {job_shop_lib-1.0.0a4/job_shop_lib/visualization → job_shop_lib-1.0.0b1/job_shop_lib/visualization/gantt}/__init__.py +5 -17
  43. {job_shop_lib-1.0.0a4/job_shop_lib/visualization → job_shop_lib-1.0.0b1/job_shop_lib/visualization/gantt}/_gantt_chart_creator.py +12 -12
  44. {job_shop_lib-1.0.0a4/job_shop_lib/visualization → job_shop_lib-1.0.0b1/job_shop_lib/visualization/gantt}/_gantt_chart_video_and_gif_creation.py +22 -22
  45. {job_shop_lib-1.0.0a4/job_shop_lib/visualization → job_shop_lib-1.0.0b1/job_shop_lib/visualization/gantt}/_plot_gantt_chart.py +12 -13
  46. job_shop_lib-1.0.0b1/job_shop_lib/visualization/graphs/__init__.py +29 -0
  47. {job_shop_lib-1.0.0a4/job_shop_lib/visualization → job_shop_lib-1.0.0b1/job_shop_lib/visualization/graphs}/_plot_disjunctive_graph.py +18 -16
  48. job_shop_lib-1.0.0b1/job_shop_lib/visualization/graphs/_plot_resource_task_graph.py +389 -0
  49. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/pyproject.toml +10 -2
  50. job_shop_lib-1.0.0a4/job_shop_lib/generation/__init__.py +0 -11
  51. job_shop_lib-1.0.0a4/job_shop_lib/visualization/_plot_agent_task_graph.py +0 -276
  52. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/LICENSE +0 -0
  53. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/_base_solver.py +0 -0
  54. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/_scheduled_operation.py +0 -0
  55. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/benchmarking/__init__.py +0 -0
  56. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/benchmarking/benchmark_instances.json +0 -0
  57. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/constraint_programming/__init__.py +0 -0
  58. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/__init__.py +0 -0
  59. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/feature_observers/__init__.py +0 -0
  60. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/feature_observers/_duration_observer.py +0 -0
  61. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/feature_observers/_is_scheduled_observer.py +0 -0
  62. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/feature_observers/_position_in_job_observer.py +0 -0
  63. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/feature_observers/_remaining_operations_observer.py +0 -0
  64. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/dispatching/rules/__init__.py +0 -0
  65. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/exceptions.py +0 -0
  66. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/graphs/_build_disjunctive_graph.py +0 -0
  67. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/graphs/_constants.py +0 -0
  68. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/graphs/graph_updaters/__init__.py +0 -0
  69. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/graphs/graph_updaters/_graph_updater.py +0 -0
  70. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/graphs/graph_updaters/_utils.py +0 -0
  71. {job_shop_lib-1.0.0a4 → job_shop_lib-1.0.0b1}/job_shop_lib/reinforcement_learning/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: job-shop-lib
3
- Version: 1.0.0a4
3
+ Version: 1.0.0b1
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
@@ -17,7 +17,7 @@ Requires-Dist: imageio[ffmpeg] (>=2.34.1,<3.0.0)
17
17
  Requires-Dist: matplotlib (>=3,<4)
18
18
  Requires-Dist: networkx (>=3,<4)
19
19
  Requires-Dist: numpy (>=1.26.4,<2.0.0)
20
- Requires-Dist: ortools (>=9.9,<9.10)
20
+ Requires-Dist: ortools (>=9.9,<10.0)
21
21
  Requires-Dist: pyarrow (>=15.0.0,<16.0.0)
22
22
  Requires-Dist: pygraphviz (>=1.12,<2.0) ; extra == "pygraphviz"
23
23
  Description-Content-Type: text/markdown
@@ -36,7 +36,7 @@ Description-Content-Type: text/markdown
36
36
 
37
37
  </div>
38
38
 
39
- JobShopLib is a Python package for creating, solving, and visualizing Job Shop Scheduling Problems (JSSP).
39
+ JobShopLib is a Python package for creating, solving, and visualizing job shop scheduling problems (JSSP).
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
 
@@ -60,10 +60,10 @@ See [this](https://colab.research.google.com/drive/1XV_Rvq1F2ns6DFG8uNj66q_rcoww
60
60
  Version 1.0.0 is currently in alpha stage and can be installed with:
61
61
 
62
62
  ```bash
63
- pip install job-shop-lib==1.0.0a4
63
+ pip install job-shop-lib==1.0.0b1
64
64
  ```
65
65
 
66
- Although this version is not stable and may contain breaking changes in subsequent releases, it is recommended to install it to access the new reinforcement learning environments and familiarize yourself with new changes (see the [latest pull requests](https://github.com/Pabloo22/job_shop_lib/pulls?q=is%3Apr+is%3Aclosed)). This version is the first one with a [documentation page](https://job-shop-lib.readthedocs.io/en/latest/).
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
67
 
68
68
  <!-- end installation -->
69
69
 
@@ -71,25 +71,25 @@ Although this version is not stable and may contain breaking changes in subseque
71
71
 
72
72
  ## Key Features :star:
73
73
 
74
- - **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).
74
+ - **Data Structures**: Easily create, manage, and manipulate job shop instances and solutions with user-friendly data structures. See [Getting Started](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/tutorial/00-Getting-Started.ipynb) and [How Solutions are Represented](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/tutorial/01-How-Solutions-are-Represented.ipynb).
75
75
 
76
- - **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).
76
+ - **Benchmark Instances**: Load well-known benchmark instances directly from the library without manual downloading. See [Load Benchmark Instances](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/examples/05-Load-Benchmark-Instances.ipynb).
77
77
 
78
78
  - **Random Instance Generation**: Create random instances with customizable sizes and properties or augment existing ones. See [`generation`](job_shop_lib/generation) package.
79
79
 
80
80
  - **Multiple Solvers**:
81
- - **Constraint Programming Solver**: OR-Tools' CP-SAT solver. See [Solving the Problem](docs/source/examples/02-Solving-the-Problem.ipynb).
81
+ - **Constraint Programming Solver**: OR-Tools' CP-SAT solver. See [Solving the Problem](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/tutorial/02-Solving-the-Problem.ipynb).
82
82
 
83
- - **Dispatching Rule Solvers**: Use any of the available dispatching rules or create custom ones. See [Dispatching Rules](docs/source/examples/03-Dispatching-Rules.ipynb).
83
+ - **Dispatching Rule Solvers**: Use any of the available dispatching rules or create custom ones. See [Dispatching Rules](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/examples/03-Dispatching-Rules.ipynb).
84
84
 
85
- - **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).
85
+ - **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](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/examples/06-Save-Gif.ipynb).
86
86
 
87
87
  - **Graph Representations**:
88
- - **Disjunctive Graphs**: Represent and visualize instances as disjunctive graphs. See [Disjunctive Graph](docs/source/examples/04-Disjunctive-Graph.ipynb).
89
- - **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).
88
+ - **Disjunctive Graphs**: Represent and visualize instances as disjunctive graphs. See [Disjunctive Graph](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/examples/04-Disjunctive-Graph.ipynb).
89
+ - **Agent-Task Graphs**: Encode instances as agent-task graphs (introduced in [ScheduleNet paper](https://arxiv.org/abs/2106.03051)). See [Agent-Task Graph](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/examples/07-Agent-Task-Graph.ipynb).
90
90
  - Build your own custom graphs with the `JobShopGraph` class.
91
91
 
92
- - **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).
92
+ - **Gymnasium Environments**: Two environments for solving the problem with graph neural networks (GNNs) or any other method, and reinforcement learning (RL). See [SingleJobShopGraphEnv](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/examples/09-SingleJobShopGraphEnv.ipynb) and [MultiJobShopGraphEnv](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/examples/10-MultiJobShopGraphEnv.ipynb).
93
93
 
94
94
  <!-- end key features -->
95
95
 
@@ -245,7 +245,7 @@ The dashed red line represents the current time step, which is computed as the e
245
245
 
246
246
  ### Representing Instances as Graphs
247
247
 
248
- One of the main purposes of this library is to provide an easy way to encode instances as graphs. This can be very useful, not only for visualization purposes but also for developing Graph Neural Network-based algorithms.
248
+ One of the main purposes of this library is to provide an easy way to encode instances as graphs. This can be very useful, not only for visualization purposes but also for developing graph neural network-based algorithms.
249
249
 
250
250
  A graph is represented by the `JobShopGraph` class, which internally stores a `networkx.DiGraph` object.
251
251
 
@@ -253,7 +253,7 @@ A graph is represented by the `JobShopGraph` class, which internally stores a `n
253
253
 
254
254
  The disjunctive graph is created by first adding nodes representing each operation in the jobs, along with two special nodes: a source $S$ and a sink $T$. Each operation node is linked to the next operation in its job sequence by **conjunctive edges**, forming a path from the source to the sink. These edges represent the order in which operations of a single job must be performed.
255
255
 
256
- Additionally, the graph includes **disjunctive edges** between operations that use the same machine but belong to different jobs. These edges are bidirectional, indicating that either of the connected operations can be performed first. The disjunctive edges thus represent the scheduling choices available: the order in which operations sharing a machine can be processed. Solving the Job Shop Scheduling problem involves choosing a direction for each disjunctive edge such that the overall processing time is minimized.
256
+ Additionally, the graph includes **disjunctive edges** between operations that use the same machine but belong to different jobs. These edges are bidirectional, indicating that either of the connected operations can be performed first. The disjunctive edges thus represent the scheduling choices available: the order in which operations sharing a machine can be processed. Solving the job shop scheduling problem involves choosing a direction for each disjunctive edge such that the overall processing time is minimized.
257
257
 
258
258
  ```python
259
259
  from job_shop_lib.visualization import plot_disjunctive_graph
@@ -295,9 +295,9 @@ Other attributes include:
295
295
  - `nodes_by_machine`: A nested list mapping each machine to its associated operation nodes, aiding in machine-specific analysis.
296
296
  - `nodes_by_job`: Similar to `nodes_by_machine`, but maps jobs to their operation nodes, useful for job-specific traversal.
297
297
 
298
- #### Agent-Task Graph
298
+ #### Resource-Task Graph
299
299
 
300
- Introduced in the paper "ScheduleNet: Learn to solve multi-agent scheduling problems with reinforcement learning" by [Park et al. (2021)](https://arxiv.org/abs/2106.03051), the Agent-Task Graph is a graph that represents the scheduling problem as a multi-agent reinforcement learning problem.
300
+ Introduced in the paper "ScheduleNet: Learn to solve multi-agent scheduling problems with reinforcement learning" by [Park et al. (2021)](https://arxiv.org/abs/2106.03051), the resource-task graph (orginally named "agent-task graph") is a graph that represents the scheduling problem as a multi-agent reinforcement learning problem.
301
301
 
302
302
  In contrast to the disjunctive graph, instead of connecting operations
303
303
  that share the same resources directly by disjunctive edges, operation
@@ -308,25 +308,27 @@ from the same job are connected by non-directed edges too.
308
308
 
309
309
  ```python
310
310
  from job_shop_lib.graphs import (
311
- build_complete_agent_task_graph,
312
- build_agent_task_graph_with_jobs,
313
- build_agent_task_graph,
311
+ build_complete_resource_task_graph,
312
+ build_resource_task_graph_with_jobs,
313
+ build_resource_task_graph,
314
314
  )
315
- from job_shop_lib.visualization import plot_agent_task_graph
315
+ from job_shop_lib.visualization import plot_resource_task_graph
316
316
 
317
- complete_agent_task_graph = build_complete_agent_task_graph(instance)
317
+ complete_resource_task_graph = build_complete_resource_task_graph(instance)
318
318
 
319
- fig = plot_agent_task_graph(complete_agent_task_graph)
319
+ fig = plot_resource_task_graph(complete_agent_task_graph)
320
320
  plt.show()
321
321
  ```
322
322
 
323
323
  <div align="center">
324
- <img src="docs/source/images/agent_task_graph.png" width="300">
324
+ <img src="docs/source/examples/output/agent_task_graph.png" width="300">
325
325
  </div>
326
326
  <br>
327
327
 
328
328
  ----
329
329
 
330
+ The library generalizes this graph by allowing the addition of job nodes and a global one (see `build_resource_task_graph_with_jobs` and `build_resource_task_graph`).
331
+
330
332
  For more details, check the [examples](examples) folder.
331
333
 
332
334
  ## Installation for development
@@ -12,7 +12,7 @@
12
12
 
13
13
  </div>
14
14
 
15
- JobShopLib is a Python package for creating, solving, and visualizing Job Shop Scheduling Problems (JSSP).
15
+ JobShopLib is a Python package for creating, solving, and visualizing job shop scheduling problems (JSSP).
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
 
@@ -36,10 +36,10 @@ See [this](https://colab.research.google.com/drive/1XV_Rvq1F2ns6DFG8uNj66q_rcoww
36
36
  Version 1.0.0 is currently in alpha stage and can be installed with:
37
37
 
38
38
  ```bash
39
- pip install job-shop-lib==1.0.0a4
39
+ pip install job-shop-lib==1.0.0b1
40
40
  ```
41
41
 
42
- Although this version is not stable and may contain breaking changes in subsequent releases, it is recommended to install it to access the new reinforcement learning environments and familiarize yourself with new changes (see the [latest pull requests](https://github.com/Pabloo22/job_shop_lib/pulls?q=is%3Apr+is%3Aclosed)). This version is the first one with a [documentation page](https://job-shop-lib.readthedocs.io/en/latest/).
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
43
 
44
44
  <!-- end installation -->
45
45
 
@@ -47,25 +47,25 @@ Although this version is not stable and may contain breaking changes in subseque
47
47
 
48
48
  ## Key Features :star:
49
49
 
50
- - **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).
50
+ - **Data Structures**: Easily create, manage, and manipulate job shop instances and solutions with user-friendly data structures. See [Getting Started](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/tutorial/00-Getting-Started.ipynb) and [How Solutions are Represented](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/tutorial/01-How-Solutions-are-Represented.ipynb).
51
51
 
52
- - **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).
52
+ - **Benchmark Instances**: Load well-known benchmark instances directly from the library without manual downloading. See [Load Benchmark Instances](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/examples/05-Load-Benchmark-Instances.ipynb).
53
53
 
54
54
  - **Random Instance Generation**: Create random instances with customizable sizes and properties or augment existing ones. See [`generation`](job_shop_lib/generation) package.
55
55
 
56
56
  - **Multiple Solvers**:
57
- - **Constraint Programming Solver**: OR-Tools' CP-SAT solver. See [Solving the Problem](docs/source/examples/02-Solving-the-Problem.ipynb).
57
+ - **Constraint Programming Solver**: OR-Tools' CP-SAT solver. See [Solving the Problem](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/tutorial/02-Solving-the-Problem.ipynb).
58
58
 
59
- - **Dispatching Rule Solvers**: Use any of the available dispatching rules or create custom ones. See [Dispatching Rules](docs/source/examples/03-Dispatching-Rules.ipynb).
59
+ - **Dispatching Rule Solvers**: Use any of the available dispatching rules or create custom ones. See [Dispatching Rules](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/examples/03-Dispatching-Rules.ipynb).
60
60
 
61
- - **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).
61
+ - **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](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/examples/06-Save-Gif.ipynb).
62
62
 
63
63
  - **Graph Representations**:
64
- - **Disjunctive Graphs**: Represent and visualize instances as disjunctive graphs. See [Disjunctive Graph](docs/source/examples/04-Disjunctive-Graph.ipynb).
65
- - **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).
64
+ - **Disjunctive Graphs**: Represent and visualize instances as disjunctive graphs. See [Disjunctive Graph](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/examples/04-Disjunctive-Graph.ipynb).
65
+ - **Agent-Task Graphs**: Encode instances as agent-task graphs (introduced in [ScheduleNet paper](https://arxiv.org/abs/2106.03051)). See [Agent-Task Graph](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/examples/07-Agent-Task-Graph.ipynb).
66
66
  - Build your own custom graphs with the `JobShopGraph` class.
67
67
 
68
- - **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).
68
+ - **Gymnasium Environments**: Two environments for solving the problem with graph neural networks (GNNs) or any other method, and reinforcement learning (RL). See [SingleJobShopGraphEnv](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/examples/09-SingleJobShopGraphEnv.ipynb) and [MultiJobShopGraphEnv](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/examples/10-MultiJobShopGraphEnv.ipynb).
69
69
 
70
70
  <!-- end key features -->
71
71
 
@@ -221,7 +221,7 @@ The dashed red line represents the current time step, which is computed as the e
221
221
 
222
222
  ### Representing Instances as Graphs
223
223
 
224
- One of the main purposes of this library is to provide an easy way to encode instances as graphs. This can be very useful, not only for visualization purposes but also for developing Graph Neural Network-based algorithms.
224
+ One of the main purposes of this library is to provide an easy way to encode instances as graphs. This can be very useful, not only for visualization purposes but also for developing graph neural network-based algorithms.
225
225
 
226
226
  A graph is represented by the `JobShopGraph` class, which internally stores a `networkx.DiGraph` object.
227
227
 
@@ -229,7 +229,7 @@ A graph is represented by the `JobShopGraph` class, which internally stores a `n
229
229
 
230
230
  The disjunctive graph is created by first adding nodes representing each operation in the jobs, along with two special nodes: a source $S$ and a sink $T$. Each operation node is linked to the next operation in its job sequence by **conjunctive edges**, forming a path from the source to the sink. These edges represent the order in which operations of a single job must be performed.
231
231
 
232
- Additionally, the graph includes **disjunctive edges** between operations that use the same machine but belong to different jobs. These edges are bidirectional, indicating that either of the connected operations can be performed first. The disjunctive edges thus represent the scheduling choices available: the order in which operations sharing a machine can be processed. Solving the Job Shop Scheduling problem involves choosing a direction for each disjunctive edge such that the overall processing time is minimized.
232
+ Additionally, the graph includes **disjunctive edges** between operations that use the same machine but belong to different jobs. These edges are bidirectional, indicating that either of the connected operations can be performed first. The disjunctive edges thus represent the scheduling choices available: the order in which operations sharing a machine can be processed. Solving the job shop scheduling problem involves choosing a direction for each disjunctive edge such that the overall processing time is minimized.
233
233
 
234
234
  ```python
235
235
  from job_shop_lib.visualization import plot_disjunctive_graph
@@ -271,9 +271,9 @@ Other attributes include:
271
271
  - `nodes_by_machine`: A nested list mapping each machine to its associated operation nodes, aiding in machine-specific analysis.
272
272
  - `nodes_by_job`: Similar to `nodes_by_machine`, but maps jobs to their operation nodes, useful for job-specific traversal.
273
273
 
274
- #### Agent-Task Graph
274
+ #### Resource-Task Graph
275
275
 
276
- Introduced in the paper "ScheduleNet: Learn to solve multi-agent scheduling problems with reinforcement learning" by [Park et al. (2021)](https://arxiv.org/abs/2106.03051), the Agent-Task Graph is a graph that represents the scheduling problem as a multi-agent reinforcement learning problem.
276
+ Introduced in the paper "ScheduleNet: Learn to solve multi-agent scheduling problems with reinforcement learning" by [Park et al. (2021)](https://arxiv.org/abs/2106.03051), the resource-task graph (orginally named "agent-task graph") is a graph that represents the scheduling problem as a multi-agent reinforcement learning problem.
277
277
 
278
278
  In contrast to the disjunctive graph, instead of connecting operations
279
279
  that share the same resources directly by disjunctive edges, operation
@@ -284,25 +284,27 @@ from the same job are connected by non-directed edges too.
284
284
 
285
285
  ```python
286
286
  from job_shop_lib.graphs import (
287
- build_complete_agent_task_graph,
288
- build_agent_task_graph_with_jobs,
289
- build_agent_task_graph,
287
+ build_complete_resource_task_graph,
288
+ build_resource_task_graph_with_jobs,
289
+ build_resource_task_graph,
290
290
  )
291
- from job_shop_lib.visualization import plot_agent_task_graph
291
+ from job_shop_lib.visualization import plot_resource_task_graph
292
292
 
293
- complete_agent_task_graph = build_complete_agent_task_graph(instance)
293
+ complete_resource_task_graph = build_complete_resource_task_graph(instance)
294
294
 
295
- fig = plot_agent_task_graph(complete_agent_task_graph)
295
+ fig = plot_resource_task_graph(complete_agent_task_graph)
296
296
  plt.show()
297
297
  ```
298
298
 
299
299
  <div align="center">
300
- <img src="docs/source/images/agent_task_graph.png" width="300">
300
+ <img src="docs/source/examples/output/agent_task_graph.png" width="300">
301
301
  </div>
302
302
  <br>
303
303
 
304
304
  ----
305
305
 
306
+ The library generalizes this graph by allowing the addition of job nodes and a global one (see `build_resource_task_graph_with_jobs` and `build_resource_task_graph`).
307
+
306
308
  For more details, check the [examples](examples) folder.
307
309
 
308
310
  ## Installation for development
@@ -19,6 +19,8 @@ from job_shop_lib._schedule import Schedule
19
19
  from job_shop_lib._base_solver import BaseSolver, Solver
20
20
 
21
21
 
22
+ __version__ = "1.0.0-b.1"
23
+
22
24
  __all__ = [
23
25
  "Operation",
24
26
  "JobShopInstance",
@@ -26,4 +28,5 @@ __all__ = [
26
28
  "Schedule",
27
29
  "Solver",
28
30
  "BaseSolver",
31
+ "__version__",
29
32
  ]
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import os
6
6
  import functools
7
- from typing import Any
7
+ from typing import Any, List, Union, Dict
8
8
 
9
9
  import numpy as np
10
10
  from numpy.typing import NDArray
@@ -51,14 +51,14 @@ class JobShopInstance:
51
51
  total_duration
52
52
 
53
53
  Attributes:
54
- jobs (list[list[Operation]]):
54
+ jobs (List[List[Operation]]):
55
55
  A list of lists of operations. Each list of operations represents
56
56
  a job, and the operations are ordered by their position in the job.
57
- The ``job_id``, ``position_in_job``, and `operation_id` attributes
58
- of the operations are set when the instance is created.
57
+ The ``job_id``, ``position_in_job``, and ``operation_id``
58
+ attributes of the operations are set when the instance is created.
59
59
  name (str):
60
60
  A string with the name of the instance.
61
- metadata (dict[str, Any]):
61
+ metadata (Dict[str, Any]):
62
62
  A dictionary with additional information about the instance.
63
63
 
64
64
  Args:
@@ -81,16 +81,16 @@ class JobShopInstance:
81
81
 
82
82
  def __init__(
83
83
  self,
84
- jobs: list[list[Operation]],
84
+ jobs: List[List[Operation]],
85
85
  name: str = "JobShopInstance",
86
86
  set_operation_attributes: bool = True,
87
87
  **metadata: Any,
88
88
  ):
89
- self.jobs: list[list[Operation]] = jobs
89
+ self.jobs: List[List[Operation]] = jobs
90
90
  if set_operation_attributes:
91
91
  self.set_operation_attributes()
92
92
  self.name: str = name
93
- self.metadata: dict[str, Any] = metadata
93
+ self.metadata: Dict[str, Any] = metadata
94
94
 
95
95
  def set_operation_attributes(self):
96
96
  """Sets the ``job_id``, ``position_in_job``, and ``operation_id``
@@ -125,10 +125,10 @@ class JobShopInstance:
125
125
  @classmethod
126
126
  def from_taillard_file(
127
127
  cls,
128
- file_path: os.PathLike | str | bytes,
128
+ file_path: Union[os.PathLike, str, bytes],
129
129
  encoding: str = "utf-8",
130
130
  comment_symbol: str = "#",
131
- name: str | None = None,
131
+ name: Union[str, None] = None,
132
132
  **metadata: Any,
133
133
  ) -> JobShopInstance:
134
134
  """Creates a JobShopInstance from a file following Taillard's format.
@@ -178,7 +178,7 @@ class JobShopInstance:
178
178
  name = name.split(".")[0]
179
179
  return cls(jobs=jobs, name=name, **metadata)
180
180
 
181
- def to_dict(self) -> dict[str, Any]:
181
+ def to_dict(self) -> Dict[str, Any]:
182
182
  """Returns a dictionary representation of the instance.
183
183
 
184
184
  This representation is useful for saving the instance to a JSON file,
@@ -186,7 +186,7 @@ class JobShopInstance:
186
186
  like Taillard's.
187
187
 
188
188
  Returns:
189
- dict[str, Any]: The returned dictionary has the following
189
+ Dict[str, Any]: The returned dictionary has the following
190
190
  structure:
191
191
 
192
192
  .. code-block:: python
@@ -208,10 +208,10 @@ class JobShopInstance:
208
208
  @classmethod
209
209
  def from_matrices(
210
210
  cls,
211
- duration_matrix: list[list[int]],
212
- machines_matrix: list[list[list[int]]] | list[list[int]],
211
+ duration_matrix: List[List[int]],
212
+ machines_matrix: List[List[List[int]]] | List[List[int]],
213
213
  name: str = "JobShopInstance",
214
- metadata: dict[str, Any] | None = None,
214
+ metadata: Dict[str, Any] | None = None,
215
215
  ) -> JobShopInstance:
216
216
  """Creates a :class:`JobShopInstance` from duration and machines
217
217
  matrices.
@@ -233,7 +233,7 @@ class JobShopInstance:
233
233
  Returns:
234
234
  A :class:`JobShopInstance` object.
235
235
  """
236
- jobs: list[list[Operation]] = [[] for _ in range(len(duration_matrix))]
236
+ jobs: List[List[Operation]] = [[] for _ in range(len(duration_matrix))]
237
237
 
238
238
  num_jobs = len(duration_matrix)
239
239
  for job_id in range(num_jobs):
@@ -290,7 +290,7 @@ class JobShopInstance:
290
290
  )
291
291
 
292
292
  @functools.cached_property
293
- def durations_matrix(self) -> list[list[int]]:
293
+ def durations_matrix(self) -> List[List[int]]:
294
294
  """Returns the duration matrix of the instance.
295
295
 
296
296
  The duration of the operation with ``job_id`` i and ``position_in_job``
@@ -305,7 +305,7 @@ class JobShopInstance:
305
305
  return [[operation.duration for operation in job] for job in self.jobs]
306
306
 
307
307
  @functools.cached_property
308
- def machines_matrix(self) -> list[list[list[int]]] | list[list[int]]:
308
+ def machines_matrix(self) -> Union[List[List[List[int]]], List[List[int]]]:
309
309
  """Returns the machines matrix of the instance.
310
310
 
311
311
  If the instance is flexible (i.e., if any operation has more than one
@@ -342,7 +342,7 @@ class JobShopInstance:
342
342
  >>> jobs = [[Operation(0, 2), Operation(1, 3)], [Operation(0, 4)]]
343
343
  >>> instance = JobShopInstance(jobs)
344
344
  >>> instance.durations_matrix_array
345
- array([[ 2., 2.],
345
+ array([[ 2., 3.],
346
346
  [ 4., nan]], dtype=float32)
347
347
  """
348
348
  duration_matrix = self.durations_matrix
@@ -358,8 +358,7 @@ class JobShopInstance:
358
358
 
359
359
  Example:
360
360
  >>> jobs = [
361
- ... [Operation(machines=[0, 1], 2), Operation(machines=1, 3)],
362
- ... [Operation(machines=0, 6)],
361
+ ... [Operation([0, 1], 2), Operation(1, 3)], [Operation(0, 6)]
363
362
  ... ]
364
363
  >>> instance = JobShopInstance(jobs)
365
364
  >>> instance.machines_matrix_array
@@ -372,25 +371,25 @@ class JobShopInstance:
372
371
  machines_matrix = self.machines_matrix
373
372
  if self.is_flexible:
374
373
  # False positive from mypy, the type of machines_matrix is
375
- # list[list[list[int]]] here
374
+ # List[List[List[int]]] here
376
375
  return self._fill_matrix_with_nans_3d(
377
376
  machines_matrix # type: ignore[arg-type]
378
377
  )
379
378
 
380
379
  # False positive from mypy, the type of machines_matrix is
381
- # list[list[int]] here
380
+ # List[List[int]] here
382
381
  return self._fill_matrix_with_nans_2d(
383
382
  machines_matrix # type: ignore[arg-type]
384
383
  )
385
384
 
386
385
  @functools.cached_property
387
- def operations_by_machine(self) -> list[list[Operation]]:
386
+ def operations_by_machine(self) -> List[List[Operation]]:
388
387
  """Returns a list of lists of operations.
389
388
 
390
389
  The i-th list contains the operations that can be processed in the
391
390
  machine with id i.
392
391
  """
393
- operations_by_machine: list[list[Operation]] = [
392
+ operations_by_machine: List[List[Operation]] = [
394
393
  [] for _ in range(self.num_machines)
395
394
  ]
396
395
  for job in self.jobs:
@@ -410,7 +409,7 @@ class JobShopInstance:
410
409
  )
411
410
 
412
411
  @functools.cached_property
413
- def max_duration_per_job(self) -> list[float]:
412
+ def max_duration_per_job(self) -> List[float]:
414
413
  """Returns the maximum duration of each job in the instance.
415
414
 
416
415
  The maximum duration of the job with id i is stored in the i-th
@@ -421,7 +420,7 @@ class JobShopInstance:
421
420
  return [max(op.duration for op in job) for job in self.jobs]
422
421
 
423
422
  @functools.cached_property
424
- def max_duration_per_machine(self) -> list[int]:
423
+ def max_duration_per_machine(self) -> List[int]:
425
424
  """Returns the maximum duration of each machine in the instance.
426
425
 
427
426
  The maximum duration of the machine with id i is stored in the i-th
@@ -440,7 +439,7 @@ class JobShopInstance:
440
439
  return max_duration_per_machine
441
440
 
442
441
  @functools.cached_property
443
- def job_durations(self) -> list[int]:
442
+ def job_durations(self) -> List[int]:
444
443
  """Returns a list with the duration of each job in the instance.
445
444
 
446
445
  The duration of a job is the sum of the durations of its operations.
@@ -451,7 +450,7 @@ class JobShopInstance:
451
450
  return [sum(op.duration for op in job) for job in self.jobs]
452
451
 
453
452
  @functools.cached_property
454
- def machine_loads(self) -> list[int]:
453
+ def machine_loads(self) -> List[int]:
455
454
  """Returns the total machine load of each machine in the instance.
456
455
 
457
456
  The total machine load of a machine is the sum of the durations of the
@@ -475,7 +474,7 @@ class JobShopInstance:
475
474
 
476
475
  @staticmethod
477
476
  def _fill_matrix_with_nans_2d(
478
- matrix: list[list[int]],
477
+ matrix: List[List[int]],
479
478
  ) -> NDArray[np.float32]:
480
479
  """Fills a matrix with ``np.nan`` values.
481
480
 
@@ -497,7 +496,7 @@ class JobShopInstance:
497
496
 
498
497
  @staticmethod
499
498
  def _fill_matrix_with_nans_3d(
500
- matrix: list[list[list[int]]],
499
+ matrix: List[List[List[int]]],
501
500
  ) -> NDArray[np.float32]:
502
501
  """Fills a 3D matrix with ``np.nan`` values.
503
502
 
@@ -523,3 +522,9 @@ class JobShopInstance:
523
522
  for j, inner_row in enumerate(row):
524
523
  squared_matrix[i, j, : len(inner_row)] = inner_row
525
524
  return squared_matrix
525
+
526
+
527
+ if __name__ == "__main__":
528
+ import doctest
529
+
530
+ doctest.testmod()
@@ -2,6 +2,8 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ from typing import Union, List
6
+
5
7
  from job_shop_lib.exceptions import UninitializedAttributeError
6
8
 
7
9
 
@@ -59,8 +61,8 @@ class Operation:
59
61
  ),
60
62
  }
61
63
 
62
- def __init__(self, machines: int | list[int], duration: int):
63
- self.machines: list[int] = (
64
+ def __init__(self, machines: Union[int, List[int]], duration: int):
65
+ self.machines: List[int] = (
64
66
  [machines] if isinstance(machines, int) else machines
65
67
  )
66
68
  self.duration: int = duration
@@ -2,7 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import Any
5
+ from typing import Any, List, Union, Dict, Optional
6
6
  from collections import deque
7
7
 
8
8
  from job_shop_lib import ScheduledOperation, JobShopInstance
@@ -55,7 +55,7 @@ class Schedule:
55
55
  def __init__(
56
56
  self,
57
57
  instance: JobShopInstance,
58
- schedule: list[list[ScheduledOperation]] | None = None,
58
+ schedule: Optional[List[List[ScheduledOperation]]] = None,
59
59
  **metadata: Any,
60
60
  ):
61
61
  if schedule is None:
@@ -65,19 +65,19 @@ class Schedule:
65
65
 
66
66
  self.instance: JobShopInstance = instance
67
67
  self._schedule = schedule
68
- self.metadata: dict[str, Any] = metadata
68
+ self.metadata: Dict[str, Any] = metadata
69
69
 
70
70
  def __repr__(self) -> str:
71
71
  return str(self.schedule)
72
72
 
73
73
  @property
74
- def schedule(self) -> list[list[ScheduledOperation]]:
74
+ def schedule(self) -> List[List[ScheduledOperation]]:
75
75
  """A list of lists of :class:`ScheduledOperation` objects. Each list
76
76
  represents the order of operations on a machine."""
77
77
  return self._schedule
78
78
 
79
79
  @schedule.setter
80
- def schedule(self, new_schedule: list[list[ScheduledOperation]]):
80
+ def schedule(self, new_schedule: List[List[ScheduledOperation]]):
81
81
  Schedule.check_schedule(new_schedule)
82
82
  self._schedule = new_schedule
83
83
 
@@ -103,7 +103,7 @@ class Schedule:
103
103
  - **"metadata"**: A dictionary with additional information
104
104
  about the schedule.
105
105
  """
106
- job_sequences: list[list[int]] = []
106
+ job_sequences: List[List[int]] = []
107
107
  for machine_schedule in self.schedule:
108
108
  job_sequences.append(
109
109
  [operation.job_id for operation in machine_schedule]
@@ -117,9 +117,9 @@ class Schedule:
117
117
 
118
118
  @staticmethod
119
119
  def from_dict(
120
- instance: dict[str, Any] | JobShopInstance,
121
- job_sequences: list[list[int]],
122
- metadata: dict[str, Any] | None = None,
120
+ instance: Union[Dict[str, Any], JobShopInstance],
121
+ job_sequences: List[List[int]],
122
+ metadata: Optional[Dict[str, Any]] = None,
123
123
  ) -> Schedule:
124
124
  """Creates a schedule from a dictionary representation."""
125
125
  if isinstance(instance, dict):
@@ -131,7 +131,7 @@ class Schedule:
131
131
  @staticmethod
132
132
  def from_job_sequences(
133
133
  instance: JobShopInstance,
134
- job_sequences: list[list[int]],
134
+ job_sequences: List[List[int]],
135
135
  ) -> Schedule:
136
136
  """Creates an active schedule from a list of job sequences.
137
137
 
@@ -240,7 +240,7 @@ class Schedule:
240
240
  return previous_operation.end_time <= scheduled_operation.start_time
241
241
 
242
242
  @staticmethod
243
- def check_schedule(schedule: list[list[ScheduledOperation]]):
243
+ def check_schedule(schedule: List[List[ScheduledOperation]]):
244
244
  """Checks if a schedule is valid and raises a
245
245
  :class:`~exceptions.ValidationError` if it is not.
246
246
 
@@ -1,6 +1,6 @@
1
1
  """Contains functions to load benchmark instances from a JSON file."""
2
2
 
3
- from typing import Any
3
+ from typing import Any, Dict
4
4
 
5
5
  import functools
6
6
  import json
@@ -10,7 +10,7 @@ from job_shop_lib import JobShopInstance
10
10
 
11
11
 
12
12
  @functools.cache
13
- def load_all_benchmark_instances() -> dict[str, JobShopInstance]:
13
+ def load_all_benchmark_instances() -> Dict[str, JobShopInstance]:
14
14
  """Loads all benchmark instances available.
15
15
 
16
16
  Returns:
@@ -48,7 +48,7 @@ def load_benchmark_instance(name: str) -> JobShopInstance:
48
48
 
49
49
 
50
50
  @functools.cache
51
- def load_benchmark_json() -> dict[str, dict[str, Any]]:
51
+ def load_benchmark_json() -> Dict[str, Dict[str, Any]]:
52
52
  """Loads the raw JSON file containing the benchmark instances.
53
53
 
54
54
  Results are cached to avoid reading the file multiple times.