def update(self, *args, **kwargs): solutions = kwargs['SOLUTIONS'] if solutions: variables = [] for s in solutions: variables.append(s.objectives) hv = HyperVolume(self.referencePoint) hv.is_minimization = True self.currentHyperVolume = hv.compute(variables) variation = float(abs(self.lastHyperVolume - self.currentHyperVolume) / self.currentHyperVolume) if variation <= self.HyperVolumeStagnationPercentage: self.counter += 1 if self.counter >= 15: self.HasReachVariation = True else: self.lastHyperVolume = copy.deepcopy(self.currentHyperVolume) else: self.lastHyperVolume = copy.deepcopy(self.currentHyperVolume) self.counter = 0 self.HasReachVariation = False print(self.counter)
def test_should_hypervolume_return_5_0(self): reference_point = [2, 2, 2] front = np.array([[1, 0, 1], [0, 1, 0]]) hv = HyperVolume(reference_point) value = hv.compute(front) self.assertEqual(5.0, value)
def test_should_hypervolume_return_the_correct_value_when_applied_to_the_ZDT1_reference_front(self): problem = ZDT1() problem.reference_front = read_solutions(filename='resources/reference_front/ZDT1.pf') reference_point = [1, 1] hv = HyperVolume(reference_point) value = hv.compute(problem.reference_front) self.assertAlmostEqual(0.666, value, delta=0.001)
def hv(true_front: NonDominatedSolutionsArchive, solution_list: List[Solution]) -> float: # prepare reference point and indicator reference_point = ResultHandler.find_reference_point( true_front.solution_list) indicator = HyperVolume(reference_point) mod = np.prod(reference_point) # prepare solution list in numpy array solutions = ResultHandler.to_numpy_array(solution_list) # calculate return indicator.compute(solutions) / mod
def test_should_hypervolume_return_5_0(self): reference_point = [2, 2, 2] solution1 = Solution(1, 3) solution1.objectives = [1, 0, 1] solution2 = Solution(1, 3) solution2.objectives = [0, 1, 0] front = [solution1, solution2] hv = HyperVolume(reference_point) value = hv.compute(front) self.assertEqual(5.0, value)
def test_should_hypervolume_return_the_correct_value_when_applied_to_the_ZDT1_reference_front( self): filepath = Path(DIRNAME, "ZDT1.pf") front = [] with open(filepath) as file: for line in file: vector = [float(x) for x in line.split()] front.append(vector) reference_point = [1, 1] hv = HyperVolume(reference_point) value = hv.compute(np.array(front)) self.assertAlmostEqual(0.666, value, delta=0.001)
def test_should_hypervolume_return_the_correct_value_when_applied_to_the_ZDT1_reference_front(self): filename = 'jmetal/core/test/ZDT1.pf' front = [] if Path(filename).is_file(): with open(filename) as file: for line in file: vector = [float(x) for x in line.split()] front.append(vector) else: print("error") reference_point = [1, 1] hv = HyperVolume(reference_point) value = hv.compute(np.array(front)) self.assertAlmostEqual(0.666, value, delta=0.001)
def test_should_SMPSO_work_when_solving_problem_ZDT1_with_standard_settings(self): problem = ZDT1() algorithm = SMPSO( problem=problem, swarm_size=100, mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), leaders=CrowdingDistanceArchive(100), termination_criterion=StoppingByEvaluations(max_evaluations=25000), ) algorithm.run() front = algorithm.get_result() hv = HyperVolume(reference_point=[1, 1]) value = hv.compute([front[i].objectives for i in range(len(front))]) self.assertTrue(value >= 0.655)
def test_should_NSGAII_work_when_solving_problem_ZDT1_with_standard_settings(self): problem = ZDT1() max_evaluations = 25000 algorithm = NSGAII( problem=problem, population_size=100, offspring_population_size=100, mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), crossover=SBXCrossover(probability=1.0, distribution_index=20), termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() front = algorithm.get_result() hv = HyperVolume(reference_point=[1, 1]) value = hv.compute([front[i].objectives for i in range(len(front))]) self.assertTrue(value >= 0.65)
def update(self, *args, **kwargs): self.evaluations = kwargs['EVALUATIONS'] solutions = kwargs['SOLUTIONS'] if solutions: variables = [] for s in solutions: variables.append(s.objectives) hv = HyperVolume(self.referencePoint) hv.is_minimization = True self.hyperVolumes.append(hv.compute(variables)) # TODO: Implement to IGD if self.evaluations >= self.max_evaluations: fileValue = self._getFileValue() filename = 'Hist/' + str(self.AlgorithmName) + '/' + 'HV-' + str(fileValue) + '.txt' with open(filename, 'w') as f: for hv in self.hyperVolumes: f.write(str(hv)) f.write('\n')
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
problem.reference_front = read_solutions(filename='resources/reference_front/DTLZ2.3D.pf') max_evaluations = 50000 algorithm = MOEAD( problem=problem, population_size=300, crossover=DifferentialEvolutionCrossover(CR=1.0, F=0.5), mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), aggregative_function=Tschebycheff(dimension=problem.number_of_objectives), neighbor_size=20, neighbourhood_selection_probability=0.9, max_number_of_replaced_solutions=2, weight_files_path='resources/MOEAD_weights', termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) ) algorithm.run() front = algorithm.get_result() hypervolume = HyperVolume([1.0, 1.0, 1.0]) print("Hypervolume: " + str(hypervolume.compute([front[i].objectives for i in range(len(front))]))) # Save results to file print_function_values_to_file(front, 'FUN.' + algorithm.label) print_variables_to_file(front, 'VAR.'+ algorithm.label) print(f'Algorithm: ${algorithm.get_name()}') print(f'Problem: ${problem.get_name()}') print(f'Computing time: ${algorithm.total_computing_time}')
problem=problem, population_size=300, crossover=DifferentialEvolutionCrossover(CR=1.0, F=0.5), mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), aggregative_function=Tschebycheff( dimension=problem.number_of_objectives), neighbor_size=20, neighbourhood_selection_probability=0.9, max_number_of_replaced_solutions=2, weight_files_path="resources/MOEAD_weights", termination_criterion=StoppingByEvaluations( max_evaluations=max_evaluations), ) algorithm.run() front = algorithm.get_result() hypervolume = HyperVolume([1.0, 1.0, 1.0]) print("Hypervolume: " + str( hypervolume.compute([front[i].objectives for i in range(len(front))]))) # Save results to file print_function_values_to_file(front, "FUN." + algorithm.label) print_variables_to_file(front, "VAR." + algorithm.label) print(f"Algorithm: {algorithm.get_name()}") print(f"Problem: {problem.get_name()}") print(f"Computing time: {algorithm.total_computing_time}")
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