Create your own variant of MOEA/D with the modularity of the framework

The moead-framework provides many components to allow you to create your own variant of the MOEA/D algorithm. The documentation of all components is available here : https://moead-framework.github.io/framework/html/api.html.

In this example, we want to use a local search algorithm (hill climber first improvement) after the generation of each new solution (offspring). To do this, we implement a new offspring generator that will extend the component `OffspringGeneratorGeneric` that is used by default in MOEA/D.

"""
The `OffspringGeneratorWithHillClimber` component is a custom `OffspringGenerator`used as an example
to show the modularity of the framework.
"""
import numpy as np
from moead_framework.core.offspring_generator import OffspringGeneratorGeneric

class OffspringGeneratorWithHillClimber(OffspringGeneratorGeneric):
    """
    Generate a new offspring by using the component OffspringGeneratorGeneric
    followed by a local search algorithm (Hill-climber First Improvement)
    """

    def run(self, population_indexes):
        candidate_solution = super().run(population_indexes)
        candidate_solution_after_localsearch = self.hill_climber_first_improvement(first_solution=candidate_solution)

        return self.algorithm.problem.evaluate(x=candidate_solution_after_localsearch)

    def hill_climber_first_improvement(self, first_solution):
        decision_vector_best_solution = first_solution.decision_vector
        best_agg_value = self.algorithm.aggregation_function.run(solution=self.algorithm.problem.evaluate(x=first_solution),
                                                                 number_of_objective=len(first_solution.F),
                                                                 weights=self.algorithm.weights,
                                                                 sub_problem=self.algorithm.current_sub_problem,
                                                                 z=self.algorithm.z)
        stuck_by_local_optima = False

        while not stuck_by_local_optima:
            for i in range(len(decision_vector_best_solution)):
                neighbor = np.copy(decision_vector_best_solution)
                neighbor[i] = abs(neighbor[i] - 1)
                self.algorithm.current_eval += 1

                neighbor_agg_value = self.algorithm.aggregation_function.run(solution=self.algorithm.problem.evaluate(x=neighbor),
                                                                             number_of_objective=len(first_solution.F),
                                                                             weights=self.algorithm.weights,
                                                                             sub_problem=self.algorithm.current_sub_problem,
                                                                             z=self.algorithm.z)

                if neighbor_agg_value < best_agg_value:  # when we minimize the aggregation function
                    best_agg_value = neighbor_agg_value
                    decision_vector_best_solution = neighbor
                else:
                    stuck_by_local_optima = True

        return decision_vector_best_solution

The component is then set as a parameter to the algorithm’s constructor.

"""
This complete example shows how to use a custom component as input to the MOEA/D algorithm.
"""
from example2.offspring_generator_local_search import OffspringGeneratorWithHillClimber
from moead_framework.aggregation import Tchebycheff
from moead_framework.algorithm.combinatorial import Moead
from moead_framework.problem.combinatorial import Rmnk


###############################
#    Initialize the problem   #
###############################
# The file is available here : https://github.com/moead-framework/data/blob/master/problem/RMNK/Instances/rmnk_0_2_100_1_0.dat
# Others instances are available here : https://github.com/moead-framework/data/tree/master/problem/RMNK/Instances
instance_file = "rmnk_0_2_100_1_0.dat"
rmnk = Rmnk(instance_file=instance_file)


###############################
#  Initialize the algorithm   #
###############################
number_of_weight = 10
number_of_weight_neighborhood = 20
number_of_evaluations = 10000
# The file is available here : https://github.com/moead-framework/data/blob/master/weights/SOBOL-2objs-10wei.ws
# Others weights files are available here : https://github.com/moead-framework/data/tree/master/weights
weight_file = "SOBOL-" + str(rmnk.number_of_objective) + "objs-" + str(number_of_weight) + "wei.ws"


###############################
#    Execute the algorithm    #
###############################
moead = Moead(problem=rmnk,
              max_evaluation=number_of_evaluations,
              number_of_weight_neighborhood=number_of_weight_neighborhood,
              weight_file=weight_file,
              aggregation_function=Tchebycheff,
              offspring_generator=OffspringGeneratorWithHillClimber,
              )

population = moead.run()