1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586 |
- """Crossover implementations for continuous solutions kind
- """
- # main imports
- import random
- import sys
- import numpy as np
- # module imports
- from macop.operators.base import Crossover
- class BasicDifferentialEvolutionCrossover(Crossover):
- """Basic Differential Evolution implementation for continuous solution
- Attributes:
- kind: {:class:`~macop.operators.base.KindOperator`} -- specify the kind of operator
- Example:
- >>> # import of solution and polynomial mutation operator
- >>> from macop.solutions.continuous import ContinuousSolution
- >>> from macop.operators.continuous.crossovers import BasicDifferentialEvolutionCrossover
- >>> solution = ContinuousSolution.random(5, (-2, 2))
- >>> list(solution.data)
- [-1.3760219186551894, -1.7676655513272022, 1.4647045830997407, 0.4044600469728352, 0.832290311184182]
- >>> crossover = BasicDifferentialEvolutionCrossover(interval=(-2, 2))
- >>> crossover_solution = crossover.apply(solution)
- >>> list(crossover_solution.data)
- [-1.7016619497704522, -0.43633033292228895, 2.0, -0.034751768954844, 0.6134819652022994]
- """
- def __init__(self, interval, CR=1.0, F=0.5):
- """"Basic Differential Evolution crossover initialiser in order to specify kind of Operator and interval of continuous solution
- Args:
- interval: {(float, float)} -- minimum and maximum values interval of variables in the solution
- CR: {float} -- probability to use of new generated solutions when modifying a value of current solution
- F: {float} -- degree of impact of the new generated solutions on the current solution when obtaining new solution
- """
- super().__init__()
- self.mini, self.maxi = interval
- self.CR = CR
- self.F = F
- def apply(self, solution):
- """Create new solution based on solution passed as parameter
- Args:
- solution: {:class:`~macop.solutions.base.Solution`} -- the solution to use for generating new solution
- Returns:
- {:class:`~macop.solutions.base.Solution`}: new continuous generated solution
- """
- size = solution.size
- solution1 = solution.clone()
- # create two new random solutions using instance and its static method
- solution2 = solution.random(size, interval=(self.mini, self.maxi))
- solution3 = solution.random(size, interval=(self.mini, self.maxi))
- # apply crossover on the new computed solution
- for i in range(len(solution1.data)):
- # use of CR to change or not the current value of the solution using new solutions
- if random.uniform(0, 1) < self.CR:
- solution1.data[i] = solution1.data[i] + self.F * (solution2.data[i] - solution3.data[i])
- # repair solution if necessary
- solution1.data = self._repair(solution1)
- return solution1
- def _repair(self, solution):
- """
- Private repair function for solutions if an element is out of bounds of an expected interval
- Args:
- solution: {:class:`~macop.solutions.base.Solution`} -- the solution to use for generating new solution
- Returns:
- {ndarray} -- repaired array of float values
- """
- return np.array([self.mini if x < self.mini else self.maxi if x > self.maxi else x for x in solution.data])
|