job-shop-lib 0.5.1__py3-none-any.whl → 1.0.0a1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. job_shop_lib/__init__.py +16 -8
  2. job_shop_lib/{base_solver.py → _base_solver.py} +1 -1
  3. job_shop_lib/{job_shop_instance.py → _job_shop_instance.py} +9 -4
  4. job_shop_lib/_operation.py +95 -0
  5. job_shop_lib/{schedule.py → _schedule.py} +73 -54
  6. job_shop_lib/{scheduled_operation.py → _scheduled_operation.py} +13 -37
  7. job_shop_lib/benchmarking/__init__.py +66 -43
  8. job_shop_lib/benchmarking/_load_benchmark.py +88 -0
  9. job_shop_lib/constraint_programming/__init__.py +13 -0
  10. job_shop_lib/{cp_sat/ortools_solver.py → constraint_programming/_ortools_solver.py} +57 -18
  11. job_shop_lib/dispatching/__init__.py +45 -41
  12. job_shop_lib/dispatching/{dispatcher.py → _dispatcher.py} +153 -80
  13. job_shop_lib/dispatching/_dispatcher_observer_config.py +54 -0
  14. job_shop_lib/dispatching/_factories.py +125 -0
  15. job_shop_lib/dispatching/{history_tracker.py → _history_observer.py} +4 -6
  16. job_shop_lib/dispatching/{pruning_functions.py → _ready_operation_filters.py} +6 -35
  17. job_shop_lib/dispatching/_unscheduled_operations_observer.py +69 -0
  18. job_shop_lib/dispatching/feature_observers/__init__.py +16 -10
  19. job_shop_lib/dispatching/feature_observers/{composite_feature_observer.py → _composite_feature_observer.py} +84 -2
  20. job_shop_lib/dispatching/feature_observers/{duration_observer.py → _duration_observer.py} +6 -17
  21. job_shop_lib/dispatching/feature_observers/{earliest_start_time_observer.py → _earliest_start_time_observer.py} +114 -35
  22. job_shop_lib/dispatching/feature_observers/{factory.py → _factory.py} +31 -5
  23. job_shop_lib/dispatching/feature_observers/{feature_observer.py → _feature_observer.py} +59 -16
  24. job_shop_lib/dispatching/feature_observers/_is_completed_observer.py +97 -0
  25. job_shop_lib/dispatching/feature_observers/_is_ready_observer.py +33 -0
  26. job_shop_lib/dispatching/feature_observers/{position_in_job_observer.py → _position_in_job_observer.py} +1 -8
  27. job_shop_lib/dispatching/feature_observers/{remaining_operations_observer.py → _remaining_operations_observer.py} +8 -26
  28. job_shop_lib/dispatching/rules/__init__.py +51 -0
  29. job_shop_lib/dispatching/rules/_dispatching_rule_factory.py +82 -0
  30. job_shop_lib/dispatching/{dispatching_rule_solver.py → rules/_dispatching_rule_solver.py} +44 -15
  31. job_shop_lib/dispatching/{dispatching_rules.py → rules/_dispatching_rules_functions.py} +74 -21
  32. job_shop_lib/dispatching/rules/_machine_chooser_factory.py +69 -0
  33. job_shop_lib/dispatching/rules/_utils.py +127 -0
  34. job_shop_lib/exceptions.py +18 -0
  35. job_shop_lib/generation/__init__.py +2 -2
  36. job_shop_lib/generation/{general_instance_generator.py → _general_instance_generator.py} +26 -7
  37. job_shop_lib/generation/{instance_generator.py → _instance_generator.py} +13 -3
  38. job_shop_lib/graphs/__init__.py +17 -6
  39. job_shop_lib/graphs/{job_shop_graph.py → _job_shop_graph.py} +81 -2
  40. job_shop_lib/graphs/{node.py → _node.py} +18 -12
  41. job_shop_lib/graphs/graph_updaters/__init__.py +13 -0
  42. job_shop_lib/graphs/graph_updaters/_graph_updater.py +59 -0
  43. job_shop_lib/graphs/graph_updaters/_residual_graph_updater.py +154 -0
  44. job_shop_lib/graphs/graph_updaters/_utils.py +25 -0
  45. job_shop_lib/reinforcement_learning/__init__.py +41 -0
  46. job_shop_lib/reinforcement_learning/_multi_job_shop_graph_env.py +366 -0
  47. job_shop_lib/reinforcement_learning/_reward_observers.py +85 -0
  48. job_shop_lib/reinforcement_learning/_single_job_shop_graph_env.py +337 -0
  49. job_shop_lib/reinforcement_learning/_types_and_constants.py +61 -0
  50. job_shop_lib/reinforcement_learning/_utils.py +96 -0
  51. job_shop_lib/visualization/__init__.py +20 -4
  52. job_shop_lib/visualization/{agent_task_graph.py → _agent_task_graph.py} +28 -9
  53. job_shop_lib/visualization/_gantt_chart_creator.py +219 -0
  54. job_shop_lib/visualization/_gantt_chart_video_and_gif_creation.py +388 -0
  55. {job_shop_lib-0.5.1.dist-info → job_shop_lib-1.0.0a1.dist-info}/METADATA +68 -44
  56. job_shop_lib-1.0.0a1.dist-info/RECORD +66 -0
  57. job_shop_lib/benchmarking/load_benchmark.py +0 -142
  58. job_shop_lib/cp_sat/__init__.py +0 -5
  59. job_shop_lib/dispatching/factories.py +0 -206
  60. job_shop_lib/dispatching/feature_observers/is_completed_observer.py +0 -98
  61. job_shop_lib/dispatching/feature_observers/is_ready_observer.py +0 -40
  62. job_shop_lib/generators/__init__.py +0 -8
  63. job_shop_lib/generators/basic_generator.py +0 -200
  64. job_shop_lib/generators/transformations.py +0 -164
  65. job_shop_lib/operation.py +0 -122
  66. job_shop_lib/visualization/create_gif.py +0 -209
  67. job_shop_lib-0.5.1.dist-info/RECORD +0 -52
  68. /job_shop_lib/dispatching/feature_observers/{is_scheduled_observer.py → _is_scheduled_observer.py} +0 -0
  69. /job_shop_lib/generation/{transformations.py → _transformations.py} +0 -0
  70. /job_shop_lib/graphs/{build_agent_task_graph.py → _build_agent_task_graph.py} +0 -0
  71. /job_shop_lib/graphs/{build_disjunctive_graph.py → _build_disjunctive_graph.py} +0 -0
  72. /job_shop_lib/graphs/{constants.py → _constants.py} +0 -0
  73. /job_shop_lib/visualization/{disjunctive_graph.py → _disjunctive_graph.py} +0 -0
  74. /job_shop_lib/visualization/{gantt_chart.py → _gantt_chart.py} +0 -0
  75. {job_shop_lib-0.5.1.dist-info → job_shop_lib-1.0.0a1.dist-info}/LICENSE +0 -0
  76. {job_shop_lib-0.5.1.dist-info → job_shop_lib-1.0.0a1.dist-info}/WHEEL +0 -0
