def __init__(self, problem: Problem, population_size: int, cr: float, f: float, termination_criterion: TerminationCriterion, k: float = 0.5, population_generator: Generator = store.default_generator, population_evaluator: Evaluator = store.default_evaluator, dominance_comparator: Comparator = DominanceComparator()): super(GDE3, self).__init__(problem=problem, population_size=population_size, offspring_population_size=population_size) self.dominance_comparator = dominance_comparator self.selection_operator = DifferentialEvolutionSelection() self.crossover_operator = DifferentialEvolutionCrossover(cr, f, k) self.population_generator = population_generator self.population_evaluator = population_evaluator self.termination_criterion = termination_criterion self.observable.register(termination_criterion)
class GDE3(EvolutionaryAlgorithm[FloatSolution, FloatSolution]): def __init__(self, problem: Problem, population_size: int, cr: float, f: float, termination_criterion: TerminationCriterion = store. default_termination_criteria, k: float = 0.5, population_generator: Generator = store.default_generator, population_evaluator: Evaluator = store.default_evaluator, dominance_comparator: Comparator = store.default_comparator): super(GDE3, self).__init__(problem=problem, population_size=population_size, offspring_population_size=population_size) self.dominance_comparator = dominance_comparator self.selection_operator = DifferentialEvolutionSelection() self.crossover_operator = DifferentialEvolutionCrossover(cr, f, k) self.population_generator = population_generator self.population_evaluator = population_evaluator self.termination_criterion = termination_criterion self.observable.register(termination_criterion) def selection(self, population: List[FloatSolution]) -> List[FloatSolution]: mating_pool = [] for i in range(self.population_size): self.selection_operator.set_index_to_exclude(i) selected_solutions = self.selection_operator.execute( self.solutions) mating_pool = mating_pool + selected_solutions return mating_pool def reproduction(self, mating_pool: List[S]) -> List[S]: offspring_population = [] first_parent_index = 0 for solution in self.solutions: self.crossover_operator.current_individual = solution parents = mating_pool[first_parent_index:first_parent_index + 3] first_parent_index += 3 offspring_population.append( self.crossover_operator.execute(parents)[0]) return offspring_population def replacement( self, population: List[S], offspring_population: List[FloatSolution] ) -> List[List[FloatSolution]]: tmp_list = [] for solution1, solution2 in zip(self.solutions, offspring_population): result = self.dominance_comparator.compare(solution1, solution2) if result == -1: tmp_list.append(solution1) elif result == 1: tmp_list.append(solution2) else: tmp_list.append(solution1) tmp_list.append(solution2) join_population = population + offspring_population return RankingAndCrowdingDistanceSelection( self.population_size, dominance_comparator=self.dominance_comparator).execute( join_population) def create_initial_solutions(self) -> List[FloatSolution]: return [ self.population_generator.new(self.problem) for _ in range(self.population_size) ] def evaluate(self, solution_list: List[FloatSolution]) -> List[FloatSolution]: return self.population_evaluator.evaluate(solution_list, self.problem) def stopping_condition_is_met(self) -> bool: return self.termination_criterion.is_met def get_result(self) -> List[FloatSolution]: return self.solutions def get_name(self) -> str: return 'GDE3'
def run(self) -> List[S]: pool_1_size = self.population_size pool_2_size = self.population_size selection_operator_1 = BinaryTournamentSelection() crossover_operator_1 = IntegerSBXCrossover(1.0, 20.0) mutation_operator_1 = IntegerPolynomialMutation( 1.0 / self.problem.number_of_variables, 20.0) selection_operator_2 = DifferentialEvolutionSelection() crossover_operator_2 = DifferentialEvolutionCrossover(0.2, 0.5, 0.5) dominance = DominanceComparator() max_iterations = self.max_iterations iterations = 0 parent_1: List[IntegerSolution] = [None, None] generational_hv: List[float] = [] current_gen = 0 """Create the initial subpopulation pools and evaluate them""" pool_1: List[IntegerSolution] = [] for i in range(pool_1_size): pool_1.append(self.problem.create_solution()) pool_1[i] = self.problem.evaluate(pool_1[i]) pool_2: List[IntegerSolution] = [] for i in range(pool_2_size): pool_2.append(self.problem.create_solution()) pool_2[i] = self.problem.evaluate(pool_2[i]) evaluations = pool_1_size + pool_2_size mix = self.mix_interval problem = self.problem h = HyperVolume(reference_point=[1] * self.problem.number_of_objectives) initial_population = True """The main evolutionary cycle""" while iterations < max_iterations: combi: List[IntegerSolution] = [] if not initial_population: offspring_pop_1: List[IntegerSolution] = [] offspring_pop_2: List[IntegerSolution] = [] """Evolve pool 1""" for i in range(pool_1_size): parent_1[0] = selection_operator_1.execute(pool_1) parent_1[1] = selection_operator_1.execute(pool_1) child_1: IntegerSolution = crossover_operator_1.execute( parent_1)[0] child_1 = mutation_operator_1.execute(child_1) child_1 = problem.evaluate(child_1) evaluations += 1 offspring_pop_1.append(child_1) """Evolve pool 2""" for i in range(pool_2_size): parent_2: List[ IntegerSolution] = selection_operator_2.execute(pool_2) crossover_operator_2.current_individual = pool_2[i] child_2 = crossover_operator_2.execute(parent_2) child_2 = problem.evaluate(child_2[0]) evaluations += 1 result = dominance.compare(pool_2[i], child_2) if result == -1: offspring_pop_2.append(pool_2[i]) elif result == 1: offspring_pop_2.append(child_2) else: offspring_pop_2.append(child_2) offspring_pop_2.append(pool_2[i]) ind_1 = pool_1[random.randint(0, pool_1_size - 1)] ind_2 = pool_2[random.randint(0, pool_2_size - 1)] offspring_pop_1.append(ind_1) offspring_pop_2.append(ind_2) offspring_pop_1.extend(pool_1) pool_1 = self.r.replace(offspring_pop_1[:pool_1_size], offspring_pop_1[pool_1_size:]) pool_2 = self.r.replace(offspring_pop_2[:pool_2_size], offspring_pop_2[pool_2_size:]) mix -= 1 if mix == 0: """Time to perform fitness sharing""" mix = self.mix_interval combi = combi + pool_1 + pool_2 # print("Combi size: ", len(combi)) """pool1size/10""" combi = self.r.replace( combi[:int(pool_1_size / 10)], combi[int(pool_1_size / 10):len(combi)], ) """ print( "Sizes: ", len(pool_1) + len(combi), len(pool_2) + len(combi), "\n", ) """ pool_1 = self.r.replace(pool_1, combi) pool_2 = self.r.replace(pool_2, combi) if initial_population: initial_population = False iterations += 1 print("Iterations: ", str(iterations)) """ hval_1 = h.compute([s.objectives for s in pool_1]) hval_2 = h.compute([s.objectives for s in pool_2]) print("hval_1: ", str(hval_1)) print("hval_2: ", str(hval_2), "\n") """ new_gen = int(evaluations / self.report_interval) if new_gen > current_gen: combi = combi + pool_1 + pool_2 combi = self.r.replace(combi[:(2 * pool_1_size)], combi[(2 * pool_1_size):]) hval = h.compute([s.objectives for s in combi]) for i in range(current_gen, new_gen, 1): generational_hv.append(hval) current_gen = new_gen """#Write runtime generational HV to file""" """Return the first non dominated front""" combi_ini: List[IntegerSolution] = [] combi_ini.extend(pool_1) combi_ini.extend(pool_2) combi_ini = self.r.replace( combi_ini[:pool_1_size + pool_2_size], combi_ini[pool_1_size + pool_2_size:], ) return combi_ini
def run(self) -> List[S]: # selection operator 1 selection_operator_1 = BinaryTournamentSelection() # selection operator 2 selection_operator_2 = DifferentialEvolutionSelection() # crossover operator 1 crossover_operator_1 = SBXCrossover(1.0, 20.0) # crossover operator 2 crossover_operator_2 = DifferentialEvolutionCrossover(0.2, 0.5, 0.5) # crossover operator 3 crossover_operator_3 = DifferentialEvolutionCrossover(1.0, 0.5, 0.5) # mutation operator 1 mutation_operator_1 = PolynomialMutation( 1.0 / self.problem.number_of_variables, 20.0) # dominance comparator dominance = DominanceComparator() # array that stores the "generational" HV quality generational_hv: List[float] = [] parent_1: List[FloatSolution] = [None, None] parent_2: List[FloatSolution] = [] parent_3: List[FloatSolution] = [] # initialize some local and global variables pool_1: List[FloatSolution] = [] pool_2: List[FloatSolution] = [] # size of elite subset used for fitness sharing between subpopulations nrOfDirectionalSolutionsToEvolve = int(self.population_size / 5) # subpopulation 1 pool_1_size = int(self.population_size - (nrOfDirectionalSolutionsToEvolve / 2)) # subpopulation 2 pool_2_size = int(self.population_size - (nrOfDirectionalSolutionsToEvolve / 2)) print( str(pool_1_size) + " - " + str(nrOfDirectionalSolutionsToEvolve) + " - " + str(self.mix_interval)) evaluations = 0 current_gen = 0 directionalArchiveSize = 2 * self.population_size weights = self.__create_uniform_weights( directionalArchiveSize, self.problem.number_of_objectives) directionalArchive = self.__create_directional_archive(weights) neighbourhoods = self.__create_neighbourhoods(directionalArchive, self.population_size) nrOfReplacements = 1 iniID = 0 # Create the initial pools # pool1 pool_1: List[FloatSolution] = [] for _ in range(pool_1_size): new_solution = self.problem.create_solution() new_solution = self.problem.evaluate(new_solution) evaluations += 1 pool_1.append(new_solution) self.__update_extreme_values(new_solution) dr = directionalArchive[iniID] dr.curr_sol = new_solution iniID += 1 # pool2 pool_2: List[FloatSolution] = [] for _ in range(pool_2_size): new_solution = self.problem.create_solution() new_solution = self.problem.evaluate(new_solution) evaluations += 1 pool_2.append(new_solution) self.__update_extreme_values(new_solution) dr = directionalArchive[iniID] dr.curr_sol = new_solution iniID += 1 # directional archive initialization pool_A: List[FloatSolution] = [] while iniID < directionalArchiveSize: new_solution = self.problem.create_solution() new_solution = self.problem.evaluate(new_solution) evaluations += 1 pool_A.append(new_solution) self.__update_extreme_values(new_solution) dr = directionalArchive[iniID] dr.curr_sol = new_solution iniID += 1 mix = self.mix_interval h = HyperVolume(reference_point=[1] * self.problem.number_of_objectives) insertionRate: List[float] = [0, 0, 0] bonusEvals: List[int] = [0, 0, nrOfDirectionalSolutionsToEvolve] testRun = True # record the generational HV of the initial population combiAll: List[FloatSolution] = [] cGen = int(evaluations / self.report_interval) if cGen > 0: combiAll = pool_1 + pool_2 + pool_A combiAll = self.r.replace( combiAll[:pool_1_size + pool_2_size], combiAll[pool_1_size + pool_2_size:], ) hval = h.compute([s.objectives for s in combiAll]) for _ in range(cGen): generational_hv.append(hval) current_gen = cGen # the main loop of the algorithm while evaluations < self.max_evaluations: offspringPop1: List[FloatSolution] = [] offspringPop2: List[FloatSolution] = [] offspringPop3: List[FloatSolution] = [] dirInsertPool1: List[FloatSolution] = [] dirInsertPool2: List[FloatSolution] = [] dirInsertPool3: List[FloatSolution] = [] # evolve pool1 - using SPEA2 evolutionary model nfe: int = 0 while nfe < (pool_1_size + bonusEvals[0]): parent_1[0] = selection_operator_1.execute(pool_1) parent_1[1] = selection_operator_1.execute(pool_1) child1a: FloatSolution = crossover_operator_1.execute( parent_1)[0] child1a = mutation_operator_1.execute(child1a) child1a = self.problem.evaluate(child1a) evaluations += 1 nfe += 1 offspringPop1.append(child1a) dirInsertPool1.append(child1a) # evolve pool2 - using DEMO SP evolutionary model i: int = 0 unselectedIDs: List[int] = [] for ID in range(len(pool_2)): unselectedIDs.append(ID) nfe = 0 while nfe < (pool_2_size + bonusEvals[1]): index = random.randint(0, len(unselectedIDs) - 1) i = unselectedIDs[index] unselectedIDs.pop(index) parent_2 = selection_operator_2.execute(pool_2) crossover_operator_2.current_individual = pool_2[i] child2 = crossover_operator_2.execute(parent_2) child2 = self.problem.evaluate(child2[0]) evaluations += 1 nfe += 1 result = dominance.compare(pool_2[i], child2) if result == -1: # solution i dominates child offspringPop2.append(pool_2[i]) elif result == 1: # child dominates offspringPop2.append(child2) else: # the two solutions are non-dominated offspringPop2.append(child2) offspringPop2.append(pool_2[i]) dirInsertPool2.append(child2) if len(unselectedIDs) == 0: for ID in range(len(pool_2)): unselectedIDs.append(random.randint( 0, len(pool_2) - 1)) # evolve pool3 - Directional Decomposition DE/rand/1/bin IDs = self.__compute_neighbourhood_Nfe_since_last_update( neighbourhoods, directionalArchive, nrOfDirectionalSolutionsToEvolve) nfe = 0 for j in range(len(IDs)): if nfe < bonusEvals[2]: nfe += 1 else: break cID = IDs[j] chosenSol: FloatSolution = None if directionalArchive[cID].curr_sol != None: chosenSol = directionalArchive[cID].curr_sol else: chosenSol = pool_1[0] print("error!") parent_3: List[FloatSolution] = [None, None, None] r1 = random.randint(0, len(neighbourhoods[cID]) - 1) r2 = random.randint(0, len(neighbourhoods[cID]) - 1) r3 = random.randint(0, len(neighbourhoods[cID]) - 1) while r2 == r1: r2 = random.randint(0, len(neighbourhoods[cID]) - 1) while r3 == r1 or r3 == r2: r3 = random.randint(0, len(neighbourhoods[cID]) - 1) parent_3[0] = directionalArchive[r1].curr_sol parent_3[1] = directionalArchive[r2].curr_sol parent_3[2] = directionalArchive[r3].curr_sol crossover_operator_3.current_individual = chosenSol child3 = crossover_operator_3.execute(parent_3)[0] child3 = mutation_operator_1.execute(child3) child3 = self.problem.evaluate(child3) evaluations += 1 dirInsertPool3.append(child3) # compute directional improvements # pool1 improvements = 0 for j in range(len(dirInsertPool1)): testSol = dirInsertPool1[j] self.__update_extreme_values(testSol) improvements += self.__update_neighbourhoods( directionalArchive, testSol, nrOfReplacements) insertionRate[0] += (1.0 * improvements) / len(dirInsertPool1) # pool2 improvements = 0 for j in range(len(dirInsertPool2)): testSol = dirInsertPool2[j] self.__update_extreme_values(testSol) improvements += self.__update_neighbourhoods( directionalArchive, testSol, nrOfReplacements) insertionRate[1] += (1.0 * improvements) / len(dirInsertPool2) # pool3 improvements = 0 for j in range(len(dirInsertPool3)): testSol = dirInsertPool3[j] self.__update_extreme_values(testSol) improvements += self.__update_neighbourhoods( directionalArchive, testSol, nrOfReplacements) # on java, dividing a floating number by 0, returns NaN # on python, dividing a floating number by 0, returns an exception if len(dirInsertPool3) == 0: insertionRate[2] = None else: insertionRate[2] += (1.0 * improvements) / len(dirInsertPool3) for dr in directionalArchive: offspringPop3.append(dr.curr_sol) offspringPop1 = offspringPop1 + pool_1 pool_1 = self.r.replace(offspringPop1[:pool_1_size], offspringPop1[pool_1_size:]) pool_2 = self.r.replace(offspringPop2[:pool_2_size], offspringPop2[pool_2_size:]) combi: List[FloatSolution] = [] mix -= 1 if mix == 0: mix = self.mix_interval combi = combi + pool_1 + pool_2 + offspringPop3 print("Combi size: " + str(len(combi))) combi = self.r.replace( combi[:nrOfDirectionalSolutionsToEvolve], combi[nrOfDirectionalSolutionsToEvolve:], ) insertionRate[0] /= self.mix_interval insertionRate[1] /= self.mix_interval if insertionRate[2] != None: insertionRate[2] /= self.mix_interval """ print( "Insertion rates: " + str(insertionRate[0]) + " - " + str(insertionRate[1]) + " - " + str(insertionRate[2]) + " - Test run:" + str(testRun) ) """ if testRun: if (insertionRate[0] > insertionRate[1]) and ( insertionRate[0] > insertionRate[2]): print("SPEA2 win - bonus run!") bonusEvals[0] = nrOfDirectionalSolutionsToEvolve bonusEvals[1] = 0 bonusEvals[2] = 0 if (insertionRate[1] > insertionRate[0]) and ( insertionRate[1] > insertionRate[2]): print("DE win - bonus run!") bonusEvals[0] = 0 bonusEvals[1] = nrOfDirectionalSolutionsToEvolve bonusEvals[2] = 0 if (insertionRate[2] > insertionRate[0]) and ( insertionRate[2] > insertionRate[1]): print("Directional win - no bonus!") bonusEvals[0] = 0 bonusEvals[1] = 0 bonusEvals[2] = nrOfDirectionalSolutionsToEvolve else: print("Test run - no bonus!") bonusEvals[0] = 0 bonusEvals[1] = 0 bonusEvals[2] = nrOfDirectionalSolutionsToEvolve testRun = not testRun insertionRate[0] = 0.0 insertionRate[1] = 0.0 insertionRate[2] = 0.0 pool_1 = pool_1 + combi pool_2 = pool_2 + combi print("Sizes: " + str(len(pool_1)) + " " + str(len(pool_2))) pool_1 = self.r.replace(pool_1[:pool_1_size], pool_1[pool_1_size:]) pool_2 = self.r.replace(pool_2[:pool_2_size], pool_2[pool_2_size:]) self.__clear_Nfe_history(directionalArchive) hVal1 = h.compute([s.objectives for s in pool_1]) hVal2 = h.compute([s.objectives for s in pool_2]) hVal3 = h.compute([s.objectives for s in offspringPop3]) newGen = int(evaluations / self.report_interval) if newGen > current_gen: print("Hypervolume: " + str(newGen) + " - " + str(hVal1) + " - " + str(hVal2) + " - " + str(hVal3)) combi = combi + pool_1 + pool_2 + offspringPop3 combi = self.r.replace(combi[:self.population_size * 2], combi[self.population_size * 2:]) hval = h.compute([s.objectives for s in combi]) for j in range(current_gen, newGen): generational_hv.append(hval) current_gen = newGen # return the final combined non-dominated set of maximum size = (populationSize * 2) combiAll: List[FloatSolution] = [] combiAll = combiAll + pool_1 + pool_2 + pool_A combiAll = self.r.replace(combiAll[:self.population_size * 2], combiAll[self.population_size * 2:]) return combiAll