job-shop-lib 1.0.0a1__py3-none-any.whl → 1.0.0a2__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (27) hide show
  1. job_shop_lib/_operation.py +24 -20
  2. job_shop_lib/_schedule.py +14 -13
  3. job_shop_lib/_scheduled_operation.py +9 -11
  4. job_shop_lib/constraint_programming/_ortools_solver.py +31 -16
  5. job_shop_lib/dispatching/feature_observers/__init__.py +34 -2
  6. job_shop_lib/dispatching/feature_observers/_composite_feature_observer.py +54 -14
  7. job_shop_lib/dispatching/feature_observers/_duration_observer.py +15 -2
  8. job_shop_lib/dispatching/feature_observers/_earliest_start_time_observer.py +62 -10
  9. job_shop_lib/dispatching/feature_observers/_factory.py +5 -1
  10. job_shop_lib/dispatching/feature_observers/_feature_observer.py +87 -16
  11. job_shop_lib/dispatching/feature_observers/_is_completed_observer.py +32 -2
  12. job_shop_lib/dispatching/feature_observers/_is_ready_observer.py +2 -2
  13. job_shop_lib/dispatching/feature_observers/_is_scheduled_observer.py +9 -5
  14. job_shop_lib/dispatching/feature_observers/_position_in_job_observer.py +7 -2
  15. job_shop_lib/dispatching/feature_observers/_remaining_operations_observer.py +1 -1
  16. job_shop_lib/dispatching/rules/_dispatching_rule_solver.py +28 -24
  17. job_shop_lib/graphs/__init__.py +2 -0
  18. job_shop_lib/graphs/_build_agent_task_graph.py +2 -2
  19. job_shop_lib/graphs/_constants.py +18 -1
  20. job_shop_lib/graphs/_job_shop_graph.py +36 -20
  21. job_shop_lib/graphs/_node.py +60 -52
  22. job_shop_lib/graphs/graph_updaters/__init__.py +11 -1
  23. job_shop_lib/visualization/_gantt_chart_video_and_gif_creation.py +1 -1
  24. {job_shop_lib-1.0.0a1.dist-info → job_shop_lib-1.0.0a2.dist-info}/METADATA +1 -1
  25. {job_shop_lib-1.0.0a1.dist-info → job_shop_lib-1.0.0a2.dist-info}/RECORD +27 -27
  26. {job_shop_lib-1.0.0a1.dist-info → job_shop_lib-1.0.0a2.dist-info}/LICENSE +0 -0
  27. {job_shop_lib-1.0.0a1.dist-info → job_shop_lib-1.0.0a2.dist-info}/WHEEL +0 -0
