@@ -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
175236class 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
244305if __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