job-shop-lib 1.3.0__tar.gz → 1.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/PKG-INFO +21 -32
  2. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/README.md +20 -32
  3. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/__init__.py +1 -1
  4. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/_base_solver.py +7 -7
  5. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/_job_shop_instance.py +158 -26
  6. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/_operation.py +48 -5
  7. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/_schedule.py +137 -18
  8. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/constraint_programming/_ortools_solver.py +12 -13
  9. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_dispatcher.py +11 -5
  10. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_ready_operation_filters.py +2 -0
  11. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/__init__.py +3 -0
  12. job_shop_lib-1.6.0/job_shop_lib/dispatching/feature_observers/_dates_observer.py +162 -0
  13. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_duration_observer.py +6 -5
  14. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/rules/__init__.py +6 -0
  15. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/rules/_dispatching_rule_factory.py +5 -0
  16. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/rules/_dispatching_rules_functions.py +31 -0
  17. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/generation/_utils.py +1 -3
  18. job_shop_lib-1.6.0/job_shop_lib/metaheuristics/__init__.py +61 -0
  19. job_shop_lib-1.6.0/job_shop_lib/metaheuristics/_job_shop_annealer.py +229 -0
  20. job_shop_lib-1.6.0/job_shop_lib/metaheuristics/_neighbor_generators.py +182 -0
  21. job_shop_lib-1.6.0/job_shop_lib/metaheuristics/_objective_functions.py +73 -0
  22. job_shop_lib-1.6.0/job_shop_lib/metaheuristics/_simulated_annealing_solver.py +163 -0
  23. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/pyproject.toml +4 -1
  24. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/LICENSE +0 -0
  25. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/_scheduled_operation.py +0 -0
  26. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/benchmarking/__init__.py +0 -0
  27. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/benchmarking/_load_benchmark.py +0 -0
  28. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/benchmarking/benchmark_instances.json +0 -0
  29. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/constraint_programming/__init__.py +0 -0
  30. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/__init__.py +0 -0
  31. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_dispatcher_observer_config.py +0 -0
  32. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_factories.py +0 -0
  33. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_history_observer.py +0 -0
  34. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_optimal_operations_observer.py +0 -0
  35. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_start_time_calculators.py +0 -0
  36. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_unscheduled_operations_observer.py +0 -0
  37. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_composite_feature_observer.py +0 -0
  38. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_earliest_start_time_observer.py +0 -0
  39. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_factory.py +0 -0
  40. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_feature_observer.py +0 -0
  41. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_is_completed_observer.py +0 -0
  42. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_is_ready_observer.py +0 -0
  43. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_is_scheduled_observer.py +0 -0
  44. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_position_in_job_observer.py +0 -0
  45. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_remaining_operations_observer.py +0 -0
  46. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/rules/_dispatching_rule_solver.py +0 -0
  47. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/rules/_machine_chooser_factory.py +0 -0
  48. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/rules/_utils.py +0 -0
  49. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/exceptions.py +0 -0
  50. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/generation/__init__.py +0 -0
  51. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/generation/_general_instance_generator.py +0 -0
  52. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/generation/_instance_generator.py +0 -0
  53. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/__init__.py +0 -0
  54. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/_build_disjunctive_graph.py +0 -0
  55. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/_build_resource_task_graphs.py +0 -0
  56. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/_constants.py +0 -0
  57. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/_job_shop_graph.py +0 -0
  58. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/_node.py +0 -0
  59. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/graph_updaters/__init__.py +0 -0
  60. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/graph_updaters/_disjunctive_graph_updater.py +0 -0
  61. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/graph_updaters/_graph_updater.py +0 -0
  62. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/graph_updaters/_residual_graph_updater.py +0 -0
  63. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/graph_updaters/_utils.py +0 -0
  64. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/py.typed +0 -0
  65. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/reinforcement_learning/__init__.py +0 -0
  66. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/reinforcement_learning/_multi_job_shop_graph_env.py +0 -0
  67. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/reinforcement_learning/_resource_task_graph_observation.py +0 -0
  68. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/reinforcement_learning/_reward_observers.py +0 -0
  69. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/reinforcement_learning/_single_job_shop_graph_env.py +0 -0
  70. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/reinforcement_learning/_types_and_constants.py +0 -0
  71. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/reinforcement_learning/_utils.py +0 -0
  72. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/visualization/__init__.py +0 -0
  73. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/visualization/gantt/__init__.py +0 -0
  74. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/visualization/gantt/_gantt_chart_creator.py +0 -0
  75. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/visualization/gantt/_gantt_chart_video_and_gif_creation.py +0 -0
  76. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/visualization/gantt/_plot_gantt_chart.py +0 -0
  77. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/visualization/graphs/__init__.py +0 -0
  78. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/visualization/graphs/_plot_disjunctive_graph.py +0 -0
  79. {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/visualization/graphs/_plot_resource_task_graph.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: job-shop-lib
3
- Version: 1.3.0
3
+ Version: 1.6.0
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
@@ -21,6 +21,7 @@ Requires-Dist: ortools (>=9.9,<10.0) ; sys_platform != "darwin"
21
21
  Requires-Dist: ortools (>=9.9,<9.13) ; sys_platform == "darwin"
22
22
  Requires-Dist: pyarrow (>=15,<21)
23
23
  Requires-Dist: pygraphviz (>=1.12,<2.0) ; extra == "pygraphviz"
24
+ Requires-Dist: simanneal (>=0.5.0,<0.6.0)
24
25
  Description-Content-Type: text/markdown
25
26
 
26
27
  <div align="center">
@@ -42,49 +43,34 @@ JobShopLib is a Python package for creating, solving, and visualizing job shop s
42
43
 
43
44
  It follows a modular design, allowing users to easily extend the library with new solvers, dispatching rules, visualization functions, etc.
44
45
 
45
- There is a [documentation page](https://job-shop-lib.readthedocs.io/en/stable/) for versions 1.0.0a3 and onward. See the [latest pull requests](https://github.com/Pabloo22/job_shop_lib/pulls?q=is%3Apr+is%3Aclosed) for the latest changes.
46
+ We support multiple solvers, including:
47
+ - **Constraint Programming**: Based on OR-Tools' CP-SAT solver. It supports **release dates, deadlines, and due dates.** See the ["Solving the Problem" tutorial](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/tutorial/02-Solving-the-Problem.ipynb) for an example.
48
+ - **Dispatching Rules**: A set of predefined rules and the ability to create custom ones. They support arbitrary **setup times, machine breakdowns, release dates, deadlines, and due dates**. See the [following example](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/examples/03-Dispatching-Rules.ipynb). You can also create videos or GIFs of the scheduling process. For creating GIFs or videos, see the [Save Gif example](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/examples/04-Save-Gif.ipynb).
49
+ - **Metaheuristics**: Currently, we have a **simulated annealing** implementation that supports **release dates, deadlines, and due dates**. We also support arbitrary neighborhood search strategies, including swapping operations in the critical path as described in the paper "Job Shop Scheduling by Simulated Annealing" by van Laarhoven et al. (1992); and energy functions. See our [simulated annealing tutorial](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/tutorial/03-Simulated-Annealing.ipynb).
50
+ - **Reinforcement Learning**: Two Gymnasium environments for solving the problem with **graph neural networks** (GNNs) or any other method. The environments support **setup times, release dates, deadlines, and due dates.** We're currently building a tutorial on how to use them.
46
51
 
47
- See [`gnn_scheduler`](https://github.com/Pabloo22/gnn_scheduler/blob/main/gnn_scheduler/) for an example implementation of a graph neural network-based dispatcher trained with [PyTorch Geometric](https://pyg.org/).
48
-
49
- See [this](https://colab.research.google.com/drive/1XV_Rvq1F2ns6DFG8uNj66q_rcowwTZ4H?usp=sharing) Google Colab notebook for a quick start guide! More advanced examples can be found [here](https://job-shop-lib.readthedocs.io/en/stable/examples.html).
52
+ We also provide useful utilities, data structures, and visualization functions:
53
+ - **Intuitive 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).
54
+ - **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).
55
+ - **Random Instance Generation**: Create random instances with customizable sizes and properties. See [`generation`](https://job-shop-lib.readthedocs.io/en/stable/api/job_shop_lib.generation.html#module-job_shop_lib.generation) module.
56
+ - **Gantt Charts**: Visualize final schedules and how they are created iteratively by dispatching rule solvers or sequences of scheduling decisions with GIFs or videos.
57
+ - **Graph Representations**: Represent and visualize instances as disjunctive graphs or agent-task graphs (introduced in the ScheduleNet paper). Build your own custom graphs with the `JobShopGraph` class. See the [Disjunctive Graphs](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/tutorial/04-Disjunctive-Graphs.ipynb) and [Resource Task Graphs](https://job-shop-lib.readthedocs.io/en/stable/examples/07-Resource-Task-Graph.html) examples.
50
58
 
51
59
  ## Installation :package:
52
60
 
53
61
  <!-- start installation -->
54
62
 
55
- JobShopLib is distributed on [PyPI](https://pypi.org/project/job-shop-lib/). You can install the latest stable version using `pip`:
56
-
57
63
  ```bash
58
64
  pip install job-shop-lib
59
65
  ```
60
66
 
61
- <!-- end installation -->
62
-
63
- <!-- key features -->
64
-
65
- ## Key Features :star:
66
-
67
- - **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).
68
-
69
- - **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).
70
-
71
- - **Random Instance Generation**: Create random instances with customizable sizes and properties. See [`generation`](job_shop_lib/generation) package.
72
-
73
- - **Multiple Solvers**:
74
- - **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).
75
-
76
- - **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).
77
-
78
- - **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).
79
-
80
- - **Graph Representations**:
81
- - **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).
82
- - **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).
83
- - Build your own custom graphs with the `JobShopGraph` class.
67
+ or
84
68
 
