mutators.py 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. """Mutation implementations for continuous solution
  2. """
  3. # main imports
  4. import random
  5. import sys
  6. import numpy as np
  7. # module imports
  8. from macop.operators.base import Mutation
  9. class PolynomialMutation(Mutation):
  10. """Polynomial Mutation implementation for continuous solution
  11. Attributes:
  12. kind: {:class:`~macop.operators.base.KindOperator`} -- specify the kind of operator
  13. Example:
  14. >>> # import of solution and polynomial mutation operator
  15. >>> from macop.solutions.continuous import ContinuousSolution
  16. >>> from macop.operators.continuous.mutators import PolynomialMutation
  17. >>> solution = ContinuousSolution.random(5, (-2, 2))
  18. >>> list(solution.data)
  19. [-0.50183952461055, 1.8028572256396647, 0.9279757672456204, 0.3946339367881464, -1.375925438230254]
  20. >>> mutator = PolynomialMutation(interval=(-2, 2))
  21. >>> mutation_solution = mutator.apply(solution)
  22. >>> list(mutation_solution.data)
  23. [-0.50183952461055, 1.8028572256396647, 0.9279757672456204, 0.3946339367881464, -1.375925438230254]
  24. """
  25. def __init__(self, interval):
  26. """Polynomial Mutation initialiser in order to specify kind of Operator and interval of continuous solution
  27. Args:
  28. interval: {(float, float)} -- minimum and maximum values interval of variables in the solution
  29. """
  30. super().__init__()
  31. self.mini, self.maxi = interval
  32. def apply(self, solution):
  33. """Create new solution based on solution passed as parameter
  34. Args:
  35. solution: {:class:`~macop.solutions.base.Solution`} -- the solution to use for generating new solution
  36. Returns:
  37. {:class:`~macop.solutions.base.Solution`}: new generated solution
  38. """
  39. size = solution.size
  40. rate = float(1/size)
  41. copy_solution = solution.clone()
  42. rand = random.uniform(0, 1)
  43. # apply mutation over the new computed solution
  44. copy_solution.data = [x if rand > rate else x + self._sigma(size) * (self.maxi - (self.mini)) for x in solution.data]
  45. copy_solution.data = self._repair(copy_solution)
  46. return copy_solution
  47. def _repair(self, solution):
  48. """
  49. Private repair function for solutions if an element is out of bounds of an expected interval
  50. Args:
  51. solution: {:class:`~macop.solutions.base.Solution`} -- the solution to use for generating new solution
  52. Returns:
  53. {ndarray} -- repaired array of float values
  54. """
  55. return np.array([self.mini if x < self.mini else self.maxi if x > self.maxi else x for x in solution.data])
  56. def _sigma(self, size):
  57. """
  58. Compute the sigma value for polynomial mutation
  59. Args:
  60. size: {integer} --
  61. Returns:
  62. {float} -- expected sigma value depending on solution size
  63. """
  64. rand = random.uniform(0, 1)
  65. sigma = 0
  66. if rand < 0.5:
  67. sigma = pow(2 * rand, 1 / (size + 1)) - 1
  68. else:
  69. sigma = 1 - pow(2 - 2 * rand, 1 / (size - 1))
  70. return sigma