Skip to content

Commit

Permalink
Enhanced job-level measures
Browse files Browse the repository at this point in the history
  • Loading branch information
framinan committed Sep 21, 2022
1 parent b6dce21 commit 30619b5
Show file tree
Hide file tree
Showing 8 changed files with 319 additions and 114 deletions.
187 changes: 140 additions & 47 deletions build/lib/scheptk/scheptk.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import operator # for sorted functions
import matplotlib.pyplot as plt
from random import randint # random solutions
import math # maths

from scheptk.util import random_sequence, read_tag, find_index_min, print_tag, sorted_index_asc, sorted_value_asc, sorted_value_desc, write_tag

Expand Down Expand Up @@ -173,6 +174,26 @@ def __init__(self):
def ct(self, sequence):
pass


# complete completion times of all jobs in all machines (even if a partial solution is provided).
# 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
def ctn(instance, solution):

# obtains the completion time of the jobs in the partial solution
ct, job_order = instance.ct(solution)

# initially, all positions are nan
ctn = [[float('nan') for j in range(instance.jobs)] for i in range(len(ct))]

# change the corresponding values
for i in range(len(ct)):
for j,job in enumerate(job_order):
ctn[i][job] = ct[i][j]

return ctn



# concrete method: it returns the completion time of each job in the sequence
# it is a bit tricky so it can support different codifications of the solutions in each layout
def Cj(instance, seq):
Expand All @@ -184,49 +205,123 @@ def Cj(instance, seq):

return Cj

# Cjn returns a list with the completion times of all jobs in the model (even if a partial solution has been provided) in the order of the jobs,
# i.e. first element in Cjn corresponding to the completion times of job 0, second to the completion times of job 1, etc.
# When a partial solution is given, the completion times of the jobs not included in the partial solution are given as 'Nan' (non-available number)
def Cjn(instance, solution):

ct, order = instance.ct(solution)
cj = [max([ct[i][j] for i in range(len(ct))]) for j in range(len(order))]
cjn = [float('nan') for j in range(instance.jobs)]
for j in range(len(order)):
cjn[order[j]] = cj[j]

return cjn


# concrete method makespan
def Cmax(self, sequence):
return max(self.Cj(sequence))

# earliness of all jobs
def Ej(self, sequence):
# earliness of all jobs in a solution
def Ej(self, solution):
if(self.dd == -1):
print("The instance does not have due dates and due-date related objective cannot be computed.")
return [ max(self.dd[sequence[index]] - item,0) for index,item in enumerate(self.Cj(sequence))]
print("The instance does not have due dates and due-date related objective cannot be computed. The program cannot continue.")
sys.exit()
ct, job_order = self.ct(solution)
Cj = [max([ct[i][j] for i in range(len(ct))]) for j in range(len(job_order))]
return [max(self.dd[job_order[j]] - Cj[j],0) for j in range(len(job_order))]

# earliness of all jobs according to a solution (natural order of the jobs)
def Ejn(self, sequence):
if(self.dd == -1):
print("The instance does not have due dates and due-date related objective cannot be computed. The program cannot continue.")
sys.exit()
return [max(self.dd[j] - x ,0) for j, x in enumerate(self.Cjn(sequence))]


# max earliness
def Emax(self, sequence):
return max(self.Lj(sequence))

# flowtime de cada uno de los trabajos
def Fj(self, sequence):
return [item - self.r[sequence[index]] for index,item in enumerate(self.Cj(sequence))]
# flowtime of all jobs in a solution
def Fj(self, solution):
ct, job_order = self.ct(solution)
Cj = [max([ct[i][j] for i in range(len(ct))]) for j in range(len(job_order))]
return [Cj[j] - min([ct[i][j] - self.pt[i][job_order[j]] for i in range(len(ct))]) for j in range(len(job_order))]


# flowtime of all jobs according to a solution (natural order of the jobs)
def Fjn(self, solution):
return [self.Cjn(solution)[j] - self.Sjn(solution)[j] for j in range(self.jobs)]


# max flowtime
def Fmax(self, sequence):
return max( self.Fj(sequence))

# lateness of all jobs in the sequence
def Lj(self, sequence):
# lateness of all jobs in the solution
def Lj(self, solution):
if(self.dd == -1):
print("The instance does not have due dates and due-date related objective cannot be computed. The program cannot continue.")
sys.exit()
ct, job_order = self.ct(solution)
Cj = [max([ct[i][j] for i in range(len(ct))]) for j in range(len(job_order))]
return [Cj[j] - self.dd[job_order[j]] for j in range(len(job_order))]

# lateness of all jobs according to a solution (natural order of the jobs)
def Ljn(self, sequence):
if(self.dd == -1):
print("The instance does not have due dates and due-date related objective cannot be computed.")
return [item - self.dd[sequence[index]] for index,item in enumerate(self.Cj(sequence))]
print("The instance does not have due dates and due-date related objective cannot be computed. The program cannot continue.")
sys.exit()
return [item - self.dd[index] for index,item in enumerate(self.Cjn(sequence))]


# max lateness
def Lmax(self, sequence):
return max(self.Lj(sequence))

# tardiness of all jobs
def Tj(self, sequence):

# weighted makespan
def max_WjCj(self, sequence):
return max([item * self.w[sequence[index]] for index,item in enumerate(self.Cj(sequence))])

# weighted max earliness
def max_WjEj(self, sequence):
if(self.dd == -1):
print("The instance does not have due dates and due-date related objective cannot be computed.")
return max([ (max(self.dd[sequence[index]] - item,0) * self.w[sequence[index]]) for index,item in enumerate(self.Cj(sequence))])

# weighted max flowtime
def max_WjFj(self, sequence):
return max([(item - self.r[sequence[index]])* self.w[sequence[index]] for index,item in enumerate(self.Cj(sequence))])

# weighted max lateness
def max_WjLj(self, sequence):
if(self.dd == -1):
print("The instance does not have due dates and due-date related objective cannot be computed.")
return [ max(item - self.dd[sequence[index]],0) for index,item in enumerate(self.Cj(sequence))]
return max([ (item - self.dd[sequence[index]])*self.w[sequence[index]] for index,item in enumerate(self.Cj(sequence))])

# max tardiness
def Tmax(self, sequence):
return max(self.Tj(sequence))
# weighted max tardiness
def max_WjTj(self, sequence):
if(self.dd == -1):
print("The instance does not have due dates and due-date related objective cannot be computed.")
return max([ (max(item - self.dd[sequence[index]],0) * self.w[sequence[index]]) for index,item in enumerate(self.Cj(sequence))])


# starting times of all jobs in a solution
def Sj(self, solution):
ct, job_order = self.ct(solution)
return [min([ct[i][j] - self.pt[i][job_order[j]] for i in range(len(ct))]) for j in range(len(job_order))]

# starting times of all jobs according to a solution (natural order of the jobs)
def Sjn(self, solution):
sjn = [float('nan') for j in range(self.jobs)]
ct, job_order = self.ct(solution)
for j, job in enumerate(job_order):
sjn[job] = min([ct[i][j] - self.pt[i][job] for i in range(len(ct))])
return sjn

# sum of completion tme
def SumCj(self, sequence):
return sum(self.Cj(sequence))
Expand All @@ -250,33 +345,7 @@ def SumTj(self, sequence):
# sum of tardy jobs
def SumUj(self, sequence):
return sum( self.Uj(sequence))

# weighted makespan
def WjCmax(self, sequence):
return max([item * self.w[sequence[index]] for index,item in enumerate(self.Cj(sequence))])

# weighted max earliness
def WjEmax(self, sequence):
if(self.dd == -1):
print("The instance does not have due dates and due-date related objective cannot be computed.")
return max([ (max(self.dd[sequence[index]] - item,0) * self.w[sequence[index]]) for index,item in enumerate(self.Cj(sequence))])

# weighted max flowtime
def WjFmax(self, sequence):
return max([(item - self.r[sequence[index]])* self.w[sequence[index]] for index,item in enumerate(self.Cj(sequence))])

# weighted max lateness
def WjLmax(self, sequence):
if(self.dd == -1):
print("The instance does not have due dates and due-date related objective cannot be computed.")
return max([ (item - self.dd[sequence[index]])*self.w[sequence[index]] for index,item in enumerate(self.Cj(sequence))])

# weighted max tardiness
def WjTmax(self, sequence):
if(self.dd == -1):
print("The instance does not have due dates and due-date related objective cannot be computed.")
return max([ (max(item - self.dd[sequence[index]],0) * self.w[sequence[index]]) for index,item in enumerate(self.Cj(sequence))])


# weighted sum of completion times
def SumWjCj(self, sequence):
return sum([item * self.w[sequence[index]] for index,item in enumerate(self.Cj(sequence))])
Expand All @@ -288,7 +357,7 @@ def SumWjEj(self, sequence):
return sum([ (max(self.dd[sequence[index]] - item,0) * self.w[sequence[index]]) for index,item in enumerate(self.Cj(sequence))])