85
- - **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
+ ```bash
70
+ poetry add job-shop-lib
71
+ ```
86
72
 
87
- <!-- end key features -->
73
+ <!-- end installation -->
88
74
 
89
75
  ## Publication :scroll:
90
76
 
@@ -219,6 +205,7 @@ A dispatching rule is a heuristic guideline used to prioritize and sequence jobs
219
205
  ```python
220
206
  class DispatchingRule(str, Enum):
221
207
  SHORTEST_PROCESSING_TIME = "shortest_processing_time"
208
+ LARGEST_PROCESSING_TIME = "largest_processing_time"
222
209
  FIRST_COME_FIRST_SERVED = "first_come_first_served"
223
210
  MOST_WORK_REMAINING = "most_work_remaining"
224
211
  MOST_OPERATION_REMAINING = "most_operation_remaining"
@@ -432,6 +419,8 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
432
419
 
433
420
  ## References :books:
434
421
 
422
+ - Peter J. M. van Laarhoven, Emile H. L. Aarts, Jan Karel Lenstra, (1992) Job Shop Scheduling by Simulated Annealing. Operations Research 40(1):113-125.
423
+
435
424
  - J. Adams, E. Balas, and D. Zawack, "The shifting bottleneck procedure
436
425
  for job shop scheduling," Management Science, vol. 34, no. 3,
437
426
  pp. 391–401, 1988.
@@ -17,49 +17,34 @@ JobShopLib is a Python package for creating, solving, and visualizing job shop s
17
17
 
18
18
  It follows a modular design, allowing users to easily extend the library with new solvers, dispatching rules, visualization functions, etc.
19
19
 
20
- There is a [documentation page](https://job-shop-lib.readthedocs.io/en/stable/) for versions 1.0.0a3 and onward. See the [latest pull requests](https://github.com/Pabloo22/job_shop_lib/pulls?q=is%3Apr+is%3Aclosed) for the latest changes.
21
-
22
- See [`gnn_scheduler`](https://github.com/Pabloo22/gnn_scheduler/blob/main/gnn_scheduler/) for an example implementation of a graph neural network-based dispatcher trained with [PyTorch Geometric](https://pyg.org/).
23
-
24
- See [this](https://colab.research.google.com/drive/1XV_Rvq1F2ns6DFG8uNj66q_rcowwTZ4H?usp=sharing) Google Colab notebook for a quick start guide! More advanced examples can be found [here](https://job-shop-lib.readthedocs.io/en/stable/examples.html).
20
+ We support multiple solvers, including:
21
+ - **Constraint Programming**: Based on OR-Tools' CP-SAT solver. It supports **release dates, deadlines, and due dates.** See the ["Solving the Problem" tutorial](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/tutorial/02-Solving-the-Problem.ipynb) for an example.
22
+ - **Dispatching Rules**: A set of predefined rules and the ability to create custom ones. They support arbitrary **setup times, machine breakdowns, release dates, deadlines, and due dates**. See the [following example](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/examples/03-Dispatching-Rules.ipynb). You can also create videos or GIFs of the scheduling process. For creating GIFs or videos, see the [Save Gif example](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/examples/04-Save-Gif.ipynb).
23
+ - **Metaheuristics**: Currently, we have a **simulated annealing** implementation that supports **release dates, deadlines, and due dates**. We also support arbitrary neighborhood search strategies, including swapping operations in the critical path as described in the paper "Job Shop Scheduling by Simulated Annealing" by van Laarhoven et al. (1992); and energy functions. See our [simulated annealing tutorial](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/tutorial/03-Simulated-Annealing.ipynb).
24
+ - **Reinforcement Learning**: Two Gymnasium environments for solving the problem with **graph neural networks** (GNNs) or any other method. The environments support **setup times, release dates, deadlines, and due dates.** We're currently building a tutorial on how to use them.
25
+
26
+ We also provide useful utilities, data structures, and visualization functions:
27
+ - **Intuitive 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).
28
+ - **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).
29
+ - **Random Instance Generation**: Create random instances with customizable sizes and properties. See [`generation`](https://job-shop-lib.readthedocs.io/en/stable/api/job_shop_lib.generation.html#module-job_shop_lib.generation) module.
30
+ - **Gantt Charts**: Visualize final schedules and how they are created iteratively by dispatching rule solvers or sequences of scheduling decisions with GIFs or videos.
31
+ - **Graph Representations**: Represent and visualize instances as disjunctive graphs or agent-task graphs (introduced in the ScheduleNet paper). Build your own custom graphs with the `JobShopGraph` class. See the [Disjunctive Graphs](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/tutorial/04-Disjunctive-Graphs.ipynb) and [Resource Task Graphs](https://job-shop-lib.readthedocs.io/en/stable/examples/07-Resource-Task-Graph.html) examples.
25
32
 
26
33
  ## Installation :package:
27
34
 
28
35
  <!-- start installation -->
29
36
 
30
- JobShopLib is distributed on [PyPI](https://pypi.org/project/job-shop-lib/). You can install the latest stable version using `pip`:
31
-
32
37
  ```bash
