Commit cf8913a1 authored by Dipo Olaitan's avatar Dipo Olaitan

ACO Updates and Default Shift Pattern in Exceptions Sheet

parent 8c8ef0db
...@@ -24,6 +24,11 @@ class ACO(plugin.ExecutionPlugin): ...@@ -24,6 +24,11 @@ class ACO(plugin.ExecutionPlugin):
""" """
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
...@@ -52,12 +57,14 @@ class ACO(plugin.ExecutionPlugin): ...@@ -52,12 +57,14 @@ class ACO(plugin.ExecutionPlugin):
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)
...@@ -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
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(), 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
...@@ -160,6 +173,13 @@ class ACO(plugin.ExecutionPlugin): ...@@ -160,6 +173,13 @@ class ACO(plugin.ExecutionPlugin):
# 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:
result, = ant['result']['result_list'] result, = ant['result']['result_list']
......
...@@ -25,6 +25,19 @@ class JobShopACO(ACO): ...@@ -25,6 +25,19 @@ class JobShopACO(ACO):
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
def createCollatedScenarios(self,data): def createCollatedScenarios(self,data):
......
...@@ -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