算法篇——人工蜂群算法python实现

最终效果与测试函数

1迭代过程

在这里插入图片描述

2效果曲线

在这里插入图片描述

3测试函数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

artiBeeColony.py

面向对象的实现方式,简单明了。如有转载请注明出处。
直接运行,有bug的评论区私聊

#encoding:utf-8
#author:FuJun WANG
from functools import reduce
import math
import random
import copy
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei'] #显示中文标签
plt.rcParams['axes.unicode_minus'] = False

from mpl_toolkits.mplot3d import Axes3D
import numpy as np
##默认所有的函数都是求最小值问题
class testPro:
    def __init__(self):
        self.Pro1=None
    def GriewankFunction(self,x):
        itemOne=0
        itmeTwo=0
        for i,value in enumerate(x):
            itemOne+=(value**2)/4000
            itmeTwo*=(math.cos(value/math.sqrt(i+1)))
        return 1+itemOne-itmeTwo
    def GeneralizeRastrigin(self,x):
        s=0
        for value in x:
            s+=(value**2-10*math.cos(2*math.pi*value)+10)
        return -s
    def AckleyFunction(self,x):
        s1=0
        s2=0
        for value in x:
            s1+=value**2
            s2+=math.cos(2*math.pi*value)
        s1=s1/len(x)
        s2=s2/len(x)
        return -20*math.exp(-0.2*math.sqrt(s1))-math.exp(s2)+20+math.e
    def showGriewankFunction(self,n,bounds):##可视化函数
        """
        :param n: 可视化几阶次的函数,一般取2或3(因为最高我们只能可视化三维)
        :param bounds: 函数的边界
        :return:
        """
        if n==2:
            fig=plt.figure()
            value=[self.GriewankFunction(x) for x in np.arange(bounds[0],bounds[1],(bounds[1]-bounds[0])/1000)]
            plt.plot(range(len(value)),value)
            plt.title("GriewankFunction")
            plt.xlabel("x")
            plt.ylabel("value")
        elif n==3:
            fig=plt.figure()
            ax=plt.axes(projection='3d')
            xx=np.arange(bounds[0],bounds[1],(bounds[1]-bounds[0])/2000)
            yy=np.arange(bounds[0],bounds[1],(bounds[1]-bounds[0])/2000)
            X,Y=np.meshgrid(xx,yy)
            Z=1+(X**2+Y**2)/4000-(np.cos(X/1)*np.cos(Y/np.sqrt(2)))
            minZ=np.min(Z)
            indexMin=np.argmin(Z)
            ax.plot_surface(X,Y,Z,cmap='rainbow')
            plt.title("GriewankFunction,minValue%s" % round(minZ,2))
            plt.show()
    def showGeneralizeRastrigin(self,n,bounds):
        if n==2:
            pass
        if n==3:
            fig = plt.figure()
            ax = plt.axes(projection='3d')
            xx = np.arange(bounds[0], bounds[1], (bounds[1] - bounds[0]) / 2000)
            yy = np.arange(bounds[0], bounds[1], (bounds[1] - bounds[0]) / 2000)
            X, Y = np.meshgrid(xx, yy)
            Z = -(X**2-10*np.cos(2*math.pi*X)+10)+(Y**2-10*np.cos(2*np.pi*Y)+10)
            minZ = np.min(Z)
            ax.plot_surface(X, Y, Z, cmap='rainbow')
            plt.title("GeneralizeRastrigin,minValue%s" % round(minZ,2))
            plt.show()
    def showAckleyFunction(self,n,bounds):
        if n==2:
            pass
        if n==3:
            fig = plt.figure()
            ax = plt.axes(projection='3d')
            xx = np.arange(bounds[0], bounds[1], (bounds[1] - bounds[0]) / 2000)
            yy = np.arange(bounds[0], bounds[1], (bounds[1] - bounds[0]) / 2000)
            X, Y = np.meshgrid(xx, yy)
            Z =-20*np.exp(-0.2*np.sqrt((X**2+Y**2)/2))-np.exp((np.cos(2*np.pi*X)+np.cos(2*np.pi*Y))/2)+20+math.e
            minZ = np.min(Z)
            ax.plot_surface(X, Y, Z, cmap='rainbow')
            plt.title("AckleyFunction,minValue%s" % round(minZ,2))
            plt.show()




class fitnessFunc:
    def fitneForMin(self,value,average):
        # math.exp(-(value / (average)))
        if value>=0:
            return 1/(1+value)
        else:
            return 1+math.fabs(value)
    def fitneForMax(self,value,average):
        return math.exp(value/average)