33
38
  pip install job-shop-lib
34
39
  ```
35
40
 
36
- <!-- end installation -->
37
-
38
- <!-- key features -->
39
-
40
- ## Key Features :star:
41
-
42
- - **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).
43
-
44
- - **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).
41
+ or
45
42
 
46
- - **Random Instance Generation**: Create random instances with customizable sizes and properties. See [`generation`](job_shop_lib/generation) package.
47
-
48
- - **Multiple Solvers**:
49
- - **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).
50
-
51
- - **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).
52
-
53
- - **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).
54
-
55
- - **Graph Representations**:
56
- - **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).
57
- - **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).
58
- - Build your own custom graphs with the `JobShopGraph` class.
59
-
60
- - **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).
43
+ ```bash
44
+ poetry add job-shop-lib
45
+ ```
61
46
 
62
- <!-- end key features -->
47
+ <!-- end installation -->
63
48
 
64
49
  ## Publication :scroll:
65
50
 
@@ -194,6 +179,7 @@ A dispatching rule is a heuristic guideline used to prioritize and sequence jobs
194
179
  ```python
195
180
  class DispatchingRule(str, Enum):
196
181
  SHORTEST_PROCESSING_TIME = "shortest_processing_time"
182
+ LARGEST_PROCESSING_TIME = "largest_processing_time"
197
183
  FIRST_COME_FIRST_SERVED = "first_come_first_served"
