首先声明,本代码参考了https://www.cnblogs.com/biaoyu/p/4857904.html,但它的实现逻辑上有些bug,我对其进行了完善和简化,并加了注释,理解起来很简单,效果也更好。
代码基于python2.7,python 3上应该也可以运行,不过没测试。
import numpy as np
import random, math, copy
import matplotlib.pyplot as plt
def GrieFunc(data): #目标函数
s1 = 0.
s2 = 1.
for k, x in enumerate(data):
s1 = s1 + x ** 2
s2 = s2 * math.cos(x / math.sqrt(k+1))
y = (1. / 4000.) * s1 - s2 + 1
return 1. / (1. + y)
class ABSIndividual:
def __init__(self, bound):
self.score = 0.
self.invalidCount = 0 #无效次数(成绩没有更新的累积次数)
self.chrom = [random.uniform(a,b) for a,b in zip(bound[0,:],bound[1,:])] #随机初始化
self.calculateFitness()
def calculateFitness(self):
self.score = GrieFunc(self.chrom) #计算当前成绩
class ArtificialBeeSwarm:
def __init__(self, foodCount, onlookerCount, bound, maxIterCount=1000, maxInvalidCount=200):
self.foodCount = foodCount #蜜源个数,等同于雇佣蜂数目
self.onlookerCount = onlookerCount #观察蜂个数
self.bound = bound #各参数上下界
self.maxIterCount = maxIterCount #迭代次数
self.maxInvalidCount = maxInvalidCount #最大无效次数
self.foodList = [ABSIndividual(self.bound) for k in range(self.foodCount)] #初始化各蜜源
self.foodScore = [d.score for d in self.foodList] #各蜜源最佳成绩
self.bestFood = self.foodList[np.argmax(self.foodScore)] #全局最佳蜜源
def updateFood(self, i): #更新第i个蜜源
k = random.randint(0, self.bound.shape[1] - 1) #随机选择调整参数的维度
j = random.choice([d for d in range(self.bound.shape[1]) if d !=i]) #随机选择另一蜜源作参考,j是其索引号
vi = copy.deepcopy(self.foodList[i])
vi.chrom[k] += random.uniform(-1.0, 1.0) * (vi.chrom[k] - self.foodList[j].chrom[k]) #调整参数
vi.chrom[k] = np.clip(vi.chrom[k], self.bound[0, k], self.bound[1, k]) #参数不能越界
vi.calculateFitness()
if vi.score > self.foodList[i].score: #如果成绩比当前蜜源好
self.foodList[i] = vi
if vi.score > self.foodScore[i]: #如果成绩比历史成绩好(如重新初始化,当前成绩可能低于历史成绩)
self.foodScore[i] = vi.score
if vi.score > self.bestFood.score: #如果成绩全局最优
self.bestFood = vi
self.foodList[i].invalidCount = 0
else:
self.foodList[i].invalidCount += 1
def employedBeePhase(self):
for i in xrange(0, self.foodCount): #各蜜源依次更新
self.updateFood(i)
def onlookerBeePhase(self):
foodScore = [d.score for d in self.foodList]
maxScore = np.max(foodScore)
accuFitness = [(0.9*d/maxScore+0.1, k) for k,d in enumerate(foodScore)] #得到各蜜源的 相对分数和索引号
for k in xrange(0, self.onlookerCount):
i = random.choice([d[1] for d in accuFitness if d[0] >= random.random()]) #随机从相对分数大于随机门限的蜜源中选择跟随
self.updateFood(i)
def scoutBeePhase(self):
for i in xrange(0, self.foodCount):
if self.foodList[i].invalidCount > self.maxInvalidCount: #如果该蜜源没有更新的次数超过指定门限,则重新初始化
self.foodList[i] = ABSIndividual(self.bound)
self.foodScore[i] = max(self.foodScore[i], self.foodList[i].score)
def solve(self):
trace = []
trace.append((self.bestFood.score, np.mean(self.foodScore)))
for k in range(self.maxIterCount):
self.employedBeePhase()
self.onlookerBeePhase()
self.scoutBeePhase()
trace.append((self.bestFood.score, np.mean(self.foodScore)))
print(self.bestFood.score)
self.printResult(np.array(trace))
def printResult(self, trace):
x = np.arange(0, trace.shape[0])
plt.plot(x, [(1-d)/d for d in trace[:, 0]], 'r', label='optimal value')
plt.plot(x, [(1-d)/d for d in trace[:, 1]], 'g', label='average value')
plt.xlabel("Iteration")
plt.ylabel("function value")
plt.title("Artificial Bee Swarm algorithm for function optimization")
plt.legend()
plt.show()
if __name__ == "__main__":
random.seed()
vardim = 25
bound = np.tile([[-600], [600]], vardim)
abs = ArtificialBeeSwarm(30, 30, bound, 1000, 200)
abs.solve()
下面是收敛曲线: