job-shop-lib 0.1.3__py3-none-any.whl → 0.2.0__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.
@@ -0,0 +1,164 @@
1
+ """Classes for generating transformed JobShopInstance objects."""
2
+
3
+ import abc
4
+ import copy
5
+ import random
6
+
7
+ from job_shop_lib import JobShopInstance, Operation
8
+
9
+
10
+ class Transformation(abc.ABC):
11
+ """Base class for transformations applied to JobShopInstance objects."""
12
+
13
+ def __init__(self, suffix: str = ""):
14
+ self.suffix = suffix
15
+ self.counter = 0
16
+
17
+ @abc.abstractmethod
18
+ def apply(self, instance: JobShopInstance) -> JobShopInstance:
19
+ """Applies the transformation to a given JobShopInstance.
20
+
21
+ Args:
22
+ instance: The JobShopInstance to transform.
23
+
24
+ Returns:
25
+ A new JobShopInstance with the transformation applied.
26
+ """
27
+
28
+ def __call__(self, instance: JobShopInstance) -> JobShopInstance:
29
+ instance = self.apply(instance)
30
+ suffix = f"{self.suffix}_id={self.counter}"
31
+ instance.name += suffix
32
+ self.counter += 1
33
+ return instance
34
+
35
+
36
+ # pylint: disable=too-few-public-methods
37
+ class RemoveMachines(Transformation):
38
+ """Removes operations associated with randomly selected machines until
39
+ there are exactly num_machines machines left."""
40
+
41
+ def __init__(self, num_machines: int, suffix: str | None = None):
42
+ if suffix is None:
43
+ suffix = f"_machines={num_machines}"
44
+ super().__init__(suffix=suffix)
45
+ self.num_machines = num_machines
46
+
47
+ def apply(self, instance: JobShopInstance) -> JobShopInstance:
48
+ if instance.num_machines <= self.num_machines:
49
+ return instance # No need to remove machines
50
+
51
+ # Select machine indices to keep
52
+ machines_to_keep = set(
53
+ random.sample(range(instance.num_machines), self.num_machines)
54
+ )
55
+
56
+ # Re-index machines
57
+ machine_reindex_map = {
58
+ old_id: new_id
59
+ for new_id, old_id in enumerate(sorted(machines_to_keep))
60
+ }
61
+
62
+ new_jobs = []
63
+ for job in instance.jobs:
64
+ # Keep operations whose machine_id is in machines_to_keep and
65
+ # re-index them
66
+ new_jobs.append(
67
+ [
68
+ Operation(machine_reindex_map[op.machine_id], op.duration)
69
+ for op in job
70
+ if op.machine_id in machines_to_keep
71
+ ]
72
+ )
73
+
74
+ return JobShopInstance(new_jobs, instance.name)
75
+
76
+
77
+ # pylint: disable=too-few-public-methods
78
+ class AddDurationNoise(Transformation):
79
+ """Adds uniform integer noise to operation durations."""
80
+
81
+ def __init__(
82
+ self,
83
+ min_duration: int = 1,
84
+ max_duration: int = 100,
85
+ noise_level: int = 10,
86
+ suffix: str | None = None,
87
+ ):
88
+ if suffix is None:
89
+ suffix = f"_noise={noise_level}"
90
+ super().__init__(suffix=suffix)
91
+ self.min_duration = min_duration
92
+ self.max_duration = max_duration
93
+ self.noise_level = noise_level
94
+
95
+ def apply(self, instance: JobShopInstance) -> JobShopInstance:
96
+ new_jobs = []
97
+ for job in instance.jobs:
98
+ new_job = []
99
+ for op in job:
100
+ noise = random.randint(-self.noise_level, self.noise_level)
101
+ new_duration = max(
102
+ self.min_duration,
103
+ min(self.max_duration, op.duration + noise),
104
+ )
105
+
106
+ new_job.append(Operation(op.machine_id, new_duration))
107
+ new_jobs.append(new_job)
108
+
109
+ return JobShopInstance(new_jobs, instance.name)
110
+
111
+
112
+ class RemoveJobs(Transformation):
113
+ """Removes jobs randomly until the number of jobs is within a specified
114
+ range."""
115
+
116
+ def __init__(
117
+ self,
118
+ min_jobs: int,
119
+ max_jobs: int,
120
+ target_jobs: int | None = None,
121
+ suffix: str | None = None,
122
+ ):
123
+ """
124
+ Args:
125
+ min_jobs: The minimum number of jobs to remain in the instance.
126
+ max_jobs: The maximum number of jobs to remain in the instance.
127
+ target_jobs: If specified, the number of jobs to remain in the
128
+ instance. Overrides min_jobs and max_jobs.
129
+ """
130
+ if suffix is None:
131
+ suffix = f"_jobs={min_jobs}-{max_jobs}"
132
+ super().__init__(suffix=suffix)
133
+ self.min_jobs = min_jobs
134
+ self.max_jobs = max_jobs
135
+ self.target_jobs = target_jobs
136
+
137
+ def apply(self, instance: JobShopInstance) -> JobShopInstance:
138
+ if self.target_jobs is None:
139
+ target_jobs = random.randint(self.min_jobs, self.max_jobs)
140
+ else:
141
+ target_jobs = self.target_jobs
142
+ new_jobs = copy.deepcopy(instance.jobs)
143
+
144
+ while len(new_jobs) > target_jobs:
145
+ new_jobs.pop(random.randint(0, len(new_jobs) - 1))
146
+
147
+ return JobShopInstance(new_jobs, instance.name)
148
+
149
+ @staticmethod
150
+ def remove_job(
151
+ instance: JobShopInstance, job_index: int
152
+ ) -> JobShopInstance:
153
+ """Removes a specific job from the instance.
154
+
155
+ Args:
156
+ instance: The JobShopInstance from which to remove the job.
157
+ job_index: The index of the job to remove.
158
+
159
+ Returns:
160
+ A new JobShopInstance with the specified job removed.
161
+ """
162
+ new_jobs = copy.deepcopy(instance.jobs)
163
+ new_jobs.pop(job_index)
164
+ return JobShopInstance(new_jobs, instance.name)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: job-shop-lib
3
- Version: 0.1.3
3
+ Version: 0.2.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
@@ -33,8 +33,6 @@ Description-Content-Type: text/markdown
33
33
 
