job-shop-lib 1.0.0a3__tar.gz → 1.0.0a4__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/PKG-INFO +5 -5
  2. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/README.md +4 -4
  3. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/_job_shop_instance.py +104 -38
  4. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/_operation.py +12 -3
  5. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/_schedule.py +10 -12
  6. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/_scheduled_operation.py +15 -16
  7. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/_dispatcher.py +12 -15
  8. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/_dispatcher_observer_config.py +15 -2
  9. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/_factories.py +2 -2
  10. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/feature_observers/_composite_feature_observer.py +0 -1
  11. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/feature_observers/_factory.py +21 -18
  12. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/feature_observers/_is_completed_observer.py +1 -0
  13. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/rules/_dispatching_rule_solver.py +1 -1
  14. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/generation/_general_instance_generator.py +33 -34
  15. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/generation/_instance_generator.py +14 -17
  16. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/generation/_transformations.py +11 -8
  17. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/graphs/__init__.py +3 -0
  18. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/graphs/_build_disjunctive_graph.py +41 -3
  19. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/graphs/graph_updaters/_graph_updater.py +11 -13
  20. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/graphs/graph_updaters/_residual_graph_updater.py +17 -20
  21. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/reinforcement_learning/__init__.py +16 -7
  22. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/reinforcement_learning/_multi_job_shop_graph_env.py +69 -57
  23. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/reinforcement_learning/_single_job_shop_graph_env.py +42 -31
  24. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/reinforcement_learning/_types_and_constants.py +2 -2
  25. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/visualization/__init__.py +24 -5
  26. job_shop_lib-1.0.0a4/job_shop_lib/visualization/_gantt_chart_creator.py +257 -0
  27. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/visualization/_gantt_chart_video_and_gif_creation.py +15 -11
  28. job_shop_lib-1.0.0a4/job_shop_lib/visualization/_plot_disjunctive_graph.py +382 -0
  29. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/pyproject.toml +2 -1
  30. job_shop_lib-1.0.0a3/job_shop_lib/visualization/_disjunctive_graph.py +0 -210
  31. job_shop_lib-1.0.0a3/job_shop_lib/visualization/_gantt_chart_creator.py +0 -219
  32. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/LICENSE +0 -0
  33. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/__init__.py +0 -0
  34. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/_base_solver.py +0 -0
  35. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/benchmarking/__init__.py +0 -0
  36. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/benchmarking/_load_benchmark.py +0 -0
  37. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/benchmarking/benchmark_instances.json +0 -0
  38. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/constraint_programming/__init__.py +0 -0
  39. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/constraint_programming/_ortools_solver.py +0 -0
  40. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/__init__.py +0 -0
  41. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/_history_observer.py +0 -0
  42. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/_ready_operation_filters.py +0 -0
  43. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/_unscheduled_operations_observer.py +0 -0
  44. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/feature_observers/__init__.py +0 -0
  45. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/feature_observers/_duration_observer.py +0 -0
  46. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/feature_observers/_earliest_start_time_observer.py +0 -0
  47. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/feature_observers/_feature_observer.py +0 -0
  48. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/feature_observers/_is_ready_observer.py +0 -0
  49. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/feature_observers/_is_scheduled_observer.py +0 -0
  50. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/feature_observers/_position_in_job_observer.py +0 -0
  51. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/feature_observers/_remaining_operations_observer.py +0 -0
  52. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/rules/__init__.py +0 -0
  53. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/rules/_dispatching_rule_factory.py +0 -0
  54. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/rules/_dispatching_rules_functions.py +0 -0
  55. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/rules/_machine_chooser_factory.py +0 -0
  56. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/dispatching/rules/_utils.py +0 -0
  57. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/exceptions.py +0 -0
  58. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/generation/__init__.py +0 -0
  59. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/graphs/_build_agent_task_graph.py +0 -0
  60. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/graphs/_constants.py +0 -0
  61. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/graphs/_job_shop_graph.py +0 -0
  62. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/graphs/_node.py +0 -0
  63. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/graphs/graph_updaters/__init__.py +0 -0
  64. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/graphs/graph_updaters/_utils.py +0 -0
  65. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/reinforcement_learning/_reward_observers.py +0 -0
  66. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/reinforcement_learning/_utils.py +0 -0
  67. /job_shop_lib-1.0.0a3/job_shop_lib/visualization/_agent_task_graph.py → /job_shop_lib-1.0.0a4/job_shop_lib/visualization/_plot_agent_task_graph.py +0 -0
  68. {job_shop_lib-1.0.0a3 → job_shop_lib-1.0.0a4}/job_shop_lib/visualization/_plot_gantt_chart.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: job-shop-lib
