Commit cf8913a1 authored by Dipo Olaitan's avatar Dipo Olaitan

ACO Updates and Default Shift Pattern in Exceptions Sheet

parent 8c8ef0db
...@@ -23,7 +23,12 @@ class ACO(plugin.ExecutionPlugin): ...@@ -23,7 +23,12 @@ class ACO(plugin.ExecutionPlugin):
"""Calculate the score of this ant. Implemented in the Subclass, raises NotImplementedError """Calculate the score of this ant. Implemented in the Subclass, raises NotImplementedError
""" """
raise NotImplementedError("ACO subclass must define '_calculateAntScore' method") raise NotImplementedError("ACO subclass must define '_calculateAntScore' method")
def _calculateAntActualDelay(self, ant):
"""Calculate the score of this ant. Implemented in the Subclass, raises NotImplementedError
"""
raise NotImplementedError("ACO subclass must define '_calculateAntActualDelay' method")
def createCollatedScenarios(self,data): def createCollatedScenarios(self,data):
"""creates the collated scenarios, i.e. the list of options collated into a dictionary for ease of referencing in ManPy """creates the collated scenarios, i.e. the list of options collated into a dictionary for ease of referencing in ManPy
to be implemented in the subclass to be implemented in the subclass
...@@ -51,14 +56,16 @@ class ACO(plugin.ExecutionPlugin): ...@@ -51,14 +56,16 @@ class ACO(plugin.ExecutionPlugin):
tested_ants = set() tested_ants = set()
start = time.time() # start counting execution time start = time.time() # start counting execution time
collated=self.createCollatedScenarios(data) collated=self.createCollatedScenarios(data)
resetCollated = deepcopy(collated)#starting pheromone level, use for reset after every generation
assert collated assert collated
max_results = int(data['general'].get('numberOfSolutions',0)) max_results = int(data['general'].get('numberOfSolutions',0))
assert max_results >= 1 assert max_results >= 1
ants = [] #list of ants for keeping track of their performance ants = [] #list of ants for keeping track of their performance
solutionConvergence = [] #for monitoring solution convergence
# Number of times new ants are to be created, i.e. number of generations (a # Number of times new ants are to be created, i.e. number of generations (a
# generation can have more than 1 ant) # generation can have more than 1 ant)
seedPlus = 0 seedPlus = 0
...@@ -133,6 +140,7 @@ class ACO(plugin.ExecutionPlugin): ...@@ -133,6 +140,7 @@ class ACO(plugin.ExecutionPlugin):
for ant in scenario_list: for ant in scenario_list:
ant['score'] = self._calculateAntScore(ant) ant['score'] = self._calculateAntScore(ant)
ant['actualDelays'] = self._calculateAntActualDelay(ant)
ants.extend(scenario_list) ants.extend(scenario_list)
...@@ -147,9 +155,14 @@ class ACO(plugin.ExecutionPlugin): ...@@ -147,9 +155,14 @@ class ACO(plugin.ExecutionPlugin):
# The ants in this generation are ranked based on their scores and the # The ants in this generation are ranked based on their scores and the
# best (max_results) are selected # best (max_results) are selected
ants = sorted(ants_without_duplicates.values(), if max([ant['score'] for ant in ants]) == 0:#if all ants achieved zero delays, then use their earliness values
ants = sorted(ants_without_duplicates.values(),
key=operator.itemgetter('actualDelays'))[:max_results]
else:
ants = sorted(ants_without_duplicates.values(),
key=operator.itemgetter('score'))[:max_results] key=operator.itemgetter('score'))[:max_results]
collated = deepcopy(resetCollated)#reset previous pheromone updates
for l in ants: for l in ants:
# update the options list to ensure that good performing queue-rule # update the options list to ensure that good performing queue-rule
# combinations have increased representation and good chance of # combinations have increased representation and good chance of
...@@ -159,6 +172,13 @@ class ACO(plugin.ExecutionPlugin): ...@@ -159,6 +172,13 @@ class ACO(plugin.ExecutionPlugin):
# 'EDD' is added to Q1 so there is a higher chance that it is # 'EDD' is added to Q1 so there is a higher chance that it is
# selected by the next ants. # selected by the next ants.
collated[m].append(l[m]) collated[m].append(l[m])
#termination criterion: after four generations check if the solution has been improving
solutionConvergence.append(max([ant['actualDelays'] for ant in ants])) #add the worst solution after the last generation
solutionConvergence.sort()
del(solutionConvergence[int(data['general'].get('numberOfSolutions',0)):]) #extract the last 4 worst solutions among the best, if there has been no improvement, terminate the optimisation process
if len(solutionConvergence) == int(data['general'].get('numberOfSolutions',0)) and max(solutionConvergence) == min(solutionConvergence):
break
data['result']['result_list'] = result_list = [] data['result']['result_list'] = result_list = []
for ant in ants: for ant in ants:
......
...@@ -24,6 +24,19 @@ class JobShopACO(ACO): ...@@ -24,6 +24,19 @@ class JobShopACO(ACO):
# should not be considered better than being on time. # should not be considered better than being on time.
totalDelay += max(delay, 0) totalDelay += max(delay, 0)
return totalDelay return totalDelay
def _calculateAntActualDelay(self, ant):
antActualDelay = 0 #used to further compare ants with the earliness if they all had zero delay
result, = ant['result']['result_list'] #read the result as JSON
#loop through the elements
for element in result['elementList']:
element_family = element.get('family', None)
#id the class is Job
if element_family == 'Job':
results=element['results']
delay = float(results.get('delay', "0"))
antActualDelay += delay
return antActualDelay
# creates the collated scenarios, i.e. the list # creates the collated scenarios, i.e. the list
# of options collated into a dictionary for ease of referencing in ManPy # of options collated into a dictionary for ease of referencing in ManPy
......
...@@ -52,7 +52,12 @@ class ReadJSShifts(plugin.InputPreparationPlugin, TimeSupportMixin): ...@@ -52,7 +52,12 @@ class ReadJSShifts(plugin.InputPreparationPlugin, TimeSupportMixin):
exceptionShiftPattern = {} # exceptions for shift pattern dictionary as defined in the spreadsheet exceptionShiftPattern = {} # exceptions for shift pattern dictionary as defined in the spreadsheet
if shiftData: if shiftData:
shiftData.pop(0) shiftData.pop(0)#remove headers from the shiftData
standardStartTime = shiftData[0][2]
standardEndTime = shiftData[0][3]
shiftData.pop(0) #remove standard times declared on the first line from the shiftData
#iteration through the raw data to structure it into ManPy config
lastrec=None
#iteration through the raw data to structure it into ManPy config #iteration through the raw data to structure it into ManPy config
for line in shiftData: for line in shiftData:
# if all the records of that line are none then continue # if all the records of that line are none then continue
...@@ -70,12 +75,12 @@ class ReadJSShifts(plugin.InputPreparationPlugin, TimeSupportMixin): ...@@ -70,12 +75,12 @@ class ReadJSShifts(plugin.InputPreparationPlugin, TimeSupportMixin):
#if no shift start was given, assume standard 8:00 #if no shift start was given, assume standard 8:00
startTime = line[2] startTime = line[2]
if startTime == '' or startTime == None: if startTime == '' or startTime == None:
startTime = "08:00" startTime = standardStartTime
shiftStart = self.convertToSimulationTime(strptime("%s %s" % (line[1], startTime), '%Y/%m/%d %H:%M')) shiftStart = self.convertToSimulationTime(strptime("%s %s" % (line[1], startTime), '%Y/%m/%d %H:%M'))
#if no shift end was given, assume standard 18:00 #if no shift end was given, assume standard 18:00
endTime = line[3] endTime = line[3]
if endTime == '' or endTime == None: if endTime == '' or endTime == None:
endTime = "18:00" endTime = standardEndTime
shiftEnd = self.convertToSimulationTime(strptime("%s %s" % (line[1], endTime), '%Y/%m/%d %H:%M')) shiftEnd = self.convertToSimulationTime(strptime("%s %s" % (line[1], endTime), '%Y/%m/%d %H:%M'))
timePair = self.correctTimePair(shiftStart, shiftEnd) timePair = self.correctTimePair(shiftStart, shiftEnd)
if not timePair: if not timePair:
...@@ -146,8 +151,8 @@ class ReadJSShifts(plugin.InputPreparationPlugin, TimeSupportMixin): ...@@ -146,8 +151,8 @@ class ReadJSShifts(plugin.InputPreparationPlugin, TimeSupportMixin):
timeStartList = [] timeStartList = []
timeEndList = [] timeEndList = []
for dayNumber in range(0,20): for dayNumber in range(0,20):
startTime = "08:00" startTime = standardStartTime
endTime = "18:00" endTime = standardEndTime
upDate = now.date()+datetime.timedelta(days=dayNumber) upDate = now.date()+datetime.timedelta(days=dayNumber)
shiftStart = self.convertToSimulationTime(strptime("%s %s" % (upDate, startTime), '%Y-%m-%d %H:%M')) shiftStart = self.convertToSimulationTime(strptime("%s %s" % (upDate, startTime), '%Y-%m-%d %H:%M'))
shiftEnd = self.convertToSimulationTime(strptime("%s %s" % (upDate, endTime), '%Y-%m-%d %H:%M')) shiftEnd = self.convertToSimulationTime(strptime("%s %s" % (upDate, endTime), '%Y-%m-%d %H:%M'))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment