job-shop-lib 0.3.0__tar.gz → 0.4.0__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/PKG-INFO +1 -1
  2. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/dispatching/dispatcher.py +8 -15
  3. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/operation.py +4 -4
  4. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/schedule.py +96 -1
  5. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/scheduled_operation.py +17 -5
  6. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/pyproject.toml +1 -1
  7. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/LICENSE +0 -0
  8. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/README.md +0 -0
  9. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/__init__.py +0 -0
  10. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/base_solver.py +0 -0
  11. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/benchmarking/__init__.py +0 -0
  12. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/benchmarking/benchmark_instances.json +0 -0
  13. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/benchmarking/load_benchmark.py +0 -0
  14. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/cp_sat/__init__.py +0 -0
  15. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/cp_sat/ortools_solver.py +0 -0
  16. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/dispatching/__init__.py +0 -0
  17. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/dispatching/dispatching_rule_solver.py +0 -0
  18. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/dispatching/dispatching_rules.py +0 -0
  19. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/dispatching/factories.py +0 -0
  20. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/dispatching/history_tracker.py +0 -0
  21. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/dispatching/pruning_functions.py +0 -0
  22. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/exceptions.py +0 -0
  23. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/generators/__init__.py +0 -0
  24. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/generators/basic_generator.py +0 -0
  25. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/generators/transformations.py +0 -0
  26. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/graphs/__init__.py +0 -0
  27. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/graphs/build_agent_task_graph.py +0 -0
  28. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/graphs/build_disjunctive_graph.py +0 -0
  29. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/graphs/constants.py +0 -0
  30. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/graphs/job_shop_graph.py +0 -0
  31. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/graphs/node.py +0 -0
  32. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/job_shop_instance.py +0 -0
  33. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/visualization/__init__.py +0 -0
  34. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/visualization/agent_task_graph.py +0 -0
  35. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/visualization/create_gif.py +0 -0
  36. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/visualization/disjunctive_graph.py +0 -0
  37. {job_shop_lib-0.3.0 → job_shop_lib-0.4.0}/job_shop_lib/visualization/gantt_chart.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: job-shop-lib
3
- Version: 0.3.0
3
+ Version: 0.4.0
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
@@ -7,6 +7,7 @@ from typing import Any
7
7
  from collections.abc import Callable
8
8
  from collections import deque
9
9
  from functools import wraps
10
+ from warnings import warn
10
11
 
