def __init__(
     self,
     problem: MOProblem,
     pop_size: int,
     pop_params: Dict = None,
     use_surrogates: bool = False,
 ):
     super().__init__(problem, pop_size)
     self.lower_limits = self.problem.get_variable_lower_bounds()
     self.upper_limits = self.problem.get_variable_upper_bounds()
     self.individuals_archive = {}
     self.objectives_archive = {}
     self.uncertainty_archive = {}
     self.gen_count = 1
     #self.individuals_archive[str(self.gen_count)] = self.individuals
     #self.objectives_archive[str(self.gen_count)] = self.objectives
     #self.uncertainty_archive[str(self.gen_count)] = self.uncertainity
     if pop_params is None:
         design = "LHSDesign"
     if pop_params is not None:
         if "design" in pop_params.keys():
             design = pop_params["design"]
         else:
             design = "LHSDesign"
     if design == "InitSamples":
         individuals = pop_params["init_pop"]
     else:
         individuals = create_new_individuals(design, problem, pop_size)
     self.add(individuals, use_surrogates)
     self.xover = SBX_xover()
     self.mutation = BP_mutation(self.lower_limits, self.upper_limits)
Example #2
0
 def __init__(self, problem: MOProblem, pop_size: int, pop_params: Dict = None):
     super().__init__(problem, pop_size)
     self.lower_limits = self.problem.get_variable_lower_bounds()
     self.upper_limits = self.problem.get_variable_upper_bounds()
     if pop_params is None:
         design = "LHSDesign"
     if pop_params is not None:
         if "design" in pop_params.keys():
             design = pop_params["design"]
         else:
             design = "LHSDesign"
     individuals = create_new_individuals(design, problem, pop_size)
     self.add(individuals)
     self.xover = SBX_xover()
     self.mutation = BP_mutation(self.lower_limits, self.upper_limits)
Example #3
0
    def __init__(  # parameters of the class
        self,
        problem: MOProblem,
        scalarization_function: MOEADSF = Tchebycheff(),
        n_neighbors: int = 20,
        population_params: Dict = None,
        initial_population: Population = None,
        lattice_resolution: int = None,
        use_repair: bool = True,
        n_parents: int = 2,
        a_priori: bool = False,
        interact: bool = False,
        use_surrogates: bool = False,
        n_iterations: int = 10,
        n_gen_per_iter: int = 100,
        total_function_evaluations: int = 0,
    ):
        super().__init__(  # parameters for decomposition based approach
            problem=problem,
            population_size=None,
            population_params=population_params,
            initial_population=initial_population,
            lattice_resolution=lattice_resolution,
            a_priori=a_priori,
            interact=interact,
            use_surrogates=use_surrogates,
            n_iterations=n_iterations,
            n_gen_per_iter=n_gen_per_iter,
            total_function_evaluations=total_function_evaluations,
        )
        self.population_size = self.population.pop_size
        self.problem = problem
        self.scalarization_function = scalarization_function
        self.n_neighbors = n_neighbors

        self.use_repair = use_repair
        self.n_parents = n_parents
        self.population.mutation = BP_mutation(
            problem.get_variable_lower_bounds(),
            problem.get_variable_upper_bounds(),
            0.5,
            20,
        )
        self.population.recombination = SBX_xover(1.0, 20)

        selection_operator = MOEAD_select(self.population,
                                          SF_type=self.scalarization_function)
        self.selection_operator = selection_operator
        # Compute the distance between each pair of reference vectors
        distance_matrix_vectors = distance_matrix(
            self.reference_vectors.values, self.reference_vectors.values)
        # Get the closest vectors to obtain the neighborhoods
        self.neighborhoods = np.argsort(distance_matrix_vectors,
                                        axis=1,
                                        kind="quicksort")[:, :n_neighbors]
        self.population.update_ideal()
        self._ideal_point = self.population.ideal_objective_vector
