job-shop-lib 1.0.0b2__py3-none-any.whl → 1.0.0b4__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.
- job_shop_lib/__init__.py +1 -1
- job_shop_lib/graphs/__init__.py +3 -3
- job_shop_lib/reinforcement_learning/__init__.py +15 -1
- job_shop_lib/reinforcement_learning/_multi_job_shop_graph_env.py +2 -2
- job_shop_lib/reinforcement_learning/_resource_task_graph_observation.py +258 -0
- job_shop_lib/reinforcement_learning/_single_job_shop_graph_env.py +21 -2
- job_shop_lib/reinforcement_learning/_utils.py +77 -3
- {job_shop_lib-1.0.0b2.dist-info → job_shop_lib-1.0.0b4.dist-info}/METADATA +2 -6
- {job_shop_lib-1.0.0b2.dist-info → job_shop_lib-1.0.0b4.dist-info}/RECORD +11 -10
- {job_shop_lib-1.0.0b2.dist-info → job_shop_lib-1.0.0b4.dist-info}/LICENSE +0 -0
- {job_shop_lib-1.0.0b2.dist-info → job_shop_lib-1.0.0b4.dist-info}/WHEEL +0 -0
job_shop_lib/__init__.py
CHANGED
job_shop_lib/graphs/__init__.py
CHANGED
@@ -8,9 +8,9 @@ The main classes and functions available in this package are:
|
|
8
8
|
NodeType
|
9
9
|
build_disjunctive_graph
|
10
10
|
build_solved_disjunctive_graph
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
build_resource_task_graph
|
12
|
+
build_complete_resource_task_graph
|
13
|
+
build_resource_task_graph_with_jobs
|
14
14
|
|
15
15
|
"""
|
16
16
|
|
@@ -12,6 +12,9 @@
|
|
12
12
|
IdleTimeReward
|
13
13
|
RenderConfig
|
14
14
|
add_padding
|
15
|
+
create_edge_type_dict
|
16
|
+
ResourceTaskGraphObservation
|
17
|
+
ResourceTaskGraphObservationDict
|
15
18
|
|
16
19
|
"""
|
17
20
|
|
@@ -27,7 +30,11 @@ from job_shop_lib.reinforcement_learning._reward_observers import (
|
|
27
30
|
IdleTimeReward,
|
28
31
|
)
|
29
32
|
|
30
|
-
from job_shop_lib.reinforcement_learning._utils import
|
33
|
+
from job_shop_lib.reinforcement_learning._utils import (
|
34
|
+
add_padding,
|
35
|
+
create_edge_type_dict,
|
36
|
+
map_values,
|
37
|
+
)
|
31
38
|
|
32
39
|
from job_shop_lib.reinforcement_learning._single_job_shop_graph_env import (
|
33
40
|
SingleJobShopGraphEnv,
|
@@ -35,6 +42,9 @@ from job_shop_lib.reinforcement_learning._single_job_shop_graph_env import (
|
|
35
42
|
from job_shop_lib.reinforcement_learning._multi_job_shop_graph_env import (
|
36
43
|
MultiJobShopGraphEnv,
|
37
44
|
)
|
45
|
+
from ._resource_task_graph_observation import (
|
46
|
+
ResourceTaskGraphObservation, ResourceTaskGraphObservationDict
|
47
|
+
)
|
38
48
|
|
39
49
|
|
40
50
|
__all__ = [
|
@@ -47,4 +57,8 @@ __all__ = [
|
|
47
57
|
"ObservationDict",
|
48
58
|
"add_padding",
|
49
59
|
"MultiJobShopGraphEnv",
|
60
|
+
"create_edge_type_dict",
|
61
|
+
"ResourceTaskGraphObservation",
|
62
|
+
"map_values",
|
63
|
+
"ResourceTaskGraphObservationDict",
|
50
64
|
]
|
@@ -235,13 +235,13 @@ class MultiJobShopGraphEnv(gym.Env):
|
|
235
235
|
@ready_operations_filter.setter
|
236
236
|
def ready_operations_filter(
|
237
237
|
self,
|
238
|
-
|
238
|
+
ready_operations_filter: Callable[
|
239
239
|
[Dispatcher, List[Operation]], List[Operation]
|
240
240
|
],
|
241
241
|
) -> None:
|
242
242
|
"""Sets the ready operations filter."""
|
243
243
|
self.single_job_shop_graph_env.dispatcher.ready_operations_filter = (
|
244
|
-
|
244
|
+
ready_operations_filter
|
245
245
|
)
|
246
246
|
|
247
247
|
@property
|
@@ -0,0 +1,258 @@
|
|
1
|
+
"""Contains wrappers for the environments."""
|
2
|
+
|
3
|
+
from typing import TypeVar, TypedDict
|
4
|
+
from gymnasium import ObservationWrapper
|
5
|
+
import numpy as np
|
6
|
+
from numpy.typing import NDArray
|
7
|
+
|
8
|
+
from job_shop_lib.reinforcement_learning import (
|
9
|
+
ObservationDict,
|
10
|
+
SingleJobShopGraphEnv,
|
11
|
+
MultiJobShopGraphEnv,
|
12
|
+
create_edge_type_dict,
|
13
|
+
map_values,
|
14
|
+
)
|
15
|
+
from job_shop_lib.graphs import NodeType, JobShopGraph
|
16
|
+
from job_shop_lib.exceptions import ValidationError
|
17
|
+
from job_shop_lib.dispatching.feature_observers import FeatureType
|
18
|
+
|
19
|
+
T = TypeVar("T", bound=np.number)
|
20
|
+
|
21
|
+
|
22
|
+
class ResourceTaskGraphObservationDict(TypedDict):
|
23
|
+
"""Represents a dictionary for resource task graph observations."""
|
24
|
+
|
25
|
+
edge_index_dict: dict[str, NDArray[np.int64]]
|
26
|
+
node_features_dict: dict[str, NDArray[np.float32]]
|
27
|
+
original_ids_dict: dict[str, NDArray[np.int32]]
|
28
|
+
|
29
|
+
|
30
|
+
# pylint: disable=line-too-long
|
31
|
+
class ResourceTaskGraphObservation(ObservationWrapper):
|
32
|
+
"""Observation wrapper that converts an observation following the
|
33
|
+
:class:`ObservationDict` format to a format suitable to PyG's
|
34
|
+
[`HeteroData`](https://pytorch-geometric.readthedocs.io/en/latest/generated/torch_geometric.data.HeteroData.html).
|
35
|
+
|
36
|
+
In particular, the ``edge_index`` is converted into a ``edge_index_dict``
|
37
|
+
with keys ``(node_type_i, "to", node_type_j)``. The ``node_type_i`` and
|
38
|
+
``node_type_j`` are the node types of the source and target nodes,
|
39
|
+
respectively.
|
40
|
+
|
41
|
+
Attributes:
|
42
|
+
global_to_local_id: A dictionary mapping global node IDs to local node
|
43
|
+
IDs for each node type.
|
44
|
+
type_ranges: A dictionary mapping node type names to (start, end) index
|
45
|
+
ranges.
|
46
|
+
|
47
|
+
Args:
|
48
|
+
env: The environment to wrap.
|
49
|
+
"""
|
50
|
+
|
51
|
+
def __init__(self, env: SingleJobShopGraphEnv | MultiJobShopGraphEnv):
|
52
|
+
super().__init__(env)
|
53
|
+
self.global_to_local_id = self._compute_id_mappings()
|
54
|
+
self.type_ranges = self._compute_node_type_ranges()
|
55
|
+
|
56
|
+
@property
|
57
|
+
def job_shop_graph(self) -> JobShopGraph:
|
58
|
+
"""Returns the job shop graph from the environment.
|
59
|
+
|
60
|
+
Raises:
|
61
|
+
ValidationError: If the environment is not an instance of
|
62
|
+
``SingleJobShopGraphEnv`` or ``MultiJobShopGraphEnv``.
|
63
|
+
"""
|
64
|
+
if isinstance(self.env, (SingleJobShopGraphEnv, MultiJobShopGraphEnv)):
|
65
|
+
return self.env.job_shop_graph
|
66
|
+
raise ValidationError(
|
67
|
+
"The environment must be an instance of "
|
68
|
+
"SingleJobShopGraphEnv or MultiJobShopGraphEnv"
|
69
|
+
)
|
70
|
+
|
71
|
+
def step(self, action: tuple[int, int]):
|
72
|
+
"""Takes a step in the environment.
|
73
|
+
|
74
|
+
Args:
|
75
|
+
action:
|
76
|
+
The action to take. The action is a tuple of two integers
|
77
|
+
(job_id, machine_id):
|
78
|
+
the job ID and the machine ID in which to schedule the
|
79
|
+
operation.
|
80
|
+
|
81
|
+
Returns:
|
82
|
+
A tuple containing the following elements:
|
83
|
+
|
84
|
+
- The observation of the environment.
|
85
|
+
- The reward obtained.
|
86
|
+
- Whether the environment is done.
|
87
|
+
- Whether the episode was truncated (always False).
|
88
|
+
- A dictionary with additional information. The dictionary
|
89
|
+
contains the following keys: "feature_names", the names of the
|
90
|
+
features in the observation; and "available_operations_with_ids",
|
91
|
+
a list of available actions in the form of (operation_id,
|
92
|
+
machine_id, job_id).
|
93
|
+
"""
|
94
|
+
observation, reward, done, truncated, info = self.env.step(action)
|
95
|
+
return self.observation(observation), reward, done, truncated, info
|
96
|
+
|
97
|
+
def reset(self, *, seed: int | None = None, options: dict | None = None):
|
98
|
+
"""Resets the environment.
|
99
|
+
|
100
|
+
Args:
|
101
|
+
seed:
|
102
|
+
Added to match the signature of the parent class. It is not
|
103
|
+
used in this method.
|
104
|
+
options:
|
105
|
+
Additional options to pass to the environment. Not used in
|
106
|
+
this method.
|
107
|
+
|
108
|
+
Returns:
|
109
|
+
A tuple containing the following elements:
|
110
|
+
|
111
|
+
- The observation of the environment.
|
112
|
+
- A dictionary with additional information, keys
|
113
|
+
include: "feature_names", the names of the features in the
|
114
|
+
observation; and "available_operations_with_ids", a list of
|
115
|
+
available a list of available actions in the form of
|
116
|
+
(operation_id, machine_id, job_id).
|
117
|
+
"""
|
118
|
+
observation, info = self.env.reset()
|
119
|
+
return self.observation(observation), info
|
120
|
+
|
121
|
+
def _compute_id_mappings(self) -> dict[int, int]:
|
122
|
+
"""Computes mappings from global node IDs to type-local IDs.
|
123
|
+
|
124
|
+
Returns:
|
125
|
+
A dictionary mapping global node IDs to local node IDs for each
|
126
|
+
node type.
|
127
|
+
"""
|
128
|
+
mappings = {}
|
129
|
+
for node_type in NodeType:
|
130
|
+
type_nodes = self.job_shop_graph.nodes_by_type[node_type]
|
131
|
+
if not type_nodes:
|
132
|
+
continue
|
133
|
+
# Create mapping from global ID to local ID
|
134
|
+
# (0 to len(type_nodes)-1)
|
135
|
+
type_mapping = {
|
136
|
+
node.node_id: local_id
|
137
|
+
for local_id, node in enumerate(type_nodes)
|
138
|
+
}
|
139
|
+
mappings.update(type_mapping)
|
140
|
+
|
141
|
+
return mappings
|
142
|
+
|
143
|
+
def _compute_node_type_ranges(self) -> dict[str, tuple[int, int]]:
|
144
|
+
"""Computes index ranges for each node type.
|
145
|
+
|
146
|
+
Returns:
|
147
|
+
Dictionary mapping node type names to (start, end) index ranges
|
148
|
+
"""
|
149
|
+
type_ranges = {}
|
150
|
+
for node_type in NodeType:
|
151
|
+
type_nodes = self.job_shop_graph.nodes_by_type[node_type]
|
152
|
+
if not type_nodes:
|
153
|
+
continue
|
154
|
+
start = min(node.node_id for node in type_nodes)
|
155
|
+
end = max(node.node_id for node in type_nodes) + 1
|
156
|
+
type_ranges[node_type.name.lower()] = (start, end)
|
157
|
+
|
158
|
+
return type_ranges
|
159
|
+
|
160
|
+
def observation(self, observation: ObservationDict):
|
161
|
+
edge_index_dict = create_edge_type_dict(
|
162
|
+
observation["edge_index"],
|
163
|
+
type_ranges=self.type_ranges,
|
164
|
+
relationship="to",
|
165
|
+
)
|
166
|
+
# mapping from global node ID to local node ID
|
167
|
+
for key, edge_index in edge_index_dict.items():
|
168
|
+
edge_index_dict[key] = map_values(
|
169
|
+
edge_index, self.global_to_local_id
|
170
|
+
)
|
171
|
+
node_features_dict = self._create_node_features_dict(observation)
|
172
|
+
node_features_dict, original_ids_dict = self._remove_nodes(
|
173
|
+
node_features_dict, observation["removed_nodes"]
|
174
|
+
)
|
175
|
+
|
176
|
+
return {
|
177
|
+
"edge_index_dict": edge_index_dict,
|
178
|
+
"node_features_dict": node_features_dict,
|
179
|
+
"original_ids_dict": original_ids_dict,
|
180
|
+
}
|
181
|
+
|
182
|
+
def _create_node_features_dict(
|
183
|
+
self, observation: ObservationDict
|
184
|
+
) -> dict[str, NDArray]:
|
185
|
+
"""Creates a dictionary of node features for each node type.
|
186
|
+
|
187
|
+
Args:
|
188
|
+
observation: The observation dictionary.
|
189
|
+
|
190
|
+
Returns:
|
191
|
+
Dictionary mapping node type names to node features.
|
192
|
+
"""
|
193
|
+
node_type_to_feature_type = {
|
194
|
+
NodeType.OPERATION: FeatureType.OPERATIONS,
|
195
|
+
NodeType.MACHINE: FeatureType.MACHINES,
|
196
|
+
NodeType.JOB: FeatureType.JOBS,
|
197
|
+
}
|
198
|
+
node_features_dict = {}
|
199
|
+
for node_type, feature_type in node_type_to_feature_type.items():
|
200
|
+
if node_type in self.job_shop_graph.nodes_by_type:
|
201
|
+
node_features_dict[feature_type.value] = observation[
|
202
|
+
feature_type.value
|
203
|
+
]
|
204
|
+
continue
|
205
|
+
if feature_type != FeatureType.JOBS:
|
206
|
+
continue
|
207
|
+
assert FeatureType.OPERATIONS.value in observation
|
208
|
+
job_features = observation[
|
209
|
+
feature_type.value # type: ignore[literal-required]
|
210
|
+
]
|
211
|
+
job_ids_of_ops = [
|
212
|
+
node.operation.job_id
|
213
|
+
for node in self.job_shop_graph.nodes_by_type[
|
214
|
+
NodeType.OPERATION
|
215
|
+
]
|
216
|
+
]
|
217
|
+
job_features_expanded = job_features[job_ids_of_ops]
|
218
|
+
operation_features = observation[FeatureType.OPERATIONS.value]
|
219
|
+
node_features_dict[FeatureType.OPERATIONS.value] = np.concatenate(
|
220
|
+
(operation_features, job_features_expanded), axis=1
|
221
|
+
)
|
222
|
+
return node_features_dict
|
223
|
+
|
224
|
+
def _remove_nodes(
|
225
|
+
self,
|
226
|
+
node_features_dict: dict[str, NDArray[np.float32]],
|
227
|
+
removed_nodes: NDArray[np.bool_],
|
228
|
+
) -> tuple[dict[str, NDArray[np.float32]], dict[str, NDArray[np.int32]]]:
|
229
|
+
"""Removes nodes from the node features dictionary.
|
230
|
+
|
231
|
+
Args:
|
232
|
+
node_features_dict: The node features dictionary.
|
233
|
+
|
234
|
+
Returns:
|
235
|
+
The node features dictionary with the nodes removed and a
|
236
|
+
dictionary containing the original node ids.
|
237
|
+
"""
|
238
|
+
removed_nodes_dict: dict[str, NDArray[np.float32]] = {}
|
239
|
+
original_ids_dict: dict[str, NDArray[np.int32]] = {}
|
240
|
+
feature_type_to_node_type = {
|
241
|
+
FeatureType.OPERATIONS.value: NodeType.OPERATION,
|
242
|
+
FeatureType.MACHINES.value: NodeType.MACHINE,
|
243
|
+
FeatureType.JOBS.value: NodeType.JOB,
|
244
|
+
}
|
245
|
+
for feature_type, features in node_features_dict.items():
|
246
|
+
node_type = feature_type_to_node_type[feature_type].name.lower()
|
247
|
+
if node_type not in self.type_ranges:
|
248
|
+
continue
|
249
|
+
start, end = self.type_ranges[node_type]
|
250
|
+
removed_nodes_of_this_type = removed_nodes[start:end]
|
251
|
+
removed_nodes_dict[node_type] = features[
|
252
|
+
~removed_nodes_of_this_type
|
253
|
+
]
|
254
|
+
original_ids_dict[node_type] = np.where(
|
255
|
+
~removed_nodes_of_this_type
|
256
|
+
)[0]
|
257
|
+
|
258
|
+
return removed_nodes_dict, original_ids_dict
|
@@ -243,8 +243,27 @@ class SingleJobShopGraphEnv(gym.Env):
|
|
243
243
|
*,
|
244
244
|
seed: Optional[int] = None,
|
245
245
|
options: Optional[Dict[str, Any]] = None,
|
246
|
-
) -> Tuple[ObservationDict, dict]:
|
247
|
-
"""Resets the environment.
|
246
|
+
) -> Tuple[ObservationDict, dict[str, Any]]:
|
247
|
+
"""Resets the environment.
|
248
|
+
|
249
|
+
Args:
|
250
|
+
seed:
|
251
|
+
Added to match the signature of the parent class. It is not
|
252
|
+
used in this method.
|
253
|
+
options:
|
254
|
+
Additional options to pass to the environment. Not used in
|
255
|
+
this method.
|
256
|
+
|
257
|
+
Returns:
|
258
|
+
A tuple containing the following elements:
|
259
|
+
|
260
|
+
- The observation of the environment.
|
261
|
+
- A dictionary with additional information, keys
|
262
|
+
include: "feature_names", the names of the features in the
|
263
|
+
observation; and "available_operations_with_ids", a list of
|
264
|
+
available a list of available actions in the form of
|
265
|
+
(operation_id, machine_id, job_id).
|
266
|
+
"""
|
248
267
|
super().reset(seed=seed, options=options)
|
249
268
|
self.dispatcher.reset()
|
250
269
|
obs = self.get_observation()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
"""Utility functions for reinforcement learning."""
|
2
2
|
|
3
|
-
from typing import TypeVar, Any,
|
3
|
+
from typing import TypeVar, Any, Type
|
4
4
|
|
5
5
|
import numpy as np
|
6
6
|
from numpy.typing import NDArray
|
@@ -12,9 +12,9 @@ T = TypeVar("T", bound=np.number)
|
|
12
12
|
|
13
13
|
def add_padding(
|
14
14
|
array: NDArray[Any],
|
15
|
-
output_shape:
|
15
|
+
output_shape: tuple[int, ...],
|
16
16
|
padding_value: float = -1,
|
17
|
-
dtype:
|
17
|
+
dtype: Type[T] | None = None,
|
18
18
|
) -> NDArray[T]:
|
19
19
|
"""Adds padding to the array.
|
20
20
|
|
@@ -90,6 +90,80 @@ def add_padding(
|
|
90
90
|
return padded_array
|
91
91
|
|
92
92
|
|
93
|
+
def create_edge_type_dict(
|
94
|
+
edge_index: NDArray[T],
|
95
|
+
type_ranges: dict[str, tuple[int, int]],
|
96
|
+
relationship: str = "to",
|
97
|
+
) -> dict[tuple[str, str, str], NDArray[T]]:
|
98
|
+
"""Organizes edges based on node types.
|
99
|
+
|
100
|
+
Args:
|
101
|
+
edge_index:
|
102
|
+
numpy array of shape (2, E) where E is number of edges
|
103
|
+
type_ranges: dict[str, tuple[int, int]]
|
104
|
+
Dictionary mapping type names to their corresponding index ranges
|
105
|
+
[start, end) in the ``edge_index`` array.
|
106
|
+
relationship:
|
107
|
+
A string representing the relationship type between nodes.
|
108
|
+
|
109
|
+
Returns:
|
110
|
+
A dictionary with keys (type_i, relationship, type_j) and values as
|
111
|
+
edge indices
|
112
|
+
"""
|
113
|
+
edge_index_dict: dict[tuple[str, str, str], NDArray] = {}
|
114
|
+
for type_name_i, (start_i, end_i) in type_ranges.items():
|
115
|
+
for type_name_j, (start_j, end_j) in type_ranges.items():
|
116
|
+
key: tuple[str, str, str] = (
|
117
|
+
type_name_i,
|
118
|
+
relationship,
|
119
|
+
type_name_j,
|
120
|
+
)
|
121
|
+
# Find edges where source is in type_i and target is in type_j
|
122
|
+
mask = (
|
123
|
+
(edge_index[0] >= start_i)
|
124
|
+
& (edge_index[0] < end_i)
|
125
|
+
& (edge_index[1] >= start_j)
|
126
|
+
& (edge_index[1] < end_j)
|
127
|
+
)
|
128
|
+
edge_index_dict[key] = edge_index[:, mask]
|
129
|
+
|
130
|
+
return edge_index_dict
|
131
|
+
|
132
|
+
|
133
|
+
def map_values(array: NDArray[T], mapping: dict[int, int]) -> NDArray[T]:
|
134
|
+
"""Maps values in an array using a mapping.
|
135
|
+
|
136
|
+
Args:
|
137
|
+
array:
|
138
|
+
An NumPy array.
|
139
|
+
|
140
|
+
Returns:
|
141
|
+
A NumPy array where each element has been replaced by its
|
142
|
+
corresponding value from the mapping.
|
143
|
+
|
144
|
+
Raises:
|
145
|
+
ValidationError:
|
146
|
+
If the array contains values that are not in the mapping.
|
147
|
+
|
148
|
+
Examples:
|
149
|
+
>>> map_values(np.array([1, 2, 3]), {1: 10, 2: 20, 3: 30})
|
150
|
+
array([10, 20, 30])
|
151
|
+
|
152
|
+
>>> map_values(np.array([1, 2]), {1: 10, 2: 10, 3: 30})
|
153
|
+
array([10, 10])
|
154
|
+
|
155
|
+
"""
|
156
|
+
if array.size == 0:
|
157
|
+
return array
|
158
|
+
try:
|
159
|
+
vectorized_mapping = np.vectorize(mapping.get)
|
160
|
+
return vectorized_mapping(array)
|
161
|
+
except TypeError as e:
|
162
|
+
raise ValidationError(
|
163
|
+
"The array contains values that are not in the mapping."
|
164
|
+
) from e
|
165
|
+
|
166
|
+
|
93
167
|
if __name__ == "__main__":
|
94
168
|
import doctest
|
95
169
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: job-shop-lib
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.0b4
|
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
|
@@ -60,7 +60,7 @@ See [this](https://colab.research.google.com/drive/1XV_Rvq1F2ns6DFG8uNj66q_rcoww
|
|
60
60
|
Version 1.0.0 is currently in beta stage and can be installed with:
|
61
61
|
|
62
62
|
```bash
|
63
|
-
pip install job-shop-lib==1.0.
|
63
|
+
pip install job-shop-lib==1.0.0b4
|
64
64
|
```
|
65
65
|
|
66
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)). There is a [documentation page](https://job-shop-lib.readthedocs.io/en/latest/) for versions 1.0.0a3 and onward.
|
@@ -89,11 +89,7 @@ Although this version is not stable and may contain breaking changes in subseque
|
|
89
89
|
- **Agent-Task Graphs**: Encode instances as agent-task graphs (introduced in [ScheduleNet paper](https://arxiv.org/abs/2106.03051)). See [Agent-Task Graph](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/examples/07-Agent-Task-Graph.ipynb).
|
90
90
|
- Build your own custom graphs with the `JobShopGraph` class.
|
91
91
|
|
92
|
-
<<<<<<< HEAD
|
93
92
|
- **Gymnasium Environments**: Two environments for solving the problem with graph neural networks (GNNs) or any other method, and reinforcement learning (RL). See [SingleJobShopGraphEnv](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/examples/09-SingleJobShopGraphEnv.ipynb) and [MultiJobShopGraphEnv](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/examples/10-MultiJobShopGraphEnv.ipynb).
|
94
|
-
=======
|
95
|
-
- **Gymnasium Environments**: Two environments for solving the problem with Graph Neural Networks (GNNs) or any other method, and Reinforcement Learning (RL). See [SingleJobShopGraphEnv](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/examples/09-SingleJobShopGraphEnv.ipynb) and [MultiJobShopGraphEnv](https://github.com/Pabloo22/job_shop_lib/blob/main/docs/source/examples/10-MultiJobShopGraphEnv.ipynb).
|
96
|
-
>>>>>>> 031bdf3 ([Docs] Update links in README to point to the correct GitHub URLs for tutorials and examples)
|
97
93
|
|
98
94
|
<!-- end key features -->
|
99
95
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
job_shop_lib/__init__.py,sha256=
|
1
|
+
job_shop_lib/__init__.py,sha256=I9Ifdoq10hPCyLVpLFUKHTjSldDRCqJx-raUQKid0aw,643
|
2
2
|
job_shop_lib/_base_solver.py,sha256=p17XmtufNc9Y481cqZUT45pEkUmmW1HWG53dfhIBJH8,1363
|
3
3
|
job_shop_lib/_job_shop_instance.py,sha256=hNQGSJj0rEQpS-YhzwWmM6QzCWp6r--89jkghSgLvUs,18380
|
4
4
|
job_shop_lib/_operation.py,sha256=hx2atpP8LPj9fvxpZIfhBFr9Uq6JP-MKAX5JzTvFXso,3847
|
@@ -40,7 +40,7 @@ job_shop_lib/generation/_general_instance_generator.py,sha256=e-NDkH-NoCwa14oADj
|
|
40
40
|
job_shop_lib/generation/_instance_generator.py,sha256=VV0OKX4JgFq3I1EY6s3LrOdPjM3v4lH6S1hkUebTkFQ,4615
|
41
41
|
job_shop_lib/generation/_transformations.py,sha256=X-hTAJVIHZ3bmF1rqS0zCit8r5SGpHpV8Fcl92fejow,5336
|
42
42
|
job_shop_lib/generation/_utils.py,sha256=cBhGILE0FE3TqvWoHqpaFEffO8D2fb869pF-BdMlYsg,3617
|
43
|
-
job_shop_lib/graphs/__init__.py,sha256=
|
43
|
+
job_shop_lib/graphs/__init__.py,sha256=RI9vGUR_89X34UoHpl1HYZpxT8JOWg8dwZTe5ImDCVg,1849
|
44
44
|
job_shop_lib/graphs/_build_disjunctive_graph.py,sha256=UbUYdeQaaeEqLchcKJGHEFGl4wElfGLb1o_R-u8wqnA,5120
|
45
45
|
job_shop_lib/graphs/_build_resource_task_graphs.py,sha256=GHUHkUNPxVf1miScgPPMe2YqlXFEMxIy5cDhNw7OZ1E,6954
|
46
46
|
job_shop_lib/graphs/_constants.py,sha256=K-GeVvh_DTWpo1KOX1clmxWS_pkUJbq19yOBmrCVIxI,1086
|
@@ -50,12 +50,13 @@ job_shop_lib/graphs/graph_updaters/__init__.py,sha256=UhnZL55e3cAv7hVetB6bRmIOn8
|
|
50
50
|
job_shop_lib/graphs/graph_updaters/_graph_updater.py,sha256=j1f7iWsa62GVszK2BPaMxnKBCEGWa9owm8g4VWUje8w,1967
|
51
51
|
job_shop_lib/graphs/graph_updaters/_residual_graph_updater.py,sha256=SfgmDyMwfW56OBjJPaU76c42IsX5qx9j-eMtrv0DjKk,6047
|
52
52
|
job_shop_lib/graphs/graph_updaters/_utils.py,sha256=X5YfwJA1CCgpm1r9C036Gal2CkDh2SSak7wl7TbdjHw,704
|
53
|
-
job_shop_lib/reinforcement_learning/__init__.py,sha256=
|
54
|
-
job_shop_lib/reinforcement_learning/_multi_job_shop_graph_env.py,sha256=
|
53
|
+
job_shop_lib/reinforcement_learning/__init__.py,sha256=opqJyVJ6VPyeaQOQr4hmUTkiUAXOi5tbyCnuNw5jLTI,1421
|
54
|
+
job_shop_lib/reinforcement_learning/_multi_job_shop_graph_env.py,sha256=memQefVWqatRNodt8hBXVvFcgQKJRmnuB8AWqiDl8_k,15746
|
55
|
+
job_shop_lib/reinforcement_learning/_resource_task_graph_observation.py,sha256=C4sEssy4TqHdr6nLJlg7Cdg48RBRSvmkYDzG1vaTf6U,9920
|
55
56
|
job_shop_lib/reinforcement_learning/_reward_observers.py,sha256=iWHccnujeAKyTQn2ilQ4BhcEccoSTyJqQ5yOiP5GG_Y,2984
|
56
|
-
job_shop_lib/reinforcement_learning/_single_job_shop_graph_env.py,sha256=
|
57
|
+
job_shop_lib/reinforcement_learning/_single_job_shop_graph_env.py,sha256=3mljeI4k9haLDuDZZhv4NcLpb1_xOlQNdEqMoRsh6bw,16592
|
57
58
|
job_shop_lib/reinforcement_learning/_types_and_constants.py,sha256=xozdM_Wabdbe9e1a769p5980OSNBwQqc9yyaSGW2ODQ,1743
|
58
|
-
job_shop_lib/reinforcement_learning/_utils.py,sha256=
|
59
|
+
job_shop_lib/reinforcement_learning/_utils.py,sha256=giikAj9Xl2f_cYq_AKCrgHn79TRLfGhYNqXz7bEnKuk,4827
|
59
60
|
job_shop_lib/visualization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
60
61
|
job_shop_lib/visualization/gantt/__init__.py,sha256=HGXwRgDuMAldqU0JBdiZCd5e79XBz1r96qHeDVlzE54,1145
|
61
62
|
job_shop_lib/visualization/gantt/_gantt_chart_creator.py,sha256=LTsVhpB1Fb_2o08HRZPPXSekwzR7fyTSC6h549XMqhU,8638
|
@@ -64,7 +65,7 @@ job_shop_lib/visualization/gantt/_plot_gantt_chart.py,sha256=9-NSSNsVcW8gYLZtAuF
|
|
64
65
|
job_shop_lib/visualization/graphs/__init__.py,sha256=282hZFg07EyQu4HVt4GzFfYnY6ZF376IMjnWZ5eg0ZQ,611
|
65
66
|
job_shop_lib/visualization/graphs/_plot_disjunctive_graph.py,sha256=4VBMYiFXXkCGSnGYN9iqNtWrbLJQxAMHojPHhAbdA0s,14387
|
66
67
|
job_shop_lib/visualization/graphs/_plot_resource_task_graph.py,sha256=RgJqHS5hJh3KkyaLbtpG_bER981BFRwGpflz7I7gS64,13271
|
67
|
-
job_shop_lib-1.0.
|
68
|
-
job_shop_lib-1.0.
|
69
|
-
job_shop_lib-1.0.
|
70
|
-
job_shop_lib-1.0.
|
68
|
+
job_shop_lib-1.0.0b4.dist-info/LICENSE,sha256=9mggivMGd5taAu3xbmBway-VQZMBzurBGHofFopvUsQ,1069
|
69
|
+
job_shop_lib-1.0.0b4.dist-info/METADATA,sha256=9tz-kjhEJIDvEjr5B69IOBI6_gREvO53E1sAN0iKFQk,16424
|
70
|
+
job_shop_lib-1.0.0b4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
71
|
+
job_shop_lib-1.0.0b4.dist-info/RECORD,,
|
File without changes
|
File without changes
|