198
184
  MOST_WORK_REMAINING = "most_work_remaining"
199
185
  MOST_OPERATION_REMAINING = "most_operation_remaining"
@@ -407,6 +393,8 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
407
393
 
408
394
  ## References :books:
409
395
 
396
+ - Peter J. M. van Laarhoven, Emile H. L. Aarts, Jan Karel Lenstra, (1992) Job Shop Scheduling by Simulated Annealing. Operations Research 40(1):113-125.
397
+
410
398
  - J. Adams, E. Balas, and D. Zawack, "The shifting bottleneck procedure
411
399
  for job shop scheduling," Management Science, vol. 34, no. 3,
412
400
  pp. 391–401, 1988.
@@ -19,7 +19,7 @@ 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.3.0"
22
+ __version__ = "1.6.0"
23
23
 
24
24
  __all__ = [
25
25
  "Operation",
@@ -15,13 +15,13 @@ Solver = Callable[[JobShopInstance], Schedule]
15
15
  class BaseSolver(abc.ABC):
16
16
  """Base class for all solvers implemented as classes.
17
17
 
18
- A `Solver` is any `Callable` that takes a `JobShopInstance` and returns a
19
- `Schedule`. Therefore, solvers can be implemented as functions or as
20
- classes. This class is provided as a base class for solvers implemented as
21
- classes. It provides a default implementation of the `__call__` method that
22
- measures the time taken to solve the instance and stores it in the
23
- schedule's metadata under the key "elapsed_time" if it is not already
24
- present.
18
+ A ``Solver`` is any ``Callable`` that takes a :class:`JobShopInstance` and
19
+ returns a :class:`Schedule`. Therefore, solvers can be implemented as
20
+ functions or as classes. This class is provided as a base class for solvers
21
+ implemented as classes. It provides a default implementation of the
22
+ ``__call__`` method that measures the time taken to solve the instance
23
+ and stores it in the schedule's metadata under the key "elapsed_time" if
24
+ it is not alreadypresent.
25
25
  """
26
26
 
27
27
  @abc.abstractmethod
@@ -3,8 +3,10 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import os
6
+ from collections.abc import Sequence
6
7
  import functools
7
8
  from typing import Any
9
+ import warnings
8
10
 
9
11
  import numpy as np
10
12
  from numpy.typing import NDArray
@@ -40,6 +42,9 @@ class JobShopInstance:
40
42
  is_flexible
41
43
  durations_matrix
42
44
  machines_matrix
45
+ release_dates_matrix
46
+ deadlines_matrix
47
+ due_dates_matrix
43
48
  durations_matrix_array
44
49
  machines_matrix_array
45
50
  operations_by_machine
@@ -92,6 +97,24 @@ class JobShopInstance:
92
97
  self.name: str = name
93
98
  self.metadata: dict[str, Any] = metadata
94
99
 
100
+ deprecated_keys = {
101
+ "release_dates_matrix",
102
+ "deadlines_matrix",
103
+ "due_dates_matrix",
104
+ }
105
+ if any(key in self.metadata for key in deprecated_keys):
106
+ warnings.warn(
107
+ "The use of 'release_dates_matrix', 'deadlines_matrix', or "
108
+ "'due_dates_matrix' in metadata is deprecated."
109
+ "Please add these attributes "
110
+ "directly to the Operation class. Not doing so may cause bugs "
111
+ "when using the dispatching module.You can use the "
112
+ "`JobShopInstance.from_matrices` method to create an "
113
+ "instance from 2D sequences. ",
114
+ DeprecationWarning,
115
+ stacklevel=2,
116
+ )
117
+
95
118
  def set_operation_attributes(self):
96
119
  """Sets the ``job_id``, ``position_in_job``, and ``operation_id``
97
120
  attributes for each operation in the instance.
@@ -196,14 +219,25 @@ class JobShopInstance:
196
219
  "duration_matrix": self.durations_matrix,
197
220
  "machines_matrix": self.machines_matrix,
198
221
  "metadata": self.metadata,
222
+ # Optionally (if the instance has them):
223
+ "release_dates_matrix": self.release_dates_matrix,
224
+ "deadlines_matrix": self.deadlines_matrix,
225
+ "due_dates_matrix": self.due_dates_matrix,
199
226
  }
200
227
  """
201
- return {
228
+ data = {
202
229
  "name": self.name,
203
230
  "duration_matrix": self.durations_matrix,
204
231
  "machines_matrix": self.machines_matrix,
205
232
  "metadata": self.metadata,
206
233
  }
234
+ if self.has_release_dates:
235
+ data["release_dates_matrix"] = self.release_dates_matrix
236
+ if self.has_deadlines:
237
+ data["deadlines_matrix"] = self.deadlines_matrix
238
+ if self.has_due_dates:
239
+ data["due_dates_matrix"] = self.due_dates_matrix
240
+ return data
207
241
 
208
242
  @classmethod
209
243
  def from_matrices(
@@ -212,6 +246,9 @@ class JobShopInstance:
212
246
  machines_matrix: list[list[list[int]]] | list[list[int]],
213
247
  name: str = "JobShopInstance",
214
248
  metadata: dict[str, Any] | None = None,
249
+ release_dates_matrix: list[list[int]] | None = None,
250
+ deadlines_matrix: list[list[int | None]] | None = None,
251
+ due_dates_matrix: list[list[int | None]] | None = None,
215
252
  ) -> JobShopInstance:
216
253
  """Creates a :class:`JobShopInstance` from duration and machines
217
254
  matrices.
@@ -219,16 +256,26 @@ class JobShopInstance:
219
256
  Args:
220
257
  duration_matrix:
221
258
  A list of lists of integers. The i-th list contains the
222
- durations of the operations of the job with id i.
259
+ durations of the operations of the job with id ``i``.
223
260
  machines_matrix:
224
261
  A list of lists of lists of integers if the
225
262
  instance is flexible, or a list of lists of integers if the
226
263
  instance is not flexible. The i-th list contains the machines
227
- in which the operations of the job with id i can be processed.
264
+ in which the operations of the job with id ``i`` can be
265
+ processed.
228
266
  name:
229
267
  A string with the name of the instance.
230
268
  metadata:
231
269
  A dictionary with additional information about the instance.
270
+ release_dates_matrix:
271
+ A list of lists of integers. The i-th list contains the
272
+ release dates of the operations of the job with id ``i``.
273
+ deadlines_matrix:
274
+ A list of lists of optional integers. The i-th list contains
275
+ the deadlines of the operations of the job with id ``i``.
276
+ due_dates_matrix:
277
+ A list of lists of optional integers. The i-th list contains
278
+ the due dates of the operations of the job with id ``i``.
232
279
 
233
280
  Returns:
234
281
  A :class:`JobShopInstance` object.
@@ -241,8 +288,29 @@ class JobShopInstance:
241
288
  for position_in_job in range(num_operations):
242
289
  duration = duration_matrix[job_id][position_in_job]
243
290
  machines = machines_matrix[job_id][position_in_job]
291
+ release_date = (
292
+ release_dates_matrix[job_id][position_in_job]
293
+ if release_dates_matrix
294
+ else 0
295
+ )
296
+ deadline = (
297
+ deadlines_matrix[job_id][position_in_job]
298
+ if deadlines_matrix
299
+ else None
300
+ )
301
+ due_date = (
302
+ due_dates_matrix[job_id][position_in_job]
303
+ if due_dates_matrix
304
+ else None
305
+ )
244
306
  jobs[job_id].append(
245
- Operation(duration=duration, machines=machines)
307
+ Operation(
308
+ duration=duration,
309
+ machines=machines,
310
+ release_date=release_date,
311
+ deadline=deadline,
312
+ due_date=due_date,
313
+ )
246
314
  )
247
315
 
248
316
  metadata = {} if metadata is None else metadata
@@ -289,6 +357,21 @@ class JobShopInstance:
289
357
  for job in self.jobs
290
358
  )
291
359
 
360
+ @functools.cached_property
361
+ def has_release_dates(self) -> bool:
362
+ """Returns ``True`` if any operation has a release date > 0."""
363
+ return any(op.release_date > 0 for job in self.jobs for op in job)
364
+
365
+ @functools.cached_property
366
+ def has_deadlines(self) -> bool:
367
+ """Returns ``True`` if any operation has a deadline."""
368
+ return any(op.deadline is not None for job in self.jobs for op in job)
369
+
370
+ @functools.cached_property
371
+ def has_due_dates(self) -> bool:
372
+ """Returns ``True`` if any operation has a due date."""
373
+ return any(op.due_date is not None for job in self.jobs for op in job)
374
+
292
375
  @functools.cached_property
293
376
  def durations_matrix(self) -> list[list[int]]:
294
377
  """Returns the duration matrix of the instance.
@@ -330,23 +413,75 @@ class JobShopInstance:
330
413
  [operation.machine_id for operation in job] for job in self.jobs
331
414
  ]
332
415
 
416
+ @functools.cached_property
417
+ def release_dates_matrix(self) -> list[list[int]]:
418
+ """Returns the release dates matrix of the instance.
419
+
420
+ The release date of the operation with ``job_id`` i and
421
+ ``position_in_job`` j is stored in the i-th position of the j-th list
422
+ of the returned matrix.
423
+ """
424
+ return [
425
+ [operation.release_date for operation in job] for job in self.jobs
426
+ ]
427
+
428
+ @functools.cached_property
429
+ def deadlines_matrix(self) -> list[list[int | None]]:
430
+ """Returns the deadlines matrix of the instance.
431
+
432
+ The deadline of the operation with ``job_id`` i and
433
+ ``position_in_job`` j is stored in the i-th position of the j-th list
434
+ of the returned matrix.
435
+ """
436
+ return [[operation.deadline for operation in job] for job in self.jobs]
437
+
438
+ @functools.cached_property
439
+ def due_dates_matrix(self) -> list[list[int | None]]:
440
+ """Returns the due dates matrix of the instance.
441
+
442
+ The due date of the operation with ``job_id`` i and
443
+ ``position_in_job`` j is stored in the i-th position of the j-th list
444
+ of the returned matrix.
445
+ """
446
+ return [[operation.due_date for operation in job] for job in self.jobs]
447
+
333
448
  @functools.cached_property
334
449
  def durations_matrix_array(self) -> NDArray[np.float32]:
335
450
  """Returns the duration matrix of the instance as a numpy array.
336
451
 
337
- The returned array has shape (``num_jobs``,
338
- ``max_num_operations_per_job``).
339
- Non-existing operations are filled with ``np.nan``.
452
+ If the jobs have different number of operations, the matrix is
453
+ padded with ``np.nan`` to make it rectangular.
454
+ """
455
+ return self._fill_matrix_with_nans_2d(self.durations_matrix)
340
456
 
341
- Example:
342
- >>> jobs = [[Operation(0, 2), Operation(1, 3)], [Operation(0, 4)]]
343
- >>> instance = JobShopInstance(jobs)
344
- >>> instance.durations_matrix_array
345
- array([[ 2., 3.],
346
- [ 4., nan]], dtype=float32)
457
+ @functools.cached_property
458
+ def release_dates_matrix_array(self) -> NDArray[np.float32]:
459
+ """Returns the release dates matrix of the instance as a numpy array.
460
+
461
+ If the jobs have different number of operations, the matrix is
462
+ padded with ``np.nan`` to make it rectangular.
347
463
  """
348
- duration_matrix = self.durations_matrix
349
- return self._fill_matrix_with_nans_2d(duration_matrix)
464
+ return self._fill_matrix_with_nans_2d(self.release_dates_matrix)
465
+
466
+ @functools.cached_property
467
+ def deadlines_matrix_array(self) -> NDArray[np.float32]:
468
+ """Returns the deadlines matrix of the instance as a numpy array.
469
+
470
+ If the jobs have different number of operations, the matrix is
471
+ padded with ``np.nan`` to make it rectangular. None values are also
472
+ converted to ``np.nan``.
473
+ """
474
+ return self._fill_matrix_with_nans_2d(self.deadlines_matrix)
475
+
476
+ @functools.cached_property
477
+ def due_dates_matrix_array(self) -> NDArray[np.float32]:
478
+ """Returns the due dates matrix of the instance as a numpy array.
479
+
480
+ If the jobs have different number of operations, the matrix is
481
+ padded with ``np.nan`` to make it rectangular. None values are also
482
+ converted to ``np.nan``.
483
+ """
484
+ return self._fill_matrix_with_nans_2d(self.due_dates_matrix)
350
485
 
351
486
  @functools.cached_property
352
487
  def machines_matrix_array(self) -> NDArray[np.float32]:
@@ -474,13 +609,13 @@ class JobShopInstance:
474
609
 
475
610
  @staticmethod
476
611
  def _fill_matrix_with_nans_2d(
477
- matrix: list[list[int]],
612
+ matrix: Sequence[Sequence[int | None]],
478
613
  ) -> NDArray[np.float32]:
479
- """Fills a matrix with ``np.nan`` values.
614
+ """Creates a 2D numpy array padded with ``np.nan`` values.
480
615
 
481
616
  Args:
482
617
  matrix:
483
- A list of lists of integers.
618
+ A list of lists of integers or Nones.
484
619
 
485
620
  Returns:
486
621
  A numpy array with the same shape as the input matrix, filled with
@@ -491,14 +626,17 @@ class JobShopInstance:
491
626
  (len(matrix), max_length), np.nan, dtype=np.float32
492
627
  )
