Tutorials¶
Implement your own problem¶
To make your problem compliant with the framework, your problem class has to extend the class moead_framework.problem.Problem
and implement the following 2 required functions :
the fitness function
f(function_id, solution)
has 2 required parameters. The function must return the objective value of the givensolution
for the objective specified byfunction_id
.
Note
For compatibility with existing components, problems should be converted to minimization problems.
def f(self, function_id, solution):
...
return objective_value
The function
generate_random_solution()
generates a solution randomly. You can see an example to generate pseudo-boolean solutions :
def generate_random_solution(self):
return self.evaluate(x=np.random.randint(0, 2, self.number_of_objects).tolist()[:])
Examples are available in this repository : https://github.com/moead-framework/framework/tree/master/moead_framework/problem/combinatorial.
Implement your own algorithm¶
All components are set with default values to implement the first version of MOEA/D. You can customize each algorithm in the framework with your own components that you can set as parameter of the algorithm contructor.
Note
Not all available components are compatible with each other. Refer to each component’s documentation for more details on required attributes.
Example for moead_framework.algorithm.combinatorial.moead
:
moead = Moead(
# Mandatory parameters
problem=rmnk,
max_evaluation = number_of_evaluations,
number_of_weight_neighborhood=number_of_weight_neighborhood,
weight_file=weight_file,
aggregation_function=Tchebycheff,
# Optional parameters
termination_criteria=MaxEvaluation,
number_of_crossover_points=2,
mutation_probability=1,
mating_pool_selector=ClosestNeighborsSelector,
genetic_operator=CrossoverAndMutation,
parent_selector=TwoRandomParentSelector,
sps_strategy=SpsAllSubproblems,
offspring_generator=OffspringGeneratorGeneric
)
If you want to manage the way to use all these components, you have to create a new algorithm by extending an available algorithm. Examples are available in this repository : https://github.com/moead-framework/framework/tree/master/moead_framework/algorithm.
An example is the implementation of MOEA/D-DE [LZ09] in the class moead_framework.algorithm.combinatorial.moead_delta_nr
that extends Moead to rewrite the
function update_solutions()
and adds two new parameters.
Manage the reproducibility of results¶
Reproducibility of results is a major principle for scientific research. The feature used here is not specific to the framework but can be used for every python project that uses the numpy and built-in random modules.
Because the framework uses the random and numpy modules, you can be sure to have the same results by running the same script several times if you add the following instructions before initializing problems or algorithms:
from moead_framework.tool.result import set_seed
seed = 0
set_seed(seed)
Warning
This approach is not safe in threaded environments. By re-using a seed value, the same sequence should be reproducible from run to run as long as multiple threads are not running (https://docs.python.org/3/library/random.html#notes-on-reproducibility)
You can find more information at the following links:
Save data with the framework¶
You can easily save a set of solutions by using the function save_population("population.txt", population)
.
The function must be imported with : from moead_framework.tool.result import save_population
.
If you want to save all non-dominated solutions (attribute self.ep
in the algorithm) every e.g. 10 evaluations, you can use the checkpoint parameter of the function algorithm.run()
:
moead = Moead(
problem=rmnk,
max_evaluation = number_of_evaluations,
number_of_weight_neighborhood=number_of_weight_neighborhood,
weight_file=weight_file,
aggregation_function=Tchebycheff
)
def checkpoint(moead_algorithm: AbstractMoead):
if moead_algorithm.current_eval % 10 ==0 :
filename = "non_dominated_solutions-eval" + str(moead_algorithm.current_eval) + ".txt"
save_population(file_name=filename, population=moead_algorithm.ep)
moead.run(checkpoint=checkpoint)
Extract and plot the Pareto front¶
The method run() of each algorithm returns a list of moead_framework.solution.one_dimension_solution.OneDimensionSolution
.
moead = Moead(
problem=rmnk,
max_evaluation = number_of_evaluations,
number_of_weight_neighborhood=number_of_weight_neighborhood,
weight_file=weight_file,
aggregation_function=Tchebycheff
)
list_of_solutions = moead.run(checkpoint=checkpoint)
You can then extract the Pareto set and the Pareto front :
pareto_front = []
pareto_set = []
for solution_object in list_of_solutions:
pareto_front.append(solution_object.F)
pareto_set.append(solution_object.decision_vector)
If you want plot the Pareto front with matplotlib, you can do it with :
from matplotlib import pyplot as plt
import numpy as np
data = np.array(pareto_front)
x, y = data.T
plt.scatter(x,y)
plt.show()