# encoding=utf8
import logging
from niapy.algorithms.algorithm import Individual
from niapy.algorithms.basic.de import DifferentialEvolution, cross_best1, cross_rand1, cross_curr2best1, cross_best2, \
cross_curr2rand1, multi_mutations
from niapy.util import objects_to_array
logging.basicConfig()
logger = logging.getLogger('niapy.algorithms.modified')
logger.setLevel('INFO')
__all__ = [
'SolutionJDE',
'SelfAdaptiveDifferentialEvolution',
'MultiStrategySelfAdaptiveDifferentialEvolution',
]
class SolutionJDE(Individual):
r"""Individual for jDE algorithm.
Attributes:
differential_weight (float): Scale factor.
crossover_probability (float): Crossover probability.
See Also:
:class:`niapy.algorithms.Individual`
"""
def __init__(self, differential_weight=2, crossover_probability=0.5, **kwargs):
r"""Initialize SolutionJDE.
Attributes:
differential_weight (float): Scale factor.
crossover_probability (float): Crossover probability.
See Also:
:func:`niapy.algorithm.Individual.__init__`
"""
super().__init__(**kwargs)
self.differential_weight = differential_weight
self.crossover_probability = crossover_probability
[docs]class SelfAdaptiveDifferentialEvolution(DifferentialEvolution):
r"""Implementation of Self-adaptive differential evolution algorithm.
Algorithm:
Self-adaptive differential evolution algorithm
Date:
2018
Author:
Uros Mlakar and Klemen Berkovič
License:
MIT
Reference paper:
Brest, J., Greiner, S., Boskovic, B., Mernik, M., Zumer, V. Self-adapting control parameters in differential evolution: A comparative study on numerical benchmark problems. IEEE transactions on evolutionary computation, 10(6), 646-657, 2006.
Attributes:
Name (List[str]): List of strings representing algorithm name
f_lower (float): Scaling factor lower limit.
f_upper (float): Scaling factor upper limit.
tao1 (float): Change rate for differential_weight parameter update.
tao2 (float): Change rate for crossover_probability parameter update.
See Also:
* :class:`niapy.algorithms.basic.DifferentialEvolution`
"""
Name = ['SelfAdaptiveDifferentialEvolution', 'jDE']
[docs] @staticmethod
def info():
r"""Get algorithm information.
Returns:
str: Algorithm information.
See Also:
* :func:`niapy.algorithms.Algorithm.info`
"""
return r"""Brest, J., Greiner, S., Boskovic, B., Mernik, M., Zumer, V. Self-adapting control parameters in differential evolution: A comparative study on numerical benchmark problems. IEEE transactions on evolutionary computation, 10(6), 646-657, 2006."""
[docs] def __init__(self, f_lower=0.0, f_upper=1.0, tao1=0.4, tao2=0.2, *args, **kwargs):
"""Initialize SelfAdaptiveDifferentialEvolution.
Args:
f_lower (Optional[float]): Scaling factor lower limit.
f_upper (Optional[float]): Scaling factor upper limit.
tao1 (Optional[float]): Change rate for differential_weight parameter update.
tao2 (Optional[float]): Change rate for crossover_probability parameter update.
See Also:
* :func:`niapy.algorithms.basic.DifferentialEvolution.__init__`
"""
super().__init__(individual_type=kwargs.pop('individual_type', SolutionJDE), *args, **kwargs)
self.f_lower = f_lower
self.f_upper = f_upper
self.tao1 = tao1
self.tao2 = tao2
[docs] def set_parameters(self, f_lower=0.0, f_upper=1.0, tao1=0.4, tao2=0.2, **kwargs):
r"""Set the parameters of an algorithm.
Args:
f_lower (Optional[float]): Scaling factor lower limit.
f_upper (Optional[float]): Scaling factor upper limit.
tao1 (Optional[float]): Change rate for differential_weight parameter update.
tao2 (Optional[float]): Change rate for crossover_probability parameter update.
See Also:
* :func:`niapy.algorithms.basic.DifferentialEvolution.set_parameters`
"""
super().set_parameters(individual_type=kwargs.pop('individual_type', SolutionJDE), **kwargs)
self.f_lower = f_lower
self.f_upper = f_upper
self.tao1 = tao1
self.tao2 = tao2
[docs] def get_parameters(self):
r"""Get algorithm parameters.
Returns:
Dict[str, Any]: Algorithm parameters.
"""
d = DifferentialEvolution.get_parameters(self)
d.update({
'f_lower': self.f_lower,
'f_upper': self.f_upper,
'tao1': self.tao1,
'tao2': self.tao2
})
return d
[docs] def adaptive_gen(self, x):
r"""Adaptive update scale factor in crossover probability.
Args:
x (IndividualJDE): Individual to apply function on.
Returns:
Individual: New individual with new parameters
"""
f = self.f_lower + self.random() * (self.f_upper - self.f_lower) if self.random() < self.tao1 else x.differential_weight
cr = self.random() if self.random() < self.tao2 else x.crossover_probability
return self.individual_type(x=x.x, differential_weight=f, crossover_probability=cr, e=False)
[docs] def evolve(self, pop, xb, task, **_kwargs):
r"""Evolve current population.
Args:
pop (numpy.ndarray[Individual]): Current population.
xb (Individual): Global best individual.
task (Task): Optimization task.
Returns:
numpy.ndarray: New population.
"""
new_pop = objects_to_array([self.adaptive_gen(e) for e in pop])
for i, e in enumerate(new_pop):
new_pop[i].x = self.strategy(new_pop, i, e.differential_weight, e.crossover_probability, rng=self.rng, x_b=xb)
for e in new_pop:
e.evaluate(task, rng=self.random)
return new_pop
[docs]class MultiStrategySelfAdaptiveDifferentialEvolution(SelfAdaptiveDifferentialEvolution):
r"""Implementation of self-adaptive differential evolution algorithm with multiple mutation strategies.
Algorithm:
Self-adaptive differential evolution algorithm with multiple mutation strategies
Date:
2018
Author:
Klemen Berkovič
License:
MIT
Attributes:
Name (List[str]): List of strings representing algorithm name
See Also:
* :class:`niapy.algorithms.modified.SelfAdaptiveDifferentialEvolution`
"""
Name = ['MultiStrategySelfAdaptiveDifferentialEvolution', 'MsjDE']
[docs] def __init__(self, strategies=(cross_curr2rand1, cross_curr2best1, cross_rand1, cross_best1, cross_best2), *args,
**kwargs):
"""Initialize MultiStrategySelfAdaptiveDifferentialEvolution.
Args:
strategies (Optional[Iterable[Callable]]): Mutations strategies to use in algorithm.
See Also:
* :func:`niapy.algorithms.modified.SelfAdaptiveDifferentialEvolution.__init__`
"""
super().__init__(strategy=kwargs.pop('strategy', multi_mutations), *args, **kwargs)
self.strategies = strategies
[docs] def set_parameters(self, strategies=(cross_curr2rand1, cross_curr2best1, cross_rand1, cross_best1, cross_best2),
**kwargs):
r"""Set core parameters of MultiStrategySelfAdaptiveDifferentialEvolution algorithm.
Args:
strategies (Optional[Iterable[Callable]]): Mutations strategies to use in algorithm.
See Also:
* :func:`niapy.algorithms.modified.SelfAdaptiveDifferentialEvolution.set_parameters`
"""
super().set_parameters(strategy=kwargs.pop('strategy', multi_mutations), **kwargs)
self.strategies = strategies
[docs] def get_parameters(self):
r"""Get parameters of the algorithm.
Returns:
Dict[str, Any]: Algorithm parameters.
"""
params = super().get_parameters()
params.update({'strategies': self.strategies})
return params
[docs] def evolve(self, pop, xb, task, **kwargs):
r"""Evolve population with the help multiple mutation strategies.
Args:
pop (numpy.ndarray[Individual]): Current population.
xb (Individual): Current best individual.
task (Task): Optimization task.
Returns:
numpy.ndarray[Individual]: New population of individuals.
"""
return objects_to_array(
[self.strategy(pop, i, xb, self.differential_weight, self.crossover_probability, self.rng, task, self.individual_type, self.strategies) for i in
range(len(pop))])