@@ -15,8 +15,38 @@ from job_shop_lib.dispatching.feature_observers import (
15
15
 
16
16
 
17
17
  class IsCompletedObserver(FeatureObserver):
18
- """Observer that adds a binary feature indicating whether each operation,
19
- machine, or job has been completed."""
18
+ """Adds a binary feature indicating whether each operation,
19
+ machine, or job has been completed.
20
+
21
+ An operation is considered completed if it has been scheduled and the
22
+ current time is greater than or equal to the sum of the operation's start
23
+ time and duration.
24
+
25
+ A machine or job is considered completed if all of its operations have been
26
+ completed.
27
+
28
+ Args:
29
+ dispatcher:
30
+ The :class:`~job_shop_lib.dispatching.Dispatcher` to observe.
31
+ feature_types:
32
+ A list of :class:`FeatureType` or a single :class:`FeatureType`
33
+ that specifies the types of features to observe. They must be a
34
+ subset of the class attribute :attr:`supported_feature_types`.
35
+ If ``None``, all supported feature types are tracked.
36
+ subscribe:
37
+ If ``True``, the observer is subscribed to the dispatcher upon
38
+ initialization. Otherwise, the observer must be subscribed later
39
+ or manually updated.
40
+ """
41
+
42
+ __slots__ = {
43
+ "remaining_ops_per_machine": (
44
+ "The number of unscheduled operations per machine."
45
+ ),
46
+ "remaining_ops_per_job": (
47
+ "The number of unscheduled operations per job."
48
+ ),
49
+ }
20
50
 
21
51
  def __init__(
22
52
  self,
@@ -7,8 +7,8 @@ from job_shop_lib.dispatching.feature_observers import (
7
7
 
8
8
 
9
9
  class IsReadyObserver(FeatureObserver):
10
- """Feature creator that adds a binary feature indicating if the operation
11
- is ready to be dispatched."""
10
+ """Feature creator that adds a binary feature indicating if the operation,
11
+ machine or job is ready to be dispatched."""
12
12
 
13
13
  def initialize_features(self):
14
14
  self.set_features_to_zero()
@@ -8,14 +8,18 @@ from job_shop_lib.dispatching.feature_observers import (
8
8
 
9
9
 
10
10
  class IsScheduledObserver(FeatureObserver):
11
- """Observer that updates features based on scheduling operations.
11
+ """Updates features based on scheduling operations.
12
12
 
13
13
  This observer tracks which operations have been scheduled and updates
14
- feature matrices accordingly. It updates a feature in the
15
- `FeatureType.OPERATIONS` matrix to indicate that an operation has been
16
- scheduled. Additionally, it counts the number of uncompleted but
14
+ feature matrices accordingly.
15
+
16
+ It updates a feature in the
17
+ :meth:`FeatureType.OPERATIONS` matrix to indicate that an operation has
18
+ been scheduled.
19
+
20
+ Additionally, it counts the number of uncompleted but
17
21
  scheduled operations for each machine and job, updating the respective
18
- `FeatureType.MACHINES` and `FeatureType.JOBS` feature matrices.
22
+ :meth:`FeatureType.MACHINES` and :meth:`FeatureType.JOBS` feature matrices.
19
23
  """
20
24
 
21
25
  def update(self, scheduled_operation: ScheduledOperation):
@@ -8,10 +8,15 @@ from job_shop_lib.dispatching.feature_observers import (
8
8
 
9
9
 
10
10
  class PositionInJobObserver(FeatureObserver):
11
- """Observer that adds a feature indicating the position of
11
+ """Adds a feature indicating the position of
12
12
  operations in their respective jobs.
13
13
 
14
- Positions are adjusted dynamically as operations are scheduled.
14
+ Positions are adjusted dynamically as operations are scheduled. In other
15
+ words, the position of an operation is the number of unscheduled operations
16
+ that precede it in the job.
17
+
18
+ It only supports the :meth:`~job_shop_lib.FeatureType.OPERATIONS` feature
19
+ type.
15
20
  """
16
21
 
17
22
  _supported_feature_types = [FeatureType.OPERATIONS]
@@ -12,7 +12,7 @@ class RemainingOperationsObserver(FeatureObserver):
12
12
  """Adds a feature indicating the number of remaining operations for each
13
13
  job and machine.
14
14
 
15
- It does not support :class:`FeatureType.OPERATIONS`.
15
+ It does not support :meth:`FeatureType.OPERATIONS`.
16
16
  """
17
17
 
18
18
  _supported_feature_types = [FeatureType.MACHINES, FeatureType.JOBS]
@@ -40,7 +40,7 @@ class DispatchingRuleSolver(BaseSolver):
40
40
  machine_chooser: (
41
41
  str | Callable[[Dispatcher, Operation], int]
42
42
  ) = MachineChooserType.FIRST,
43
- pruning_function: (
43
+ ready_operations_filter: (
44
44
  str
45
45
  | Callable[[Dispatcher, list[Operation]], list[Operation]]
46
46
  | None
@@ -60,25 +60,25 @@ class DispatchingRuleSolver(BaseSolver):
60
60
  of the machine chooser, a MachineChooser enum member, or a
61
61
  callable that takes a dispatcher and an operation and returns
62
62
  the machine id where the operation will be dispatched.
63
- pruning_function:
64
- The pruning function to use. It can be a string with the name
65
- of the pruning function, a PruningFunction enum member, or a
66
- callable that takes a dispatcher and a list of operations and
67
- returns a list of operations that should be considered for
68
- dispatching.
63
+ ready_operations_filter:
64
+ The ready operations filter to use. It can be a string with
65
+ the name of the pruning function, a PruningFunction enum
66
+ member, or a callable that takes a dispatcher and a list of
67
+ operations and returns a list of operations that should be
68
+ considered for dispatching.
69
69
  """
70
70
  if isinstance(dispatching_rule, str):
71
71
  dispatching_rule = dispatching_rule_factory(dispatching_rule)
72
72
  if isinstance(machine_chooser, str):
73
73
  machine_chooser = machine_chooser_factory(machine_chooser)
74
- if isinstance(pruning_function, str):
75
- pruning_function = ready_operations_filter_factory(
76
- pruning_function
74
+ if isinstance(ready_operations_filter, str):
75
+ ready_operations_filter = ready_operations_filter_factory(
76
+ ready_operations_filter
77
77
  )
78
78
 
79
79
  self.dispatching_rule = dispatching_rule
80
80
  self.machine_chooser = machine_chooser
81
- self.pruning_function = pruning_function
81
+ self.ready_operations_filter = ready_operations_filter
82
82
 
83
83
  def solve(
84
84
  self, instance: JobShopInstance, dispatcher: Dispatcher | None = None
@@ -87,7 +87,7 @@ class DispatchingRuleSolver(BaseSolver):
87
87
  dispatching rule algorithm."""
88
88
  if dispatcher is None:
89
89
  dispatcher = Dispatcher(
90
- instance, ready_operations_filter=self.pruning_function
90
+ instance, ready_operations_filter=self.ready_operations_filter
91
91
  )
92
92
  while not dispatcher.schedule.is_complete():
93
93
  self.step(dispatcher)
@@ -110,19 +110,23 @@ class DispatchingRuleSolver(BaseSolver):
110
110
  if __name__ == "__main__":
111
111
  import time
112
112
  import cProfile
113
- import pstats
114
- from io import StringIO
115
- from job_shop_lib.benchmarking import load_benchmark_instance
113
+ # import pstats
114
+ # from io import StringIO
115
+ from job_shop_lib.benchmarking import (
116
+ # load_benchmark_instance,
117
+ load_all_benchmark_instances,
118
+ )
116
119
 
117
120
  # from job_shop_lib.dispatching.rules._dispatching_rules_functions import (
118
121
  # most_work_remaining_rule_2,
119
122
  # )
120
123
 
121
- ta_instances = [
122
- load_benchmark_instance(f"ta{i:02d}") for i in range(1, 81)
123
- ]
124
+ # ta_instances = [
125
+ # load_benchmark_instance(f"ta{i:02d}") for i in range(1, 81)
126
+ # ]
127
+ ta_instances = load_all_benchmark_instances().values()
124
128
  solver = DispatchingRuleSolver(
125
- dispatching_rule="most_work_remaining", pruning_function=None
129
+ dispatching_rule="most_work_remaining", ready_operations_filter=None
126
130
  )
127
131
 
128
132
  start = time.perf_counter()
@@ -131,10 +135,10 @@ if __name__ == "__main__":
131
135
  profiler = cProfile.Profile()
132
136
 
133
137
  # Run the code under profiling
134
- profiler.enable()
138
+ # profiler.enable()
135
139
  for instance_ in ta_instances:
136
140
  solver.solve(instance_)
137
- profiler.disable()
141
+ # profiler.disable()
138
142
 
139
143
  end = time.perf_counter()
140
144
 
@@ -142,7 +146,7 @@ if __name__ == "__main__":
142
146
  print(f"Elapsed time: {end - start:.2f} seconds.")
143
147
 
144
148
  # Print profiling results
145
- s = StringIO()
146
- ps = pstats.Stats(profiler, stream=s).sort_stats("cumulative")
147
- profiler.print_stats("cumtime") # Print top 20 time-consuming functions
149
+ # s = StringIO()
150
+ # ps = pstats.Stats(profiler, stream=s).sort_stats("cumulative")
151
+ # profiler.print_stats("cumtime") # Print top 20 time-consuming functions
148
152
  # print(s.getvalue())
@@ -1,5 +1,7 @@
1
1
  """Package for graph related classes and functions.
2
2
 
3
+ The main classes and functions available in this package are:
4
+
3
5
  .. autosummary::
4
6
  JobShopGraph
5
7
  Node
@@ -13,8 +13,8 @@ job, and the global node is connected to all machine and job nodes.
13
13
 
14
14
  References:
15
15
  - Junyoung Park, Sanjar Bakhtiyar, and Jinkyoo Park. Schedulenet: Learn to
16
- solve multi-agent scheduling problems with reinforcement learning. ArXiv,
17
- abs/2106.03051, 2021.
16
+ solve multi-agent scheduling problems with reinforcement learning. ArXiv,
17
+ abs/2106.03051, 2021.
18
18
  """
19
19
 
20
20
  import itertools
@@ -11,7 +11,24 @@ class EdgeType(enum.Enum):
11
11
 
12
12
 
13
13
  class NodeType(enum.Enum):
14
- """Enumeration of node types."""
14
+ """Enumeration of node types.
15
+
16
+ Nodes of type :class:`NodeType.OPERATION`, :class:`NodeType.MACHINE`, and
17
+ :class:`NodeType.JOB` have specific attributes associated with them in the
18
+ :class:`Node` class.
19
+
20
+ On the other hand, Nodes of type :class:`NodeType.GLOBAL`,
21
+ :class:`NodeType.SOURCE`, and :class:`NodeType.SINK` are used to represent
22
+ different concepts in the graph and accesing them, but they do not have
23
+ specific attributes associated with them.
24
+
25
+ .. tip::
26
+
27
+ While uncommon, it can be useful to extend this enumeration with
28
+ additional node types. This can be achieved using
29
+ `aenum <https://github.com/ethanfurman/aenum>`_'s
30
+ ``extend_enum`` (requires using Python 3.11+).
31
+ """
15
32
 
16
33
  OPERATION = enum.auto()
17
34
  MACHINE = enum.auto()
@@ -13,10 +13,10 @@ NODE_ATTR = "node"
13
13
 
14
14
  # pylint: disable=too-many-instance-attributes
15
15
  class JobShopGraph:
16
- """Data structure to represent a `JobShopInstance` as a graph.
16
+ """Represents a :class:`JobShopInstance` as a heterogeneous directed graph.
17
17
 
18
18
  Provides a comprehensive graph-based representation of a job shop
19
- scheduling problem, utilizing the `networkx` library to model the complex
19
+ scheduling problem, utilizing the ``networkx`` library to model the complex
20
20
  relationships between jobs, operations, and machines. This class transforms
21
21
  the abstract scheduling problem into a directed graph, where various
22
22
  entities (jobs, machines, and operations) are nodes, and the dependencies
@@ -25,25 +25,40 @@ class JobShopGraph:
25
25
  This transformation allows for the application of graph algorithms
26
26
  to analyze and solve scheduling problems.
27
27
 
28
- Attributes:
28
+ Args:
29
29
  instance:
30
- The job shop instance encapsulated by this graph.
31
- graph:
32
- The directed graph representing the job shop, where nodes are
33
- operations, machines, jobs, or abstract concepts like global,
34
- source, and sink, with edges indicating dependencies.
30
+ The job shop instance that the graph represents.
31
+ add_operation_nodes:
32
+ Whether to add nodes of type :class:`NodeType.OPERATION` to the
33
+ to the graph. If set to ``False``, the graph will be empty, and
34
+ operation nodes will need to be added manually.
35
35
  """
36
36
 
37
- def __init__(self, instance: JobShopInstance):
38
- """Initializes the graph with the given instance.
39
-
40
- Nodes of type `OPERATION` are added to the graph based on the
41
- operations of the instance.
42
-
43
- Args:
44
- instance:
45
- The job shop instance that the graph represents.
46
- """
37
+ __slots__ = {
38
+ "instance": "The job shop instance that the graph represents.",
39
+ "graph": (
40
+ "The directed graph representing the job shop, where nodes are "
41
+ "operations, machines, jobs, or abstract concepts like global, "
42
+ "source, and sink, with edges indicating dependencies."
43
+ ),
44
+ "_nodes": "List of all nodes added to the graph.",
45
+ "_nodes_by_type": "Dictionary mapping node types to lists of nodes.",
46
+ "_nodes_by_machine": (
47
+ "List of lists mapping machine ids to operation nodes."
48
+ ),
49
+ "_nodes_by_job": "List of lists mapping job ids to operation nodes.",
50
+ "_next_node_id": (
51
+ "The id to assign to the next node added to thegraph."
52
+ ),
53
+ "removed_nodes": (
54
+ "List of boolean values indicating whether a node has been "
55
+ "removed from the graph."
56
+ ),
57
+ }
58
+
59
+ def __init__(
60
+ self, instance: JobShopInstance, add_operation_nodes: bool = True
61
+ ):
47
62
  self.graph = nx.DiGraph()
48
63
  self.instance = instance
49
64
 
@@ -59,7 +74,8 @@ class JobShopGraph:
59
74
  ]
60
75
  self._next_node_id = 0
61
76
  self.removed_nodes: list[bool] = []
62
- self._add_operation_nodes()
77
+ if add_operation_nodes:
78
+ self.add_operation_nodes()
63
79
 
64
80
  @property
65
81
  def nodes(self) -> list[Node]:
@@ -103,7 +119,7 @@ class JobShopGraph:
103
119
  """Number of job nodes in the graph."""
104
120
  return len(self._nodes_by_type[NodeType.JOB])
105
121
 
106
- def _add_operation_nodes(self) -> None:
122
+ def add_operation_nodes(self) -> None:
107
123
  """Adds operation nodes to the graph."""
108
124
  for job in self.instance.jobs:
109
125
  for operation in job:
@@ -9,7 +9,7 @@ from job_shop_lib.graphs._constants import NodeType
9
9
 
10
10
 
11
11
  class Node:
12
- """Data structure to represent a node in the `JobShopGraph`.
12
+ """Represents a node in the :class:`JobShopGraph`.
13
13
 
14
14
  A node is hashable by its id. The id is assigned when the node is added to
15
15
  the graph. The id must be unique for each node in the graph, and should be
@@ -18,11 +18,15 @@ class Node:
18
18
  Depending on the type of the node, it can have different attributes. The
19
19
  following table shows the attributes of each type of node:
20
20
 
21
- Node Type | Required Attribute
22
- ----------------|---------------------
23
- OPERATION | `operation`
24
- MACHINE | `machine_id`
25
- JOB | `job_id`
21
+ +----------------+---------------------+
22
+ | Node Type | Required Attribute |
23
+ +================+=====================+
24
+ | OPERATION | ``operation`` |
25
+ +----------------+---------------------+
26
+ | MACHINE | ``machine_id`` |
27
+ +----------------+---------------------+
28
+ | JOB | ``job_id`` |
29
+ +----------------+---------------------+
26
30
 
27
31
  In terms of equality, two nodes are equal if they have the same id.
28
32
  Additionally, one node is equal to an integer if the integer is equal to
@@ -31,25 +35,47 @@ class Node:
31
35
  This allows for using the node as a key in a dictionary, at the same time
32
36
  we can use its id to index that dictionary. Example:
33
37
 
34
- ```python
35
- node = Node(NodeType.SOURCE)
36
- node.node_id = 1
37
- graph = {node: "some value"}
38
- print(graph[node]) # "some value"
39
- print(graph[1]) # "some value"
40
- ```
38
+ .. code-block:: python
41
39
 
42
- Attributes:
40
+ node = Node(NodeType.SOURCE)
41
+ node.node_id = 1
42
+ graph = {node: "some value"}
43
+ print(graph[node]) # "some value"
44
+ print(graph[1]) # "some value"
45
+
46
+ Args:
43
47
  node_type:
44
- The type of the node. It can be one of the following:
45
- - NodeType.OPERATION
46
- - NodeType.MACHINE
47
- - NodeType.JOB
48
- - NodeType.GLOBAL
49
- ...
48
+ The type of the node. See :class:`NodeType` for theavailable types.
49
+ operation:
50
+ The operation of the node. Required if ``node_type`` is
51
+ :attr:`NodeType.OPERATION`.
52
+ machine_id:
53
+ The id of the machine. Required if ``node_type`` is
54
+ :attr:`NodeType.MACHINE`.
55
+ job_id:
56
+ The id of the job. Required if ``node_type`` is
57
+ :attr:`NodeType.JOB`.
58
+
59
+ Raises:
60
+ ValidationError:
61
+ If the ``node_type`` is :attr:`NodeType.OPERATION`,
62
+ :attr:`NodeType.MACHINE`, or :attr:`NodeType.JOB` and the
63
+ corresponding ``operation``, ``machine_id``, or ``job_id`` is
64
+ ``None``, respectively.
65
+
50
66
  """
51
67
 
52
- __slots__ = "node_type", "_node_id", "_operation", "_machine_id", "_job_id"
68
+ __slots__ = {
69
+ "node_type": "The type of the node.",
70
+ "_node_id": "Unique identifier for the node.",
71
+ "_operation": (
72
+ "The operation associated with the node."
73
+ ),
74
+ "_machine_id": (
75
+ "The machine ID associated with the node."
76
+ ),
77
+ "_job_id": "The job ID associated with the node.",
78
+ }
53
79
 
54
80
  def __init__(
55
81
  self,
@@ -58,34 +84,6 @@ class Node:
58
84
  machine_id: int | None = None,
59
85
  job_id: int | None = None,
60
86
  ):
61
- """Initializes the node with the given attributes.
62
-
63
- Args:
64
- node_type:
65
- The type of the node. It can be one of the following:
66
- - NodeType.OPERATION
67
- - NodeType.MACHINE
68
- - NodeType.JOB
69
- - NodeType.GLOBAL
70
- ...
71
- operation:
72
- The operation of the node. It should be provided if the
73
- `node_type` is NodeType.OPERATION.
74
- machine_id:
75
- The id of the machine of the node. It should be provided if the
76
- node_type is NodeType.MACHINE.
77
- job_id:
78
- The id of the job of the node. It should be provided if the
79
- node_type is NodeType.JOB.
80
-
81
- Raises:
82
- ValidationError:
83
- If the node_type is OPERATION and operation is None.
84
- ValidationError:
85
- If the node_type is MACHINE and machine_id is None.
86
- ValidationError:
87
- If the node_type is JOB and job_id is None.
88
- """
89
87
  if node_type == NodeType.OPERATION and operation is None:
90
88
  raise ValidationError("Operation node must have an operation.")
91
89
 
@@ -95,7 +93,7 @@ class Node:
95
93
  if node_type == NodeType.JOB and job_id is None:
96
94
  raise ValidationError("Job node must have a job_id.")
97
95
 
98
- self.node_type = node_type
96
+ self.node_type: NodeType = node_type
99
97
  self._node_id: int | None = None
100
98
 
101
99
  self._operation = operation
@@ -119,7 +117,11 @@ class Node:
119
117
  def operation(self) -> Operation:
120
118
  """Returns the operation of the node.
121
119
 
122
- This property is mandatory for nodes of type `OPERATION`.
120
+ This property is mandatory for nodes of type
121
+ :class:`NodeType.OPERATION`.
122
+
123
+ Raises:
124
+ UninitializedAttributeError: If the node has no operation.
123
125
  """
124
126
  if self._operation is None:
125
127
  raise UninitializedAttributeError("Node has no operation.")
@@ -130,9 +132,12 @@ class Node:
130
132
  """Returns the `machine_id` of the node.
131
133
 
132
134
  This property is mandatory for nodes of type `MACHINE`.
135
+
136
+ Raises:
137
+ UninitializedAttributeError: If the node has no ``machine_id``.
133
138
  """
134
139
  if self._machine_id is None:
135
- raise UninitializedAttributeError("Node has no `machine_id`.")
140
+ raise UninitializedAttributeError("Node has no ``machine_id``.")
136
141
  return self._machine_id
137
142
 
138
143
  @property
@@ -140,6 +145,9 @@ class Node:
140
145
  """Returns the `job_id` of the node.
141
146
 
142
147
  This property is mandatory for nodes of type `JOB`.
148
+
149
+ Raises:
150
+ UninitializedAttributeError: If the node has no `job_id`.
143
151
  """
144
152
  if self._job_id is None:
145
153
  raise UninitializedAttributeError("Node has no `job_id`.")
@@ -1,5 +1,15 @@
1
1
  """Contains classes and functions for updating the graph representation of the
2
- job shop scheduling problem."""
2
+ job shop scheduling problem.
3
+
4
+ Currently, the following classes and utilities are available:
5
+
6
+ .. autosummary::
7
+
8
+ GraphUpdater
9
+ ResidualGraphUpdater
10
+ remove_completed_operations
11
+
12
+ """
3
13
 
4
14
  from ._graph_updater import GraphUpdater
5
15
  from ._utils import remove_completed_operations
@@ -263,7 +263,7 @@ def create_gantt_chart_frames(
263
263
  """
264
264
  if solver is not None and schedule_history is None:
265
265
  dispatcher = Dispatcher(
266
- instance, ready_operations_filter=solver.pruning_function
266
+ instance, ready_operations_filter=solver.ready_operations_filter
267
267
  )
268
268
  history_tracker = HistoryObserver(dispatcher)
269
269
  makespan = solver.solve(instance, dispatcher).makespan()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: job-shop-lib
3
- Version: 1.0.0a1
3
+ Version: 1.0.0a2
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
@@ -1,14 +1,14 @@
1
1
  job_shop_lib/__init__.py,sha256=Ci5ipn-zciO88C5aX5Wx-UN8iBTbpde3dSSg02ZcfwM,597
2
2
  job_shop_lib/_base_solver.py,sha256=p17XmtufNc9Y481cqZUT45pEkUmmW1HWG53dfhIBJH8,1363
3
3
  job_shop_lib/_job_shop_instance.py,sha256=Q0ml3C36tmcBskBo8MyaZWILJPbdvHjJcvXzD_YfLsU,16475
4
- job_shop_lib/_operation.py,sha256=8Wj8ZLpxmHw4lJJbLCZoTpFhLaap9MSzwOA5VOJQ-DY,3099
5
- job_shop_lib/_schedule.py,sha256=2QjhU21pZr7Gl6qEVJ9kXujx-bSrvaTdyZvjGbrQqzs,11193
6
- job_shop_lib/_scheduled_operation.py,sha256=w7jKhgJ4dQycJ5wSItAd_B9gH5ipcoqy5KxtHFxWTP0,2775
4
+ job_shop_lib/_operation.py,sha256=lJ4srQs82cYhUYuBxqkfKr9MuZoG0X2x0z3M1_QXkAs,3360
5
+ job_shop_lib/_schedule.py,sha256=H6PREUE9KCC0DtrQV8y9MB8S4sh3qnDwby5Y4WVDfzg,11333
6
+ job_shop_lib/_scheduled_operation.py,sha256=ptqYRW39EvG5tnk4DLQGFCOkbGTTYIQJhUMcuLSbdSA,2812
7
7
  job_shop_lib/benchmarking/__init__.py,sha256=BYCrJUNr_uk2c0xIbDt07OnUMhQx8Dudkukx3TFWxgw,3271
8
8
  job_shop_lib/benchmarking/_load_benchmark.py,sha256=-cgyx0Kn6uAc3KdGFSQb6eUVQjQggmpVKOH9qusNkXI,2930
9
9
  job_shop_lib/benchmarking/benchmark_instances.json,sha256=F9EvyzFwVxiKAN6rQTsrMhsKstmyUmroyWduM7a00KQ,464841
10
10
  job_shop_lib/constraint_programming/__init__.py,sha256=kKQRUxxS_nVFUdXGnf4bQOD9mqrXxZZWElS753A4YiA,454
11
- job_shop_lib/constraint_programming/_ortools_solver.py,sha256=U6kkk2pHsAgKLOhEjl6R1FFLy-i5_5sxBHaXezMR1tI,9860
11
+ job_shop_lib/constraint_programming/_ortools_solver.py,sha256=gRoImEBUa8_io-TzbSS-3f0CJ7UwacU5Lrz0bsDqibo,10462
12
12
  job_shop_lib/dispatching/__init__.py,sha256=QV7qy-y0sSoKp_FslTm7sdqczYzpq0YctzKQ36l0ykg,1510
13
13
  job_shop_lib/dispatching/_dispatcher.py,sha256=PCSBpYAF6QPXWrjwkBQXTxOdGdq6Y1Uqw8esQTW05TQ,21357
14
14
  job_shop_lib/dispatching/_dispatcher_observer_config.py,sha256=l_lbaw9JJ5icVOmDAzAL6G5t6wG25bQLpRedN1bys8c,1932
@@ -16,20 +16,20 @@ job_shop_lib/dispatching/_factories.py,sha256=UAZLq7d_-puzMYteiAbbhkcW5ucKO-lo3b
16
16
  job_shop_lib/dispatching/_history_observer.py,sha256=Vl8rQaxekUeEB-AyNxyC3c76zQakeh-rdri2iDnZvXw,610
17
17
  job_shop_lib/dispatching/_ready_operation_filters.py,sha256=q8Xv4kp_2GsvEMC5mlTuJXivAz_b8bbrqo5sXaS3PJU,3110
18
18
  job_shop_lib/dispatching/_unscheduled_operations_observer.py,sha256=LNEzqOWqEf6fvtkQrDmDWFEhCfA75OgEtzdomzbxYII,2683
19
- job_shop_lib/dispatching/feature_observers/__init__.py,sha256=oPrhxw65znMhLugMqUD-1swNi8MufejQbHKiMxtgCU0,1103
20
- job_shop_lib/dispatching/feature_observers/_composite_feature_observer.py,sha256=SqZ7Th97p1SkmHz2O_xdPCoqiPNwEs71n_iSkCO3FQM,6397
21
- job_shop_lib/dispatching/feature_observers/_duration_observer.py,sha256=RfWXtxXvS4lakIRWPa1tD0I_UGgb7-h4-tTVvA_x4tA,3490
22
- job_shop_lib/dispatching/feature_observers/_earliest_start_time_observer.py,sha256=iBkfGxG9-peO8shJKTl2P59YFq63aX_Z4XUvOL6m79g,8912
23
- job_shop_lib/dispatching/feature_observers/_factory.py,sha256=3nlLDzdf_UJqmNO1Om69ygxj-9mF4kfPBp0rFFUC_a0,2773
24
- job_shop_lib/dispatching/feature_observers/_feature_observer.py,sha256=N-UhOsw3VbasKucuZlAJyF-k0O7CiwtGFez39xOF66Q,5174
25
- job_shop_lib/dispatching/feature_observers/_is_completed_observer.py,sha256=_ZSmHt1ZtLNXBipaeSOXwgY14WWN3tIm9sx8WY4-zBw,3448
26
- job_shop_lib/dispatching/feature_observers/_is_ready_observer.py,sha256=iRr2MsCAglb6dO5fhHKSD7Z2ZHRjYqXK7E8bimAfpOY,1244
27
- job_shop_lib/dispatching/feature_observers/_is_scheduled_observer.py,sha256=PeLxPVLJX_TP4TG8ViEQFR8WS43wIp6CqyuapM8lIt8,1477
28
- job_shop_lib/dispatching/feature_observers/_position_in_job_observer.py,sha256=hvztjuajYRx-CnmflWqN4lG06pJelZIRZmarjPK9Afo,1107
29
- job_shop_lib/dispatching/feature_observers/_remaining_operations_observer.py,sha256=kNvRVbxsx5SI2nMc9ZbmcPd5wDaxiljhkXpk6biV2rI,1442
19
+ job_shop_lib/dispatching/feature_observers/__init__.py,sha256=EuJLvSpJpoXUK8A4UuC2k6Mpa293ZR3oCnnvYivIBtU,2240
20
+ job_shop_lib/dispatching/feature_observers/_composite_feature_observer.py,sha256=DOS961MtWaDk2gxjOLA_75SyT6Nmn3IKuNtYO8odk8s,7938
21
+ job_shop_lib/dispatching/feature_observers/_duration_observer.py,sha256=fbkUIVScF1iNjdVCYr1ImQm53TfahvVnGXhsRAsgdzY,4129
22
+ job_shop_lib/dispatching/feature_observers/_earliest_start_time_observer.py,sha256=SOdXs-uzTzcLqOsmpbKvf-OGlGXOMVVJL9zgVVVDvF8,11442
23
+ job_shop_lib/dispatching/feature_observers/_factory.py,sha256=b5YyzdnorijtWUNrYWs4sf-G17eDxw8oYrol1rzMN1Q,2919
24
+ job_shop_lib/dispatching/feature_observers/_feature_observer.py,sha256=crbqG1KrmUOfG4z7shHNzhUg7-uSP4_RWxyOi-RRWmE,8635
25
+ job_shop_lib/dispatching/feature_observers/_is_completed_observer.py,sha256=wKmlASLjodztAB2ypTsi0XFLZ3h1ltzvsa9BpPrbksU,4581
26
+ job_shop_lib/dispatching/feature_observers/_is_ready_observer.py,sha256=KYDUO3Zz1wgkClZ64i5-az6W-SFpi8rckAlv4Zjcii4,1260
27
+ job_shop_lib/dispatching/feature_observers/_is_scheduled_observer.py,sha256=OcuMUB9_By6ZMtX-1_3z-xaxGbP85a5Zv0ywAv7XxWQ,1491
28
+ job_shop_lib/dispatching/feature_observers/_position_in_job_observer.py,sha256=WRknpQBKXs6h6cXLFJW7ZCvjtU8CPL-iXXNPw3g-mLE,1303
29
+ job_shop_lib/dispatching/feature_observers/_remaining_operations_observer.py,sha256=5V87lCrJUabEe8AkTGXPu5yS8OGxeN8L3-xNyHmdmLs,1441
30
30
  job_shop_lib/dispatching/rules/__init__.py,sha256=p1rkqf66L62uvAOM1ZxNV8xHoh7SuYjHi_8ZNBvPIjg,1450
31
31
  job_shop_lib/dispatching/rules/_dispatching_rule_factory.py,sha256=5fNpv90fAoR6rcE6NeJOWiB7ir-FVnoONIhHtKJ9H0E,2904
32
- job_shop_lib/dispatching/rules/_dispatching_rule_solver.py,sha256=r-z3AHwbYNRRnrifoz1gmKASpWqxrUQoxvyfara92KM,5331
32
+ job_shop_lib/dispatching/rules/_dispatching_rule_solver.py,sha256=Nb3EPSIdnbeqKaIf5ufE2zxQsNpNkZxmYa0Eh1jnCnw,5537
33
33
  job_shop_lib/dispatching/rules/_dispatching_rules_functions.py,sha256=Wb9fQIfePvCJi4RqJ59UrRSnYufgQw5nQ_Am8M6-JOI,7569
34
34
  job_shop_lib/dispatching/rules/_machine_chooser_factory.py,sha256=xsJ8nJwPDBi-sfLJRQF_BBQDbyXDfopD1U-efXffQAE,2331
35
35
  job_shop_lib/dispatching/rules/_utils.py,sha256=X8vET2p1D3RyoB9mFfsfRgmilcTmxPssKYyJQ2zEt0Q,4605
@@ -38,13 +38,13 @@ job_shop_lib/generation/__init__.py,sha256=hUqjnE0bEoknuUwFoLUWjBH26qTTCGsJAW4gs
38
38
  job_shop_lib/generation/_general_instance_generator.py,sha256=8DG70qT2TUTyPp-3Q1DHWo3DhtUvyB4Yo_u0eAa5CIc,7431
39
39
  job_shop_lib/generation/_instance_generator.py,sha256=fPcbNoyk0t1JtJpBMiwk3SlyPkWYNkYS7-Vs8qH_eDM,4642
40
40
  job_shop_lib/generation/_transformations.py,sha256=FI2qHrETATJUrQP3-RYhZAQ5boyEZ0CF2StDbacBej8,5290
41
- job_shop_lib/graphs/__init__.py,sha256=Kzw__atE5q_bbLf-vDwqya453RP-CfgV7RlURbdOfSc,1646
42
- job_shop_lib/graphs/_build_agent_task_graph.py,sha256=ktj-oNLUPmWHfL81EVyaoF4hXClWYfnN7oG2Nn4pOsg,7128
41
+ job_shop_lib/graphs/__init__.py,sha256=ALZNmvCi5XveMneVJ2VQpQ5msYwIqFWFloiwyFtJhAo,1709
42
+ job_shop_lib/graphs/_build_agent_task_graph.py,sha256=6mvWJ7fFD5CmxkTuXEwY7f_-qxjKdNgFmWk4a4mgiD8,7132
43
43
  job_shop_lib/graphs/_build_disjunctive_graph.py,sha256=z1jiuTTaWPJZj-vSZdo064quGx4LEDKjtZIb1FieZW4,3705
44
- job_shop_lib/graphs/_constants.py,sha256=dqPF--okue5sF70Iv-YR14QKFx4pxPwT2dL1Rh5jylM,374
45
- job_shop_lib/graphs/_job_shop_graph.py,sha256=QmYj-DptmV3Mca0JHplPa1YPt6D4zDSdIwclKK15Ib0,9938
46
- job_shop_lib/graphs/_node.py,sha256=FcV92cH1RK6xv8qK3d4QaCRzB-C2kY0MtVeWNgsdi6U,5769
47
- job_shop_lib/graphs/graph_updaters/__init__.py,sha256=utejVUdKNa3g_6HpfTKanv-9K9sVFlRnqhWpRPGxEHU,358
44
+ job_shop_lib/graphs/_constants.py,sha256=K-GeVvh_DTWpo1KOX1clmxWS_pkUJbq19yOBmrCVIxI,1086
45
+ job_shop_lib/graphs/_job_shop_graph.py,sha256=Fv0TOwtmjqdhH-A_TBH0wSzQkGgqTyc7vvEcfzbQiwA,10681
46
+ job_shop_lib/graphs/_node.py,sha256=hGgdnD9wlsTbkaDizFZMsxPXa2-m91iBNLu0vtkVbxw,6034
47
+ job_shop_lib/graphs/graph_updaters/__init__.py,sha256=UhnZL55e3cAv7hVetB6bRmIOn8BDhG2bsbrdRoHtxLY,516
48
48
  job_shop_lib/graphs/graph_updaters/_graph_updater.py,sha256=H8PtBj4gv6y5wQKOstF2CSnLsFjO1YeVHpzvYK3vMRM,2053
49
49
  job_shop_lib/graphs/graph_updaters/_residual_graph_updater.py,sha256=kPuBmion70-GAQsyFal8gHylHvZSoBJae9eF8iGOkvA,6097
50
50
  job_shop_lib/graphs/graph_updaters/_utils.py,sha256=X5YfwJA1CCgpm1r9C036Gal2CkDh2SSak7wl7TbdjHw,704
@@ -59,8 +59,8 @@ job_shop_lib/visualization/_agent_task_graph.py,sha256=AaBTD_S34WjrsZnL_iMAplR_f
59
59
  job_shop_lib/visualization/_disjunctive_graph.py,sha256=pg4KG9BfQbnBPnXYgbyPGe0AuHSmhYqPeqWYAf_spWQ,5905
60
60
  job_shop_lib/visualization/_gantt_chart.py,sha256=B9sn4XrEUqgQhRKju-1VUG5R67AZXRu7jbrtA8VcndU,4412
61
61
  job_shop_lib/visualization/_gantt_chart_creator.py,sha256=qFhCfk3oC3uF7Mau3lrNhH-34sfHXvkqEXbsDzrIbBk,7721
62
- job_shop_lib/visualization/_gantt_chart_video_and_gif_creation.py,sha256=XXRLpC05E3zY4SIytdFP2QuxmGA95VohUVmzoFzEt7Q,13206
63
- job_shop_lib-1.0.0a1.dist-info/LICENSE,sha256=9mggivMGd5taAu3xbmBway-VQZMBzurBGHofFopvUsQ,1069
64
- job_shop_lib-1.0.0a1.dist-info/METADATA,sha256=h5mdFHRaXbnL7F4lMjGNVE5-TSx35rvAG8SlzX3wWiU,14810
65
- job_shop_lib-1.0.0a1.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
66
- job_shop_lib-1.0.0a1.dist-info/RECORD,,
62
+ job_shop_lib/visualization/_gantt_chart_video_and_gif_creation.py,sha256=GQhQF2YzSRQT_DdUjJYHFKMZMjk_hPrYjQU5PpedNvs,13213
63
+ job_shop_lib-1.0.0a2.dist-info/LICENSE,sha256=9mggivMGd5taAu3xbmBway-VQZMBzurBGHofFopvUsQ,1069
64
+ job_shop_lib-1.0.0a2.dist-info/METADATA,sha256=IVDNFeNtFCpjUzIGXkEn0uQ3aBgJLSLXHuJKEgpBajI,14810
65
+ job_shop_lib-1.0.0a2.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
66
+ job_shop_lib-1.0.0a2.dist-info/RECORD,,