493
628
  for i, row in enumerate(matrix):
494
- squared_matrix[i, : len(row)] = row
629
+ processed_row = [
630
+ item if item is not None else np.nan for item in row
631
+ ]
632
+ squared_matrix[i, : len(processed_row)] = processed_row
495
633
  return squared_matrix
496
634
 
497
635
  @staticmethod
498
636
  def _fill_matrix_with_nans_3d(
499
637
  matrix: list[list[list[int]]],
500
638
  ) -> NDArray[np.float32]:
501
- """Fills a 3D matrix with ``np.nan`` values.
639
+ """Creates a 3D numpy array padded with ``np.nan`` values.
502
640
 
503
641
  Args:
504
642
  matrix:
@@ -522,9 +660,3 @@ class JobShopInstance:
522
660
  for j, inner_row in enumerate(row):
523
661
  squared_matrix[i, j, : len(inner_row)] = inner_row
524
662
  return squared_matrix
525
-
526
-
527
- if __name__ == "__main__":
528
- import doctest
529
-
530
- doctest.testmod()
@@ -30,6 +30,16 @@ class Operation:
30
30
  an integer.
31
31
  duration:
32
32
  The time it takes to perform the operation.
33
+ release_date:
34
+ The earliest moment this operation can be scheduled to start.
35
+ Defaults to ``0``.
36
+ deadline:
37
+ A hard cutoff time by which the job must be finished. A schedule
38
+ is invalid if the job completes after this time. Defaults to
39
+ ``None``.
40
+ due_date:
41
+ The target completion time for the job. Finishing late is allowed
42
+ but incurs a penalty (e.g., tardiness). Defaults to ``None``.
33
43
  """
34
44
 
35
45
  __slots__ = {
@@ -42,6 +52,20 @@ class Operation:
42
52
  "The time it takes to perform the operation. Often referred"
43
53
  " to as the processing time."
44
54
  ),
55
+ "release_date": (
56
+ "The earliest moment this operation can be scheduled to start. "
57
+ "Defaults to ``0``."
58
+ ),
59
+ "deadline": (
60
+ "A hard cutoff time by which the job must be finished. A schedule "
61
+ "is invalid if the job completes after this time. Defaults to "
62
+ "``None``."
63
+ ),
64
+ "due_date": (
65
+ "The target completion time for the job. Finishing late is "
66
+ "allowed but incurs a penalty (e.g., tardiness). Defaults to "
67
+ "``None``."
68
+ ),
45
69
  "job_id": (
46
70
  "The id of the job the operation belongs to. Defaults to -1. "
47
71
  "It is usually set by the :class:`JobShopInstance` class after "
@@ -59,11 +83,21 @@ class Operation:
59
83
  ),
60
84
  }
61
85
 
62
- def __init__(self, machines: int | list[int], duration: int):
86
+ def __init__(
87
+ self,
88
+ machines: int | list[int],
89
+ duration: int,
90
+ release_date: int = 0,
91
+ deadline: int | None = None,
92
+ due_date: int | None = None,
93
+ ):
63
94
  self.machines: list[int] = (
64
95
  [machines] if isinstance(machines, int) else machines
65
96
  )
66
97
  self.duration: int = duration
98
+ self.release_date: int = release_date
99
+ self.deadline: int | None = deadline
100
+ self.due_date: int | None = due_date
67
101
 
68
102
  # Defined outside the class by the JobShopInstance class:
69
103
  self.job_id: int = -1
@@ -93,9 +127,9 @@ class Operation:
93
127
  def is_initialized(self) -> bool:
94
128
  """Returns whether the operation has been initialized."""
95
129
  return (
96
- self.job_id == -1
97
- or self.position_in_job == -1
98
- or self.operation_id == -1
130
+ self.job_id != -1
131
+ and self.position_in_job != -1
132
+ and self.operation_id != -1
99
133
  )
100
134
 
101
135
  def __hash__(self) -> int:
@@ -104,7 +138,16 @@ class Operation:
104
138
  def __eq__(self, value: object) -> bool:
105
139
  if not isinstance(value, Operation):
106
140
  return False
107
- return self.__slots__ == value.__slots__
141
+ return (
142
+ self.machines == value.machines
143
+ and self.duration == value.duration
144
+ and self.release_date == value.release_date
145
+ and self.deadline == value.deadline
146
+ and self.due_date == value.due_date
147
+ and self.job_id == value.job_id
148
+ and self.position_in_job == value.position_in_job
149
+ and self.operation_id == value.operation_id
150
+ )
108
151
 
109
152
  def __repr__(self) -> str:
110
153
  machines = (