11
12
  from job_shop_lib import (
12
13
  JobShopInstance,
@@ -155,21 +156,13 @@ class Dispatcher:
155
156
  def create_schedule_from_raw_solution(
156
157
  cls, instance: JobShopInstance, raw_solution: list[list[Operation]]
157
158
  ) -> Schedule:
158
- """Creates a schedule from a raw solution.
159
-
160
- A raw solution is a list of lists of operations, where each list
161
- represents the order of operations for a machine.
162
-
163
- Args:
164
- instance:
165
- The instance of the job shop problem to be solved.
166
- raw_solution:
167
- A list of lists of operations, where each list represents the
168
- order of operations for a machine.
169
-
170
- Returns:
171
- A Schedule object representing the solution.
172
- """
159
+ """Deprecated method, use `Schedule.from_job_sequences` instead."""
160
+ warn(
161
+ "Dispatcher.create_schedule_from_raw_solution is deprecated. "
162
+ "Use Schedule.from_job_sequences instead. It will be removed in "
163
+ "version 1.0.0.",
164
+ DeprecationWarning,
165
+ )
173
166
  dispatcher = cls(instance)
174
167
  dispatcher.reset()
175
168
  raw_solution_deques = [
@@ -107,10 +107,10 @@ class Operation:
107
107
  def __hash__(self) -> int:
108
108
  return hash(self.operation_id)
109
109
 
110
- def __eq__(self, __value: object) -> bool:
111
- if isinstance(__value, Operation):
112
- return self.operation_id == __value.operation_id
113
- return False
110
+ def __eq__(self, value: object) -> bool:
111
+ if not isinstance(value, Operation):
112
+ return False
113
+ return self.__slots__ == value.__slots__
114
114
 
115
115
  def __repr__(self) -> str:
116
116
  machines = (
@@ -1,6 +1,11 @@
1
1
  """Home of the `Schedule` class."""
2
2
 
3
- from job_shop_lib import ScheduledOperation, JobShopInstance
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+ from collections import deque
7
+
8
+ from job_shop_lib import ScheduledOperation, JobShopInstance, JobShopLibError
4
9
 
5
10
 
6
11
  class Schedule:
@@ -71,6 +76,96 @@ class Schedule:
71
76
  """Returns the number of operations that have been scheduled."""
72
77
  return sum(len(machine_schedule) for machine_schedule in self.schedule)
73
78
 
79
+ def to_dict(self) -> dict:
80
+ """Returns a dictionary representation of the schedule.
81
+
82
+ This representation is useful for saving the instance to a JSON file.
83
+
84
+ Returns:
85
+ A dictionary representation of the schedule with the following
86
+ keys:
87
+ - "instance": A dictionary representation of the instance.
88
+ - "job_sequences": A list of lists of job ids. Each list of job
89
+ ids represents the order of operations on the machine. The
90
+ machine that the list corresponds to is determined by the
91
+ index of the list.
92
+ - "metadata": A dictionary with additional information about
93
+ the schedule.
94
+ """
95
+ job_sequences: list[list[int]] = []
96
+ for machine_schedule in self.schedule:
97
+ job_sequences.append(
98
+ [operation.job_id for operation in machine_schedule]
99
+ )
100
+
101
+ return {
102
+ "instance": self.instance.to_dict(),
103
+ "job_sequences": job_sequences,
104
+ "metadata": self.metadata,
105
+ }
106
+
107
+ @staticmethod
108
+ def from_dict(
109
+ instance: dict[str, Any] | JobShopInstance,
110
+ job_sequences: list[list[int]],
111
+ metadata: dict[str, Any] | None = None,
112
+ ) -> Schedule:
113
+ """Creates a schedule from a dictionary representation."""
114
+ if isinstance(instance, dict):
115
+ instance = JobShopInstance.from_matrices(**instance)
116
+ schedule = Schedule.from_job_sequences(instance, job_sequences)
117
+ schedule.metadata = metadata if metadata is not None else {}
118
+ return schedule
119
+
120
+ @staticmethod
121
+ def from_job_sequences(
122
+ instance: JobShopInstance,
123
+ job_sequences: list[list[int]],
124
+ ) -> Schedule:
125
+ """Creates an active schedule from a list of job sequences.
126
+
127
+ An active schedule is the optimal schedule for the given job sequences.
128
+ In other words, it is not possible to construct another schedule,
129
+ through changes in the order of processing on the machines, with at
130
+ least one operation finishing earlier and no operation finishing later.
131
+
132
+ Args:
133
+ instance:
134
+ The `JobShopInstance` object that the schedule is for.
135
+ job_sequences:
136
+ A list of lists of job ids. Each list of job ids represents the
137
+ order of operations on the machine. The machine that the list
138
+ corresponds to is determined by the index of the list.
139
+
140
+ Returns:
141
+ A `Schedule` object with the given job sequences.
142
+ """
143
+ from job_shop_lib.dispatching import Dispatcher
144
+
145
+ dispatcher = Dispatcher(instance)
146
+ dispatcher.reset()
147
+ raw_solution_deques = [deque(job_ids) for job_ids in job_sequences]
148
+
149
+ while not dispatcher.schedule.is_complete():
150
+ at_least_one_operation_scheduled = False
151
+ for machine_id, job_ids in enumerate(raw_solution_deques):
152
+ if not job_ids:
153
+ continue
154
+ job_id = job_ids[0]
155
+ operation_index = dispatcher.job_next_operation_index[job_id]
156
+ operation = instance.jobs[job_id][operation_index]
157
+ is_ready = dispatcher.is_operation_ready(operation)
158
+ if is_ready and machine_id in operation.machines:
159
+ dispatcher.dispatch(operation, machine_id)
160
+ job_ids.popleft()
161
+ at_least_one_operation_scheduled = True
162
+
163
+ if not at_least_one_operation_scheduled:
164
+ raise JobShopLibError(
165
+ "Invalid job sequences. No valid operation to schedule."
166
+ )
167
+ return dispatcher.schedule
168
+
74
169
  def reset(self):
75
170
  """Resets the schedule to an empty state."""
76
171
  self.schedule = [[] for _ in range(self.instance.num_machines)]
@@ -1,6 +1,8 @@
1
1
  """Home of the `ScheduledOperation` class."""
2
2
 
3
- from job_shop_lib import Operation
3
+ from warnings import warn
4
+
5
+ from job_shop_lib import Operation, JobShopLibError
4
6
 
5
7
 
6
8
  class ScheduledOperation:
@@ -47,7 +49,7 @@ class ScheduledOperation:
47
49
  @machine_id.setter
48
50
  def machine_id(self, value: int):
49
51
  if value not in self.operation.machines:
50
- raise ValueError(
52
+ raise JobShopLibError(
51
53
  f"Operation cannot be scheduled on machine {value}. "
52
54
  f"Valid machines are {self.operation.machines}."
53
55
  )
@@ -62,18 +64,28 @@ class ScheduledOperation:
62
64
  """
63
65
 
64
66
  if self.operation.job_id is None:
65
- raise ValueError("Operation has no job_id.")
67
+ raise JobShopLibError("Operation has no job_id.")
66
68
  return self.operation.job_id
67
69
 
68
70
  @property
69
71
  def position(self) -> int:
72
+ """Deprecated. Use `position_in_job` instead."""
73
+ warn(
74
+ "The `position` attribute is deprecated. Use `position_in_job` "
75
+ "instead. It will be removed in version 1.0.0.",
76
+ DeprecationWarning,
77
+ )
78
+ return self.position_in_job
79
+
80
+ @property
81
+ def position_in_job(self) -> int:
70
82
  """Returns the position (starting at zero) of the operation in the job.
71
83
 
72
84
  Raises:
73
85
  ValueError: If the operation has no position_in_job.
74
86
  """
75
87
  if self.operation.position_in_job is None:
76
- raise ValueError("Operation has no position.")
88
+ raise JobShopLibError("Operation has no position.")
77
89
  return self.operation.position_in_job
78
90
 
79
91
  @property
@@ -91,7 +103,7 @@ class ScheduledOperation:
91
103
  if not isinstance(value, ScheduledOperation):
92
104
  return False
93
105
  return (
94
- self.operation is value.operation
106
+ self.operation == value.operation
95
107
  and self.start_time == value.start_time
96
108
  and self.machine_id == value.machine_id
97
109
  )
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "job-shop-lib"
3
- version = "0.3.0"
3
+ version = "0.4.0"
4
4
  description = "An easy-to-use and modular Python library for the Job Shop Scheduling Problem (JSSP)"
5
5
  authors = ["Pabloo22 <pablete.arino@gmail.com>"]
6
6
  license = "MIT"
File without changes
File without changes