From e9690cd03abe3e70afcc7669cb260049224732b6 Mon Sep 17 00:00:00 2001 From: Dipo Olaitan <oladipupo.olaitan2@mail.dcu.ie> Date: Fri, 4 Sep 2015 13:24:25 +0200 Subject: [PATCH] ACO Updates and Default Shift Pattern in Exceptions Sheet --- dream/plugins/ACO.py | 30 ++++++++++++++++++++++----- dream/plugins/JobShop/JobShopACO.py | 13 ++++++++++++ dream/plugins/JobShop/ReadJSShifts.py | 11 +++++++--- 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/dream/plugins/ACO.py b/dream/plugins/ACO.py index 54cc640a..5d4f6150 100644 --- a/dream/plugins/ACO.py +++ b/dream/plugins/ACO.py @@ -23,7 +23,12 @@ class ACO(plugin.ExecutionPlugin): """Calculate the score of this ant. Implemented in the Subclass, raises NotImplementedError """ 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): """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 @@ -51,14 +56,16 @@ class ACO(plugin.ExecutionPlugin): tested_ants = set() 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 max_results = int(data['general'].get('numberOfSolutions',0)) assert max_results >= 1 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 # generation can have more than 1 ant) seedPlus = 0 @@ -133,6 +140,7 @@ class ACO(plugin.ExecutionPlugin): for ant in scenario_list: ant['score'] = self._calculateAntScore(ant) + ant['actualDelays'] = self._calculateAntActualDelay(ant) ants.extend(scenario_list) @@ -147,9 +155,14 @@ class ACO(plugin.ExecutionPlugin): # The ants in this generation are ranked based on their scores and the # 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] - + + collated = deepcopy(resetCollated)#reset previous pheromone updates for l in ants: # update the options list to ensure that good performing queue-rule # combinations have increased representation and good chance of @@ -159,6 +172,13 @@ class ACO(plugin.ExecutionPlugin): # 'EDD' is added to Q1 so there is a higher chance that it is # selected by the next ants. 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 = [] for ant in ants: diff --git a/dream/plugins/JobShop/JobShopACO.py b/dream/plugins/JobShop/JobShopACO.py index b66e6faf..d5266a8e 100644 --- a/dream/plugins/JobShop/JobShopACO.py +++ b/dream/plugins/JobShop/JobShopACO.py @@ -24,6 +24,19 @@ class JobShopACO(ACO): # should not be considered better than being on time. totalDelay += max(delay, 0) 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 # of options collated into a dictionary for ease of referencing in ManPy diff --git a/dream/plugins/JobShop/ReadJSShifts.py b/dream/plugins/JobShop/ReadJSShifts.py index 2d862a29..1073ab14 100644 --- a/dream/plugins/JobShop/ReadJSShifts.py +++ b/dream/plugins/JobShop/ReadJSShifts.py @@ -52,7 +52,12 @@ class ReadJSShifts(plugin.InputPreparationPlugin, TimeSupportMixin): exceptionShiftPattern = {} # exceptions for shift pattern dictionary as defined in the spreadsheet 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 lastrec=None for line in shiftData: @@ -71,12 +76,12 @@ class ReadJSShifts(plugin.InputPreparationPlugin, TimeSupportMixin): #if no shift start was given, assume standard 8:00 startTime = line[2] if startTime == '' or startTime == None: - startTime = "08:00" + startTime = standardStartTime shiftStart = self.convertToSimulationTime(strptime("%s %s" % (line[1], startTime), '%Y/%m/%d %H:%M')) #if no shift end was given, assume standard 18:00 endTime = line[3] if endTime == '' or endTime == None: - endTime = "18:00" + endTime = standardEndTime shiftEnd = self.convertToSimulationTime(strptime("%s %s" % (line[1], endTime), '%Y/%m/%d %H:%M')) timePair = self.correctTimePair(shiftStart, shiftEnd) if not timePair: -- 2.30.9