class Nectar:##蜜源
    def __init__(self,pos):
        # self.pro=pro##蜜源对应的评价函数
        self.LIMIT=8
        self.pos=pos##蜜源位置
        self.beAbandoned=0##被丢弃的次数
        self.beChoosed=1#被选择的
        self.followers=[]
        self.func=testPro().GriewankFunction
        self.fitFunc=fitnessFunc().fitneForMin
    def getValue(self):##该位置在所给评价标准为pro的情况下的值,即蜜源大小
        return self.func(self.pos)
    def getBeAbandoned(self):
        return self.beAbandoned
    def addAbandoned(self):
        self.beAbandoned+=1
    def addBechoosed(self):
        self.beChoosed+=1
    def getPos(self):
        return self.pos
    def setPos(self,pos):
        self.pos=pos
    def getFollowers(self):
        return self.followers
    def setFollowers(self,newFoll):
        self.followers=newFoll
    def addFolloers(self,f):##该蜜源增加的采蜜者
        self.followers.append(f)
    def getLimit(self):
        return self.LIMIT
class Bee:
    def __init__(self,id,type):
        self.id=id
        self.type=type##type=1表示是雇佣蜂2表示是追随蜂3表示的是侦察蜂
    def setType(self):
        self.type=type
    def getType(self):
        return self.type
    def getId(self):
        return self.id


class ABC:
    def __init__(self,pro,B,E,L,S,I,bound):
        self.pro=pro#问题
        self.B=B#蜂群的大小
        self.E=E#雇佣蜂的数目
        self.L=L#追随蜂的数目
        self.S=S#侦察峰的数目
        self.I=I#最大的迭代次数
        self.st=[]#保存蜜源
        self.bound=bound
        self.onLookList=[]##追随蜂列表
        self.scoutsList=[]#侦察蜂列表
        self.bestValue=None#最优值
        self.bestPos=None#最优值位置
        self.fitnessFun=fitnessFunc().fitneForMin
        self.resultRecord=[]##存放中间最优值
        self.resultForPicture=[]
        self.pictureIndex=[0,10,20,30,50,70,90,int(100+0*(self.I-100)/5),int(100+1*(self.I-100)/5),int(100+2*(self.I-100)/5),int(100+3*(self.I-100)/5),int(100+4*(self.I-100)/5)]#在第几次循环中拍快照
    ##用二阶的grienWankFunc进行测试
    def getFeasibleSol(slef, bounds):  ##随机产生点
        return bounds[0] + random.random() * (bounds[1] - bounds[0])
    def initial(self):
        #初始化蜜源
        for i in range(self.B):
            if i <self.E:##前E个是雇佣蜂,雇佣蜂的数量与
                # thisBee=Bee(i,1)##初始化一只小蜜蜂
                randomPos=[self.getFeasibleSol(self.bound),self.getFeasibleSol(self.bound)]
                thisNectar=Nectar(randomPos)##初始化蜜源的位置
                thisNectar.addFolloers(i)##将这只雇佣蜂添加到这个蜂源上
                self.st.append(thisNectar)
            else:
                ##这些是追随峰
                # thisBee=Bee(i,2)
                self.onLookList.append(i)
        for i in range(self.S):##侦察蜂
            # thisBee=Bee(i,3)
            self.scoutsList.append(i)
        bestIndex,self.bestValue=list(min(enumerate([item.getValue() for item in self.st])))
        self.bestPos=self.st[bestIndex].getPos()#目前最优的函数值,以及最优值对应的点
    def getRandomPos(self,pos1,pos2):
        randomStep=random.random()
        return [pos1[0]+randomStep*(pos2[0]-pos1[0]),pos1[1]+randomStep*(pos2[1]-pos1[1])]
    def roulette(self,pList):
        arrow=random.random()
        s=0
        for index,value in enumerate(pList):
            s+=value
            if s>=arrow:
                return index
    def employedPro(self):
        newStList = []  # 新的蜂源集合
        for nc in self.st:
            if len(nc.getFollowers())==0:
                pass  # 如果这个蜜源没有一个开采这者了,就废弃
            else:
                flyAway = []
                notFly = []
                for bee in nc.getFollowers():
                    if random.random()<0.3:
                        self.onLookList.append(bee)
                        continue#成为跟随峰
                    if random.random()<0.6 and random.random()>0.3:#成为侦察蜂
                        self.scoutsList.append(bee)
                        continue
                    else:
                        # 探索一个新的位置,先随机的从现有的st中随机的选择一个元素
                        ranNc = random.choice(self.st)
                        newPos = self.getRandomPos(nc.getPos(),ranNc.getPos())
                        newNc = Nectar(newPos)
                        ##贪婪求法,
                        if newNc.getValue() < nc.getValue():  # 如果新探索的位置好,就放弃现在的位置

                            newNc.addFolloers(bee)
                            newStList.append(newNc)
                            flyAway.append(bee)  ##这只小蜜蜂飞走了
                            nc.addAbandoned()  ##被丢弃的个数加1
                            if newNc.getValue()<self.bestValue:#是否能信最优值
                                self.bestValue=newNc.getValue()
                                self.bestPos=newNc.getPos()
                                print("目前最优", self.bestValue, "|", self.bestPos)
                        else:
                            nc.addBechoosed()  # 坚持现在的,当前位置被宠幸加1
                            notFly.append(bee)
                ##所有蜜蜂遍历结束看当前还剩几个蜜蜂
                if len(flyAway) == len(nc.getFollowers()):  # 当前蜜源的蜜蜂飞走完了,该位置被废弃
                    pass
                elif (nc.getBeAbandoned()>=nc.getLimit()):##如果当前位置被丢弃过多,放弃该蜜源,此地的小蜜蜂成为其他峰
                    for bee in nc.getFollowers():
                        if random.random()<0.5:##等概率的成为追随峰或者侦察峰
                            self.onLookList.append(bee)
                        else:
                            self.scoutsList.append(bee)
                else:
                    nc.setFollowers(notFly)
                    newStList.append(nc)
        self.st = copy.deepcopy(newStList)

    def onLookerPro(self):
        valueList = []
        for nc in self.st:
            valueList.append(nc.getValue())
        aveValue = sum(valueList) / len(valueList)
        fitnessList = [self.fitnessFun(item, aveValue) for item in valueList]  ##适应度
        sumFit = sum(fitnessList)
        pList = [item / sumFit for item in fitnessList]  ##被选概率
        notBeEmployed=[]
        for bee in self.onLookList:
            if random.random()<0.3:#百分之30的概率不成为雇佣蜂
                notBeEmployed.append(bee)
            else:
                follow=self.roulette(pList)
                self.st[follow].addFolloers(bee)
        self.onLookList=copy.deepcopy(notBeEmployed)#现在依然是雇佣峰的
    def scoutsPro(self):
        newScoutList = []
        for bee in self.scoutsList:
            newSt=Nectar([self.getFeasibleSol(self.bound), self.getFeasibleSol(self.bound)])
            for i in range(30):##侦察峰的探索次数
                temPos = [self.getFeasibleSol(self.bound), self.getFeasibleSol(self.bound)]
                temSt = Nectar(temPos)
                if temSt.getValue()>newSt.getValue():
                    newSt=temSt
            if newSt.getValue() < self.bestValue:
                self.st.append(newSt)
                self.bestValue = newSt.getValue()
                self.bestPos = newSt.getPos()
                print("目前最优", self.bestValue, "|", self.bestPos)
            else:#r
                if random.random() < 0.3:
                    self.onLookList.append(bee)
                else:
                    newScoutList.append(bee)
        self.scoutsList = copy.deepcopy(newScoutList)


    def solve(self):
        self.initial()  # 初始化完成
        ##雇佣蜂行动找下一个峰源
        for i in range(self.I):
            self.employedPro()
            ##跟随峰行动
            self.onLookerPro()
            ##侦察峰出动
            self.scoutsPro()
            self.resultRecord.append(self.bestValue)
            if i in self.pictureIndex :##抓取蜜源快照
                self.resultForPicture.append(self.st)
    def showResult(self):
        ##画优化过程曲线
        fig=plt.figure()
        plt.plot(range(len(self.resultRecord)),self.resultRecord)
        plt.title("优化过程曲线")
        ##画快照
        fig1=plt.figure()
        for i in range(len(self.pictureIndex)):
            ax=fig1.add_subplot(3,4,i+1)
            x,y=[],[]
            for st in self.resultForPicture[i]:
                x.append(st.getPos()[0])
                y.append(st.getPos()[1])
            ax.scatter(x,y)
            plt.xlabel("第%s次迭代"%(self.pictureIndex[i]))
        plt.tight_layout()
        plt.show()




if __name__ == '__main__':
    #初始化蜂群的大小,追随者数目,雇佣者的数目,侦察者的数目
    I=200##最好大于100好画图
    B=120
    onLookers=int(0.5*B)
    employedBee = int(0.5 * B)
    scouts=80
    myPros=testPro()
    grienWankFunc=myPros.GriewankFunction
    bounds=[-10,10]
    myBCA=ABC(grienWankFunc,B,onLookers,employedBee,scouts,I,bounds)
    myBCA.solve()
    print(myBCA.bestValue)
    print(myBCA.bestPos)
    myBCA.showResult()
    myPros.showGriewankFunction(3,bounds)
    myPros.showGeneralizeRastrigin(3,bounds)
    myPros.showAckleyFunction(3,bounds)



  • 22
    点赞
  • 139
    收藏
    觉得还不错? 一键收藏
  • 73
    评论
评论 73
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值