job-shop-lib 1.0.0b5__py3-none-any.whl → 1.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. job_shop_lib/__init__.py +1 -1
  2. job_shop_lib/_job_shop_instance.py +2 -2
  3. job_shop_lib/_operation.py +9 -3
  4. job_shop_lib/_scheduled_operation.py +3 -0
  5. job_shop_lib/benchmarking/__init__.py +1 -0
  6. job_shop_lib/dispatching/__init__.py +12 -10
  7. job_shop_lib/dispatching/_dispatcher.py +6 -13
  8. job_shop_lib/dispatching/_factories.py +3 -3
  9. job_shop_lib/dispatching/_optimal_operations_observer.py +0 -2
  10. job_shop_lib/dispatching/_ready_operation_filters.py +4 -4
  11. job_shop_lib/dispatching/feature_observers/_composite_feature_observer.py +11 -6
  12. job_shop_lib/dispatching/feature_observers/_factory.py +8 -3
  13. job_shop_lib/dispatching/feature_observers/_feature_observer.py +1 -1
  14. job_shop_lib/dispatching/feature_observers/_is_completed_observer.py +35 -67
  15. job_shop_lib/dispatching/rules/__init__.py +11 -8
  16. job_shop_lib/dispatching/rules/_dispatching_rule_factory.py +1 -1
  17. job_shop_lib/dispatching/rules/_machine_chooser_factory.py +3 -2
  18. job_shop_lib/generation/__init__.py +12 -1
  19. job_shop_lib/graphs/__init__.py +42 -8
  20. job_shop_lib/graphs/_build_resource_task_graphs.py +1 -1
  21. job_shop_lib/graphs/_job_shop_graph.py +38 -19
  22. job_shop_lib/graphs/graph_updaters/__init__.py +5 -1
  23. job_shop_lib/graphs/graph_updaters/_disjunctive_graph_updater.py +108 -0
  24. job_shop_lib/graphs/graph_updaters/_residual_graph_updater.py +3 -1
  25. job_shop_lib/graphs/graph_updaters/_utils.py +2 -2
  26. job_shop_lib/py.typed +0 -0
  27. job_shop_lib/reinforcement_learning/__init__.py +13 -7
  28. job_shop_lib/reinforcement_learning/_multi_job_shop_graph_env.py +1 -1
  29. job_shop_lib/reinforcement_learning/_resource_task_graph_observation.py +102 -24
  30. job_shop_lib/reinforcement_learning/_single_job_shop_graph_env.py +11 -2
  31. job_shop_lib/reinforcement_learning/_types_and_constants.py +11 -10
  32. job_shop_lib/reinforcement_learning/_utils.py +29 -0
  33. job_shop_lib/visualization/gantt/__init__.py +7 -3
  34. job_shop_lib/visualization/gantt/_gantt_chart_video_and_gif_creation.py +5 -2
  35. job_shop_lib/visualization/graphs/__init__.py +1 -0
  36. job_shop_lib/visualization/graphs/_plot_disjunctive_graph.py +53 -19
  37. {job_shop_lib-1.0.0b5.dist-info → job_shop_lib-1.0.2.dist-info}/METADATA +19 -18
  38. {job_shop_lib-1.0.0b5.dist-info → job_shop_lib-1.0.2.dist-info}/RECORD +40 -38
  39. {job_shop_lib-1.0.0b5.dist-info → job_shop_lib-1.0.2.dist-info}/LICENSE +0 -0
  40. {job_shop_lib-1.0.0b5.dist-info → job_shop_lib-1.0.2.dist-info}/WHEEL +0 -0
job_shop_lib/__init__.py CHANGED
@@ -19,7 +19,7 @@ from job_shop_lib._schedule import Schedule
19
19
  from job_shop_lib._base_solver import BaseSolver, Solver
20
20
 
21
21
 
22
- __version__ = "1.0.0-b.5"
22
+ __version__ = "1.0.2"
23
23
 