Example #4
0
class Population(BasePopulation):
    def __init__(
        self,
        problem: MOProblem,
        pop_size: int,
        pop_params: Dict = None,
        use_surrogates: bool = False,
    ):
        super().__init__(problem, pop_size)
        self.lower_limits = self.problem.get_variable_lower_bounds()
        self.upper_limits = self.problem.get_variable_upper_bounds()
        if pop_params is None:
            design = "LHSDesign"
        if pop_params is not None:
            if "design" in pop_params.keys():
                design = pop_params["design"]
            else:
                design = "LHSDesign"
        individuals = create_new_individuals(design, problem, pop_size)
        self.add(individuals, use_surrogates)
        self.xover = SBX_xover()
        self.mutation = BP_mutation(self.lower_limits, self.upper_limits)

    def add(self,
            offsprings: Union[List, np.ndarray],
            use_surrogates: bool = False) -> List:
        """Evaluate and add offspring to the population.

        Parameters
        ----------
        offsprings : Union[List, np.ndarray]
            List or array of individuals to be evaluated and added to the population.
        
        use_surrogates: bool
            If true, use surrogate models rather than true function evaluations.

        use_surrogates: bool
            If true, use surrogate models rather than true function evaluations.

        Returns
        -------
        List
            Indices of the evaluated individuals
        """
        results = self.problem.evaluate(offsprings, use_surrogates)
        objectives = results.objectives
        fitness = results.fitness
        constraints = results.constraints
        uncertainity = results.uncertainity
        if self.individuals is None:
            self.individuals = offsprings
            self.objectives = objectives
            self.fitness = fitness
            self.constraint = constraints
            self.uncertainity = uncertainity
            first_offspring_index = 0
        else:
            first_offspring_index = self.individuals.shape[0]
            if self.individuals.ndim - offsprings.ndim == 1:
                self.individuals = np.vstack((self.individuals, [offsprings]))
            elif self.individuals.ndim == offsprings.ndim:
                self.individuals = np.vstack((self.individuals, offsprings))
            else:
                pass  # TODO raise error
            self.objectives = np.vstack((self.objectives, objectives))
            self.fitness = np.vstack((self.fitness, fitness))
            if self.problem.n_of_constraints != 0:
                self.constraint = np.vstack((self.constraint, constraints))
            if uncertainity is None:
                self.uncertainity = None
            else:
                self.uncertainity = np.vstack(
                    (self.uncertainity, uncertainity))
        last_offspring_index = self.individuals.shape[0]
        self.update_ideal()
        return list(range(first_offspring_index, last_offspring_index))

    def keep(self, indices: List):
        """Save the population members given by the list of indices for the next
            generation. Delete the rest.

        Parameters
        ----------
        indices : List
            List of indices of the population members to be kept for the next
                generation.
        """
        mask = np.zeros(self.individuals.shape[0], dtype=bool)
        mask[indices] = True
        self.individuals = self.individuals[mask]
        self.objectives = self.objectives[mask]
        self.fitness = self.fitness[mask]
        if self.uncertainity is not None:
            self.uncertainity = self.uncertainity[mask]
        if self.problem.n_of_constraints > 0:
            self.constraint = self.constraint[mask]

    def delete(self, indices: List):
        """Delete the population members given by the list of indices for the next
            generation. Keep the rest.

        Parameters
        ----------
        indices : List
            List of indices of the population members to be deleted.
        """
        mask = np.ones(self.individuals.shape[0], dtype=bool)
        mask[indices] = False
        self.individuals = self.individuals[mask]
        if len(self.individuals) == 0:
            self.individuals = None
        self.objectives = self.objectives[mask]
        self.fitness = self.fitness[mask]
        if self.uncertainity is not None:
            self.uncertainity = self.uncertainity[mask]
        if self.problem.n_of_constraints > 0:
            self.constraint = self.constraint[mask]

    def mate(self, mating_individuals: List = None) -> Union[List, np.ndarray]:
        """Perform crossover and mutation over the population members.

        Parameters
        ----------
        mating_individuals : List, optional
            List of individuals taking part in recombination. By default None, which
                recombinated all individuals in random order.
        params : Dict, optional
            Parameters for the mutation or crossover operator, by default None.

        Returns
        -------
        Union[List, np.ndarray]
            The offspring population
        """
        if self.recombination is not None:
            offspring = self.recombination.do(self.individuals,
                                              mating_individuals)
        else:
            offspring = self.xover.do(self.individuals, mating_individuals)
            offspring = self.mutation.do(offspring)
        return offspring

    def update_ideal(self):
        if self.ideal_fitness_val is None:
            self.ideal_fitness_val = np.amin(self.fitness, axis=0)
        else:
            self.ideal_fitness_val = np.amin(np.vstack(
                (self.ideal_fitness_val, self.fitness)),
                                             axis=0)
        self.ideal_objective_vector = (self.ideal_fitness_val *
                                       self.problem._max_multiplier)