34
34
  </div>
35
35
 
36
-
37
-
38
36
  An easy-to-use and modular Python library for the Job Shop Scheduling Problem (JSSP) with a special focus on graph representations.
39
37
 
40
38
  It provides intuitive data structures to represent instances and solutions, as well as solvers and visualization tools.
@@ -174,7 +172,7 @@ We can visualize the solution with a `DispatchingRuleSolver` as a gif:
174
172
 
175
173
  ```python
176
174
  from job_shop_lib.visualization import create_gif, get_plot_function
177
- from job_shop_lib.solvers import DispatchingRuleSolver, DispatchingRule
175
+ from job_shop_lib.dispatching import DispatchingRuleSolver, DispatchingRule
178
176
 
179
177
  plt.style.use("ggplot")
180
178
 
@@ -14,6 +14,7 @@ job_shop_lib/dispatching/pruning_functions.py,sha256=d94_uBHuESp4NSf_jBk1q8eBCfT
14
14
  job_shop_lib/exceptions.py,sha256=0Wla1lK6E2u1o3t2hJj9hUwyoJ-1ebkXd42GdXFAhV0,899
15
15
  job_shop_lib/generators/__init__.py,sha256=CrMExfhRbw_0TnYgJ1HwFmq13LEFYFU9wSFANmlSTSQ,154
16
16
  job_shop_lib/generators/basic_generator.py,sha256=pbRDQWC2mnHU0dbc-T8wkdwVeJPlRn06nhFXuwKataQ,7533
17
+ job_shop_lib/generators/transformations.py,sha256=FI2qHrETATJUrQP3-RYhZAQ5boyEZ0CF2StDbacBej8,5290
17
18
  job_shop_lib/graphs/__init__.py,sha256=mWyF0MypyYfvFhy2F93BJkFIVsxS_0ZqvPuc29B7TJg,1454
18
19
  job_shop_lib/graphs/build_agent_task_graph.py,sha256=ktj-oNLUPmWHfL81EVyaoF4hXClWYfnN7oG2Nn4pOsg,7128
19
20
  job_shop_lib/graphs/build_disjunctive_graph.py,sha256=IRMBtHw8aru5rYGz796-dc6QyaLJFh4LlPlN_BPSq5c,2877
@@ -29,7 +30,7 @@ job_shop_lib/visualization/agent_task_graph.py,sha256=G-c9eiawz6m9sdnDM1r-ZHz6K-
29
30
  job_shop_lib/visualization/create_gif.py,sha256=3j339wjgGZKLOyMWGdVqVBQu4WFDUhyualHx8b3CJMQ,6382
30
31
  job_shop_lib/visualization/disjunctive_graph.py,sha256=feiRAMxuG5CG2naO7I3HtcrSQw99yWxWzIGgZC_pxIs,5803
31
32
  job_shop_lib/visualization/gantt_chart.py,sha256=OyBMBnjSsRC769qXimJ3IIQWlssgPfx-nlVeSeU5sWY,4415
32
- job_shop_lib-0.1.3.dist-info/LICENSE,sha256=9mggivMGd5taAu3xbmBway-VQZMBzurBGHofFopvUsQ,1069
33
- job_shop_lib-0.1.3.dist-info/METADATA,sha256=eHS0PpOAZqCUNW0-eWPOydr_l4CQ_VpkTWBJhN6be9w,12622
34
- job_shop_lib-0.1.3.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
35
- job_shop_lib-0.1.3.dist-info/RECORD,,
33
+ job_shop_lib-0.2.0.dist-info/LICENSE,sha256=9mggivMGd5taAu3xbmBway-VQZMBzurBGHofFopvUsQ,1069
34
+ job_shop_lib-0.2.0.dist-info/METADATA,sha256=KWTHYD4dNAAzSmNRUoATnMKKvwtBudbMwcI4yAnCiqQ,12624
35
+ job_shop_lib-0.2.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
36
+ job_shop_lib-0.2.0.dist-info/RECORD,,