2022年 11月 9日

人工蜂群算法的python实现

对于网上的一些蜂群算法python实现的代码,笔者认为多数不够简洁易懂且可扩展性和可修改性不足,干脆自己实现一个吧(虽然可能也存在上述问题…)。蜂群算法原理较简单,在此不再赘述,可参考这篇博客,且其中的C++代码比较好理解。

代码如下(python3.6,画图需要matplotlib包):

  1. import math
  2. import random
  3. import matplotlib.pyplot as plt
  4. from typing import List
  5. class ProblemModel:
  6. def __init__(self, bounds=None):
  7. self.bounds = bounds
  8. def getIndependentVar(self):
  9. if self.bounds is not None:
  10. independentVar = []
  11. for bound in self.bounds:
  12. independentVar.append(bound[0] + random.random() * (bound[1] - bound[0]))
  13. return independentVar
  14. else:
  15. pass
  16. def getNewVar(self, var_1, var_2):
  17. if self.bounds is not None:
  18. newVar = []
  19. step_random = random.random()
  20. for v_1, v_2 in zip(var_1, var_2):
  21. newVar.append(v_1 + step_random * (v_2 - v_1))
  22. return newVar
  23. else:
  24. pass
  25. def getValue(self, variable):
  26. if len(variable) == 2:
  27. x = variable[0]
  28. y = variable[1]
  29. return 1+(x**2+y**2)/4000-(math.cos(x)*math.cos(y/math.sqrt(2)))
  30. # return -(x**2-10*math.cos(2*math.pi*x)+10)+(y**2-10*math.cos(2*math.pi*y)+10)
  31. # return -20*math.exp(-0.2*math.sqrt((x**2+y**2)/2))-math.exp((math.cos(2*math.pi*x)+math.cos(2*math.pi*y))/2)+20+math.e
  32. else:
  33. return 1
  34. class NectarSource:
  35. problem_src = None # static variable
  36. def __init__(self, position):
  37. self.position = position
  38. self.value = self.problem_src.getValue(position)
  39. if self.value >= 0:
  40. self.fitness = 1/(1+self.value)
  41. else:
  42. self.fitness = 1+math.fabs(self.value)
  43. # this definition of fitness means looking for the minimum
  44. self.trail = 0
  45. class ABCAlgor:
  46. LIMIT = 10 # If the num of times a source not be updated is more than this, then give up.
  47. def __init__(self, problem, employedNum, onlookerNum, maxIteration):
  48. NectarSource.problem_src = problem
  49. self.problem = problem # type:ProblemModel
  50. self.employedNum = employedNum
  51. self.onlookerNum = onlookerNum
  52. self.maxIteration = maxIteration
  53. self.nectarSrc = [] # type:List[NectarSource]
  54. self.bestNectar = NectarSource(self.problem.getIndependentVar())
  55. self.resultRecord = []
  56. for i in range(self.employedNum):
  57. self.nectarSrc.append(NectarSource(self.problem.getIndependentVar()))
  58. def updateNectarSrc(self, index):
  59. # produce a new nectar; if new.fit>old.fit: replace the old; else: old.trail++;
  60. src = self.nectarSrc[index]
  61. src_another = random.choice(self.nectarSrc) # type:NectarSource
  62. while src_another is src:
  63. src_another = random.choice(self.nectarSrc)
  64. src_new = NectarSource(self.problem.getNewVar(src.position, src_another.position))
  65. if src_new.fitness > src.fitness:
  66. self.nectarSrc[index] = src_new
  67. else:
  68. self.nectarSrc[index].trail += 1
  69. def employedProcedure(self):
  70. length = len(self.nectarSrc) # len(self.nectarSrc) may be changed in self.updateNectarSrc
  71. for i in range(length):
  72. self.updateNectarSrc(i)
  73. def onlookerProcedure(self):
  74. sum_fitness = 0
  75. for src in self.nectarSrc:
  76. sum_fitness += src.fitness
  77. length = len(self.nectarSrc)
  78. for i in range(length):
  79. probability_fit = self.nectarSrc[i].fitness/sum_fitness
  80. for onlookerBee in range(self.onlookerNum):
  81. if random.random() < probability_fit:
  82. self.updateNectarSrc(i)
  83. def updateBestNectar(self):
  84. # use the fitness to select the best, if the problem is finding the max, change the definition of fitness
  85. for src in self.nectarSrc:
  86. if src.fitness > self.bestNectar.fitness:
  87. self.bestNectar = src
  88. def scoutProcedure(self):
  89. length = len(self.nectarSrc)
  90. for i in range(length):
  91. if self.nectarSrc[i].trail >= self.LIMIT:
  92. self.nectarSrc[i] = NectarSource(self.problem.getIndependentVar())
  93. def solve(self):
  94. for i in range(self.maxIteration):
  95. self.employedProcedure()
  96. self.onlookerProcedure()
  97. self.updateBestNectar()
  98. self.scoutProcedure()
  99. self.updateBestNectar()
  100. self.resultRecord.append(self.bestNectar.value)
  101. def showResult(self):
  102. for result in self.resultRecord:
  103. print(result)
  104. print('best solution:', self.bestNectar.position)
  105. print('best value:', self.bestNectar.value)
  106. plt.plot(self.resultRecord)
  107. plt.title('result curve')
  108. plt.tight_layout()
  109. plt.show()
  110. if __name__ == '__main__':
  111. beesNum = 100
  112. employedNum = int(beesNum/2)
  113. onlookerNum = int(beesNum/2)
  114. maxIteration = 200
  115. problem = ProblemModel(bounds=[[-10, 10], [-10, 10]])
  116. abcSolution = ABCAlgor(problem, employedNum, onlookerNum, maxIteration)
  117. abcSolution.solve()
  118. abcSolution.showResult()