Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
geoffreyp committed Jun 23, 2020
2 parents 4b9c2a2 + 1ac4c3e commit 9d49e68
Show file tree
Hide file tree
Showing 13 changed files with 144 additions and 84 deletions.
15 changes: 11 additions & 4 deletions moead_framework/algorithm/abstract_moead.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from moead_framework.core.offspring_generator.offspring_generator import OffspringGeneratorGeneric
from moead_framework.core.selector.closest_neighbors_selector import ClosestNeighborsSelector
from moead_framework.core.sps_strategy.sps_all import SpsAllSubproblems
from moead_framework.core.termination_criteria.max_evaluation import MaxEvaluation
from moead_framework.tool.mop import is_duplicated, get_non_dominated, generate_weight_vectors

Expand All @@ -15,9 +16,11 @@ def __init__(self, problem, max_evaluation, number_of_objective, number_of_weigh
genetic_operator=None,
parent_selector=None,
mating_pool_selector=None,
sps_strategy=None,
weight_file=None):
self.problem = problem
self.aggregation_function = aggregation_function()

if termination_criteria is None:
self.termination_criteria = MaxEvaluation(algorithm_instance=self)
else:
Expand All @@ -35,6 +38,11 @@ def __init__(self, problem, max_evaluation, number_of_objective, number_of_weigh
self.b = self.generate_closest_weight_vectors()
self.current_sub_problem = -1

if sps_strategy is None:
self.sps_strategy = SpsAllSubproblems(algorithm_instance=self)
else:
self.sps_strategy = sps_strategy(algorithm_instance=self)

if mating_pool_selector is None:
self.mating_pool_selector = ClosestNeighborsSelector(algorithm_instance=self)
else:
Expand All @@ -44,7 +52,6 @@ def __init__(self, problem, max_evaluation, number_of_objective, number_of_weigh
self.parent_selector = parent_selector
self.offspring_generator = OffspringGeneratorGeneric(algorithm_instance=self)


@abstractmethod
def run(self, checkpoint=None):
pass
Expand All @@ -53,14 +60,14 @@ def run(self, checkpoint=None):
def update_solutions(self, solution, scal_function, sub_problem):
pass

def sps_strategy(self):
return range(self.number_of_weight)
def get_sub_problems_to_visit(self):
return self.sps_strategy.get_sub_problems()

def mating_pool_selection(self, sub_problem):
return self.mating_pool_selector.select(sub_problem)

def generate_offspring(self, population):
return self.offspring_generator.run(population_indexes=population) # useless d'utiliser une class si c'est générique
return self.offspring_generator.run(population_indexes=population)

def repair(self, solution):
return solution
Expand Down
4 changes: 3 additions & 1 deletion moead_framework/algorithm/combinatorial/moead.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def __init__(self, problem,
mating_pool_selector=None,
genetic_operator=None,
parent_selector=None,
sps_strategy=None,
weight_file=None):

self.current_eval = 1
Expand All @@ -32,6 +33,7 @@ def __init__(self, problem,
genetic_operator=genetic_operator,
mating_pool_selector=mating_pool_selector,
parent_selector=parent_selector,
sps_strategy=sps_strategy,
weight_file=weight_file)
self.number_of_crossover_points = number_of_crossover_points

Expand All @@ -50,7 +52,7 @@ def run(self, checkpoint=None):
while self.termination_criteria.test():

# For each sub-problem i
for i in self.sps_strategy():
for i in self.get_sub_problems_to_visit():

if checkpoint is not None:
checkpoint()
Expand Down
2 changes: 2 additions & 0 deletions moead_framework/algorithm/combinatorial/moead_delta_nr.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ def __init__(self, problem,
delta,
number_of_replacement,
aggregation_function,
sps_strategy=None,
number_of_crossover_points=2,
parent_selector=None,
weight_file=None):
Expand All @@ -33,6 +34,7 @@ def __init__(self, problem,
mating_pool_selector=mating_pool_selector,
parent_selector=parent_selector,
number_of_crossover_points=number_of_crossover_points,
sps_strategy=sps_strategy,
weight_file=weight_file)

def update_solutions(self, solution, aggregation_function, sub_problem):
Expand Down
52 changes: 3 additions & 49 deletions moead_framework/algorithm/combinatorial/moead_dra.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import random
import numpy as np
from moead_framework.algorithm.combinatorial.moead_delta_nr import MoeadDeltaNr
from moead_framework.core.sps_strategy.sps_dra import SpsDra


class MoeadDRA(MoeadDeltaNr):
Expand All @@ -27,6 +28,7 @@ def __init__(self, problem,
number_of_replacement=number_of_replacement,
aggregation_function=aggregation_function,
number_of_crossover_points=number_of_crossover_points,
sps_strategy=SpsDra,
weight_file=weight_file)

self.pi = np.ones(self.number_of_weight)
Expand All @@ -43,7 +45,7 @@ def run(self, checkpoint=None):

while self.current_eval < self.max_evaluation:

for i in self.sps_strategy():
for i in self.get_sub_problems_to_visit():

if checkpoint is not None:
checkpoint(self.current_eval)
Expand Down Expand Up @@ -75,54 +77,6 @@ def run(self, checkpoint=None):

return self.ep

def get_xtrem_index(self):
xtrem_index = []
for i in range(self.number_of_weight):
weight = self.weights[i]
for j in range(self.number_of_objective):
if weight[j] == 1:
xtrem_index.append(i)
break

return xtrem_index

def sps_strategy(self):
"""
Select at first the indexes of the sub problems whose objectives are MOP
individual objectives fi ([1, 0] and [0, 1] for example)
and add sub problems by a 10-tournament
:return:
"""
selection = []

for w in range(self.number_of_weight):
count_zero = 0
for o in self.weights[w]:
if o == 0:
count_zero += 1

if count_zero == self.number_of_objective - 1:
selection.append(w)
break

xtrem_index = self.get_xtrem_index()

# 10-tournament
for i in range(int((self.number_of_weight / 5) - self.number_of_objective)):
range_list = list(range(self.number_of_weight))
random_indexes = random.sample(list(set(range_list) - set(xtrem_index)), 10)

best_index = random_indexes[0]
best_pi = self.pi[random_indexes[0]]
for index in random_indexes:
if self.pi[index] > best_pi:
best_index = index
best_pi = self.pi[index]

selection.append(best_index)

return selection

def update_scores(self, sub_problem, score):
"""
self.scores[sub_problem][0] = old score
Expand Down
31 changes: 4 additions & 27 deletions moead_framework/algorithm/combinatorial/moead_sps_random.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import random
from moead_framework.algorithm.combinatorial.moead import Moead
from moead_framework.core.sps_strategy.sps_random_and_boundaries import SpsRandomAndBoundaries


class MoeadSPSRandom(Moead):
Expand All @@ -9,7 +10,7 @@ def __init__(self, problem,
number_of_objective,
number_of_weight,
number_of_weight_neighborhood,
number_of_subproblem,
number_of_subproblem_to_visit,
aggregation_function,
number_of_crossover_points=2,
mating_pool_selector=None,
Expand All @@ -28,32 +29,8 @@ def __init__(self, problem,
genetic_operator=genetic_operator,
mating_pool_selector=mating_pool_selector,
parent_selector=parent_selector,
sps_strategy=SpsRandomAndBoundaries,
weight_file=weight_file)

self.current_eval = 1
self.number_of_subproblem = number_of_subproblem

def sps_strategy(self):
"""
Select one random sub problems in each cluster
:return: an array of sub problems
"""
range_list = list(range(self.number_of_weight))
xtrem_index = self.get_xtrem_index()
random_indexes = random.sample(list(set(range_list)-set(xtrem_index)), self.number_of_subproblem)

random_indexes = random_indexes + xtrem_index
random.shuffle(random_indexes)

return random_indexes

def get_xtrem_index(self):
xtrem_index = []
for i in range(self.number_of_weight):
weight = self.weights[i]
for j in range(self.number_of_objective):
if weight[j] == 1:
xtrem_index.append(i)
break

return xtrem_index
self.number_of_subproblem = number_of_subproblem_to_visit
4 changes: 3 additions & 1 deletion moead_framework/algorithm/numerical/moead.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def __init__(self, problem,
mating_pool_selector=None,
genetic_operator=None,
parent_selector=None,
sps_strategy=None,
weight_file=None):

self.current_eval = 1
Expand All @@ -32,6 +33,7 @@ def __init__(self, problem,
genetic_operator=genetic_operator,
mating_pool_selector=mating_pool_selector,
parent_selector=parent_selector,
sps_strategy=sps_strategy,
weight_file=weight_file)

if genetic_operator is None:
Expand All @@ -49,7 +51,7 @@ def run(self, checkpoint=None):
while self.termination_criteria.test():

# For each sub-problem i
for i in self.sps_strategy():
for i in self.get_sub_problems_to_visit():

if checkpoint is not None:
checkpoint()
Expand Down
Empty file.
11 changes: 11 additions & 0 deletions moead_framework/core/sps_strategy/abstract_sps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from abc import ABC, abstractmethod


class SpsStrategy(ABC):

def __init__(self, algorithm_instance):
self.algorithm = algorithm_instance

@abstractmethod
def get_sub_problems(self):
pass
9 changes: 9 additions & 0 deletions moead_framework/core/sps_strategy/sps_all.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from moead_framework.core.sps_strategy.abstract_sps import SpsStrategy


class SpsAllSubproblems(SpsStrategy):
"""
It is the classic SPS Strategy of MOEA/D, we visit all sub-problems at each generation
"""
def get_sub_problems(self):
return range(self.algorithm.number_of_weight)
60 changes: 60 additions & 0 deletions moead_framework/core/sps_strategy/sps_dra.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import random

from moead_framework.core.sps_strategy.abstract_sps import SpsStrategy


class SpsDra(SpsStrategy):
"""
Q. Zhang, W. Liu and H. Li,
"The performance of a new version of MOEA/D on CEC09 unconstrained MOP test instances"
2009 IEEE Congress on Evolutionary Computation
Trondheim, 2009, pp. 203-208
doi: 10.1109/CEC.2009.4982949.
"""
def get_sub_problems(self):
"""
Select at first the indexes of the sub problems whose objectives are MOP
individual objectives fi ([1, 0] and [0, 1] for example)
and add sub problems by a 10-tournament
:return:
"""
selection = []

for w in range(self.algorithm.number_of_weight):
count_zero = 0
for o in self.algorithm.weights[w]:
if o == 0:
count_zero += 1

if count_zero == self.algorithm.number_of_objective - 1:
selection.append(w)
break

xtrem_index = self.get_xtrem_index()

# 10-tournament
for i in range(int((self.algorithm.number_of_weight / 5) - self.algorithm.number_of_objective)):
range_list = list(range(self.algorithm.number_of_weight))
random_indexes = random.sample(list(set(range_list) - set(xtrem_index)), 10)

best_index = random_indexes[0]
best_pi = self.algorithm.pi[random_indexes[0]]
for index in random_indexes:
if self.algorithm.pi[index] > best_pi:
best_index = index
best_pi = self.algorithm.pi[index]

selection.append(best_index)

return selection

def get_xtrem_index(self):
xtrem_index = []
for i in range(self.algorithm.number_of_weight):
weight = self.algorithm.weights[i]
for j in range(self.algorithm.number_of_objective):
if weight[j] == 1:
xtrem_index.append(i)
break

return xtrem_index
36 changes: 36 additions & 0 deletions moead_framework/core/sps_strategy/sps_random_and_boundaries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import random

from moead_framework.core.sps_strategy.abstract_sps import SpsStrategy


class SpsRandomAndBoundaries(SpsStrategy):
"""
Pruvost, Geoffrey, et al.
"On the Combined Impact of Population Size and Sub-problem Selection in MOEA/D."
European Conference on Evolutionary Computation in Combinatorial Optimization (Part of EvoStar).
Springer, Cham, 2020
"""
def get_sub_problems(self):
"""
Select one random sub problems in each cluster
:return: an array of sub problems
"""
range_list = list(range(self.algorithm.number_of_weight))
xtrem_index = self.get_xtrem_index()
random_indexes = random.sample(list(set(range_list) - set(xtrem_index)), self.algorithm.number_of_subproblem)

random_indexes = random_indexes + xtrem_index
random.shuffle(random_indexes)

return random_indexes

def get_xtrem_index(self):
xtrem_index = []
for i in range(self.algorithm.number_of_weight):
weight = self.algorithm.weights[i]
for j in range(self.algorithm.number_of_objective):
if weight[j] == 1:
xtrem_index.append(i)
break

return xtrem_index
2 changes: 1 addition & 1 deletion moead_framework/test/test_combinatorial_algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def test_moead_sps_random(self):
aggregation_function=Tchebycheff,
number_of_weight_neighborhood=self.number_of_weight_neighborhood,
number_of_crossover_points=self.number_of_crossover_points,
number_of_subproblem=number_of_subproblem,
number_of_subproblem_to_visit=number_of_subproblem,
weight_file=self.weight_file,
)

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setuptools.setup(
name="moead-framework",
version="0.4.0",
version="0.5.0",
author="Geoffrey Pruvost",
author_email="geoffrey@pruvost.xyz",
description="MOEA/D Framework in Python 3",
Expand Down

0 comments on commit 9d49e68

Please sign in to comment.