@@ -149,7 +149,6 @@ def print(self, filename=None):
149149 # printing only meaningful NAPS (>0)
150150 if (void [0 ][0 ][0 ] != void [0 ][0 ][1 ]):
151151 gantt .broken_barh (void [0 ],void [1 ],facecolors = 'white' , edgecolors = 'black' , label = self .NAP_list [i ].name , hatch = '//' )
152- #gantt.text(void[0][0][0] + void[0][0][1]/2, void[1][0] + task_height/2 - font_height, self.NAP_list[i].name)
153152 gantt .text (void [0 ][0 ][0 ] + (void [0 ][0 ][1 ]- len (self .NAP_list [i ].name ))/ 2 , void [1 ][0 ] + task_height / 2 - font_height , self .NAP_list [i ].name )
154153
155154 # optionally, the gantt is printed in hi-res
@@ -170,11 +169,12 @@ def __init__(self):
170169 self .w = [] # weigths
171170 self .r = [] # release dates
172171
172+ # COMPLETION TIME RELATED METHODS (ABSTRACT FOR ct, SPECIFIC FOR ctn)
173+ # ctn can be specific as it is based on ct
173174 @abstractmethod
174- def ct (self , sequence ):
175+ def ct (self , solution ):
175176 pass
176177
177-
178178 # complete completion times of all jobs in all machines (even if a partial solution is provided).
179179 # Here ct[i][j] indicates the completion time of job j on machine i. If this job is not in the partial solution, then nan is set as its corresponding completion times
180180 def ctn (instance , solution ):
@@ -192,15 +192,12 @@ def ctn(instance, solution):
192192
193193 return ctn
194194
195-
196-
197- # concrete method: it returns the completion time of each job in the sequence
195+ # JOB-LEVEL MEASURES (UNWEIDHTED)
196+ # completion time: it returns the completion time of each job in the (partial) solution
198197 # it is a bit tricky so it can support different codifications of the solutions in each layout
199- def Cj (instance , seq ):
198+ def Cj (instance , solution ):
200199
201- ct , job_order = instance .ct (seq )
202- # it is done with len(ct[0]) in order to support JobShop and OpenShop, because len(seq) is different than the number of jobs in ct
203- # and it is done with len(ct) instead of machines to support SingleMachine
200+ ct , job_order = instance .ct (solution )
204201 Cj = [max ([ct [i ][j ] for i in range (len (ct ))]) for j in range (len (job_order ))]
205202
206203 return Cj
@@ -218,11 +215,6 @@ def Cjn(instance, solution):
218215
219216 return cjn
220217
221-
222- # concrete method makespan
223- def Cmax (self , sequence ):
224- return max (self .Cj (sequence ))
225-
226218 # earliness of all jobs in a solution
227219 def Ej (self , solution ):
228220 if (self .dd == - 1 ):
@@ -240,9 +232,16 @@ def Ejn(self, sequence):
240232 return [max (self .dd [j ] - x ,0 ) for j , x in enumerate (self .Cjn (sequence ))]
241233
242234
235+
236+ # UNWEIGHTED CRITERIA (MAX AND SUM)
237+
238+ # concrete method makespan
239+ def Cmax (self , solution ):
240+ return max (self .Cj (solution ))
241+
243242 # max earliness
244- def Emax (self , sequence ):
245- return max (self .Ej (sequence ))
243+ def Emax (self , solution ):
244+ return max (self .Ej (solution ))
246245
247246 # flowtime (Cj - rj) of all jobs in a solution
248247 def Fj (self , solution ):
@@ -259,10 +258,9 @@ def Fjn(self, solution):
259258
260259 return fjn
261260
262-
263261 # max flowtime
264- def Fmax (self , sequence ):
265- return max ( self .Fj (sequence ))
262+ def Fmax (self , solution ):
263+ return max ( self .Fj (solution ))
266264
267265 # lateness of all jobs in the solution
268266 def Lj (self , solution ):
@@ -274,44 +272,16 @@ def Lj(self, solution):
274272 return [Cj [j ] - self .dd [job_order [j ]] for j in range (len (job_order ))]
275273
276274 # lateness of all jobs according to a solution (natural order of the jobs)
277- def Ljn (self , sequence ):
275+ def Ljn (self , solution ):
278276 if (self .dd == - 1 ):
279277 print ("The instance does not have due dates and due-date related objective cannot be computed. The program cannot continue." )
280278 sys .exit ()
281- return [item - self .dd [index ] for index ,item in enumerate (self .Cjn (sequence ))]
279+ return [item - self .dd [index ] for index ,item in enumerate (self .Cjn (solution ))]
282280
283281
284282 # max lateness
285- def Lmax (self , sequence ):
286- return max (self .Lj (sequence ))
287-
288-
289- # weighted makespan
290- def max_WjCj (self , sequence ):
291- return max ([item * self .w [sequence [index ]] for index ,item in enumerate (self .Cj (sequence ))])
292-
293- # weighted max earliness
294- def max_WjEj (self , sequence ):
295- if (self .dd == - 1 ):
296- print ("The instance does not have due dates and due-date related objective cannot be computed." )
297- return max ([ (max (self .dd [sequence [index ]] - item ,0 ) * self .w [sequence [index ]]) for index ,item in enumerate (self .Cj (sequence ))])
298-
299- # weighted max flowtime
300- def max_WjFj (self , sequence ):
301- return max ([(item - self .r [sequence [index ]])* self .w [sequence [index ]] for index ,item in enumerate (self .Cj (sequence ))])
302-
303- # weighted max lateness
304- def max_WjLj (self , sequence ):
305- if (self .dd == - 1 ):
306- print ("The instance does not have due dates and due-date related objective cannot be computed." )
307- return max ([ (item - self .dd [sequence [index ]])* self .w [sequence [index ]] for index ,item in enumerate (self .Cj (sequence ))])
308-
309- # weighted max tardiness
310- def max_WjTj (self , sequence ):
311- if (self .dd == - 1 ):
312- print ("The instance does not have due dates and due-date related objective cannot be computed." )
313- return max ([ (max (item - self .dd [sequence [index ]],0 ) * self .w [sequence [index ]]) for index ,item in enumerate (self .Cj (sequence ))])
314-
283+ def Lmax (self , solution ):
284+ return max (self .Lj (solution ))
315285
316286 # starting times of all jobs in a solution
317287 def Sj (self , solution ):
@@ -327,60 +297,73 @@ def Sjn(self, solution):
327297 return sjn
328298
329299 # sum of completion tme
330- def SumCj (self , sequence ):
331- return sum (self .Cj (sequence ))
300+ def SumCj (self , solution ):
301+ return sum (self .Cj (solution ))
332302
333303 # sum earliness
334- def SumEj (self , sequence ):
335- return sum (self .Ej (sequence ))
304+ def SumEj (self , solution ):
305+ return sum (self .Ej (solution ))
336306
337307 # sum flowtime
338- def SumFj (self , sequence ):
339- return sum (self .Fj (sequence ))
308+ def SumFj (self , solution ):
309+ return sum (self .Fj (solution ))
340310
341311 # sum lateness
342- def SumLj (self , sequence ):
343- return sum ( self .Lj (sequence ))
312+ def SumLj (self , solution ):
313+ return sum ( self .Lj (solution ))
344314
345315 # sum tardiness
346- def SumTj (self , sequence ):
347- return sum ( self .Tj (sequence ))
316+ def SumTj (self , solution ):
317+ return sum ( self .Tj (solution ))
348318
349319 # sum of tardy jobs
350- def SumUj (self , sequence ):
351- return sum ( self .Uj (sequence ))
352-
353- # weighted sum of completion times
354- def SumWjCj (self , sequence ):
355- return sum ([item * self .w [sequence [index ]] for index ,item in enumerate (self .Cj (sequence ))])
320+ def SumUj (self , solution ):
321+ return sum ( self .Uj (solution ))
322+
323+ # WEIGHTED CRITERIA (MAX AND SUM)
324+ # weighted makespan
325+ def max_WjCj (self , solution ):
326+ return max ( self .WjCj (solution ) )
327+
328+ # weighted max earliness
329+ def max_WjEj (self , solution ):
330+ return max ( self .WjEj (solution ) )
331+
332+ # weighted max flowtime
333+ def max_WjFj (self , solution ):
334+ return max ( self .WjFj (solution ) )
335+
336+ # weighted max lateness
337+ def max_WjLj (self , solution ):
338+ return max ( self .WjLj ( solution ) )
339+
340+ # weighted max tardiness
341+ def max_WjTj (self , solution ):
342+ return max ( self .WjTj ( solution ) )
356343
344+ # weighted sum of completion times
345+ def SumWjCj (self , solution ):
346+ return sum ( self .WjCj ( solution ))
347+
357348 # weighted sum of earliness
358- def SumWjEj (self , sequence ):
359- if (self .dd == - 1 ):
360- print ("The instance does not have due dates and due-date related objective cannot be computed." )
361- return sum ([ (max (self .dd [sequence [index ]] - item ,0 ) * self .w [sequence [index ]]) for index ,item in enumerate (self .Cj (sequence ))])
349+ def SumWjEj (self , solution ):
350+ return sum ( self .WjEj ( solution ) )
362351
363352 # weighted sum of flowtime
364- def SumWjFj (self , sequence ):
365- return sum ([( item - self .r [ sequence [ index ]]) * self . w [ sequence [ index ]] for index , item in enumerate ( self . Cj ( sequence ))] )
353+ def SumWjFj (self , solution ):
354+ return sum ( self .WjFj ( solution ) )
366355
367356 # weighted sum of lateness
368- def SumWjLj (self , sequence ):
369- if (self .dd == - 1 ):
370- print ("The instance does not have due dates and due-date related objective cannot be computed." )
371- return sum ([ (item - self .dd [sequence [index ]])* self .w [sequence [index ]] for index ,item in enumerate (self .Cj (sequence ))])
357+ def SumWjLj (self , solution ):
358+ return sum ( self .WjLj ( solution ) )
372359
373360 # weighted sum of tardiness
374- def SumWjTj (self , sequence ):
375- if (self .dd == - 1 ):
376- print ("The instance does not have due dates and due-date related objective cannot be computed." )
377- return sum ([ (max (item - self .dd [sequence [index ]],0 ) * self .w [sequence [index ]]) for index ,item in enumerate (self .Cj (sequence ))])
361+ def SumWjTj (self , solution ):
362+ return sum ( self .WjTj ( solution ) )
378363
379364 # weighted sum of tardy jobs
380- def SumWjUj (self , sequence ):
381- if (self .dd == - 1 ):
382- print ("The instance does not have due dates and due-date related objective cannot be computed." )
383- return sum ([1 if (item - self .dd [sequence [index ]]) > 0 else 0 for index ,item in enumerate (self .Cj (sequence ))])
365+ def SumWjUj (self , solution ):
366+ return sum ( self .WjUj (solution ) )
384367
385368 # tardiness of all jobs in a solution
386369 def Tj (self , solution ):
@@ -392,25 +375,74 @@ def Tj(self, solution):
392375 return [max (Cj [j ] - self .dd [job_order [j ]],0 ) for j in range (len (job_order ))]
393376
394377 # tardiness of all jobs according to a solution (natural order of the jobs)
395- def Tjn (self , sequence ):
378+ def Tjn (self , solution ):
396379 if (self .dd == - 1 ):
397380 print ("The instance does not have due dates and due-date related objective cannot be computed. The program cannot continue." )
398381 sys .exit ()
399- return [max (item - self .dd [index ],0 ) for index ,item in enumerate (self .Cjn (sequence ))]
382+ return [max (item - self .dd [index ],0 ) for index ,item in enumerate (self .Cjn (solution ))]
400383
401384 # max tardiness
402- def Tmax (self , sequence ):
403- return max (self .Tj (sequence ))
385+ def Tmax (self , solution ):
386+ return max (self .Tj (solution ))
404387
405388 # vector of tardy jobs: 1 if the job is tardy, 0 otherwise
406- def Uj (self , sequence ):
407- return [1 if t > 0 else 0 for t in self .Tj (sequence )]
389+ def Uj (self , solution ):
390+ return [1 if t > 0 else 0 for t in self .Tj (solution )]
408391
409392 def Ujn (self , solution ):
410393 return [float ('nan' ) if math .isnan (t ) else 1 if t > 0 else 0 for t in self .Tjn (solution )]
411394
395+ # WEIGHTED JOB-LEVEL MEASURES (only jobs in seq, even if it is a partial solution)
396+ # these measures have to be implemented since the order of the jobs is not returned by the un-weighted job-level measures
397+ def WjCj (self , seq ):
398+ ct , job_order = self .ct (seq )
399+ # it is done with len(ct) instead of machines to support SingleMachine
400+ return [max ([ct [i ][j ] for i in range (len (ct ))]) * self .w [job_order [j ]] for j in range (len (job_order ))]
401+
402+ # weighted earliness of all jobs in a (partial) solution
403+ def WjEj (self , solution ):
404+ if (self .dd == - 1 ):
405+ print ("The instance does not have due dates and due-date related objective cannot be computed. The program cannot continue." )
406+ sys .exit ()
407+ ct , job_order = self .ct (solution )
408+ Cj = [max ([ct [i ][j ] for i in range (len (ct ))]) for j in range (len (job_order ))]
409+ return [max (self .dd [job_order [j ]] - Cj [j ],0 )* self .w [job_order [j ]] for j in range (len (job_order ))]
410+
411+ # weighted flowtime (Cj - rj) of all jobs in a (partial) solution
412+ def WjFj (self , solution ):
413+ ct , job_order = self .ct (solution )
414+ return [(max ([ct [i ][j ] for i in range (len (ct ))]) - self .r [job_order [j ]])* self .w [job_order [j ]] for j in range (len (job_order ))]
412415
416+ # weighted lateness of the jobs in a (partial) solution
417+ def WjLj (self , solution ):
418+ if (self .dd == - 1 ):
419+ print ("The instance does not have due dates and due-date related objective cannot be computed. The program cannot continue." )
420+ sys .exit ()
421+ ct , job_order = self .ct (solution )
422+ Cj = [max ([ct [i ][j ] for i in range (len (ct ))]) for j in range (len (job_order ))]
423+ return [(Cj [j ] - self .dd [job_order [j ]])* self .w [job_order [j ]] for j in range (len (job_order ))]
413424
425+ # weighted tardiness of all jobs in a (partial) solution
426+ def WjTj (self , solution ):
427+ if (self .dd == - 1 ):
428+ print ("The instance does not have due dates and due-date related objective cannot be computed. The program cannot continue." )
429+ sys .exit ()
430+ ct , job_order = self .ct (solution )
431+ Cj = [max ([ct [i ][j ] for i in range (len (ct ))]) for j in range (len (job_order ))]
432+ return [(max (Cj [j ] - self .dd [job_order [j ]],0 ))* self .w [job_order [j ]] for j in range (len (job_order ))]
433+
434+ # weighted number of tardy jobs in (partial) solution
435+ def WjUj (self , solution ):
436+ if (self .dd == - 1 ):
437+ print ("The instance does not have due dates and due-date related objective cannot be computed. The program cannot continue." )
438+ sys .exit ()
439+ ct , job_order = self .ct (solution )
440+ Cj = [max ([ct [i ][j ] for i in range (len (ct ))]) for j in range (len (job_order ))]
441+ Tj = [max (Cj [j ] - self .dd [job_order [j ]],0 ) for j in range (len (job_order ))]
442+ return [self .w [job_order [j ]] if Tj [j ] > 0 else 0 for j in range (len (job_order ))]
443+
444+
445+ # CHECKING METHODS
414446 # other methods to check data that are implemented in all children
415447 def check_duedates (self , filename ):
416448 # due dates (if not, -1 is assumed)
@@ -461,6 +493,7 @@ def check_releasedates(self, filename):
461493 else :
462494 print_tag ("R" , self .r )
463495
496+ # SCHEDULE/GANTT - RELATED METHODS
464497 # method to create a schedule. This method is implemented by the children clasess
465498 # The method is a bit tricky to treat the case of a single machine and parallel machines (which is not ideal for a parent class :-( )),
466499 # as in this case it is not usual to use a matrix for the processing times
@@ -490,8 +523,6 @@ def create_schedule(self, solution):
490523 gantt .add_task (Task (job , mach , ct [mach ][j ] - pt [mach ][job ], ct [mach ][j ]))
491524
492525 return gantt
493-
494-
495526
496527 # method to write a schedule in a file
497528 def write_schedule (self , solution , filename ):
@@ -860,14 +891,6 @@ def __init__(self, filename):
860891 # release dates (if not, 0 is assumed)
861892 self .check_releasedates (filename )
862893
863- # release dates (if not, 0 is assumed)
864- self .r = read_tag (filename ,"R" )
865- if (self .r == - 1 ):
866- self .r = [0 for i in range (self .jobs )]
867- print ("No release dates specified for the jobs. All release dates set to zero." )
868- else :
869- print_tag ("R" , self .r )
870-
871894 print ("----- end of JobShop instance data from file " + filename + " -------" )
872895
873896
0 commit comments