job-shop-lib 1.5.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.5.0 → job_shop_lib-1.6.0}/PKG-INFO +21 -32
  2. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/README.md +20 -32
  3. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/__init__.py +1 -1
  4. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/_base_solver.py +7 -7
  5. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/_schedule.py +137 -18
  6. job_shop_lib-1.6.0/job_shop_lib/metaheuristics/__init__.py +61 -0
  7. job_shop_lib-1.6.0/job_shop_lib/metaheuristics/_job_shop_annealer.py +229 -0
  8. job_shop_lib-1.6.0/job_shop_lib/metaheuristics/_neighbor_generators.py +182 -0
  9. job_shop_lib-1.6.0/job_shop_lib/metaheuristics/_objective_functions.py +73 -0
  10. job_shop_lib-1.6.0/job_shop_lib/metaheuristics/_simulated_annealing_solver.py +163 -0
  11. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/pyproject.toml +3 -1
  12. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/LICENSE +0 -0
  13. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/_job_shop_instance.py +0 -0
  14. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/_operation.py +0 -0
  15. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/_scheduled_operation.py +0 -0
  16. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/benchmarking/__init__.py +0 -0
  17. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/benchmarking/_load_benchmark.py +0 -0
  18. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/benchmarking/benchmark_instances.json +0 -0
  19. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/constraint_programming/__init__.py +0 -0
  20. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/constraint_programming/_ortools_solver.py +0 -0
  21. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/__init__.py +0 -0
  22. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_dispatcher.py +0 -0
  23. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_dispatcher_observer_config.py +0 -0
  24. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_factories.py +0 -0
  25. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_history_observer.py +0 -0
  26. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_optimal_operations_observer.py +0 -0
  27. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_ready_operation_filters.py +0 -0
  28. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_start_time_calculators.py +0 -0
  29. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_unscheduled_operations_observer.py +0 -0
  30. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/__init__.py +0 -0
  31. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_composite_feature_observer.py +0 -0
  32. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_dates_observer.py +0 -0
  33. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_duration_observer.py +0 -0
  34. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_earliest_start_time_observer.py +0 -0
  35. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_factory.py +0 -0
  36. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_feature_observer.py +0 -0
  37. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_is_completed_observer.py +0 -0
  38. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_is_ready_observer.py +0 -0
  39. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_is_scheduled_observer.py +0 -0
  40. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_position_in_job_observer.py +0 -0
  41. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_remaining_operations_observer.py +0 -0
  42. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/rules/__init__.py +0 -0
  43. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/rules/_dispatching_rule_factory.py +0 -0
  44. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/rules/_dispatching_rule_solver.py +0 -0
  45. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/rules/_dispatching_rules_functions.py +0 -0
  46. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/rules/_machine_chooser_factory.py +0 -0
  47. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/rules/_utils.py +0 -0
  48. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/exceptions.py +0 -0
  49. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/generation/__init__.py +0 -0
  50. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/generation/_general_instance_generator.py +0 -0
  51. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/generation/_instance_generator.py +0 -0
  52. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/generation/_utils.py +0 -0
  53. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/__init__.py +0 -0
  54. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/_build_disjunctive_graph.py +0 -0
  55. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/_build_resource_task_graphs.py +0 -0
  56. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/_constants.py +0 -0
  57. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/_job_shop_graph.py +0 -0
  58. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/_node.py +0 -0
  59. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/graph_updaters/__init__.py +0 -0
  60. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/graph_updaters/_disjunctive_graph_updater.py +0 -0
  61. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/graph_updaters/_graph_updater.py +0 -0
  62. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/graph_updaters/_residual_graph_updater.py +0 -0
  63. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/graph_updaters/_utils.py +0 -0
  64. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/py.typed +0 -0
  65. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/reinforcement_learning/__init__.py +0 -0
  66. {job_shop_lib-1.5.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.5.0 → job_shop_lib-1.6.0}/job_shop_lib/reinforcement_learning/_resource_task_graph_observation.py +0 -0
  68. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/reinforcement_learning/_reward_observers.py +0 -0
  69. {job_shop_lib-1.5.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.5.0 → job_shop_lib-1.6.0}/job_shop_lib/reinforcement_learning/_types_and_constants.py +0 -0
  71. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/reinforcement_learning/_utils.py +0 -0
  72. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/visualization/__init__.py +0 -0
  73. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/visualization/gantt/__init__.py +0 -0
  74. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/visualization/gantt/_gantt_chart_creator.py +0 -0
  75. {job_shop_lib-1.5.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.5.0 → job_shop_lib-1.6.0}/job_shop_lib/visualization/gantt/_plot_gantt_chart.py +0 -0
  77. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/visualization/graphs/__init__.py +0 -0
  78. {job_shop_lib-1.5.0 → job_shop_lib-1.6.0}/job_shop_lib/visualization/graphs/_plot_disjunctive_graph.py +0 -0
  79. {job_shop_lib-1.5.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.5.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.5.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
@@ -5,7 +5,7 @@ from __future__ import annotations
5
5
  from typing import Any, TYPE_CHECKING
6
6
  from collections import deque
7
7
 
8
- from job_shop_lib import ScheduledOperation, JobShopInstance
8
+ from job_shop_lib import ScheduledOperation, JobShopInstance, Operation
9
9
  from job_shop_lib.exceptions import ValidationError
10
10
 
11
11
  if TYPE_CHECKING:
@@ -53,6 +53,19 @@ class Schedule:
53
53
  "schedule. It can be used to store information about the "
54
54
  "algorithm that generated the schedule, for example."
55
55
  ),