3
- Version: 1.0.0a3
3
+ Version: 1.0.0a4
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
@@ -40,7 +40,7 @@ JobShopLib is a Python package for creating, solving, and visualizing Job Shop S
40
40
 
41
41
  It follows a modular design, allowing users to easily extend the library with new solvers, dispatching rules, visualization functions, etc.
42
42
 
43
- See the [documentation](https://job-shop-lib.readthedocs.io/en/latest/) for more details about the latest version (1.0.0a2).
43
+ See the [documentation](https://job-shop-lib.readthedocs.io/en/latest/) for more details about the latest version.
44
44
 
45
45
  ## Installation :package:
46
46
 
@@ -57,13 +57,13 @@ pip install job-shop-lib
57
57
  See [this](https://colab.research.google.com/drive/1XV_Rvq1F2ns6DFG8uNj66q_rcowwTZ4H?usp=sharing) Google Colab notebook for a quick start guide!
58
58
 
59
59
 
60
- Version 1.0.0 is currently in beta stage and can be installed with:
60
+ Version 1.0.0 is currently in alpha stage and can be installed with:
61
61
 
62
62
  ```bash
63
- pip install job-shop-lib==1.0.0a3
63
+ pip install job-shop-lib==1.0.0a4
64
64
  ```
65
65
 
66
- Although this version is not stable and may contain breaking changes in subsequent releases, it is recommended to install it to access the new reinforcement learning environments and familiare yourself with new changes (see the [latest pull requests](https://github.com/Pabloo22/job_shop_lib/pulls?q=is%3Apr+is%3Aclosed)). This version is the first one with a [documentation page](https://job-shop-lib.readthedocs.io/en/latest/).
66
+ Although this version is not stable and may contain breaking changes in subsequent releases, it is recommended to install it to access the new reinforcement learning environments and familiarize yourself with new changes (see the [latest pull requests](https://github.com/Pabloo22/job_shop_lib/pulls?q=is%3Apr+is%3Aclosed)). This version is the first one with a [documentation page](https://job-shop-lib.readthedocs.io/en/latest/).
67
67
 
68
68
  <!-- end installation -->
69
69
 
@@ -16,7 +16,7 @@ JobShopLib is a Python package for creating, solving, and visualizing Job Shop S
16
16
 
17
17
  It follows a modular design, allowing users to easily extend the library with new solvers, dispatching rules, visualization functions, etc.
18
18
 
19
- See the [documentation](https://job-shop-lib.readthedocs.io/en/latest/) for more details about the latest version (1.0.0a2).
19
+ See the [documentation](https://job-shop-lib.readthedocs.io/en/latest/) for more details about the latest version.
20
20
 
21
21
  ## Installation :package:
22
22
 
@@ -33,13 +33,13 @@ pip install job-shop-lib
33
33
  See [this](https://colab.research.google.com/drive/1XV_Rvq1F2ns6DFG8uNj66q_rcowwTZ4H?usp=sharing) Google Colab notebook for a quick start guide!
34
34
 
35
35
 
36
- Version 1.0.0 is currently in beta stage and can be installed with:
36
+ Version 1.0.0 is currently in alpha stage and can be installed with:
37
37
 
38
38
  ```bash
39
- pip install job-shop-lib==1.0.0a3
39
+ pip install job-shop-lib==1.0.0a4
40
40
  ```
41
41
 
42
- Although this version is not stable and may contain breaking changes in subsequent releases, it is recommended to install it to access the new reinforcement learning environments and familiare yourself with new changes (see the [latest pull requests](https://github.com/Pabloo22/job_shop_lib/pulls?q=is%3Apr+is%3Aclosed)). This version is the first one with a [documentation page](https://job-shop-lib.readthedocs.io/en/latest/).
42
+ Although this version is not stable and may contain breaking changes in subsequent releases, it is recommended to install it to access the new reinforcement learning environments and familiarize yourself with new changes (see the [latest pull requests](https://github.com/Pabloo22/job_shop_lib/pulls?q=is%3Apr+is%3Aclosed)). This version is the first one with a [documentation page](https://job-shop-lib.readthedocs.io/en/latest/).
43
43
 
44
44
  <!-- end installation -->
45
45
 
@@ -15,16 +15,47 @@ from job_shop_lib import Operation
15
15
  class JobShopInstance:
16
16
  """Data structure to store a Job Shop Scheduling Problem instance.
17
17
 
18
- Additional attributes such as `num_jobs` or `num_machines` can be computed
19
- from the instance and are cached for performance if they require expensive
20
- computations.
18
+ Additional attributes such as ``num_machines`` or ``durations_matrix`` can
19
+ be computed from the instance and are cached for performance if they
20
+ require expensive computations.
21
+
22
+ Methods:
23
+
24
+ .. autosummary::
25
+ :nosignatures:
26
+
27
+ from_taillard_file
28
+ to_dict
29
+ from_matrices
30
+ set_operation_attributes
31
+
32
+ Properties:
33
+
34
+ .. autosummary::
35
+ :nosignatures:
36
+
37
+ num_jobs
38
+ num_machines
39
+ num_operations
40
+ is_flexible
41
+ durations_matrix
42
+ machines_matrix
43
+ durations_matrix_array
44
+ machines_matrix_array
45
+ operations_by_machine
46
+ max_duration
47
+ max_duration_per_job
48
+ max_duration_per_machine
49
+ job_durations
50
+ machine_loads
51
+ total_duration
21
52
 
22
53
  Attributes:
23
54
  jobs (list[list[Operation]]):
24
55
  A list of lists of operations. Each list of operations represents
25
56
  a job, and the operations are ordered by their position in the job.
26
- The `job_id`, `position_in_job`, and `operation_id` attributes of
27
- the operations are set when the instance is created.
57
+ The ``job_id``, ``position_in_job``, and `operation_id` attributes
58
+ of the operations are set when the instance is created.
28
59
  name (str):
29
60
  A string with the name of the instance.
30
61
  metadata (dict[str, Any]):
@@ -34,11 +65,16 @@ class JobShopInstance:
34
65
  jobs:
35
66
  A list of lists of operations. Each list of operations
36
67
  represents a job, and the operations are ordered by their
37
- position in the job. The `job_id`, `position_in_job`, and
38
- `operation_id` attributes of the operations are set when the
68
+ position in the job. The ``job_id``, ``position_in_job``, and
69
+ ``operation_id`` attributes of the operations are set when the
39
70
  instance is created.
40
71
  name:
41
72
  A string with the name of the instance.
73
+ set_operation_attributes:
74
+ If True, the ``job_id``, ``position_in_job``, and ``operation_id``
75
+ attributes of the operations are set when the instance is created.
76
+ See :meth:`set_operation_attributes` for more information. Defaults
77
+ to True.
42
78
  **metadata:
43
79
  Additional information about the instance.
44
80
  """
@@ -47,15 +83,37 @@ class JobShopInstance:
47
83
  self,
48
84
  jobs: list[list[Operation]],
49
85
  name: str = "JobShopInstance",
86
+ set_operation_attributes: bool = True,
50
87
  **metadata: Any,
51
88
  ):
52
89
  self.jobs: list[list[Operation]] = jobs
53
- self.set_operation_attributes()
90
+ if set_operation_attributes:
91
+ self.set_operation_attributes()
54
92
  self.name: str = name
55
93
  self.metadata: dict[str, Any] = metadata
56
94
 
57
95
  def set_operation_attributes(self):
58
- """Sets the job_id and position of each operation."""
96
+ """Sets the ``job_id``, ``position_in_job``, and ``operation_id``
97
+ attributes for each operation in the instance.
98
+
99
+ The ``job_id`` attribute is set to the id of the job to which the
100
+ operation belongs.
101
+
102
+ The ``position_in_job`` attribute is set to the
103
+ position of the operation in the job (starts from 0).
104
+
105
+ The ``operation_id`` attribute is set to a unique identifier for the
106
+ operation (starting from 0).
107
+
108
+ The formula to compute the ``operation_id`` in a job shop instance with
109
+ a fixed number of operations per job is:
110
+
111
+ .. code-block:: python
112
+
113
+ operation_id = job_id * num_operations_per_job + position_in_job
114
+
115
+ """
116
+
59
117
  operation_id = 0
60
118
  for job_id, job in enumerate(self.jobs):
61
119
  for position, operation in enumerate(job):
@@ -90,8 +148,8 @@ class JobShopInstance:
90
148
  Additional information about the instance.
91
149
 
92
150
  Returns:
93
- A JobShopInstance object with the operations read from the file,
94
- and the name and metadata provided.
151
+ A :class:`JobShopInstance` object with the operations read from the
152
+ file, and the name and metadata provided.
95
153
  """
96
154
  with open(file_path, "r", encoding=encoding) as file:
97
155
  lines = file.readlines()
@@ -128,13 +186,17 @@ class JobShopInstance:
128
186
  like Taillard's.
129
187
 
130
188
  Returns:
131
- The returned dictionary has the following structure:
132
- {
133
- "name": self.name,
134
- "duration_matrix": self.durations_matrix,
135
- "machines_matrix": self.machines_matrix,
136
- "metadata": self.metadata,
137
- }
189
+ dict[str, Any]: The returned dictionary has the following
190
+ structure:
191
+
192
+ .. code-block:: python
193
+
194
+ {
195
+ "name": self.name,
196
+ "duration_matrix": self.durations_matrix,
197
+ "machines_matrix": self.machines_matrix,
198
+ "metadata": self.metadata,
199
+ }
138
200
  """
139
201
  return {
140
202
  "name": self.name,
@@ -151,7 +213,8 @@ class JobShopInstance:
151
213
  name: str = "JobShopInstance",
152
214
  metadata: dict[str, Any] | None = None,
153
215
  ) -> JobShopInstance:
154
- """Creates a JobShopInstance from duration and machines matrices.
216
+ """Creates a :class:`JobShopInstance` from duration and machines
217
+ matrices.
155
218
 
156
219
  Args:
157
220
  duration_matrix:
@@ -168,7 +231,7 @@ class JobShopInstance:
168
231
  A dictionary with additional information about the instance.
169
232
 
170
233
  Returns:
171
- A JobShopInstance object.
234
+ A :class:`JobShopInstance` object.
172
235
  """
173
236
  jobs: list[list[Operation]] = [[] for _ in range(len(duration_matrix))]
174
237
 
@@ -220,7 +283,7 @@ class JobShopInstance:
220
283
 
221
284
  @functools.cached_property
222
285
  def is_flexible(self) -> bool:
223
- """Returns True if any operation has more than one machine."""
286
+ """Returns ``True`` if any operation has more than one machine."""
224
287
  return any(
225
288
  any(len(operation.machines) > 1 for operation in job)
226
289
  for job in self.jobs
@@ -230,12 +293,14 @@ class JobShopInstance:
230
293
  def durations_matrix(self) -> list[list[int]]:
231
294
  """Returns the duration matrix of the instance.
232
295
 
233
- The duration of the operation with `job_id` i and `position_in_job` j
234
- is stored in the i-th position of the j-th list of the returned matrix:
296
+ The duration of the operation with ``job_id`` i and ``position_in_job``
297
+ j is stored in the i-th position of the j-th list of the returned
298
+ matrix:
299
+
300
+ .. code-block:: python
301
+
302
+ duration = instance.durations_matrix[i][j]
235
303
 
236
- ```python
237
- duration = instance.durations_matrix[i][j]
238
- ```
239
304
  """
240
305
  return [[operation.duration for operation in job] for job in self.jobs]
241
306
 
@@ -252,9 +317,9 @@ class JobShopInstance:
252
317
  To access the machines of the operation with position i in the job
253
318
  with id j, the following code must be used:
254
319
 
255
- ```python
256
- machines = instance.machines_matrix[j][i]
257
- ```
320
+ .. code-block:: python
321
+
322
+ machines = instance.machines_matrix[j][i]
258
323
 
259
324
  """
260
325
  if self.is_flexible:
@@ -269,8 +334,9 @@ class JobShopInstance:
269
334
  def durations_matrix_array(self) -> NDArray[np.float32]:
270
335
  """Returns the duration matrix of the instance as a numpy array.
271
336
 
272
- The returned array has shape (num_jobs, max_num_operations_per_job).
273
- Non-existing operations are filled with np.nan.
337
+ The returned array has shape (``num_jobs``,
338
+ ``max_num_operations_per_job``).
339
+ Non-existing operations are filled with ``np.nan``.
274
340
 
275
341
  Example:
276
342
  >>> jobs = [[Operation(0, 2), Operation(1, 3)], [Operation(0, 4)]]
@@ -286,9 +352,9 @@ class JobShopInstance:
286
352
  def machines_matrix_array(self) -> NDArray[np.float32]:
287
353
  """Returns the machines matrix of the instance as a numpy array.
288
354
 
289
- The returned array has shape (num_jobs, max_num_operations_per_job,
290
- max_num_machines_per_operation). Non-existing machines are filled with
291
- np.nan.
355
+ The returned array has shape (``num_jobs``,
356
+ ``max_num_operations_per_job``, ``max_num_machines_per_operation``).
357
+ Non-existing machines are filled with ``np.nan``.
292
358
 
293
359
  Example:
294
360
  >>> jobs = [
@@ -411,7 +477,7 @@ class JobShopInstance:
411
477
  def _fill_matrix_with_nans_2d(
412
478
  matrix: list[list[int]],
413
479
  ) -> NDArray[np.float32]:
414
- """Fills a matrix with np.nan values.
480
+ """Fills a matrix with ``np.nan`` values.
415
481
 
416
482
  Args:
417
483
  matrix:
@@ -419,7 +485,7 @@ class JobShopInstance:
419
485
 
420
486
  Returns:
421
487
  A numpy array with the same shape as the input matrix, filled with
422
- np.nan values.
488
+ ``np.nan`` values.
423
489
  """
424
490
  max_length = max(len(row) for row in matrix)
425
491
  squared_matrix = np.full(
@@ -433,7 +499,7 @@ class JobShopInstance:
433
499
  def _fill_matrix_with_nans_3d(
434
500
  matrix: list[list[list[int]]],
435
501
  ) -> NDArray[np.float32]:
436
- """Fills a 3D matrix with np.nan values.
502
+ """Fills a 3D matrix with ``np.nan`` values.
437
503
 
438
504
  Args:
439
505
  matrix:
@@ -441,7 +507,7 @@ class JobShopInstance:
441
507
 
442
508
  Returns:
443
509
  A numpy array with the same shape as the input matrix, filled with
444
- np.nan values.
510
+ ``np.nan`` values.
445
511
  """
446
512
  max_length = max(len(row) for row in matrix)
447
513
  max_inner_length = len(matrix[0][0])
@@ -42,11 +42,20 @@ class Operation:
42
42
  "The time it takes to perform the operation. Often referred"
43
43
  " to as the processing time."
44
44
  ),
45
- "job_id": "The id of the job the operation belongs to.",
46
- "position_in_job": "The index of the operation in the job.",
45
+ "job_id": (
46
+ "The id of the job the operation belongs to. Defaults to -1. "
47
+ "It is usually set by the :class:`JobShopInstance` class after "
48
+ "initialization."
49
+ ),
50
+ "position_in_job": (
51
+ "The index of the operation in the job. Defaults to -1. "
52
+ "It is usually set by the :class:`JobShopInstance` class after "
53
+ "initialization."
54
+ ),
47
55
  "operation_id": (
48
56
  "The id of the operation. This is unique within a "
49
- ":class:`JobShopInstance`."
57
+ ":class:`JobShopInstance`. Defaults to -1. It is usually set by "
58
+ "the :class:`JobShopInstance` class after initialization."
50
59
  ),
51
60
  }
52
61
 
@@ -25,6 +25,16 @@ class Schedule:
25
25
  is_complete
26
26
  add
27
27
  reset
28
+
29
+ Args:
30
+ instance:
31
+ The :class:`JobShopInstance` object that the schedule is for.
32
+ schedule:
33
+ A list of lists of :class:`ScheduledOperation` objects. Each
34
+ list represents the order of operations on a machine. If
35
+ not provided, the schedule is initialized as an empty schedule.
36
+ **metadata:
37
+ Additional information about the schedule.
28
38
  """
29
39
 
30
40
  __slots__ = {
@@ -48,18 +58,6 @@ class Schedule:
48
58
  schedule: list[list[ScheduledOperation]] | None = None,
49
59
  **metadata: Any,
50
60
  ):
51
- """Initializes the object with the given instance and schedule.
52
-
53
- Args:
54
- instance:
55
- The :class:`JobShopInstance` object that the schedule is for.
56
- schedule:
57
- A list of lists of :class:`ScheduledOperation` objects. Each
58
- list represents the order of operations on a machine. If
59
- not provided, the schedule is initialized as an empty schedule.
60
- **metadata:
61
- Additional information about the schedule.
62
- """
63
61
  if schedule is None:
64
62
  schedule = [[] for _ in range(instance.num_machines)]
65
63
 
@@ -5,7 +5,21 @@ from job_shop_lib.exceptions import ValidationError
5
5
 
6
6
 
7
7
  class ScheduledOperation:
8
- """Data structure to store a scheduled operation."""
8
+ """Data structure to store a scheduled operation.
9
+
10
+ Args:
11
+ operation:
12
+ The :class:`Operation` object that is scheduled.
13
+ start_time:
14
+ The time at which the operation is scheduled to start.
15
+ machine_id:
16
+ The id of the machine on which the operation is scheduled.
17
+
18
+ Raises:
19
+ ValidationError:
20
+ If the given machine_id is not in the list of valid machines
21
+ for the operation.
22
+ """
9
23
 
10
24
  __slots__ = {
11
25
  "operation": "The :class:`Operation` object that is scheduled.",
@@ -16,21 +30,6 @@ class ScheduledOperation:
16
30
  }
17
31
 
18
32
  def __init__(self, operation: Operation, start_time: int, machine_id: int):
19
- """Initializes a new instance of the :class:`ScheduledOperation` class.
20
-
21
- Args:
22
- operation:
23
- The :class:`Operation` object that is scheduled.
24
- start_time:
25
- The time at which the operation is scheduled to start.
26
- machine_id:
27
- The id of the machine on which the operation is scheduled.
28
-
29
- Raises:
30
- ValidationError:
31
- If the given machine_id is not in the list of valid machines
32
- for the operation.
33
- """
34
33
  self.operation: Operation = operation
35
34
  self.start_time: int = start_time
36
35
  self._machine_id = machine_id
@@ -29,6 +29,18 @@ class DispatcherObserver(abc.ABC):
29
29
  dispatcher:
30
30
  The :class:`Dispatcher` instance to observe.
31
31
 
32
+ Args:
33
+ dispatcher:
34
+ The :class:`Dispatcher` instance to observe.
35
+ subscribe:
36
+ If ``True``, automatically subscribes the observer to the
37
+ dispatcher when it is initialized. Defaults to ``True``.
38
+
39
+ Raises:
40
+ ValidationError: If ``is_singleton`` is ``True`` and an observer of the
41
+ same type already exists in the dispatcher's list of
42
+ subscribers.
43
+
32
44
  Example:
33
45
 
34
46
  .. code-block:: python
@@ -61,21 +73,6 @@ class DispatcherObserver(abc.ABC):
61
73
  *,
62
74
  subscribe: bool = True,
63
75
  ):
64
- """Initializes the observer with the :class:`Dispatcher` and subscribes
65
- to it.
66
-
67
- Args:
68
- dispatcher:
69
- The `Dispatcher` instance to observe.
70
- subscribe:
71
- If True, automatically subscribes the observer to the
72
- dispatcher.
73
-
74
- Raises:
75
- ValidationError: If ``is_singleton`` is True and an observer of the
76
- same type already exists in the dispatcher's list of
77
- subscribers.
78
- """
79
76
  if self._is_singleton and any(
80
77
  isinstance(observer, self.__class__)
81
78
  for observer in dispatcher.subscribers
@@ -26,14 +26,21 @@ class DispatcherObserverConfig(Generic[T]):
26
26
  keyword arguments to pass to the dispatcher observer constructor while
27
27
  not containing the ``dispatcher`` argument.
28
28
 
29
- Attributes:
29
+ Args:
30
30
  class_type:
31
31
  Type of the class to be initialized. It can be the class type, an
32
32
  enum value, or a string. This is useful for the creation of
33
- DispatcherObserver instances from the factory functions.
33
+ :class:`~job_shop_lib.dispatching.DispatcherObserver` instances
34
+ from the factory functions.
34
35
  kwargs:
35
36
  Keyword arguments needed to initialize the class. It must not
36
37
  contain the ``dispatcher`` argument.
38
+
39
+ .. seealso::
40
+
41
+ - :class:`~job_shop_lib.dispatching.DispatcherObserver`
42
+ - :func:`job_shop_lib.dispatching.feature_observers.\\
43
+ feature_observer_factory`
37
44
  """
38
45
 
39
46
  # We use the type hint T, instead of ObserverType, to allow for string or
@@ -44,7 +51,13 @@ class DispatcherObserverConfig(Generic[T]):
44
51
  # This allows for the creation of a FeatureObserver instance
45
52
  # from the factory function.
46
53
  class_type: T
54
+ """Type of the class to be initialized. It can be the class type, an
55
+ enum value, or a string. This is useful for the creation of
56
+ :class:`DispatcherObserver` instances from the factory functions."""
57
+
47
58
  kwargs: dict[str, Any] = field(default_factory=dict)
59
+ """Keyword arguments needed to initialize the class. It must not
60
+ contain the ``dispatcher`` argument."""
48
61
 
49
62
  def __post_init__(self):
50
63
  if "dispatcher" in self.kwargs:
@@ -51,13 +51,13 @@ def create_composite_operation_filter(
51
51
  'non_immediate_machines' or any Callable that takes a
52
52
  :class:`~job_shop_lib.dispatching.Dispatcher` instance and a list
53
53
  of :class:`~job_shop_lib.Operation` instances as input
54
- and returns a list of :class:`~job_shop_lib.Operation`instances.
54
+ and returns a list of :class:`~job_shop_lib.Operation` instances.
55
55
 
56
56
  Returns:
57
57
  A function that takes a :class:`~job_shop_lib.dispatching.Dispatcher`
58
58
  instance and a list of :class:`~job_shop_lib.Operation`
59
59
  instances as input and returns a list of
60
- :class:`~job_shop_lib.Operation`instances based on
60
+ :class:`~job_shop_lib.Operation` instances based on
61
61
  the specified list of filter strategies.
62
62
 
63
63
  Raises:
@@ -193,7 +193,6 @@ if __name__ == "__main__":
193
193
  dispatcher=dispatcher_,
194
194
  )
195
195
  for observer_type in feature_observer_types_
196
- if not observer_type == FeatureObserverType.COMPOSITE
197
196
  # and not FeatureObserverType.EARLIEST_START_TIME
198
197
  ]
199
198
  composite_observer_ = CompositeFeatureObserver(
@@ -1,4 +1,4 @@
1
- """Contains factory functions for creating node feature encoders."""
1
+ """Contains factory functions for creating :class:`FeatureObserver`s."""
2
2
 
3
3
  from enum import Enum
4
4
 
@@ -18,8 +18,12 @@ from job_shop_lib.dispatching.feature_observers import (
18
18
  class FeatureObserverType(str, Enum):
19
19
  """Enumeration of the different feature observers.
20
20
 
21
- Each feature observer is associated with a string value that can be used
22
- to create the feature observer using the factory function.
21
+ Each :class:`FeatureObserver` is associated with a string value that can be
22
+ used to create the :class:`FeatureObserver` using the factory function.
23
+
24
+ It does not include the :class:`CompositeFeatureObserver` class since this
25
+ observer is often managed separately from the others. For example, a
26
+ common use case is to create a list of feature observers and pass them to
23
27
  """
24
28
 
25
29
  IS_READY = "is_ready"
@@ -29,7 +33,6 @@ class FeatureObserverType(str, Enum):
29
33
  POSITION_IN_JOB = "position_in_job"
30
34
  REMAINING_OPERATIONS = "remaining_operations"
31
35
  IS_COMPLETED = "is_completed"
32
- COMPOSITE = "composite"
33
36
 
34
37
 
35
38
  # FeatureObserverConfig = DispatcherObserverConfig[
@@ -43,7 +46,7 @@ FeatureObserverConfig = (
43
46
 
44
47
 
45
48
  def feature_observer_factory(
46
- feature_creator_type: (
49
+ feature_observer_type: (
47
50
  str
48
51
  | FeatureObserverType
49
52
  | type[FeatureObserver]
@@ -51,29 +54,29 @@ def feature_observer_factory(
51
54
  ),
52
55
  **kwargs,
53
56
  ) -> FeatureObserver:
54
- """Creates and returns a node feature creator based on the specified
55
- node feature creator type.
57
+ """Creates and returns a :class:`FeatureObserver` based on the specified
58
+ :class:`FeatureObserver` type.
56
59
 
57
60
  Args:
58
61
  feature_creator_type:
59
- The type of node feature creator to create.
62
+ The type of :class:`FeatureObserver` to create.
60
63
  **kwargs:
61
- Additional keyword arguments to pass to the node
62
- feature creator constructor.
64
+ Additional keyword arguments to pass to the
65
+ :class:`FeatureObserver` constructor.
63
66
 
64
67
  Returns:
65
- A node feature creator instance.
68
+ A :class:`FeatureObserver` instance.
66
69
  """
67
- if isinstance(feature_creator_type, DispatcherObserverConfig):
70
+ if isinstance(feature_observer_type, DispatcherObserverConfig):
68
71
  return feature_observer_factory(
69
- feature_creator_type.class_type,
70
- **feature_creator_type.kwargs,
72
+ feature_observer_type.class_type,
73
+ **feature_observer_type.kwargs,
71
74
  **kwargs,
72
75
  )
73
76
  # if the instance is of type type[FeatureObserver] we can just
74
77
  # call the object constructor with the keyword arguments
75
- if isinstance(feature_creator_type, type):
76
- return feature_creator_type(**kwargs)
78
+ if isinstance(feature_observer_type, type):
79
+ return feature_observer_type(**kwargs)
77
80
 
78
81
  mapping: dict[FeatureObserverType, type[FeatureObserver]] = {
79
82
  FeatureObserverType.IS_READY: IsReadyObserver,
@@ -84,5 +87,5 @@ def feature_observer_factory(
84
87
  FeatureObserverType.REMAINING_OPERATIONS: RemainingOperationsObserver,
85
88
  FeatureObserverType.IS_COMPLETED: IsCompletedObserver,
86
89
  }
87
- feature_creator = mapping[feature_creator_type] # type: ignore[index]
88
- return feature_creator(**kwargs)
90
+ feature_observer = mapping[feature_observer_type] # type: ignore[index]
91
+ return feature_observer(**kwargs)
@@ -51,6 +51,7 @@ class IsCompletedObserver(FeatureObserver):
51
51
  def __init__(
52
52
  self,
53
53
  dispatcher: Dispatcher,
54
+ *,
54
55
  feature_types: list[FeatureType] | FeatureType | None = None,
55
56
  subscribe: bool = True,
56
57
  ):
@@ -55,7 +55,7 @@ class DispatchingRuleSolver(BaseSolver):
55
55
  - a list with names or actual ready operations filters to be used.
56
56
  If a list is provided, a composite filter will be created
57
57
  using the specified filters.
58
-
58
+
59
59
  .. seealso::
60
60
  - :func:`job_shop_lib.dispatching.rules.dispatching_rule_factory`
61
61
  - :func:`job_shop_lib.dispatching.rules.machine_chooser_factory`