Skip to content

Commit f1e3e71

Browse files
committed
Cleaning weighted objectives
1 parent 5d67cc2 commit f1e3e71

File tree

6 files changed

+266
-1106
lines changed

6 files changed

+266
-1106
lines changed

build/lib/scheptk/scheptk.py

Lines changed: 125 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -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

scheptk.egg-info/PKG-INFO

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
11
Metadata-Version: 2.1
22
Name: scheptk
3-
Version: 0.1.0
3+
Version: 0.1.2
44
Summary: Python scheduling package
55
Home-page: https://github.com/framinan/scheptk
66
Author: Jose M Framinan
77
Author-email: framinan@us.es
8-
License: UNKNOWN
9-
Description: ## `scheptk` - Scheduling Python ToolKit
10-
11-
`scheptk` is a collection of classes and functions to model and solve machine scheduling problems using Python. It is intended basically for teaching purposes, even if the algorithms can be integrated with MOIST, a more advanced scheduling tool.
12-
13-
# How to use it
14-
15-
In order to use `scheptk` you can install it as a Python package using `pip`:
16-
17-
`pip install scheptk`
18-
19-
At this point, the clasess and functions of `scheptk` should be available. You might want to have a look at the [wiki pages](https://github.com/framinan/scheptk/wiki) to get a handle on the documentation.
20-
21-
22-
Platform: UNKNOWN
238
Classifier: Programming Language :: Python :: 3.7
249
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
2510
Description-Content-Type: text/markdown
11+
License-File: LICENSE
12+
13+
## `scheptk` - Scheduling Python ToolKit
14+
15+
`scheptk` is a collection of classes and functions to model and solve machine scheduling problems using Python. It is intended basically for teaching purposes, even if the algorithms can be integrated with MOIST, a more advanced scheduling tool.
16+
17+
# How to use it
18+
19+
In order to use `scheptk` you can install it as a Python package using `pip`:
20+
21+
`pip install scheptk`
22+
23+
At this point, the clasess and functions of `scheptk` should be available. You might want to have a look at the [wiki pages](https://github.com/framinan/scheptk/wiki) to get a handle on the documentation.
24+

0 commit comments

Comments
 (0)