56
+ "operation_to_scheduled_operation": (
57
+ "A dictionary that maps an :class:`Operation` to its "
58
+ ":class:`ScheduledOperation` in the schedule. This is used to "
59
+ "quickly find the scheduled operation associated with a given "
60
+ "operation."
61
+ ),
62
+ "num_scheduled_operations": (
63
+ "The number of operations that have been scheduled so far."
64
+ ),
65
+ "operation_with_latest_end_time": (
66
+ "The :class:`ScheduledOperation` with the latest end time. "
67
+ "This is used to quickly find the last operation in the schedule."
68
+ ),
56
69
  }
57
70
 
58
71
  def __init__(
@@ -69,6 +82,25 @@ class Schedule:
69
82
  self.instance: JobShopInstance = instance
70
83
  self._schedule = schedule
71
84
  self.metadata: dict[str, Any] = metadata
85
+ self.operation_to_scheduled_operation: dict[
86
+ Operation, ScheduledOperation
87
+ ] = {
88
+ scheduled_op.operation: scheduled_op
89
+ for machine_schedule in schedule
90
+ for scheduled_op in machine_schedule
91
+ }
92
+ self.num_scheduled_operations = sum(
93
+ len(machine_schedule) for machine_schedule in schedule
94
+ )
95
+ self.operation_with_latest_end_time: ScheduledOperation | None = max(
96
+ (
97
+ scheduled_op
98
+ for machine_schedule in schedule
99
+ for scheduled_op in machine_schedule
100
+ ),
101
+ key=lambda op: op.end_time, # type: ignore[union-attr]
102
+ default=None,
103
+ )
72
104
 
73
105
  def __repr__(self) -> str:
74
106
  return str(self.schedule)
@@ -84,11 +116,6 @@ class Schedule:
84
116
  Schedule.check_schedule(new_schedule)
85
117
  self._schedule = new_schedule
86
118
 
87
- @property
88
- def num_scheduled_operations(self) -> int:
89
- """The number of operations that have been scheduled so far."""
90
- return sum(len(machine_schedule) for machine_schedule in self.schedule)
91
-
92
119
  def to_dict(self) -> dict:
93
120
  """Returns a dictionary representation of the schedule.
94
121
 
@@ -106,15 +133,9 @@ class Schedule:
106
133
  - **"metadata"**: A dictionary with additional information
107
134
  about the schedule.
108
135
  """
109
- job_sequences: list[list[int]] = []
110
- for machine_schedule in self.schedule:
111
- job_sequences.append(
112
- [operation.job_id for operation in machine_schedule]
113
- )
114
-
115
136
  return {
116
137
  "instance": self.instance.to_dict(),
117
- "job_sequences": job_sequences,
138
+ "job_sequences": self.job_sequences(),
118
139
  "metadata": self.metadata,
119
140
  }
120
141
 
@@ -211,20 +232,35 @@ class Schedule:
211
232
  )
