Source code for desdeo_emo.EAs.MOEAD

from typing import Dict

from desdeo_emo.EAs.BaseEA import BaseDecompositionEA
from desdeo_emo.population.Population import Population
from desdeo_emo.selection.MOEAD_select import MOEAD_select
from desdeo_problem import MOProblem
from desdeo_problem.problem.Problem import EvaluationResults
from desdeo_tools.scalarization import MOEADSF
from desdeo_tools.scalarization.MOEADSF import PBI


[docs]class MOEA_D(BaseDecompositionEA): """Python implementation of MOEA/D .. Q. Zhang and H. Li, "MOEA/D: A Multiobjective Evolutionary Algorithm Based on Decomposition," in IEEE Transactions on Evolutionary Computation, vol. 11, no. 6, pp. 712-731, Dec. 2007, doi: 10.1109/TEVC.2007.892759. Parameters ---------- problem: MOProblem The problem class object specifying the details of the problem. scalarization_function: MOEADSF The scalarization function to compare the solutions. Some implementations can be found in desdeo-tools/scalarization/MOEADSF. By default it uses the PBI function. n_neighbors: int, optional Number of reference vectors considered in the neighborhoods creation. The default number is 20. population_params: Dict, optional The parameters for the population class, by default None. See desdeo_emo.population.Population for more details. initial_population: Population, optional An initial population class, by default None. Use this if you want to set up a specific starting population, such as when the output of one EA is to be used as the input of another. lattice_resolution: int, optional The number of divisions along individual axes in the objective space to be used while creating the reference vector lattice by the simplex lattice design. By default None n_parents: int, optional Number of individuals considered for the generation of offspring solutions. The default option is 2. a_priori: bool, optional A bool variable defining whether a priori preference is to be used or not. By default False interact: bool, optional A bool variable defining whether interactive preference is to be used or not. By default False use_surrogates: bool, optional A bool variable defining whether surrogate problems are to be used or not. By default False n_iterations: int, optional The total number of iterations to be run, by default 10. This is not a hard limit and is only used for an internal counter. n_gen_per_iter: int, optional The total number of generations in an iteration to be run, by default 100. This is not a hard limit and is only used for an internal counter. total_function_evaluations: int, optional Set an upper limit to the total number of function evaluations. When set to zero, this argument is ignored and other termination criteria are used. """ def __init__( # parameters of the class self, problem: MOProblem, n_neighbors: int = 20, n_parents: int = 2, use_repair: bool = True, initial_population: Population = None, population_size: int = None, population_params: Dict = None, lattice_resolution: int = None, interact: bool = False, n_iterations: int = 10, n_gen_per_iter: int = 100, use_surrogates: bool = False, total_function_evaluations: int = 0, scalarization_function: MOEADSF = PBI(), keep_archive: bool = False, save_non_dominated: bool = False, ): super().__init__( # parameters for decomposition based approach problem=problem, population_params=population_params, population_size=population_size, keep_archive=keep_archive, initial_population=initial_population, lattice_resolution=lattice_resolution, interact=interact, use_surrogates=use_surrogates, n_iterations=n_iterations, n_gen_per_iter=n_gen_per_iter, total_function_evaluations=total_function_evaluations, save_non_dominated=save_non_dominated, ) self.use_repair = use_repair # New crossover and mutation operators needed for more than two parents. if n_parents != 2: raise ValueError( "n_parents must be equal to 2. Other values not yet supported." ) self.n_parents = n_parents self.selection_operator = MOEAD_select( self.population, SF_type=scalarization_function, n_neighbors=n_neighbors ) # self._ideal_point = self.population.ideal_fitness_val
[docs] def _next_gen(self): # For each individual from the population for i in range(self.population.pop_size): # Consider only the individuals of the current neighborhood # for parent selection selected_parents = self.selection_operator.choose_parents( current_neighborhood=i, n_parents=self.n_parents ) # TODO: Implement better recombination operators for this steps # Currently SBX and PolyM are used, they produce two offspring. # Apply genetic operators over two random individuals offspring = self.population.mate(selected_parents) offspring = offspring[0, :] # Repair the solution if it is needed if self.use_repair: offspring = self.population.repair(offspring) # Evaluate the offspring by adding it to the population list results = self.population.add(offspring, use_surrogates=self.use_surrogates) if not self.use_surrogates: self._function_evaluation_count += 1 # Replace individuals with a worse SF value than the offspring selected = self._select(current_neighborhood=i) self.population.replace(selected, offspring, results) # Remove the extra individual added earlier self.population.delete([-1]) if self.save_non_dominated: self.non_dominated_archive(offspring, results) self._current_gen_count += 1 self._gen_count_in_curr_iteration += 1
[docs] def _select(self, current_neighborhood: int) -> list: return self.selection_operator.do( self.population, current_neighborhood, )