Skip to content

Commit b67f47e

Browse files
committed
Adds NEH Implementation to flowshop methods
1 parent e729b04 commit b67f47e

File tree

1 file changed

+98
-36
lines changed

1 file changed

+98
-36
lines changed

flowshop.py

Lines changed: 98 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -129,47 +129,108 @@ def palmer_f(x): return -(self.nb_machines - (2*x - 1))
129129
opt_makespan = int(schedules[self.nb_machines-1][-1]["end_time"])
130130
return h_seq, schedules, opt_makespan
131131

132-
def neh(self):
133-
raise NotImplementedError
132+
def _get_makespan(self, seq, data):
133+
c = np.zeros((self.nb_machines, len(seq)), dtype=object)
134+
c[0][0] = (0, data[0][seq[0]])
135+
for m_id in range(1, self.nb_machines):
136+
s_t = c[m_id-1][0][1]
137+
e_t = s_t + data[m_id][0]
138+
c[m_id][0] = (s_t, e_t)
139+
if len(seq) > 1:
140+
for i, job_id in enumerate(seq[1::]):
141+
s_t = c[0][i][1]
142+
e_t = s_t + data[0][job_id]
143+
c[0][i+1] = (s_t, e_t)
144+
for m_id in range(1, self.nb_machines):
145+
s_t = max(c[m_id][i][1], c[m_id-1][i+1][1])
146+
e_t = s_t + data[m_id][job_id]
147+
c[m_id][i+1] = (s_t, e_t)
148+
149+
return c[self.nb_machines-1][-1][1]
150+
151+
152+
def neh_heuristic(self):
153+
sums = []
154+
for job_id in range(self.nb_jobs):
155+
p_ij = sum([self.data[j][job_id]
156+
for j in range(self.nb_machines)])
157+
sums.append((job_id, p_ij))
158+
sums.sort(key=lambda x: x[1], reverse=True)
159+
order_seq = [x[0] for x in sums]
160+
seq = [order_seq[0]]
161+
for i in range(1, self.nb_jobs):
162+
min_mkspan = float("inf")
163+
for j in range(0, i+1):
164+
tempo_seq = seq[:]
165+
tempo_seq.insert(j, order_seq[i])
166+
max_mkspn = self._get_makespan(tempo_seq, self.data)
167+
if min_mkspan > max_mkspn:
168+
max_mkspn = min_mkspan
169+
b_seq = tempo_seq
170+
seq = b_seq
171+
172+
schedules = np.zeros((self.nb_machines, self.nb_jobs), dtype=dict)
173+
# schedule first job alone first
174+
task = {"name": "job_{}".format(
175+
seq[0]+1), "start_time": 0, "end_time": self.data[0][seq[0]]}
176+
schedules[0][0] = task
177+
for m_id in range(1, self.nb_machines):
178+
start_t = schedules[m_id-1][0]["end_time"]
179+
end_t = start_t + self.data[m_id][0]
180+
task = {"name": "job_{}".format(
181+
seq[0]+1), "start_time": start_t, "end_time": end_t}
182+
schedules[m_id][0] = task
183+
184+
for index, job_id in enumerate(seq[1::]):
185+
start_t = schedules[0][index]["end_time"]
186+
end_t = start_t + self.data[0][job_id]
187+
task = {"name": "job_{}".format(
188+
job_id+1), "start_time": start_t, "end_time": end_t}
189+
schedules[0][index+1] = task
190+
for m_id in range(1, self.nb_machines):
191+
start_t = max(schedules[m_id][index]["end_time"],
192+
schedules[m_id-1][index+1]["end_time"])
193+
end_t = start_t + self.data[m_id][job_id]
194+
task = {"name": "job_{}".format(
195+
job_id+1), "start_time": start_t, "end_time": end_t}
196+
schedules[m_id][index+1] = task
197+
198+
max_mkspn = int(schedules[self.nb_machines-1][-1]["end_time"])
199+
return seq, schedules, max_mkspn
200+
134201