212
233
  return dispatcher.schedule
213
234
 
235
+ def job_sequences(self) -> list[list[int]]:
236
+ """Returns the sequence of jobs for each machine in the schedule.
237
+
238
+ This method returns a list of lists, where each sublist contains the
239
+ job ids of the operations scheduled on that machine.
240
+ """
241
+ job_sequences: list[list[int]] = []
242
+ for machine_schedule in self.schedule:
243
+ job_sequences.append(
244
+ [operation.job_id for operation in machine_schedule]
245
+ )
246
+ return job_sequences
247
+
214
248
  def reset(self):
215
249
  """Resets the schedule to an empty state."""
216
250
  self.schedule = [[] for _ in range(self.instance.num_machines)]
251
+ self.operation_to_scheduled_operation = {}
252
+ self.num_scheduled_operations = 0
253
+ self.operation_with_latest_end_time = None
217
254
 
218
255
  def makespan(self) -> int:
219
256
  """Returns the makespan of the schedule.
220
257
 
221
258
  The makespan is the time at which all operations are completed.
222
259
  """
223
- max_end_time = 0
224
- for machine_schedule in self.schedule:
225
- if machine_schedule:
226
- max_end_time = max(max_end_time, machine_schedule[-1].end_time)
227
- return max_end_time
260
+ last_operation = self.operation_with_latest_end_time
261
+ if last_operation is None:
262
+ return 0
263
+ return last_operation.end_time
228
264
 
229
265
  def is_complete(self) -> bool:
230
266
  """Returns ``True`` if all operations have been scheduled."""
@@ -245,10 +281,25 @@ class Schedule:
245
281
  constraints.