24
24
  __all__ = [
25
25
  "Operation",
@@ -16,8 +16,8 @@ class JobShopInstance:
16
16
  """Data structure to store a Job Shop Scheduling Problem instance.
17
17
 
18
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.
19
+ be computed from the instance and are cached for performance since they
20
+ might require expensive computations.
21
21
 
22
22
  Methods:
23
23
 
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  from typing import Union, List
6
6
 
7
- from job_shop_lib.exceptions import UninitializedAttributeError
7
+ from job_shop_lib.exceptions import ValidationError
8
8
 
9
9
 
10
10
  class Operation:
@@ -81,8 +81,14 @@ class Operation:
81
81
  If the operation has multiple machines in its list.
82
82
  """
83
83
  if len(self.machines) > 1:
84
- raise UninitializedAttributeError(
85
- "Operation has multiple machines."
84
+ raise ValidationError(
85
+ "Operation has multiple machines. The `machine_id` property "
86
+ "should only be used when working with a classic JSSP "
87
+ "instance. This error prevents silent bugs. To handle "
88
+ "operations with more machines you have to use the machines "
89
+ "attribute. If you get this error using `job_shop_lib` "
90
+ "objects, it means that that object does not support "
91
+ "operations with multiple machines yet."
86
92
  )
87
93
  return self.machines[0]
88
94
 
@@ -80,3 +80,6 @@ class ScheduledOperation:
80
80
  and self.start_time == value.start_time
81
81
  and self.machine_id == value.machine_id
82
82
  )
83
+
84
+ def __hash__(self) -> int:
85
+ return hash((self.operation, self.start_time, self.machine_id))
@@ -1,6 +1,7 @@
1
1
  """Contains functions to load benchmark instances.
2
2
 
3
3
  .. autosummary::
4
+ :nosignatures:
4
5
 
5
6
  load_all_benchmark_instances
6
7
  load_benchmark_instance
@@ -9,13 +9,15 @@ Problem step-by-step.
9
9
  HistoryObserver
10
10
  UnscheduledOperationsObserver
11
11
  OptimalOperationsObserver
12
- ReadyOperationsFilter
13
12
  DispatcherObserverConfig
13
+ ReadyOperationsFilter
14
+ ReadyOperationsFilterType
15
+ ready_operations_filter_factory
14
16
  filter_dominated_operations
15
17
  filter_non_immediate_machines
18
+ filter_non_idle_machines
19
+ filter_non_immediate_operations
16
20
  create_composite_operation_filter
17
- ReadyOperationsFilterType
18
- ready_operations_filter_factory
19
21
 
20
22
  Dispatching refers to the decision-making process of selecting which job
21
23
  should be processed next on a particular machine when that machine becomes
@@ -45,17 +47,17 @@ from ._factories import (
45
47
 
46
48
  __all__ = [
47
49
  "Dispatcher",
48
- "filter_dominated_operations",
49
- "filter_non_immediate_machines",
50
- "create_composite_operation_filter",
51
- "ReadyOperationsFilterType",
52
- "ready_operations_filter_factory",
53
50
  "DispatcherObserver",
54
51
  "HistoryObserver",
55
- "DispatcherObserverConfig",
56
52
  "UnscheduledOperationsObserver",
53
+ "OptimalOperationsObserver",
54
+ "DispatcherObserverConfig",
57
55
  "ReadyOperationsFilter",
56
+ "ReadyOperationsFilterType",
57
+ "ready_operations_filter_factory",
58
+ "filter_dominated_operations",
59
+ "filter_non_immediate_machines",
58
60
  "filter_non_idle_machines",
59
61
  "filter_non_immediate_operations",
60
- "OptimalOperationsObserver",
62
+ "create_composite_operation_filter",
61
63
  ]
@@ -336,8 +336,7 @@ class Dispatcher:
336
336
  The operation to be scheduled.
337
337
  machine_id:
338
338
  The id of the machine on which the operation is to be
339
- scheduled. If ``None``, the start time is computed based on the
340
- next available time for the operation on any machine.
339
+ scheduled.
341
340
  """
342
341
  return max(
343
342
  self._machine_next_available_time[machine_id],
@@ -459,12 +458,11 @@ class Dispatcher:
459
458
  return unscheduled_operations
460
459
 
461
460
  @_dispatcher_cache
462
- def scheduled_operations(self) -> List[Operation]:
461
+ def scheduled_operations(self) -> List[ScheduledOperation]:
463
462
  """Returns the list of operations that have been scheduled."""
464
463
  scheduled_operations = []
465
- for job_id, next_position in enumerate(self._job_next_operation_index):
466
- operations = self.instance.jobs[job_id][:next_position]
467
- scheduled_operations.extend(operations)
464
+ for machine_schedule in self.schedule.schedule:
465
+ scheduled_operations.extend(machine_schedule)
468
466
  return scheduled_operations
469
467
 
470
468
  @_dispatcher_cache
@@ -532,19 +530,14 @@ class Dispatcher:
532
530
  return scheduled_operation.end_time - adjusted_start_time
533
531
 
534
532
  @_dispatcher_cache
535
- def completed_operations(self) -> Set[Operation]:
533
+ def completed_operations(self) -> Set[ScheduledOperation]:
536
534
  """Returns the set of operations that have been completed.
537
535
 
538
536
  This method returns the operations that have been scheduled and the
539
537
  current time is greater than or equal to the end time of the operation.
540
538
  """
541
539
  scheduled_operations = set(self.scheduled_operations())
542
- ongoing_operations = set(
543
- map(
544
- lambda scheduled_op: scheduled_op.operation,
545
- self.ongoing_operations(),
546
- )
547
- )
540
+ ongoing_operations = set(self.ongoing_operations())
548
541
  completed_operations = scheduled_operations - ongoing_operations
549
542
  return completed_operations
550
543
 
@@ -95,9 +95,9 @@ def ready_operations_filter_factory(
95
95
 
96
96
  Args:
97
97
  filter_name:
98
- The name of the filter function to be used. Supported
99
- values are 'dominated_operations' and
100
- 'immediate_machine_operations'.
98
+ The name of the filter function to be used. See
99
+ :class:`ReadyOperationsFilterType` for supported values.
100
+ Alternatively, a custom filter function can be passed directly.
101
101
 
102
102
  Returns:
103
103
  A function that takes a :class:`~job_shop_lib.dispatching.Dispatcher`
@@ -20,8 +20,6 @@ class OptimalOperationsObserver(DispatcherObserver):
20
20
  based on the reference schedule.
21
21
  reference_schedule: The reference schedule used to determine optimal
22
22
  operations.
23
- _operation_to_scheduled: Dictionary mapping operations to their
24
- scheduled versions in the reference schedule.
25
23
 
26
24
  Args:
27
25
  dispatcher: The dispatcher instance to observe.
@@ -153,16 +153,16 @@ def _get_min_machine_end_times(
153
153
 
154
154
 
155
155
  def _get_immediate_machines(
156
- self: Dispatcher, available_operations: List[Operation]
156
+ dispatcher: Dispatcher, available_operations: List[Operation]
157
157
  ) -> List[bool]:
158
158
  """Returns the machine ids of the machines that have at least one
159
159
  operation with the lowest start time (i.e. the start time)."""
160
- working_machines = [False] * self.instance.num_machines
160
+ working_machines = [False] * dispatcher.instance.num_machines
161
161
  # We can't use the current_time directly because it will cause
162
162
  # an infinite loop.
163
- current_time = self.min_start_time(available_operations)
163
+ current_time = dispatcher.min_start_time(available_operations)
164
164
  for op in available_operations:
165
165
  for machine_id in op.machines:
166
- if self.start_time(op, machine_id) == current_time:
166
+ if dispatcher.start_time(op, machine_id) == current_time:
167
167
  working_machines[machine_id] = True
168
168
  return working_machines
@@ -2,10 +2,10 @@
2
2
 
3
3
  from collections import defaultdict
4
4
  from collections.abc import Sequence
5
- from typing import List, Dict, Union, Optional
5
+ from typing import List, Dict, Union, Optional, Type
6
6
  # The Self type can be imported directly from Python’s typing module in
7
7
  # version 3.11 and beyond. We use the typing_extensions module to support
8
- # python >=3.8
8
+ # python >=3.10
9
9
  from typing_extensions import Self
10
10
  import numpy as np
11
11
  from numpy.typing import NDArray
@@ -18,6 +18,7 @@ from job_shop_lib.dispatching.feature_observers import (
18
18
  FeatureType,
19
19
  FeatureObserverConfig,
20
20
  feature_observer_factory,
21
+ FeatureObserverType,
21
22
  )
22
23
 
23
24
 
@@ -104,7 +105,14 @@ class CompositeFeatureObserver(FeatureObserver):
104
105
  def from_feature_observer_configs(
105
106
  cls,
106
107
  dispatcher: Dispatcher,
107
- feature_observer_configs: Sequence[FeatureObserverConfig],
108
+ feature_observer_configs: Sequence[
109
+ Union[
110
+ str,
111
+ FeatureObserverType,
112
+ Type[FeatureObserver],
113
+ FeatureObserverConfig,
114
+ ],
115
+ ],
108
116
  subscribe: bool = True,
109
117
  ) -> Self:
110
118
  """Creates the composite feature observer.
@@ -178,9 +186,6 @@ if __name__ == "__main__":
178
186
  import time
179
187
  from job_shop_lib.benchmarking import load_benchmark_instance
180
188
  from job_shop_lib.dispatching.rules import DispatchingRuleSolver
181
- from job_shop_lib.dispatching.feature_observers import (
182
- FeatureObserverType,
183
- )
184
189
 
185
190
  ta80 = load_benchmark_instance("ta80")
186
191
 
@@ -39,9 +39,14 @@ class FeatureObserverType(str, Enum):
39
39
  # FeatureObserverConfig = DispatcherObserverConfig[
40
40
  # Type[FeatureObserver] | FeatureObserverType | str
41
41
  # ]
42
- FeatureObserverConfig = DispatcherObserverConfig[
43
- Union[Type[FeatureObserver], FeatureObserverType, str]
44
- ]
42
+ # FeatureObserverConfig = DispatcherObserverConfig[
43
+ # Union[Type[FeatureObserver], FeatureObserverType, str]
44
+ # ]
45
+ FeatureObserverConfig = (
46
+ DispatcherObserverConfig[Type[FeatureObserver]]
47
+ | DispatcherObserverConfig[FeatureObserverType]
48
+ | DispatcherObserverConfig[str]
49
+ )
45
50
 
46
51
 
47
52
  def feature_observer_factory(
@@ -36,7 +36,7 @@ class FeatureObserver(DispatcherObserver):
36
36
  individually. Furthermore, machine learning models can be trained on these
37
37
  arrays to predict the best dispatching decisions.
38
38
 
39
- Arrays use the data type ``np.float32``. This is because most machine
39
+ Arrays use the data type ``np.float32``.
40
40
 
41
41
  New :class:`FeatureObservers` must inherit from this class, and re-define
42
42
  the class attributes ``_singleton`` (defualt ), ``_feature_size``
@@ -4,14 +4,10 @@ from typing import Optional, Union, List
4
4
  import numpy as np
5
5
 
6
6
  from job_shop_lib import ScheduledOperation
7
- from job_shop_lib.dispatching import (
8
- Dispatcher,
9
- DispatcherObserver,
10
- )
7
+ from job_shop_lib.dispatching import Dispatcher
11
8
  from job_shop_lib.dispatching.feature_observers import (
12
9
  FeatureObserver,
13
10
  FeatureType,
14
- RemainingOperationsObserver,
15
11
  )
16
12
 
17
13
 
@@ -40,15 +36,6 @@ class IsCompletedObserver(FeatureObserver):
40
36
  or manually updated.
41
37
  """
42
38
 
43
- __slots__ = {
44
- "remaining_ops_per_machine": (
45
- "The number of unscheduled operations per machine."
46
- ),
47
- "remaining_ops_per_job": (
48
- "The number of unscheduled operations per job."
49
- ),
50
- }
51
-
52
39
  def __init__(
53
40
  self,
54
41
  dispatcher: Dispatcher,
@@ -57,11 +44,16 @@ class IsCompletedObserver(FeatureObserver):
57
44
  subscribe: bool = True,
58
45
  ):
59
46
  feature_types = self._get_feature_types_list(feature_types)
60
- self.remaining_ops_per_machine = np.zeros(
61
- (dispatcher.instance.num_machines, 1), dtype=int
47
+ self._num_of_operations_per_machine = np.array(
48
+ [
49
+ len(operations_by_machine)
50
+ for operations_by_machine in (
51
+ dispatcher.instance.operations_by_machine
52
+ )
53
+ ]
62
54
  )
63
- self.remaining_ops_per_job = np.zeros(
64
- (dispatcher.instance.num_jobs, 1), dtype=int
55
+ self._num_of_operations_per_job = np.array(
56
+ [len(job) for job in dispatcher.instance.jobs]
65
57
  )
66
58
  super().__init__(
67
59
  dispatcher,
@@ -70,60 +62,36 @@ class IsCompletedObserver(FeatureObserver):
70
62
  )
71
63
 
72
64
  def initialize_features(self):
73
- def _has_same_features(observer: DispatcherObserver) -> bool:
74
- if not isinstance(observer, RemainingOperationsObserver):
75
- return False
76
- return all(
77
- feature_type in observer.features
78
- for feature_type in remaining_ops_feature_types
79
- )
80
-
81
- self.set_features_to_zero()
82
-
83
- remaining_ops_feature_types = [
84
- feature_type
85
- for feature_type in self.features.keys()
86
- if feature_type != FeatureType.OPERATIONS
87
- ]
88
- remaining_ops_observer = self.dispatcher.create_or_get_observer(
89
- RemainingOperationsObserver,
90
- condition=_has_same_features,
91
- feature_types=remaining_ops_feature_types,
92
- )
93
- if FeatureType.JOBS in self.features:
94
- self.remaining_ops_per_job = remaining_ops_observer.features[
95
- FeatureType.JOBS
96
- ].copy()
97
- if FeatureType.MACHINES in self.features:
98
- self.remaining_ops_per_machine = remaining_ops_observer.features[
99
- FeatureType.MACHINES
100
- ].copy()
101
-
102
- def reset(self):
103
- self.initialize_features()
104
-
105
- def update(self, scheduled_operation: ScheduledOperation):
106
65
  if FeatureType.OPERATIONS in self.features:
107
66
  completed_operations = [
108
- op.operation_id
67
+ op.operation.operation_id
109
68
  for op in self.dispatcher.completed_operations()
110
69
  ]
111
70
  self.features[FeatureType.OPERATIONS][completed_operations, 0] = 1
112
71
  if FeatureType.MACHINES in self.features:
113
- self.remaining_ops_per_machine[
114
- scheduled_operation.operation.machines, 0
115
- ] -= 1
116
- is_completed = (
117
- self.remaining_ops_per_machine[
118
- scheduled_operation.operation.machines, 0
119
- ]
120
- == 0
72
+ num_completed_ops_per_machine = np.zeros(
73
+ len(self._num_of_operations_per_machine)
121
74
  )
122
- self.features[FeatureType.MACHINES][
123
- scheduled_operation.operation.machines, 0
124
- ] = is_completed
75
+ for op in self.dispatcher.completed_operations():
76
+ for machine_id in op.operation.machines:
77
+ num_completed_ops_per_machine[machine_id] += 1
78
+ self.features[FeatureType.MACHINES][:, 0] = (
79
+ num_completed_ops_per_machine
80
+ == self._num_of_operations_per_machine
81
+ ).astype(np.float32)
125
82
  if FeatureType.JOBS in self.features:
126
- job_id = scheduled_operation.job_id
127
- self.remaining_ops_per_job[job_id, 0] -= 1
128
- is_completed = self.remaining_ops_per_job[job_id, 0] == 0
129
- self.features[FeatureType.JOBS][job_id, 0] = is_completed
83
+ num_completed_ops_per_job = np.zeros(
84
+ len(self._num_of_operations_per_job)
85
+ )
86
+ for op in self.dispatcher.completed_operations():
87
+ num_completed_ops_per_job[op.operation.job_id] += 1
88
+ self.features[FeatureType.JOBS][:, 0] = (
89
+ num_completed_ops_per_job
90
+ == self._num_of_operations_per_job
91
+ ).astype(np.float32)
92
+
93
+ def reset(self):
94
+ self.set_features_to_zero()
95
+
96
+ def update(self, scheduled_operation: ScheduledOperation):
97
+ self.initialize_features()
@@ -3,17 +3,19 @@
3
3
  Main objects:
4
4
 
5
5
  .. autosummary::
6
+ :nosignatures:
6
7
 
7
8
  DispatchingRuleSolver
8
- dispatching_rule_factory
9
9
  DispatchingRuleType
10
- MachineChooserType
11
10
  dispatching_rule_factory
11
+ MachineChooserType
12
12
  machine_chooser_factory
13
+ MachineChooser
13
14
 
14
15
  Dispatching rules:
15
16
 
16
17
  .. autosummary::
18
+ :nosignatures:
17
19
 
18
20
  shortest_processing_time_rule
19
21
  first_come_first_served_rule
@@ -27,6 +29,7 @@ Dispatching rules:
27
29
  Dispatching rule scorers:
28
30
 
29
31
  .. autosummary::
32
+ :nosignatures:
30
33
 
31
34
  shortest_processing_time_score
32
35
  first_come_first_served_score
@@ -65,6 +68,11 @@ from ._dispatching_rule_solver import DispatchingRuleSolver
65
68
 
66
69
 
67
70
  __all__ = [
71
+ "DispatchingRuleSolver",
72
+ "DispatchingRuleType",
73
+ "dispatching_rule_factory",
74
+ "MachineChooserType",
75
+ "machine_chooser_factory",
68
76
  "shortest_processing_time_rule",
69
77
  "first_come_first_served_rule",
70
78
  "most_work_remaining_rule",
@@ -72,16 +80,11 @@ __all__ = [
72
80
  "random_operation_rule",
73
81
  "score_based_rule",
74
82
  "score_based_rule_with_tie_breaker",
83
+ "observer_based_most_work_remaining_rule",
75
84
  "shortest_processing_time_score",
76
85
  "first_come_first_served_score",
77
86
  "MostWorkRemainingScorer",
78
87
  "most_operations_remaining_score",
79
88
  "random_score",
80
- "dispatching_rule_factory",
81
- "DispatchingRuleType",
82
- "MachineChooserType",
83
- "machine_chooser_factory",
84
89
  "MachineChooser",
85
- "DispatchingRuleSolver",
86
- "observer_based_most_work_remaining_rule",
87
90
  ]
@@ -33,7 +33,7 @@ class DispatchingRuleType(str, Enum):
33
33
 
34
34
 
35
35
  def dispatching_rule_factory(
36
- dispatching_rule: Union[str, DispatchingRuleType,]
36
+ dispatching_rule: Union[str, DispatchingRuleType],
37
37
  ) -> Callable[[Dispatcher], Operation]:
38
38
  """Creates and returns a dispatching rule function based on the specified
39
39
  dispatching rule name.
@@ -47,8 +47,9 @@ def machine_chooser_factory(
47
47
  machine chooser strategy.
48
48
 
49
49
  Raises:
50
- ValueError: If the machine_chooser argument is not recognized or is
51
- not supported.
50
+ ValidationError:
51
+ If the ``machine_chooser`` argument is not recognized or
52
+ is not supported.
52
53
  """
53
54
  machine_choosers: Dict[str, Callable[[Dispatcher, Operation], int]] = {
54
55
  MachineChooserType.FIRST: lambda _, operation: operation.machines[0],
@@ -1,4 +1,15 @@
1
- """Package for generating job shop instances."""
1
+ """Package for generating job shop instances.
2
+
3
+ .. autosummary::
4
+ :nosignatures:
5
+
6
+ InstanceGenerator
7
+ GeneralInstanceGenerator
8
+ generate_duration_matrix
9
+ generate_machine_matrix_with_recirculation
10
+ generate_machine_matrix_without_recirculation
11
+
12
+ """
2
13
 
3
14
  from job_shop_lib.generation._utils import (
4
15
  generate_duration_matrix,
@@ -2,15 +2,47 @@
2
2
 
3
3
  The main classes and functions available in this package are:
4
4
 
5
+ Main objects:
6
+
5
7
  .. autosummary::
8
+ :nosignatures:
9
+
6
10
  JobShopGraph
7
11
  Node
8
12
  NodeType
13
+ EdgeType
14
+ NODE_ATTR
15
+
16
+ Build functions:
17
+
18
+ .. autosummary::
19
+ :nosignatures:
20
+
9
21
  build_disjunctive_graph
10
- build_solved_disjunctive_graph
11
22
  build_resource_task_graph
12
23
  build_complete_resource_task_graph
13
24
  build_resource_task_graph_with_jobs
25
+ build_solved_disjunctive_graph
26
+
27
+ Add functions:
28
+
29
+ .. autosummary::
30
+ :nosignatures:
31
+
32
+ add_disjunctive_edges
33
+ add_conjunctive_edges
34
+ add_source_sink_nodes
35
+ add_source_sink_edges
36
+ add_same_job_operations_edges
37
+ add_machine_nodes
38
+ add_operation_machine_edges
39
+ add_machine_machine_edges
40
+ add_job_nodes
41
+ add_operation_job_edges
42
+ add_global_node
43
+ add_machine_global_edges
44
+ add_job_global_edges
45
+ add_job_job_edges
14
46
 
15
47
  """
16
48
 
@@ -38,23 +70,25 @@ from job_shop_lib.graphs._build_resource_task_graphs import (
38
70
  add_global_node,
39
71
  add_machine_global_edges,
40
72
  add_job_global_edges,
73
+ add_job_job_edges,
41
74
  )
42
75
 
43
76
 
44
77
  __all__ = [
45
- "EdgeType",
46
- "NodeType",
47
- "Node",
48
78
  "JobShopGraph",
79
+ "Node",
80
+ "NodeType",
81
+ "EdgeType",
49
82
  "NODE_ATTR",
50
83
  "build_disjunctive_graph",
84
+ "build_resource_task_graph",
85
+ "build_complete_resource_task_graph",
86
+ "build_resource_task_graph_with_jobs",
87
+ "build_solved_disjunctive_graph",
51
88
  "add_disjunctive_edges",
52
89
  "add_conjunctive_edges",
53
90
  "add_source_sink_nodes",
54
91
  "add_source_sink_edges",
55
- "build_resource_task_graph",
56
- "build_complete_resource_task_graph",
57
- "build_resource_task_graph_with_jobs",
58
92
  "add_same_job_operations_edges",
59
93
  "add_machine_nodes",
60
94
  "add_operation_machine_edges",
@@ -64,5 +98,5 @@ __all__ = [
64
98
  "add_global_node",
65
99
  "add_machine_global_edges",
66
100
  "add_job_global_edges",
67
- "build_solved_disjunctive_graph",
101
+ "add_job_job_edges",
68
102
  ]
@@ -1,7 +1,7 @@
1
1
  """Contains helper functions to build the resource-task graphs from a job shop
2
2
  instance.
3
3
 
4
- The agent-task graph (renamed to resource-task graph) was introduced by
4
+ The resource-task graph (originally called agent-task graph) was introduced by
5
5
  Junyoung Park et al. (2021).
6
6
  In contrast to the disjunctive graph, instead of connecting operations that
7
7
  share the same resources directly by disjunctive edges, operation nodes are