# weighted sum of flowtime
def WjFmax(self, sequence):
def SumWjFj(self, sequence):
return sum([(item - self.r[sequence[index]])* self.w[sequence[index]] for index,item in enumerate(self.Cj(sequence))])

# weighted sum of lateness
Expand All @@ -309,10 +378,34 @@ def SumWjUj(self, sequence):
print("The instance does not have due dates and due-date related objective cannot be computed.")
return sum([1 if (item - self.dd[sequence[index]]) > 0 else 0 for index,item in enumerate(self.Cj(sequence))])

# tardiness of all jobs in a solution
def Tj(self, solution):
if(self.dd == -1):
print("The instance does not have due dates and due-date related objective cannot be computed. The program cannot continue.")
sys.exit()
ct, job_order = self.ct(solution)
Cj = [max([ct[i][j] for i in range(len(ct))]) for j in range(len(job_order))]
return [max(Cj[j] - self.dd[job_order[j]],0) for j in range(len(job_order))]

# tardiness of all jobs according to a solution (natural order of the jobs)
def Tjn(self, sequence):
if(self.dd == -1):
print("The instance does not have due dates and due-date related objective cannot be computed. The program cannot continue.")
sys.exit()
return [max(item - self.dd[index],0) for index,item in enumerate(self.Cjn(sequence))]

# max tardiness
def Tmax(self, sequence):
return max(self.Tj(sequence))

# vector of tardy jobs: 1 if the job is tardy, 0 otherwise
def Uj(self, sequence):
return [1 if t >0 else 0 for t in self.Tj(sequence)]

def Ujn(self, solution):
return [float('nan') if math.isnan(t) else 1 if t >0 else 0 for t in self.Tjn(solution)]



# other methods to check data that are implemented in all children
def check_duedates(self, filename):
Expand Down Expand Up @@ -774,10 +867,11 @@ def __init__(self, filename):
print("----- end of JobShop instance data from file " + filename + " -------")



def ct(self, solution):

# get the jobs involved in the solution in the order they are processed
jobs_involved = list(set(solution))
jobs_involved = list(dict.fromkeys(solution))

# completion times of jobs and machines
ct_jobs = [self.r[jobs_involved[j]] for j in range(len(jobs_involved))]
Expand Down Expand Up @@ -808,7 +902,6 @@ def ct(self, solution):

return ct, jobs_involved



# implementation of a random solution of the instance
def random_solution(self):
Expand Down
13 changes: 12 additions & 1 deletion build/lib/scheptk/util.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

import ast # to get the proper data type
import operator # for sorted functions
from random import randint # generation of random integer numbers
from random import randint, shuffle # generation of random integer numbers and to sort an extended seq


# utility function to edit the value of a tag in a file
Expand Down Expand Up @@ -93,6 +93,17 @@ def print_tag(tag, value):
# it is an scalar
print("[" + tag + "=" + str(value) + "]")


# utility function to generate a random extended sequence for a jobshop with a given number of jobs and machines.
def random_extended_sequence(jobs, machines):
extended_seq = []
for i in range(machines):
seq = random_sequence(jobs)
extended_seq = extended_seq + seq
shuffle(extended_seq)
return extended_seq


# utility function to generate a random sequence of length size
def random_sequence(size):
sequence = []
Expand Down
31 changes: 14 additions & 17 deletions scheptk.egg-info/PKG-INFO
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
Metadata-Version: 2.1
Name: scheptk
Version: 0.0.7
Version: 0.0.8
Summary: Python scheduling package
Home-page: https://github.com/framinan/scheptk
Author: Jose M Framinan
Author-email: framinan@us.es
License: UNKNOWN
Description: ## `scheptk` - Scheduling Python ToolKit

`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.

# How to use it

In order to use `scheptk` you can install it as a Python package using `pip`:

`pip install scheptk`

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.


Platform: UNKNOWN
Classifier: Programming Language :: Python :: 3.7
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
Description-Content-Type: text/markdown
License-File: LICENSE

## `scheptk` - Scheduling Python ToolKit

`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.

# How to use it

In order to use `scheptk` you can install it as a Python package using `pip`:

`pip install scheptk`

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.



Binary file modified scheptk/__pycache__/scheptk.cpython-39.pyc
Binary file not shown.
Binary file modified scheptk/__pycache__/util.cpython-39.pyc
Binary file not shown.
Loading

0 comments on commit 30619b5

Please sign in to comment.