246
282
  """
247
283
  self._check_start_time_of_new_operation(scheduled_operation)
284
+
285
+ # Update attributes:
248
286
  self.schedule[scheduled_operation.machine_id].append(
249
287
  scheduled_operation
250
288
  )
251
289
 
290
+ self.operation_to_scheduled_operation[
291
+ scheduled_operation.operation
292
+ ] = scheduled_operation
293
+
294
+ self.num_scheduled_operations += 1
295
+
296
+ if (
297
+ self.operation_with_latest_end_time is None
298
+ or scheduled_operation.end_time
299
+ > self.operation_with_latest_end_time.end_time
300
+ ):
301
+ self.operation_with_latest_end_time = scheduled_operation
302
+
252
303
  def _check_start_time_of_new_operation(
253
304
  self,
254
305
  new_operation: ScheduledOperation,
@@ -333,3 +384,71 @@ class Schedule:
333
384
  [machine_schedule.copy() for machine_schedule in self.schedule],
334
385
  **self.metadata,
335
386
  )
387
+
388
+ def critical_path(self) -> list[ScheduledOperation]:
389
+ """Returns the critical path of the schedule.
390
+
391
+ The critical path is the longest path of dependent operations through
392
+ the schedule, which determines the makespan. This implementation
393
+ correctly identifies the path even in non-compact schedules where
394
+ idle time may exist.
395
+
396
+ It works by starting from an operation that determines the makespan
397
+ and tracing backwards, at each step choosing the predecessor (either
398
+ from the same job or the same machine) that finished latest.
399
+ """
400
+ # 1. Start from the operation that determines the makespan
401
+ last_scheduled_op = self.operation_with_latest_end_time
402
+ if last_scheduled_op is None:
403
+ return []
404
+
405
+ critical_path = deque([last_scheduled_op])
406
+ current_scheduled_op = last_scheduled_op
407
+
408
+ # 2. Trace backwards from the last operation
409
+ while True:
410
+ job_pred = None
411
+ machine_pred = None
412
+
413
+ # Find job predecessor (the previous operation in the same job)
414
+ op_idx_in_job = current_scheduled_op.operation.position_in_job
415
+ if op_idx_in_job > 0:
416
+ prev_op_in_job = self.instance.jobs[
417
+ current_scheduled_op.job_id
418
+ ][op_idx_in_job - 1]
419
+ job_pred = self.operation_to_scheduled_operation[
420
+ prev_op_in_job
421
+ ]
422
+
423
+ # Find machine predecessor (the previous operation on the same
424
+ # machine)
425
+ machine_schedule = self.schedule[current_scheduled_op.machine_id]
426
+ op_idx_on_machine = machine_schedule.index(current_scheduled_op)
427
+ if op_idx_on_machine > 0:
428
+ machine_pred = machine_schedule[op_idx_on_machine - 1]
429
+
430
+ # 3. Determine the critical predecessor
431
+ # The critical predecessor is the one that finished latest, as it
432
+ # determined the start time of the current operation.
433
+
434
+ if job_pred is None and machine_pred is None:
435
+ # Reached the beginning of the schedule, no more predecessors
436
+ break
437
+
438
+ job_pred_end_time = (
439
+ job_pred.end_time if job_pred is not None else -1
440
+ )
441
+ machine_pred_end_time = (
442
+ machine_pred.end_time if machine_pred is not None else -1
443
+ )
444
+ critical_pred = (
445
+ job_pred
446
+ if job_pred_end_time >= machine_pred_end_time
447
+ else machine_pred
448
+ )
449
+ assert critical_pred is not None
450
+ # Prepend the critical predecessor to the path and continue tracing
451
+ critical_path.appendleft(critical_pred)
452
+ current_scheduled_op = critical_pred
453
+
454
+ return list(critical_path)
@@ -0,0 +1,61 @@
1
+ """Metaheuristic algorithms for solving job shop scheduling problems.
2
+
3
+ This module provides implementations of various metaheuristic optimization
4
+ algorithms designed to solve the job shop scheduling problem.
5
+
6
+ Metaheuristics are particularly well-suited for JSSP due to their ability to:
7
+
8
+ - Handle large solution spaces efficiently
9
+ - Escape local optima through stochastic mechanisms
10
+ - Balance exploration and exploitation of the search space
11
+ - Provide good quality solutions within reasonable computational time
12
+
13
+ Currently implemented algorithms:
14
+
15
+ - Simulated annealing: A probabilistic technique that accepts worse
16
+ solutions with decreasing probability to escape local optima
17
+
18
+ The module aims to contain implementations of other
19
+ metaheuristic algorithms such as genetic algorithms, particle swarm
20
+ optimization, tabu search, etc. Feel free to open an issue if you want to
21
+ contribute!
22
+
23
+ .. autosummary::
24
+ :nosignatures:
25
+
26
+ JobShopAnnealer
27
+ SimulatedAnnealingSolver
28
+ NeighborGenerator
29
+ swap_adjacent_operations
30
+ swap_in_critical_path
31
+ swap_random_operations
32
+ ObjectiveFunction
33
+ get_makespan_with_penalties_objective
34
+
35
+ """
36
+
37
+ from job_shop_lib.metaheuristics._objective_functions import (
38
+ ObjectiveFunction,
39
+ get_makespan_with_penalties_objective,
40
+ )
41
+ from job_shop_lib.metaheuristics._neighbor_generators import (
42
+ NeighborGenerator,
43
+ swap_adjacent_operations,
44
+ swap_in_critical_path,
45
+ swap_random_operations,
46
+ )
47
+ from job_shop_lib.metaheuristics._job_shop_annealer import JobShopAnnealer
48
+ from job_shop_lib.metaheuristics._simulated_annealing_solver import (
49
+ SimulatedAnnealingSolver,
50
+ )
51
+
52
+ __all__ = [
53
+ "JobShopAnnealer",
54
+ "SimulatedAnnealingSolver",
55
+ "NeighborGenerator",
56
+ "swap_adjacent_operations",
57
+ "swap_in_critical_path",
58
+ "swap_random_operations",
59
+ "ObjectiveFunction",
60
+ "get_makespan_with_penalties_objective",
61
+ ]