Skip to content

Commit

Permalink
Added DE
Browse files Browse the repository at this point in the history
  • Loading branch information
blankjul committed Nov 9, 2018
1 parent 1dc39c5 commit b950e12
Show file tree
Hide file tree
Showing 21 changed files with 160 additions and 314 deletions.
32 changes: 18 additions & 14 deletions pymoo/algorithms/genetic_algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ def _initialize(self):
self.evaluator.eval(self.problem, pop, D=self.data)

# that call is a dummy survival to set attributes that are necessary for the mating selection
pop = self.survival.do(self.problem, pop, self.pop_size, D=self.data)
if self.survival:
pop = self.survival.do(self.problem, pop, self.pop_size, D=self.data)

return pop

Expand Down Expand Up @@ -210,7 +211,7 @@ def _mating(self, pop):
if self.eliminate_duplicates:
# eliminate duplicates if too close to the current population or already recombined individuals
if isinstance(self.eliminate_duplicates, bool):
is_duplicate = self._is_duplicate(_off, pop, off)
is_duplicate = default_is_duplicate(_off, pop, off)
elif isinstance(self.eliminate_duplicates, function):
is_duplicate = self.eliminate_duplicates(_off, pop, off)
# filter out the duplicates from the offsprings before adding
Expand All @@ -232,21 +233,24 @@ def _mating(self, pop):

return off

def _is_duplicate(self, pop, *other, epsilon=1e-20):

if len(other) == 0:
return np.full(len(pop), False)

X = pop.get("X")
def _finalize(self):
pass

_X = other[0].get("X")
for o in other[1:]:
if len(o) > 0:
_X = np.concatenate([_X, o.get("X")])

is_duplicate = np.any(cdist(X, _X) < epsilon, axis=1)
def default_is_duplicate(pop, *other, epsilon=1e-20):

return is_duplicate
if len(other) == 0:
return np.full(len(pop), False)

def _finalize(self):
pass
X = pop.get("X")

_X = other[0].get("X")
for o in other[1:]:
if len(o) > 0:
_X = np.concatenate([_X, o.get("X")])

is_duplicate = np.any(cdist(X, _X) < epsilon, axis=1)

return is_duplicate
4 changes: 2 additions & 2 deletions pymoo/algorithms/nsga2.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
from pymoo.operators.default_operators import set_if_none
from pymoo.operators.mutation.real_polynomial_mutation import PolynomialMutation
from pymoo.operators.sampling.real_random_sampling import RealRandomSampling
from pymoo.operators.selection.tournament_selection import TournamentSelection
from pymoo.operators.selection.tournament_selection import TournamentSelection, compare
from pymoo.util.display import disp_multi_objective
from pymoo.util.dominator import Dominator, compare
from pymoo.util.dominator import Dominator
from pymoo.util.non_dominated_sorting import NonDominatedSorting
from pymoo.util.randomized_argsort import randomized_argsort

Expand Down
3 changes: 1 addition & 2 deletions pymoo/algorithms/nsga3.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@
from pymoo.operators.default_operators import set_if_none
from pymoo.operators.mutation.real_polynomial_mutation import PolynomialMutation
from pymoo.operators.sampling.real_random_sampling import RealRandomSampling
from pymoo.operators.selection.tournament_selection import TournamentSelection
from pymoo.operators.selection.tournament_selection import TournamentSelection, compare
from pymoo.rand import random
from pymoo.util.display import disp_multi_objective
from pymoo.util.dominator import compare
from pymoo.util.function_loader import load_function
from pymoo.util.non_dominated_sorting import NonDominatedSorting

Expand Down
39 changes: 39 additions & 0 deletions pymoo/algorithms/so_de.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import numpy as np

from pymoo.algorithms.genetic_algorithm import GeneticAlgorithm
from pymoo.operators.crossover.real_differental_evolution_crossover import DifferentialEvolutionCrossover
from pymoo.operators.default_operators import set_default_if_none
from pymoo.operators.mutation.real_differential_evoluation_mutation import DifferentialEvolutionMutation
from pymoo.operators.selection.random_selection import RandomSelection
from pymoo.util.display import disp_single_objective


class DifferentialEvolution(GeneticAlgorithm):
def __init__(self,
**kwargs):
set_default_if_none("real", kwargs)
super().__init__(**kwargs)
self.selection = RandomSelection()
self.crossover = DifferentialEvolutionCrossover(weight=0.75)
self.mutation = DifferentialEvolutionMutation("binomial", 0.1)
self.func_display_attrs = disp_single_objective

def _next(self, pop):

# create offsprings and add it to the data of the algorithm
P = self.selection.do(pop, self.pop_size, self.crossover.n_parents)
off = self.crossover.do(self.problem, pop, P)
self.data = {**self.data, "off": off}

# do the mutation by using the offsprings
off = self.mutation.do(self.problem, pop, D=self.data)

# evaluate the results
self.evaluator.eval(self.problem, off, D=self.data)

# replace whenever offspring is better than population member
for i in range(len(pop)):
if off[i].F < pop[i].F:
pop[i] = off[i]

return pop
3 changes: 1 addition & 2 deletions pymoo/algorithms/so_genetic_algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@
from pymoo.operators.default_operators import set_if_none
from pymoo.operators.mutation.real_polynomial_mutation import PolynomialMutation
from pymoo.operators.sampling.real_random_sampling import RealRandomSampling
from pymoo.operators.selection.tournament_selection import TournamentSelection
from pymoo.operators.selection.tournament_selection import TournamentSelection, compare
from pymoo.util.display import disp_single_objective
from pymoo.util.dominator import compare


class SingleObjectiveGeneticAlgorithm(GeneticAlgorithm):
Expand Down
3 changes: 1 addition & 2 deletions pymoo/algorithms/unsga3.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@

from pymoo.algorithms.nsga3 import NSGA3
from pymoo.operators.default_operators import set_if_none
from pymoo.operators.selection.tournament_selection import TournamentSelection
from pymoo.operators.selection.tournament_selection import TournamentSelection, compare
from pymoo.rand import random
from pymoo.util.dominator import compare


class UNSGA3(NSGA3):
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions pymoo/model/algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,9 @@ def _each_iteration(self, D, first=False, **kwargs):
def _display(self, disp, header=False):
regex = " | ".join(["{}"] * len(disp))
if header:
print("=" * 40)
print("=" * 50)
print(regex.format(*[name.ljust(width) for name, _, width in disp]))
print("=" * 40)
print("=" * 50)
print(regex.format(*[str(val).ljust(width) for _, val, width in disp]))

@abstractmethod
Expand Down
59 changes: 6 additions & 53 deletions pymoo/operators/crossover/real_differental_evolution_crossover.py
Original file line number Diff line number Diff line change
@@ -1,60 +1,13 @@
import numpy as np

from pymoo.model.crossover import Crossover
from pymoo.rand import random


class DifferentialEvolutionCrossover(Crossover):

def __init__(self, variant="DE/rand/1", prob=0.5, weight=0.8, method="binomial", bounce_back_in_bounds=True):
super().__init__(4, 1, True)
self.prob = prob
def __init__(self, weight=0.8):
super().__init__(3, 1, True)
self.weight = weight
self.type = method
self.variant = variant
self.bounce_back_in_bounds = bounce_back_in_bounds

def _do(self, p, parents, children, **kwargs):

n_var = parents.shape[2]
n_offsprings = parents.shape[0]

# do the crossover
if self.type == "binomial":

# uniformly for each individual and each entry
r = random.random(size=(n_offsprings, n_var)) < self.prob

elif self.type == "exponential":

r = np.full((n_offsprings, n_var), False)

# start point of crossover
n = random.randint(0, n_var, size=n_var)
# length of chromosome to do the crossover
L = np.argmax((random.random(n_offsprings) > self.prob), axis=1)

# create for each individual the crossover range
for i in range(n_offsprings):
for l in range(L[i] + 1):
r[i, (n[i] + l) % n_var] = True

else:
raise Exception("Unknown crossover type. Either binomial or exponential.")

# the so called donor vector
children[:, :] = parents[:, 0]

if self.variant == "DE/rand/1":
trial = parents[:, 1] + self.weight * (parents[:, 2] - parents[:, 3])
else:
raise Exception("DE variant %s not known." % self.variant)

# set only if larger than F_CR
children[r] = trial[r]

# bounce back into bounds
if self.bounce_back_in_bounds:
smaller_than_min, larger_than_max = p.xl > children, p.xu < children
children[smaller_than_min] = (p.xl + (p.xl - children))[smaller_than_min]
children[larger_than_max] = (p.xu - (children - p.xu))[larger_than_max]
def _do(self, problem, pop, parents, **kwargs):
X = pop.get("X")[parents.T]
_X = X[0] + self.weight * (X[1] - X[2])
return pop.new("X", _X)
28 changes: 28 additions & 0 deletions pymoo/operators/mutation/real_differential_evoluation_mutation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from pymoo.model.mutation import Mutation
from pymoo.rand import random


class DifferentialEvolutionMutation(Mutation):
def __init__(self, variant, CR):
super().__init__(True)
self.CR = CR
self.variant = variant

def _do(self, problem, pop, D=None, **kwargs):

X = pop.get("X")

off = D['off']
_X = off.get("X")

# do the crossover
if self.variant == "binomial":
# uniformly for each individual and each entry
r = random.random(size=(len(off), problem.n_var)) < self.CR

X[r] = _X[r]
return pop.new("X", X)




4 changes: 2 additions & 2 deletions pymoo/operators/selection/random_selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ def _do(self, pop, n_select, n_parents, **kwargs):
n_random = n_select * n_parents

# number of permutations needed
n_perms = math.ceil(n_random / pop.size())
n_perms = math.ceil(n_random / len(pop))

# get random permutations and reshape them
P = random_permuations(n_perms, pop.size())[:n_random]
P = random_permuations(n_perms, len(pop))[:n_random]

return np.reshape(P, (n_select, n_parents))
26 changes: 26 additions & 0 deletions pymoo/operators/selection/tournament_selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import numpy as np

from pymoo.model.selection import Selection
from pymoo.rand import random
from pymoo.util.misc import random_permuations


Expand Down Expand Up @@ -47,3 +48,28 @@ def _do(self, pop, n_select, n_parents=1, **kwargs):
S = self.f_comp(pop, P, **kwargs)

return np.reshape(S, (n_select, n_parents))


def compare(a, a_val, b, b_val, method, return_random_if_equal=False):
if method == 'larger_is_better':
if a_val > b_val:
return a
elif a_val < b_val:
return b
else:
if return_random_if_equal:
return random.choice([a, b])
else:
return None
elif method == 'smaller_is_better':
if a_val < b_val:
return a
elif a_val > b_val:
return b
else:
if return_random_if_equal:
return random.choice([a, b])
else:
return None
else:
raise Exception("Unknown method.")
3 changes: 3 additions & 0 deletions pymoo/optimize.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ def get_alorithm(name):
elif name == 'rnsga3':
from pymoo.algorithms.rnsga3 import RNSGA3
return RNSGA3
elif name == 'de':
from pymoo.algorithms.so_de import DifferentialEvolution
return DifferentialEvolution
else:
raise Exception("Algorithm not known.")

Expand Down
27 changes: 0 additions & 27 deletions pymoo/util/dominator.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,5 @@
import numpy as np

from pymoo.rand import random


def compare(a, a_val, b, b_val, method, return_random_if_equal=False):
if method == 'larger_is_better':
if a_val > b_val:
return a
elif a_val < b_val:
return b
else:
if return_random_if_equal:
return random.choice([a, b])
else:
return None
elif method == 'smaller_is_better':
if a_val < b_val:
return a
elif a_val > b_val:
return b
else:
if return_random_if_equal:
return random.choice([a, b])
else:
return None
else:
raise Exception("Unknown method.")


class Dominator:

Expand Down
2 changes: 1 addition & 1 deletion pymoo/util/function_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def __init__(self) -> None:
self.cythonize = False

try:
from pymoo.cython.cython_info import info
from pymoo.cython.extensions import info
if info() == "yes":
self.cythonize = True
else:
Expand Down
Loading

0 comments on commit b950e12

Please sign in to comment.