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.
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/PKG-INFO +21 -32
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/README.md +20 -32
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/__init__.py +1 -1
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/_base_solver.py +7 -7
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/_job_shop_instance.py +158 -26
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/_operation.py +48 -5
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/_schedule.py +137 -18
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/constraint_programming/_ortools_solver.py +12 -13
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_dispatcher.py +11 -5
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_ready_operation_filters.py +2 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/__init__.py +3 -0
- job_shop_lib-1.6.0/job_shop_lib/dispatching/feature_observers/_dates_observer.py +162 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_duration_observer.py +6 -5
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/rules/__init__.py +6 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/rules/_dispatching_rule_factory.py +5 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/rules/_dispatching_rules_functions.py +31 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/generation/_utils.py +1 -3
- job_shop_lib-1.6.0/job_shop_lib/metaheuristics/__init__.py +61 -0
- job_shop_lib-1.6.0/job_shop_lib/metaheuristics/_job_shop_annealer.py +229 -0
- job_shop_lib-1.6.0/job_shop_lib/metaheuristics/_neighbor_generators.py +182 -0
- job_shop_lib-1.6.0/job_shop_lib/metaheuristics/_objective_functions.py +73 -0
- job_shop_lib-1.6.0/job_shop_lib/metaheuristics/_simulated_annealing_solver.py +163 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/pyproject.toml +4 -1
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/LICENSE +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/_scheduled_operation.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/benchmarking/__init__.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/benchmarking/_load_benchmark.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/benchmarking/benchmark_instances.json +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/constraint_programming/__init__.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/__init__.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_dispatcher_observer_config.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_factories.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_history_observer.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_optimal_operations_observer.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_start_time_calculators.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/_unscheduled_operations_observer.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_composite_feature_observer.py +0 -0
- {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
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_factory.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_feature_observer.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_is_completed_observer.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_is_ready_observer.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_is_scheduled_observer.py +0 -0
- {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
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/feature_observers/_remaining_operations_observer.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/rules/_dispatching_rule_solver.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/rules/_machine_chooser_factory.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/dispatching/rules/_utils.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/exceptions.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/generation/__init__.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/generation/_general_instance_generator.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/generation/_instance_generator.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/__init__.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/_build_disjunctive_graph.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/_build_resource_task_graphs.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/_constants.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/_job_shop_graph.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/_node.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/graph_updaters/__init__.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/graph_updaters/_disjunctive_graph_updater.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/graph_updaters/_graph_updater.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/graph_updaters/_residual_graph_updater.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/graphs/graph_updaters/_utils.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/py.typed +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/reinforcement_learning/__init__.py +0 -0
- {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
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/reinforcement_learning/_resource_task_graph_observation.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/reinforcement_learning/_reward_observers.py +0 -0
- {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
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/reinforcement_learning/_types_and_constants.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/reinforcement_learning/_utils.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/visualization/__init__.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/visualization/gantt/__init__.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/visualization/gantt/_gantt_chart_creator.py +0 -0
- {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
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/visualization/gantt/_plot_gantt_chart.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/visualization/graphs/__init__.py +0 -0
- {job_shop_lib-1.3.0 → job_shop_lib-1.6.0}/job_shop_lib/visualization/graphs/_plot_disjunctive_graph.py +0 -0
- {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
|
+
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
|
-
|
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
|
-
|
48
|
-
|
49
|
-
|
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
|
-
|
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
|
-
|
69
|
+
```bash
|
70
|
+
poetry add job-shop-lib
|
71
|
+
```
|
86
72
|
|
87
|
-
<!-- end
|
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
|
-
|
21
|
-
|
22
|
-
See [
|
23
|
-
|
24
|
-
|
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
|
-
|
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
|
-
|
47
|
-
|
48
|
-
|
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
|
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.
|
@@ -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
|
19
|
-
|
20
|
-
classes. This class is provided as a base class for solvers
|
21
|
-
classes. It provides a default implementation of the
|
22
|
-
measures the time taken to solve the instance
|
23
|
-
schedule's metadata under the key "elapsed_time" if
|
24
|
-
|
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
|
-
|
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
|
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(
|
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
|
-
|
338
|
-
``
|
339
|
-
|
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
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
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
|
-
|
349
|
-
|
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:
|
612
|
+
matrix: Sequence[Sequence[int | None]],
|
478
613
|
) -> NDArray[np.float32]:
|
479
|
-
"""
|
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
|
-
|
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
|
-
"""
|
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__(
|
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
|
97
|
-
|
98
|
-
|
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
|
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 = (
|