class Population(BasePopulation):
    def __init__(
        self,
        problem: MOProblem,
        pop_size: int,
        pop_params: Dict = None,
        use_surrogates: bool = False,
    ):
        super().__init__(problem, pop_size)
        self.lower_limits = self.problem.get_variable_lower_bounds()
        self.upper_limits = self.problem.get_variable_upper_bounds()
        self.individuals_archive = {}
        self.objectives_archive = {}
        self.uncertainty_archive = {}
        self.gen_count = 1
        #self.individuals_archive[str(self.gen_count)] = self.individuals
        #self.objectives_archive[str(self.gen_count)] = self.objectives
        #self.uncertainty_archive[str(self.gen_count)] = self.uncertainity
        if pop_params is None:
            design = "LHSDesign"
        if pop_params is not None:
            if "design" in pop_params.keys():
                design = pop_params["design"]
            else:
                design = "LHSDesign"
        if design == "InitSamples":
            individuals = pop_params["init_pop"]
        else:
            individuals = create_new_individuals(design, problem, pop_size)
        self.add(individuals, use_surrogates)
        self.xover = SBX_xover()
        self.mutation = BP_mutation(self.lower_limits, self.upper_limits)

    def add(self,
            offsprings: Union[List, np.ndarray],
            use_surrogates: bool = False) -> List:
        """Evaluate and add offspring to the population.

        Parameters
        ----------
        offsprings : Union[List, np.ndarray]
            List or array of individuals to be evaluated and added to the population.
        
        use_surrogates: bool
            If true, use surrogate models rather than true function evaluations.

        Returns
        -------
        List
            Indices of the evaluated individuals
        """
        results = self.problem.evaluate(offsprings, use_surrogates)
        objectives = results.objectives
        fitness = results.fitness
        constraints = results.constraints
        uncertainity = results.uncertainity
        self.individuals_archive[str(
            self.gen_count)] = copy.deepcopy(offsprings)
        self.objectives_archive[str(
            self.gen_count)] = copy.deepcopy(objectives)
        self.uncertainty_archive[str(
            self.gen_count)] = copy.deepcopy(uncertainity)
        self.gen_count += 1
        if self.individuals is None:
            self.individuals = offsprings
            self.objectives = objectives
            self.fitness = fitness
            self.constraint = constraints
            self.uncertainity = uncertainity
            first_offspring_index = 0
        else:
            first_offspring_index = self.individuals.shape[0]
            if self.individuals.ndim - offsprings.ndim == 1:
                self.individuals = np.vstack((self.individuals, [offsprings]))
            elif self.individuals.ndim == offsprings.ndim:
                self.individuals = np.vstack((self.individuals, offsprings))
            else:
                pass  # TODO raise error
            self.objectives = np.vstack((self.objectives, objectives))
            self.fitness = np.vstack((self.fitness, fitness))
            if self.problem.n_of_constraints != 0:
                self.constraint = np.vstack((self.constraint, constraints))
            if uncertainity is None:
                self.uncertainity = None
            else:
                self.uncertainity = np.vstack(
                    (self.uncertainity, uncertainity))
        last_offspring_index = self.individuals.shape[0]
        self.update_ideal()
        return list(range(first_offspring_index, last_offspring_index))

    def keep(self, indices: List):
        """Save the population members given by the list of indices for the next
            generation. Delete the rest.

        Parameters
        ----------
        indices : List
            List of indices of the population members to be kept for the next
                generation.
        """

        mask = np.zeros(self.individuals.shape[0], dtype=bool)
        mask[indices] = True
        self.individuals = self.individuals[mask]
        self.objectives = self.objectives[mask]
        self.fitness = self.fitness[mask]
        if self.uncertainity is not None:
            self.uncertainity = self.uncertainity[mask]
        if self.problem.n_of_constraints > 0:
            self.constraint = self.constraint[mask]

    def delete(self, indices: List):
        """Delete the population members given by the list of indices for the next
            generation. Keep the rest.

        Parameters
        ----------
        indices : List
            List of indices of the population members to be deleted.
        """
        mask = np.ones(self.individuals.shape[0], dtype=bool)
        mask[indices] = False
        self.individuals = self.individuals[mask]
        if len(self.individuals) == 0:
            self.individuals = None
        self.objectives = self.objectives[mask]
        self.fitness = self.fitness[mask]
        if self.uncertainity is not None:
            self.uncertainity = self.uncertainity[mask]
        if self.problem.n_of_constraints > 0:
            self.constraint = self.constraint[mask]

    def mate(self, mating_individuals: List = None) -> Union[List, np.ndarray]:
        """Perform crossover and mutation over the population members.

        Parameters
        ----------
        mating_individuals : List, optional
            List of individuals taking part in recombination. By default None, which
                recombinated all individuals in random order.
        params : Dict, optional
            Parameters for the mutation or crossover operator, by default None.

        Returns
        -------
        Union[List, np.ndarray]
            The offspring population
        """
        if self.recombination is not None:
            offspring = self.recombination.do(self.individuals,
                                              mating_individuals)
        else:
            offspring = self.xover.do(self.individuals, mating_individuals)
            offspring = self.mutation.do(offspring)
        return offspring

    def update_ideal(self):
        if self.ideal_fitness_val is None:
            self.ideal_fitness_val = np.amin(self.fitness, axis=0)
        else:
            self.ideal_fitness_val = np.amin(np.vstack(
                (self.ideal_fitness_val, self.fitness)),
                                             axis=0)
        self.ideal_objective_vector = (self.ideal_fitness_val *
                                       self.problem._max_multiplier)

    def replace(self, indices: List, individual: np.ndarray,
                evaluation: tuple):
        """Replace the population members given by the list of indices by the given individual and its evaluation. 
           Keep the rest of the population unchanged.

        Parameters
        ----------
        indices : List
            List of indices of the population members to be replaced.
        individual: np.ndarray
            Decision variables of the individual that will replace the positions given in the list.
        evaluation: tuple
            Result of the evaluation of the objective function, constraints, etc. obtained using the evaluate method.
        """
        self.individuals[indices, :] = individual
        self.objectives[indices, :] = evaluation.objectives
        self.fitness[indices, :] = evaluation.fitness
        if self.constraint is not None:
            self.constraint[indices, :] = evaluation.constraints
        if self.uncertainity is not None:
            self.uncertainity[indices, :] = evaluation.uncertainity

    def repair(self, individual):
        """Repair the variables of an individual which are not in the boundary defined by the problem
        Parameters
        ----------
        individual : 
            Decision variables of the individual.

        Return
        ----------
        The new decision vector with the variables in the boundary defined by the problem
        """
        upper_bounds = self.problem.get_variable_upper_bounds()
        lower_bounds = self.problem.get_variable_lower_bounds()
        upper_bounds_check = np.where(individual > upper_bounds)
        lower_bounds_check = np.where(individual < lower_bounds)
        individual[upper_bounds_check] = upper_bounds[upper_bounds_check]
        individual[lower_bounds_check] = lower_bounds[lower_bounds_check]
        return individual