Algorithm.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. """Abstract Algorithm class used as basic algorithm implementation with some specific initialization
  2. """
  3. # main imports
  4. import logging
  5. # Generic algorithm class
  6. class Algorithm():
  7. """Algorithm class used as basic algorithm
  8. Attributes:
  9. initalizer: {function} -- basic function strategy to initialize solution
  10. evaluator: {function} -- basic function in order to obtained fitness (mono or multiple objectives)
  11. operators: {[Operator]} -- list of operator to use when launching algorithm
  12. policy: {Policy} -- Policy class implementation strategy to select operators
  13. validator: {function} -- basic function to check if solution is valid or not under some constraints
  14. maximise: {bool} -- specify kind of optimization problem
  15. currentSolution: {Solution} -- current solution managed for current evaluation
  16. bestSolution: {Solution} -- best solution found so far during running algorithm
  17. checkpoint: {Checkpoint} -- Checkpoint class implementation to keep track of algorithm and restart
  18. parent: {Algorithm} -- parent algorithm reference in case of inner Algorithm instance (optional)
  19. """
  20. def __init__(self,
  21. _initalizer,
  22. _evaluator,
  23. _operators,
  24. _policy,
  25. _validator,
  26. _maximise=True,
  27. _parent=None):
  28. self.initializer = _initalizer
  29. self.evaluator = _evaluator
  30. self.operators = _operators
  31. self.policy = _policy
  32. self.validator = _validator
  33. self.checkpoint = None
  34. self.bestSolution = None
  35. # other parameters
  36. self.parent = _parent # parent algorithm if it's sub algorithm
  37. #self.maxEvaluations = 0 # by default
  38. self.maximise = _maximise
  39. self.initRun()
  40. def addCheckpoint(self, _class, _every, _filepath):
  41. """Add checkpoint to algorithm specifying usefull parameters
  42. Args:
  43. _class: {class} -- Checkpoint class type
  44. _every: {int} -- checkpoint frequency based on evaluations
  45. _filepath: {str} -- file path where checkpoints will be saved
  46. """
  47. self.checkpoint = _class(self, _every, _filepath)
  48. def setCheckpoint(self, _checkpoint):
  49. """Set checkpoint instance directly
  50. Args:
  51. _checkpoint: {Checkpoint} -- checkpoint instance
  52. """
  53. self.checkpoint = _checkpoint
  54. def resume(self):
  55. """Resume algorithm using checkpoint instance
  56. Raises:
  57. ValueError: No checkpoint initialize (use `addCheckpoint` or `setCheckpoint` is you want to use this process)
  58. """
  59. if self.checkpoint is None:
  60. raise ValueError(
  61. "Need to `addCheckpoint` or `setCheckpoint` is you want to use this process"
  62. )
  63. else:
  64. print('Checkpoint loading is called')
  65. self.checkpoint.load()
  66. def initRun(self):
  67. """
  68. Method which initialiazes or re-initializes the whole algorithm context: operators, current solution, best solution (by default current solution)
  69. """
  70. # track reference of algo into operator (keep an eye into best solution)
  71. for operator in self.operators:
  72. operator.setAlgo(self)
  73. # also track reference for policy
  74. self.policy.setAlgo(self)
  75. self.currentSolution = self.initializer()
  76. # evaluate current solution
  77. self.currentSolution.evaluate(self.evaluator)
  78. # reinitialize policy
  79. # if self.parent is not None:
  80. # self.policy = globals()[type(self.policy).__name__]()
  81. # keep in memory best known solution (current solution)
  82. self.bestSolution = self.currentSolution
  83. def increaseEvaluation(self):
  84. """
  85. Increase number of evaluation once a solution is evaluated
  86. """
  87. self.numberOfEvaluations += 1
  88. if self.parent is not None:
  89. self.parent.numberOfEvaluations += 1
  90. def getGlobalEvaluation(self):
  91. """Get the global number of evaluation (if inner algorithm)
  92. Returns:
  93. {int} -- current global number of evaluation
  94. """
  95. if self.parent is not None:
  96. return self.parent.numberOfEvaluations
  97. return self.numberOfEvaluations
  98. def stop(self):
  99. """
  100. Global stopping criteria (check for inner algorithm too)
  101. """
  102. if self.parent is not None:
  103. return self.parent.numberOfEvaluations >= self.parent.maxEvaluations or self.numberOfEvaluations >= self.maxEvaluations
  104. return self.numberOfEvaluations >= self.maxEvaluations
  105. def evaluate(self, _solution):
  106. """
  107. Evaluate a solution using evaluator passed when intialize algorithm
  108. Args:
  109. solution: {Solution} -- solution to evaluate
  110. Returns:
  111. fitness score of solution which is not already evaluated or changed
  112. Note:
  113. if multi-objective problem this method can be updated using array of `evaluator`
  114. """
  115. return _solution.evaluate(self.evaluator)
  116. def update(self, _solution):
  117. """
  118. Apply update function to solution using specific `policy`
  119. Check if solution is valid after modification and returns it
  120. Args:
  121. solution: {Solution} -- solution to update using current policy
  122. Returns:
  123. {Solution} -- updated solution obtained by the selected operator
  124. """
  125. # two parameters are sent if specific crossover solution are wished
  126. sol = self.policy.apply(_solution)
  127. if (sol.isValid(self.validator)):
  128. return sol
  129. else:
  130. logging.info("-- New solution is not valid %s" % sol)
  131. return _solution
  132. def isBetter(self, _solution):
  133. """
  134. Check if solution is better than best found
  135. Args:
  136. solution: {Solution} -- solution to compare with best one
  137. Returns:
  138. {bool} -- `True` if better
  139. """
  140. # depending of problem to solve (maximizing or minimizing)
  141. if self.maximise:
  142. if _solution.fitness() > self.bestSolution.fitness():
  143. return True
  144. else:
  145. if _solution.fitness() < self.bestSolution.fitness():
  146. return True
  147. # by default
  148. return False
  149. def run(self, _evaluations):
  150. """
  151. Run the specific algorithm following number of evaluations to find optima
  152. """
  153. self.maxEvaluations = _evaluations
  154. self.initRun()
  155. # check if global evaluation is used or not
  156. if self.parent is not None and self.getGlobalEvaluation() != 0:
  157. # init number evaluations of inner algorithm depending of globalEvaluation
  158. # allows to restart from `checkpoint` last evaluation into inner algorithm
  159. rest = self.getGlobalEvaluation() % self.maxEvaluations
  160. self.numberOfEvaluations = rest
  161. else:
  162. self.numberOfEvaluations = 0
  163. logging.info("Run %s with %s evaluations" %
  164. (self.__str__(), _evaluations))
  165. def progress(self):
  166. """
  167. Log progress and apply checkpoint if necessary
  168. """
  169. if self.checkpoint is not None:
  170. self.checkpoint.run()
  171. logging.info("-- %s evaluation %s of %s (%s%%) - BEST SCORE %s" %
  172. (type(self).__name__, self.numberOfEvaluations,
  173. self.maxEvaluations, "{0:.2f}".format(
  174. (self.numberOfEvaluations) / self.maxEvaluations *
  175. 100.), self.bestSolution.fitness()))
  176. def information(self):
  177. logging.info("-- Best %s - SCORE %s" %
  178. (self.bestSolution, self.bestSolution.fitness()))
  179. def __str__(self):
  180. return "%s using %s" % (type(self).__name__, type(
  181. self.bestSolution).__name__)