@@ -1,209 +0,0 @@
1
- """Module for creating a GIF of the schedule being built by a
2
- dispatching rule solver."""
3
-
4
- import os
5
- import pathlib
6
- import shutil
7
- from collections.abc import Callable
8
-
9
- import imageio
10
- import matplotlib.pyplot as plt
11
- from matplotlib.figure import Figure
12
-
13
- from job_shop_lib import JobShopInstance, Schedule, Operation
14
- from job_shop_lib.dispatching import (
15
- DispatchingRuleSolver,
16
- Dispatcher,
17
- HistoryTracker,
18
- )
19
- from job_shop_lib.visualization.gantt_chart import plot_gantt_chart
20
-
21
-
22
- # Most of the arguments are optional with default values. There is no way to
23
- # reduce the number of arguments without losing functionality.
24
- # pylint: disable=too-many-arguments
25
- def create_gif(
26
- gif_path: str,
27
- instance: JobShopInstance,
28
- solver: DispatchingRuleSolver,
29
- plot_function: (
30
- Callable[[Schedule, int, list[Operation] | None, int | None], Figure]
31
- | None
32
- ) = None,
33
- fps: int = 1,
34
- remove_frames: bool = True,
35
- frames_dir: str | None = None,
36
- plot_current_time: bool = True,
37
- ) -> None:
38
- """Creates a GIF of the schedule being built by the given solver.
39
-
40
- Args:
41
- gif_path:
42
- The path to save the GIF file. It should end with ".gif".
43
- instance:
44
- The instance of the job shop problem to be scheduled.
45
- solver:
46
- The dispatching rule solver to use.
47
- plot_function:
48
- A function that plots a Gantt chart for a schedule. It
49
- should take a `Schedule` object and the makespan of the schedule as
50
- input and return a `Figure` object. If not provided, a default
51
- function is used.
52
- fps:
53
- The number of frames per second in the GIF.
54
- remove_frames:
55
- Whether to remove the frames after creating the GIF.
56
- frames_dir:
57
- The directory to save the frames in. If not provided,
58
- `gif_path.replace(".gif", "") + "_frames"` is used.
59
- plot_current_time:
60
- Whether to plot a vertical line at the current time.
61
- """
62
- if plot_function is None:
63
- plot_function = plot_gantt_chart_wrapper()
64
-
65
- if frames_dir is None:
66
- # Use the name of the GIF file as the directory name
67
- frames_dir = gif_path.replace(".gif", "") + "_frames"
68
- path = pathlib.Path(frames_dir)
69
- path.mkdir(exist_ok=True)
70
- frames_dir = str(path)
71
- create_gantt_chart_frames(
72
- frames_dir, instance, solver, plot_function, plot_current_time
73
- )
74
- create_gif_from_frames(frames_dir, gif_path, fps)
75
-
76
- if remove_frames:
77
- shutil.rmtree(frames_dir)
78
-
79
-
80
- def plot_gantt_chart_wrapper(
81
- title: str | None = None,
82
- cmap: str = "viridis",
83
- show_available_operations: bool = False,
84
- ) -> Callable[[Schedule, int, list[Operation] | None, int | None], Figure]:
85
- """Returns a function that plots a Gantt chart for an unfinished schedule.
86
-
87
- Args:
88
- title: The title of the Gantt chart.
89
- cmap: The name of the colormap to use.
90
- show_available_operations:
91
- Whether to show the available operations in the Gantt chart.
92
-
93
- Returns:
94
- A function that plots a Gantt chart for a schedule. The function takes
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.
102
- """
103
-
104
- def plot_function(
105
- schedule: Schedule,
106
- makespan: int,
107
- available_operations: list | None = None,
108
- current_time: int | None = None,
109
- ) -> Figure:
110
- fig, ax = plot_gantt_chart(
111
- schedule, title=title, cmap_name=cmap, xlim=makespan
112
- )
113
-
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="--")
137
- return fig
138
-
139
- return plot_function
140
-
141
-
142
- def create_gantt_chart_frames(
143
- frames_dir: str,
144
- instance: JobShopInstance,
145
- solver: DispatchingRuleSolver,
146
- plot_function: Callable[
147
- [Schedule, int, list[Operation] | None, int | None], Figure
148
- ],
149
- plot_current_time: bool = True,
150
- ) -> None:
151
- """Creates frames of the Gantt chart for the schedule being built.
152
-
153
- Args:
154
- frames_dir:
155
- The directory to save the frames in.
156
- instance:
157
- The instance of the job shop problem to be scheduled.
158
- solver:
159
- The dispatching rule solver to use.
160
- plot_function:
161
- A function that plots a Gantt chart for a schedule. It
162
- should take a `Schedule` object and the makespan of the schedule as
163
- input and return a `Figure` object.
164
- plot_current_time:
165
- Whether to plot a vertical line at the current time.
166
- """
167
- dispatcher = Dispatcher(instance, pruning_function=solver.pruning_function)
168
- history_tracker = HistoryTracker(dispatcher)
169
- makespan = solver.solve(instance, dispatcher).makespan()
170
- dispatcher.unsubscribe(history_tracker)
171
- dispatcher.reset()
172
- for i, scheduled_operation in enumerate(history_tracker.history, start=1):
173
- dispatcher.dispatch(
174
- scheduled_operation.operation, scheduled_operation.machine_id
175
- )
176
- current_time = (
177
- None if not plot_current_time else dispatcher.current_time()
178
- )
179
- fig = plot_function(
180
- dispatcher.schedule,
181
- makespan,
182
- dispatcher.available_operations(),
183
- current_time,
184
- )
185
- _save_frame(fig, frames_dir, i)
186
-
187
-
188
- def _save_frame(figure: Figure, frames_dir: str, number: int) -> None:
189
- figure.savefig(f"{frames_dir}/frame_{number:02d}.png", bbox_inches="tight")
190
- plt.close(figure)
191
-
192
-
193
- def create_gif_from_frames(frames_dir: str, gif_path: str, fps: int) -> None:
194
- """Creates a GIF from the frames in the given directory.
195
-
196
- Args:
197
- frames_dir:
198
- The directory containing the frames to be used in the GIF.
199
- gif_path:
200
- The path to save the GIF file. It should end with ".gif".
201
- fps:
202
- The number of frames per second in the GIF.
203
- """
204
- frames = [
205
- os.path.join(frames_dir, frame)
206
- for frame in sorted(os.listdir(frames_dir))
207
- ]
208
- images = [imageio.imread(frame) for frame in frames]
209
- imageio.mimsave(gif_path, images, fps=fps, loop=0)
@@ -1,52 +0,0 @@
1
- job_shop_lib/__init__.py,sha256=S1847nzbTzRPlh1bkZrsNi7ljGiDkVTGMqodFtPSgBo,582
2
- job_shop_lib/base_solver.py,sha256=WCNWVcGGVIV7V2WlTZKcNFsq_BpY4UdhEbYVZ8X3LrE,1368
3
- job_shop_lib/benchmarking/__init__.py,sha256=u1P5sP7GCXzPHMYwtqaOfyh9Pvpp9tLaPxyrLYtDk0s,3354
4
- job_shop_lib/benchmarking/benchmark_instances.json,sha256=F9EvyzFwVxiKAN6rQTsrMhsKstmyUmroyWduM7a00KQ,464841
5
- job_shop_lib/benchmarking/load_benchmark.py,sha256=CjiSALutgWcfD-SDU6w9WO3udvPVpl_-moab3vagbaw,5625
6
- job_shop_lib/cp_sat/__init__.py,sha256=DqrF9IewFMkVB5BhFOHhlJvG6w6BW4ecxBXySunGLoU,97
7
- job_shop_lib/cp_sat/ortools_solver.py,sha256=zsISUQy0dQvn7bmUsAQBCe-V92CFskJHkSfngSP4KSg,8130
8
- job_shop_lib/dispatching/__init__.py,sha256=xk6NjndZ4-EH5G_fGSEX4LQEXL53TRYn5dKEb5uFggI,1568
9
- job_shop_lib/dispatching/dispatcher.py,sha256=3WdShJtVMP4ZBeoOIegelTXziJLpEjtonAku21yqr20,19299
10
- job_shop_lib/dispatching/dispatching_rule_solver.py,sha256=fbNfSclH6Jw1F-QGY1oxAj9wm2hHhJHGnsF2HateXX8,4669
11
- job_shop_lib/dispatching/dispatching_rules.py,sha256=SIDkPx_1uTkM0loEqGMqotLBBSaGi1gH0WS85GXrT_I,5557
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
24
- job_shop_lib/dispatching/history_tracker.py,sha256=3jSh7pKEGiOcEK6bXK8AQJK4NtASxTknRjmHRKenxt8,649
25
- job_shop_lib/dispatching/pruning_functions.py,sha256=d94_uBHuESp4NSf_jBk1q8eBCfTPuU9meiL3StiqJiA,4378
26
- job_shop_lib/exceptions.py,sha256=0Wla1lK6E2u1o3t2hJj9hUwyoJ-1ebkXd42GdXFAhV0,899
27
- job_shop_lib/generation/__init__.py,sha256=ezuxKMYoldiDsD4YzUOXfL1SSv2gSkZig0dOlytIvlM,292
28
- job_shop_lib/generation/general_instance_generator.py,sha256=Xy2OKZBfCCgiu1Ewi6WbD047zc1Kt_JQqULTdRXwTJI,6698
29
- job_shop_lib/generation/instance_generator.py,sha256=nudWpr0k88WIW-JcWjqUioy-1RJXj4auxPaGWWgrHOc,4183
30
- job_shop_lib/generation/transformations.py,sha256=FI2qHrETATJUrQP3-RYhZAQ5boyEZ0CF2StDbacBej8,5290
31
- job_shop_lib/generators/__init__.py,sha256=L1e1OhPKwYi5TKhbnJ9ZeqVuhVzw0ZMfKsHHXUgEMpE,199
32
- job_shop_lib/generators/basic_generator.py,sha256=rPDhwkj2KAK9iUgexgDxC4aUqzi2NS4CKEQduvvlXyg,7683
33
- job_shop_lib/generators/transformations.py,sha256=FI2qHrETATJUrQP3-RYhZAQ5boyEZ0CF2StDbacBej8,5290
34
- job_shop_lib/graphs/__init__.py,sha256=mWyF0MypyYfvFhy2F93BJkFIVsxS_0ZqvPuc29B7TJg,1454
35
- job_shop_lib/graphs/build_agent_task_graph.py,sha256=ktj-oNLUPmWHfL81EVyaoF4hXClWYfnN7oG2Nn4pOsg,7128
36
- job_shop_lib/graphs/build_disjunctive_graph.py,sha256=z1jiuTTaWPJZj-vSZdo064quGx4LEDKjtZIb1FieZW4,3705
37
- job_shop_lib/graphs/constants.py,sha256=dqPF--okue5sF70Iv-YR14QKFx4pxPwT2dL1Rh5jylM,374
38
- job_shop_lib/graphs/job_shop_graph.py,sha256=B0buqcg7US6UvIRWsoY8_FwqzPa_nVjnBu7hPIrygUo,7404
39
- job_shop_lib/graphs/node.py,sha256=FrSndtvqgRbN69jIcU6q1TkBh-LOGg8sxxYjDZqCcf4,5613
40
- job_shop_lib/job_shop_instance.py,sha256=awEZ-xKM4yPlD4gE8SdfQdt68CWX_R3IebeVY8ST4bs,16376
41
- job_shop_lib/operation.py,sha256=S61x0xgu09JLwrRp7syd1P2psbl0ByGuK_hHoHp4ng8,3916
42
- job_shop_lib/schedule.py,sha256=aODGwMv9slFIqOTCz2hF_EIpXhddz8-iAH5gSzGO5G8,10393
43
- job_shop_lib/scheduled_operation.py,sha256=qzXzat1dQBbQ-sLyoG1iXbF9eWbdFeZDFjhAFVavHPk,3526
44
- job_shop_lib/visualization/__init__.py,sha256=Kxjk3ERYXPAHR72nkD92gFdJltSLA2kxLZrlZzZJS8o,693
45
- job_shop_lib/visualization/agent_task_graph.py,sha256=G-c9eiawz6m9sdnDM1r-ZHz6K-gYDIAreHpb6pkYE7w,8284
46
- job_shop_lib/visualization/create_gif.py,sha256=aUB_2ChyFNo4KuKiQl2ANYmVB5NFcGb7pxKeqr0CVJQ,7186
47
- job_shop_lib/visualization/disjunctive_graph.py,sha256=pg4KG9BfQbnBPnXYgbyPGe0AuHSmhYqPeqWYAf_spWQ,5905
48
- job_shop_lib/visualization/gantt_chart.py,sha256=B9sn4XrEUqgQhRKju-1VUG5R67AZXRu7jbrtA8VcndU,4412
49
- job_shop_lib-0.5.1.dist-info/LICENSE,sha256=9mggivMGd5taAu3xbmBway-VQZMBzurBGHofFopvUsQ,1069
50
- job_shop_lib-0.5.1.dist-info/METADATA,sha256=tkuyY-WKxm_FEy55v45Y7PMzssZxyxXFHvPujssZj6Q,12582
51
- job_shop_lib-0.5.1.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
52
- job_shop_lib-0.5.1.dist-info/RECORD,,
File without changes