job-shop-lib 0.4.0__py3-none-any.whl → 0.5.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- job_shop_lib/dispatching/dispatcher.py +219 -51
- job_shop_lib/dispatching/feature_observers/__init__.py +28 -0
- job_shop_lib/dispatching/feature_observers/composite_feature_observer.py +87 -0
- job_shop_lib/dispatching/feature_observers/duration_observer.py +95 -0
- job_shop_lib/dispatching/feature_observers/earliest_start_time_observer.py +156 -0
- job_shop_lib/dispatching/feature_observers/factory.py +58 -0
- job_shop_lib/dispatching/feature_observers/feature_observer.py +113 -0
- job_shop_lib/dispatching/feature_observers/is_completed_observer.py +98 -0
- job_shop_lib/dispatching/feature_observers/is_ready_observer.py +40 -0
- job_shop_lib/dispatching/feature_observers/is_scheduled_observer.py +34 -0
- job_shop_lib/dispatching/feature_observers/position_in_job_observer.py +39 -0
- job_shop_lib/dispatching/feature_observers/remaining_operations_observer.py +54 -0
- job_shop_lib/graphs/build_disjunctive_graph.py +20 -0
- job_shop_lib/job_shop_instance.py +101 -0
- job_shop_lib/visualization/create_gif.py +47 -38
- job_shop_lib/visualization/gantt_chart.py +1 -1
- {job_shop_lib-0.4.0.dist-info → job_shop_lib-0.5.0.dist-info}/METADATA +9 -5
- {job_shop_lib-0.4.0.dist-info → job_shop_lib-0.5.0.dist-info}/RECORD +20 -9
- {job_shop_lib-0.4.0.dist-info → job_shop_lib-0.5.0.dist-info}/LICENSE +0 -0
- {job_shop_lib-0.4.0.dist-info → job_shop_lib-0.5.0.dist-info}/WHEEL +0 -0
@@ -27,7 +27,8 @@ def create_gif(
|
|
27
27
|
instance: JobShopInstance,
|
28
28
|
solver: DispatchingRuleSolver,
|
29
29
|
plot_function: (
|
30
|
-
Callable[[Schedule, int, list[Operation] | None
|
30
|
+
Callable[[Schedule, int, list[Operation] | None, int | None], Figure]
|
31
|
+
| None
|
31
32
|
) = None,
|
32
33
|
fps: int = 1,
|
33
34
|
remove_frames: bool = True,
|
@@ -80,50 +81,59 @@ def plot_gantt_chart_wrapper(
|
|
80
81
|
title: str | None = None,
|
81
82
|
cmap: str = "viridis",
|
82
83
|
show_available_operations: bool = False,
|
83
|
-
) -> Callable[[Schedule, int, list[Operation] | None], Figure]:
|
84
|
+
) -> Callable[[Schedule, int, list[Operation] | None, int | None], Figure]:
|
84
85
|
"""Returns a function that plots a Gantt chart for an unfinished schedule.
|
85
86
|
|
86
87
|
Args:
|
87
88
|
title: The title of the Gantt chart.
|
88
89
|
cmap: The name of the colormap to use.
|
90
|
+
show_available_operations:
|
91
|
+
Whether to show the available operations in the Gantt chart.
|
89
92
|
|
90
93
|
Returns:
|
91
94
|
A function that plots a Gantt chart for a schedule. The function takes
|
92
|
-
|
93
|
-
|
95
|
+
the following arguments:
|
96
|
+
- schedule: The schedule to plot.
|
97
|
+
- makespan: The makespan of the schedule.
|
98
|
+
- available_operations: A list of available operations. If None,
|
99
|
+
the available operations are not shown.
|
100
|
+
- current_time: The current time in the schedule. If provided, a
|
101
|
+
red vertical line is plotted at this time.
|
94
102
|
"""
|
95
103
|
|
96
104
|
def plot_function(
|
97
105
|
schedule: Schedule,
|
98
106
|
makespan: int,
|
99
107
|
available_operations: list | None = None,
|
108
|
+
current_time: int | None = None,
|
100
109
|
) -> Figure:
|
101
110
|
fig, ax = plot_gantt_chart(
|
102
111
|
schedule, title=title, cmap_name=cmap, xlim=makespan
|
103
112
|
)
|
104
113
|
|
105
|
-
if
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
114
|
+
if show_available_operations and available_operations is not None:
|
115
|
+
|
116
|
+
operations_text = "\n".join(
|
117
|
+
str(operation) for operation in available_operations
|
118
|
+
)
|
119
|
+
text = f"Available operations:\n{operations_text}"
|
120
|
+
# Print the available operations at the bottom right corner
|
121
|
+
# of the Gantt chart
|
122
|
+
fig.text(
|
123
|
+
1.25,
|
124
|
+
0.05,
|
125
|
+
text,
|
126
|
+
ha="right",
|
127
|
+
va="bottom",
|
128
|
+
transform=ax.transAxes,
|
129
|
+
bbox={
|
130
|
+
"facecolor": "white",
|
131
|
+
"alpha": 0.5,
|
132
|
+
"boxstyle": "round,pad=0.5",
|
133
|
+
},
|
134
|
+
)
|
135
|
+
if current_time is not None:
|
136
|
+
ax.axvline(current_time, color="red", linestyle="--")
|
127
137
|
return fig
|
128
138
|
|
129
139
|
return plot_function
|
@@ -133,7 +143,9 @@ def create_gantt_chart_frames(
|
|
133
143
|
frames_dir: str,
|
134
144
|
instance: JobShopInstance,
|
135
145
|
solver: DispatchingRuleSolver,
|
136
|
-
plot_function: Callable[
|
146
|
+
plot_function: Callable[
|
147
|
+
[Schedule, int, list[Operation] | None, int | None], Figure
|
148
|
+
],
|
137
149
|
plot_current_time: bool = True,
|
138
150
|
) -> None:
|
139
151
|
"""Creates frames of the Gantt chart for the schedule being built.
|
@@ -150,7 +162,8 @@ def create_gantt_chart_frames(
|
|
150
162
|
should take a `Schedule` object and the makespan of the schedule as
|
151
163
|
input and return a `Figure` object.
|
152
164
|
plot_current_time:
|
153
|
-
Whether to plot a vertical line at the current time.
|
165
|
+
Whether to plot a vertical line at the current time.
|
166
|
+
"""
|
154
167
|
dispatcher = Dispatcher(instance, pruning_function=solver.pruning_function)
|
155
168
|
history_tracker = HistoryTracker(dispatcher)
|
156
169
|
makespan = solver.solve(instance, dispatcher).makespan()
|
@@ -160,23 +173,19 @@ def create_gantt_chart_frames(
|
|
160
173
|
dispatcher.dispatch(
|
161
174
|
scheduled_operation.operation, scheduled_operation.machine_id
|
162
175
|
)
|
176
|
+
current_time = (
|
177
|
+
None if not plot_current_time else dispatcher.current_time()
|
178
|
+
)
|
163
179
|
fig = plot_function(
|
164
180
|
dispatcher.schedule,
|
165
181
|
makespan,
|
166
182
|
dispatcher.available_operations(),
|
183
|
+
current_time,
|
167
184
|
)
|
168
|
-
|
169
|
-
None if not plot_current_time else dispatcher.current_time()
|
170
|
-
)
|
171
|
-
_save_frame(fig, frames_dir, i, current_time)
|
172
|
-
|
185
|
+
_save_frame(fig, frames_dir, i)
|
173
186
|
|
174
|
-
def _save_frame(
|
175
|
-
figure: Figure, frames_dir: str, number: int, current_time: int | None
|
176
|
-
) -> None:
|
177
|
-
if current_time is not None:
|
178
|
-
figure.gca().axvline(current_time, color="red", linestyle="--")
|
179
187
|
|
188
|
+
def _save_frame(figure: Figure, frames_dir: str, number: int) -> None:
|
180
189
|
figure.savefig(f"{frames_dir}/frame_{number:02d}.png", bbox_inches="tight")
|
181
190
|
plt.close(figure)
|
182
191
|
|
@@ -65,7 +65,7 @@ def _plot_machine_schedules(
|
|
65
65
|
) -> dict[int, Patch]:
|
66
66
|
"""Plots the schedules for each machine."""
|
67
67
|
max_job_id = schedule.instance.num_jobs - 1
|
68
|
-
cmap = plt.
|
68
|
+
cmap = plt.get_cmap(cmap_name, max_job_id + 1)
|
69
69
|
norm = Normalize(vmin=0, vmax=max_job_id)
|
70
70
|
legend_handles = {}
|
71
71
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: job-shop-lib
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.5.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
|
@@ -15,7 +15,8 @@ Provides-Extra: pygraphviz
|
|
15
15
|
Requires-Dist: imageio (>=2,<3)
|
16
16
|
Requires-Dist: matplotlib (>=3,<4)
|
17
17
|
Requires-Dist: networkx (>=3,<4)
|
18
|
-
Requires-Dist:
|
18
|
+
Requires-Dist: numpy (>=1.26.4,<2.0.0)
|
19
|
+
Requires-Dist: ortools (>=9.9,<9.10)
|
19
20
|
Requires-Dist: pyarrow (>=15.0.0,<16.0.0)
|
20
21
|
Requires-Dist: pygraphviz (>=1.12,<2.0) ; extra == "pygraphviz"
|
21
22
|
Description-Content-Type: text/markdown
|
@@ -83,7 +84,7 @@ ft06 = load_benchmark_instance("ft06")
|
|
83
84
|
```
|
84
85
|
|
85
86
|
The module `benchmarks` contains functions to load the instances from the file and return them as `JobShopInstance` objects without having to download them
|
86
|
-
manually.
|
87
|
+
manually.
|
87
88
|
|
88
89
|
The contributions to this benchmark dataset are as follows:
|
89
90
|
|
@@ -171,13 +172,15 @@ class DispatchingRule(str, Enum):
|
|
171
172
|
We can visualize the solution with a `DispatchingRuleSolver` as a gif:
|
172
173
|
|
173
174
|
```python
|
174
|
-
from job_shop_lib.visualization import create_gif,
|
175
|
+
from job_shop_lib.visualization import create_gif, plot_gantt_chart_wrapper
|
175
176
|
from job_shop_lib.dispatching import DispatchingRuleSolver, DispatchingRule
|
176
177
|
|
177
178
|
plt.style.use("ggplot")
|
178
179
|
|
179
180
|
mwkr_solver = DispatchingRuleSolver("most_work_remaining")
|
180
|
-
plot_function =
|
181
|
+
plot_function = plot_gantt_chart_wrapper(
|
182
|
+
title="Solution with Most Work Remaining Rule"
|
183
|
+
)
|
181
184
|
create_gif(
|
182
185
|
gif_path="ft06_optimized.gif",
|
183
186
|
instance=ft06,
|
@@ -350,3 +353,4 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
|
|
350
353
|
Journal of Operational Research, vol. 64, no. 2, pp. 278–285, 1993.
|
351
354
|
|
352
355
|
- Park, Junyoung, Sanjar Bakhtiyar, and Jinkyoo Park. "ScheduleNet: Learn to solve multi-agent scheduling problems with reinforcement learning." arXiv preprint arXiv:2106.03051, 2021.
|
356
|
+
|
@@ -6,10 +6,21 @@ job_shop_lib/benchmarking/load_benchmark.py,sha256=CjiSALutgWcfD-SDU6w9WO3udvPVp
|
|
6
6
|
job_shop_lib/cp_sat/__init__.py,sha256=DqrF9IewFMkVB5BhFOHhlJvG6w6BW4ecxBXySunGLoU,97
|
7
7
|
job_shop_lib/cp_sat/ortools_solver.py,sha256=zsISUQy0dQvn7bmUsAQBCe-V92CFskJHkSfngSP4KSg,8130
|
8
8
|
job_shop_lib/dispatching/__init__.py,sha256=xk6NjndZ4-EH5G_fGSEX4LQEXL53TRYn5dKEb5uFggI,1568
|
9
|
-
job_shop_lib/dispatching/dispatcher.py,sha256=
|
9
|
+
job_shop_lib/dispatching/dispatcher.py,sha256=3WdShJtVMP4ZBeoOIegelTXziJLpEjtonAku21yqr20,19299
|
10
10
|
job_shop_lib/dispatching/dispatching_rule_solver.py,sha256=fbNfSclH6Jw1F-QGY1oxAj9wm2hHhJHGnsF2HateXX8,4669
|
11
11
|
job_shop_lib/dispatching/dispatching_rules.py,sha256=SIDkPx_1uTkM0loEqGMqotLBBSaGi1gH0WS85GXrT_I,5557
|
12
12
|
job_shop_lib/dispatching/factories.py,sha256=ldyIbz3QuLuDkrqbgJXV6YoM6AV6CKyHu8z4hXLG2Vo,7267
|
13
|
+
job_shop_lib/dispatching/feature_observers/__init__.py,sha256=j7GXFCKK0mLjGc3M6bw2vePZaLyou_9BUjlHtAMriHc,1023
|
14
|
+
job_shop_lib/dispatching/feature_observers/composite_feature_observer.py,sha256=wLd5yirDekg_pFrBPWIyxKou8htimvKhtDbz0cJ8SKE,3302
|
15
|
+
job_shop_lib/dispatching/feature_observers/duration_observer.py,sha256=EMSfRsWkx94VeOF6v1f2s73hrEQ696vkFoWVVw5tWZ8,3804
|
16
|
+
job_shop_lib/dispatching/feature_observers/earliest_start_time_observer.py,sha256=pKrxaLOPHMnf-eniDhkPWVzzRpKLnpbXAeORqEmsrp0,6296
|
17
|
+
job_shop_lib/dispatching/feature_observers/factory.py,sha256=XF5spNp8T-dnPPnpWQ5dxuG7vrHLf-Wb8MP1tn4_BXA,1941
|
18
|
+
job_shop_lib/dispatching/feature_observers/feature_observer.py,sha256=q2i50LOhgjaQtu_0-3VlSH64uHcf73JddjcGijeKCVk,3646
|
19
|
+
job_shop_lib/dispatching/feature_observers/is_completed_observer.py,sha256=6UCxp-QLXxbw_1nppQJuG_qZZvjtGugYTxQdPTcIcgo,4086
|
20
|
+
job_shop_lib/dispatching/feature_observers/is_ready_observer.py,sha256=km75Pa8vd55grjvr7X-8e0K9vfxVWfms1ea6kAesKLo,1405
|
21
|
+
job_shop_lib/dispatching/feature_observers/is_scheduled_observer.py,sha256=PeLxPVLJX_TP4TG8ViEQFR8WS43wIp6CqyuapM8lIt8,1477
|
22
|
+
job_shop_lib/dispatching/feature_observers/position_in_job_observer.py,sha256=PEC-WwcyeHL8WOACElImDtAAoaf7MroaD9x5QlQddVE,1344
|
23
|
+
job_shop_lib/dispatching/feature_observers/remaining_operations_observer.py,sha256=yVde9gC0cheFNCoPa1lFgGSmzyew-zOGA98nZpBBw1I,1891
|
13
24
|
job_shop_lib/dispatching/history_tracker.py,sha256=3jSh7pKEGiOcEK6bXK8AQJK4NtASxTknRjmHRKenxt8,649
|
14
25
|
job_shop_lib/dispatching/pruning_functions.py,sha256=d94_uBHuESp4NSf_jBk1q8eBCfTPuU9meiL3StiqJiA,4378
|
15
26
|
job_shop_lib/exceptions.py,sha256=0Wla1lK6E2u1o3t2hJj9hUwyoJ-1ebkXd42GdXFAhV0,899
|
@@ -18,20 +29,20 @@ job_shop_lib/generators/basic_generator.py,sha256=pbRDQWC2mnHU0dbc-T8wkdwVeJPlRn
|
|
18
29
|
job_shop_lib/generators/transformations.py,sha256=FI2qHrETATJUrQP3-RYhZAQ5boyEZ0CF2StDbacBej8,5290
|
19
30
|
job_shop_lib/graphs/__init__.py,sha256=mWyF0MypyYfvFhy2F93BJkFIVsxS_0ZqvPuc29B7TJg,1454
|
20
31
|
job_shop_lib/graphs/build_agent_task_graph.py,sha256=ktj-oNLUPmWHfL81EVyaoF4hXClWYfnN7oG2Nn4pOsg,7128
|
21
|
-
job_shop_lib/graphs/build_disjunctive_graph.py,sha256=
|
32
|
+
job_shop_lib/graphs/build_disjunctive_graph.py,sha256=z1jiuTTaWPJZj-vSZdo064quGx4LEDKjtZIb1FieZW4,3705
|
22
33
|
job_shop_lib/graphs/constants.py,sha256=dqPF--okue5sF70Iv-YR14QKFx4pxPwT2dL1Rh5jylM,374
|
23
34
|
job_shop_lib/graphs/job_shop_graph.py,sha256=B0buqcg7US6UvIRWsoY8_FwqzPa_nVjnBu7hPIrygUo,7404
|
24
35
|
job_shop_lib/graphs/node.py,sha256=FrSndtvqgRbN69jIcU6q1TkBh-LOGg8sxxYjDZqCcf4,5613
|
25
|
-
job_shop_lib/job_shop_instance.py,sha256=
|
36
|
+
job_shop_lib/job_shop_instance.py,sha256=awEZ-xKM4yPlD4gE8SdfQdt68CWX_R3IebeVY8ST4bs,16376
|
26
37
|
job_shop_lib/operation.py,sha256=S61x0xgu09JLwrRp7syd1P2psbl0ByGuK_hHoHp4ng8,3916
|
27
38
|
job_shop_lib/schedule.py,sha256=aODGwMv9slFIqOTCz2hF_EIpXhddz8-iAH5gSzGO5G8,10393
|
28
39
|
job_shop_lib/scheduled_operation.py,sha256=qzXzat1dQBbQ-sLyoG1iXbF9eWbdFeZDFjhAFVavHPk,3526
|
29
40
|
job_shop_lib/visualization/__init__.py,sha256=Kxjk3ERYXPAHR72nkD92gFdJltSLA2kxLZrlZzZJS8o,693
|
30
41
|
job_shop_lib/visualization/agent_task_graph.py,sha256=G-c9eiawz6m9sdnDM1r-ZHz6K-gYDIAreHpb6pkYE7w,8284
|
31
|
-
job_shop_lib/visualization/create_gif.py,sha256=
|
42
|
+
job_shop_lib/visualization/create_gif.py,sha256=aUB_2ChyFNo4KuKiQl2ANYmVB5NFcGb7pxKeqr0CVJQ,7186
|
32
43
|
job_shop_lib/visualization/disjunctive_graph.py,sha256=pg4KG9BfQbnBPnXYgbyPGe0AuHSmhYqPeqWYAf_spWQ,5905
|
33
|
-
job_shop_lib/visualization/gantt_chart.py,sha256=
|
34
|
-
job_shop_lib-0.
|
35
|
-
job_shop_lib-0.
|
36
|
-
job_shop_lib-0.
|
37
|
-
job_shop_lib-0.
|
44
|
+
job_shop_lib/visualization/gantt_chart.py,sha256=B9sn4XrEUqgQhRKju-1VUG5R67AZXRu7jbrtA8VcndU,4412
|
45
|
+
job_shop_lib-0.5.0.dist-info/LICENSE,sha256=9mggivMGd5taAu3xbmBway-VQZMBzurBGHofFopvUsQ,1069
|
46
|
+
job_shop_lib-0.5.0.dist-info/METADATA,sha256=a_AtBz1LwmfrEoIVWXepewPFx2Pa1QiFJt857kCGncw,12582
|
47
|
+
job_shop_lib-0.5.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
48
|
+
job_shop_lib-0.5.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|