135202
@lru_cache(maxsize=128)
136203
def brute_force_exact(self):
137204
jobs_perm = permutations(range(self.nb_jobs))
138-
opt_makespan = float("inf")
139-
for seq in jobs_perm:
140-
schedules = np.zeros((self.nb_machines, self.nb_jobs), dtype=dict)
205+
seq = min(jobs_perm, key=lambda x: self._get_makespan(x, self.data))
206+
schedules = np.zeros((self.nb_machines, self.nb_jobs), dtype=dict)
141207
# schedule first job alone first
208+
task = {"name": "job_{}".format(
209+
seq[0]+1), "start_time": 0, "end_time": self.data[0][seq[0]]}
210+
schedules[0][0] = task
211+
for m_id in range(1, self.nb_machines):
212+
start_t = schedules[m_id-1][0]["end_time"]
213+
end_t = start_t + self.data[m_id][0]
142214
task = {"name": "job_{}".format(
143-
seq[0]+1), "start_time": 0, "end_time": self.data[0][seq[0]]}
144-
schedules[0][0] = task
145-
for m_id in range(1, self.nb_machines):
146-
start_t = schedules[m_id-1][0]["end_time"]
147-
end_t = start_t + self.data[m_id][0]
148-
task = {"name": "job_{}".format(
149-
seq[0]+1), "start_time": start_t, "end_time": end_t}
150-
schedules[m_id][0] = task
215+
seq[0]+1), "start_time": start_t, "end_time": end_t}
216+
schedules[m_id][0] = task
151217

152-
for index, job_id in enumerate(seq[1::]):
153-
start_t = schedules[0][index]["end_time"]
154-
end_t = start_t + self.data[0][job_id]
218+
for index, job_id in enumerate(seq[1::]):
219+
start_t = schedules[0][index]["end_time"]
220+
end_t = start_t + self.data[0][job_id]
221+
task = {"name": "job_{}".format(
222+
job_id+1), "start_time": start_t, "end_time": end_t}
223+
schedules[0][index+1] = task
224+
for m_id in range(1, self.nb_machines):
225+
start_t = max(schedules[m_id][index]["end_time"],
226+
schedules[m_id-1][index+1]["end_time"])
227+
end_t = start_t + self.data[m_id][job_id]
155228
task = {"name": "job_{}".format(
156229
job_id+1), "start_time": start_t, "end_time": end_t}
157-
schedules[0][index+1] = task
158-
for m_id in range(1, self.nb_machines):
159-
start_t = max(schedules[m_id][index]["end_time"],
160-
schedules[m_id-1][index+1]["end_time"])
161-
end_t = start_t + self.data[m_id][job_id]
162-
task = {"name": "job_{}".format(
163-
job_id+1), "start_time": start_t, "end_time": end_t}
164-
schedules[m_id][index+1] = task
165-
makespan = int(schedules[self.nb_machines-1][-1]["end_time"])
166-
if makespan < opt_makespan:
167-
opt_makespan = makespan
168-
best_schedule = np.copy(schedules)
169-
best_seq = np.copy(seq)
230+
schedules[m_id][index+1] = task
231+
makespan = int(schedules[self.nb_machines-1][-1]["end_time"])
170232

171-
return best_seq, best_schedule, opt_makespan
172-
233+
return seq, schedules, makespan
173234

174235

175236
class RandomFlowshop:
@@ -184,7 +245,7 @@ class RandomFlowshop:
184245
def __init__(self, nb_machines, nb_jobs):
185246
self.nb_machines = nb_machines
186247
self.nb_jobs = nb_jobs
187-
self.data = self.get_random_p_times(100)
248+
self.data = self.get_random_p_times(10)
188249

189250
def get_random_p_times(self, p_times_ub):
190251
"""
@@ -242,12 +303,13 @@ def get_problem_instance(self):
242303

243304

244305
if __name__ == "__main__":
245-
random_problem = RandomFlowshop(6, 8)
306+
random_problem = RandomFlowshop(5, 8)
246307
random_problem_instance = random_problem.get_problem_instance()
247-
seq, scheds, opt_makespan = random_problem_instance.palmer_heuristic()
308+
seq, neh_sched, mkspn = random_problem_instance.neh_heuristic()
248309
b_seq, b_scheds, b_opt_makespan = random_problem_instance.brute_force_exact()
249-
250-
print("Brute Force: {}, Palmer heuristic: {}".format(b_opt_makespan, opt_makespan))
310+
print(b_opt_makespan, mkspn)
311+
#print(seq)
312+
#print("Brute Force: {}, Palmer heuristic: {}".format(b_seq, seq))
251313

252314
#seq, jobs, opt_makespan = random_problem_instance.solve_johnson()
253315
# print("Sequence: {} \nJobs on Machine 1: \n {} \n Jobs on machine 2:\n {} \n".format(

0 commit comments

Comments
 (0)