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()