MOEAD.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. """Multi-Ojective Evolutionary Algorithm with Scalar Decomposition algorithm
  2. """
  3. # main imports
  4. import logging
  5. import math
  6. import numpy as np
  7. # module imports
  8. from ..Algorithm import Algorithm
  9. from .MOSubProblem import MOSubProblem
  10. class MOEAD(Algorithm):
  11. """Multi-Ojective Evolutionary Algorithm with Scalar Decomposition
  12. Attributes:
  13. mu: {int} -- number of sub problems
  14. T: {[float]} -- number of neightbors for each sub problem
  15. initalizer: {function} -- basic function strategy to initialize solution
  16. evaluator: {[function]} -- list of basic function in order to obtained fitness (multiple objectives)
  17. operators: {[Operator]} -- list of operator to use when launching algorithm
  18. policy: {Policy} -- Policy class implementation strategy to select operators
  19. validator: {function} -- basic function to check if solution is valid or not under some constraints
  20. maximise: {bool} -- specify kind of optimization problem
  21. currentSolution: {Solution} -- current solution managed for current evaluation
  22. bestSolution: {Solution} -- best solution found so far during running algorithm
  23. checkpoint: {Checkpoint} -- Checkpoint class implementation to keep track of algorithm and restart
  24. """
  25. def __init__(self,
  26. _mu,
  27. _T,
  28. _initalizer,
  29. _evaluator,
  30. _operators,
  31. _policy,
  32. _validator,
  33. _maximise=True,
  34. _parent=None):
  35. # redefinition of constructor to well use `initRun` method
  36. self.initializer = _initalizer
  37. self.evaluator = _evaluator
  38. self.operators = _operators
  39. self.policy = _policy
  40. self.validator = _validator
  41. self.checkpoint = None
  42. self.bestSolution = None
  43. # by default
  44. self.numberOfEvaluations = 0
  45. self.maxEvaluations = 0
  46. # other parameters
  47. self.parent = _parent # parent algorithm if it's sub algorithm
  48. #self.maxEvaluations = 0 # by default
  49. self.maximise = _maximise
  50. # track reference of algo into operator (keep an eye into best solution)
  51. for operator in self.operators:
  52. operator.setAlgo(self)
  53. # also track reference for policy
  54. self.policy.setAlgo(self)
  55. if _mu < _T:
  56. raise ValueError('`mu` cannot be less than `T`')
  57. self.mu = _mu
  58. self.T = _T
  59. # initialize neighbors for each sub problem
  60. self.setNeighbors()
  61. weights = []
  62. for i in range(self.mu):
  63. angle = math.pi / 2 * i / (self.mu - 1)
  64. weights.append([math.cos(angle), math.sin(angle)])
  65. self.subProblems = []
  66. for i in range(self.mu):
  67. # compute weight sum from solution
  68. sub_evaluator = lambda _solution: sum(list([ eval(_solution) * weights[i][w_i] for w_i, eval in enumerate(_evaluator)]))
  69. subProblem = MOSubProblem(i, weights[i], _initalizer, sub_evaluator, _operators, _policy, _validator, _maximise, self)
  70. self.subProblems.append(subProblem)
  71. self.population = [ None for n in range(self.mu) ]
  72. # no need to initialize using sub problem
  73. # self.initRun()
  74. def initRun(self):
  75. """
  76. Method which initialiazes or re-initializes the whole algorithm context specifically for MOEAD
  77. """
  78. self.currentSolution = self.initializer()
  79. # evaluate current solution
  80. self.subProblems[0].run(1)
  81. # keep in memory best known solution (current solution)
  82. self.bestSolution = self.subProblems[0].bestSolution
  83. def run(self, _evaluations):
  84. """
  85. Run the local search algorithm
  86. Args:
  87. _evaluations: {int} -- number of Local search evaluations
  88. Returns:
  89. {Solution} -- best solution found
  90. """
  91. # by default use of mother method to initialize variables
  92. super().run(_evaluations)
  93. # enable checkpoint for MOEAD
  94. if self.checkpoint is not None:
  95. self.resume()
  96. # initialize each sub problem
  97. for i in range(self.mu):
  98. self.subProblems[i].run(1)
  99. self.population[i] = self.subProblems[i].bestSolution
  100. # MOEAD algorithm implementation
  101. while not self.stop():
  102. for i in range(self.mu):
  103. # run 1 iteration into sub problem `i`
  104. self.subProblems[i].run(1)
  105. # stop algorithm if necessary
  106. if self.stop():
  107. break
  108. logging.info("End of %s, best solution found %s" %
  109. (type(self).__name__, self.bestSolution))
  110. self.end()
  111. return self.bestSolution
  112. def setNeighbors(self):
  113. dmin = dmax = 0
  114. if self.T % 2 == 1:
  115. dmin = - int(self.T / 2)
  116. dmax = int(self.T / 2) + 1
  117. else:
  118. dmin = - int(self.T/2) + 1
  119. dmax = + self.T / 2
  120. # init neighbord list
  121. self.neighbors = [ [] for n in range(self.mu) ]
  122. for direction in range(0, -dmin):
  123. for i in range(self.T):
  124. self.neighbors[direction].append(i)
  125. for direction in range(-dmin, self.mu - dmax):
  126. for i in range (direction + dmin, direction + dmax):
  127. self.neighbors[direction].append(i)
  128. for direction in range(self.mu - dmax, self.mu):
  129. for i in range(self.mu - self.T, self.mu):
  130. self.neighbors[direction].append(i)