1. 程式人生 > >蟻群算法

蟻群算法

rec 行為 sel wid arch index temp ini first

同進化算法(進化算法是受生物進化機制啟發而產生的一系列算法)和人工神經網絡算法(神經網絡是從信息處理角度對人腦的神經元網絡系統進行了模擬的相關算法)一樣,群智能優化算法也屬於一種生物啟發式方法,它們三者可以稱為是人工智能領域的三駕馬車(實際上除了上述三種算法還有一些智能算法應用也很廣泛,比如模擬金屬物質熱力學退火過程的模擬退火算法(Simulated Algorithm,簡稱SA),模擬人體免疫系統在抗原刺激下產生抗體過程的人工免疫系統算法(Artificial Immune System,簡稱AIS)等,但是相對三者而言,模擬退火算法和人工免疫系統算法已逐漸處於低潮期)。群智能優化算法主要是模擬了昆蟲,獸群、鳥群和魚群的群集行為,這些群體按照一種合作的方式尋找食物,群體中的每個成員通過學習它自身的經驗和其他成員的經驗來不斷地改變搜索的方向。群體智能優化算法的突出特點就是利用了種群的群體智慧進行協同搜索,從而在解空間內找到最優解。

常見的群體智能優化算法主要有如下幾類:

蟻群算法(Ant Colony Optimizatio,簡稱ACO)【1992年提出】;

粒子群優化算法(Particle Swarm Optimization,簡稱PSO)【1995年提出】

菌群優化算法(Bacterial Foraging Optimization,簡稱BFO)【2002年提出】

蛙跳算法(Shuffled Frog Leading Algorithm,簡稱SFLA)【2003年提出】

人工蜂群算法(Artificial Bee Colony Algorithm,簡稱ABC)【2005年提出】

除了上述幾種常見的群體智能算法以外,還有一些並不是廣泛應用的群體智能算法,比如螢火蟲算法,布谷鳥算法,蝙蝠算法以及磷蝦群算法等等。

蟻群算法

螞蟻尋找食物的過程

單只螞蟻的行為及其簡單,行為數量在10種以內,但成千上萬只螞蟻組成的蟻群卻能擁有巨大的智慧,這離不開它們信息傳遞的方式———信息素。

螞蟻在行走過程中會釋放一種稱為"信息素"的物質,用來標識自己的行走路徑。在尋找食物的過程中,根據信息素的濃度選擇行走的方向,並最終到達食物所在的地方。

信息素會隨著時間的推移而逐漸揮發。

在一開始的時候,由於地面上沒有信息素,因此螞蟻們的行走路勁是隨機的。螞蟻們在行走的過程中會不斷釋放信息素,標識自己的行走路徑。隨著時間的推移,有若幹只螞蟻找到了食物,此時便存在若幹條從洞穴到食物的路徑。由於螞蟻的行為軌跡是隨機分布的,因此在單位時間內,短路徑上的螞蟻數量比長路徑上的螞蟻數量要多,從而螞蟻留下的信息素濃度也就越高。這為後面的螞蟻們提供了強有力的方向指引,越來越多的螞蟻聚集到最短的路徑上去。

技術分享圖片

什麽是蟻群算法

蟻群算法就是模擬螞蟻尋找食物的過程,它能夠求出從原點出發,經過若幹個給定的需求點,最終返回原點的最短路徑。這也就是著名的旅行商問題(Traveling Saleman Problem, TSP)。

蟻群算法規則

覓食規則

螞蟻感知範圍是一個3*3的格子,也就是說,他這個格子有食物就直接過去

移動規則

螞蟻會朝著信息素濃的地方移動,如果沒有感知到信息素,就會按著慣性一直走下去,別忘了螞蟻會創新。

避障規則

螞蟻在遇到障礙物的時候會選擇隨機方向移動,同時遵循上面兩個規則。

信息素規則

螞蟻在剛發現食物的時候揮灑的信息素越多,距離越遠,信息素越少。

import os,sys,random
from math import *
import pylab as pl
import pandas as pd
BestTour=[]     #用於放置最佳路徑選擇城市的順序
CitySet=set()   #sets數據類型是無序的,沒有重復元素的集合,兩個sets之間可以做差集,即第一個集合中移除第二個集合中也存在的元素
CityList=[]     #城市列表即存放代表城市的序號
PheromoneTraiList=[]  #信息素列表(矩陣)
PheromoneDeltaTraiList=[]  #釋放信息素列表(矩陣)
CityDistanceList=[]   #兩兩城市距離列表(矩陣)
AntList=[]      #螞蟻列表
class BACA:#定義類BACA,執行蟻群算法
    def __init__(self,citycount=51,antCount=51,q=80,alpha=1,beta=3,rou=0.4,nMax=300):
        #初始化方法,antCount為螞蟻數,nMax為叠代次數
        self.CityCount=citycount #城市數量
        self.AnCount=antCount   #螞蟻數量
        self.Q=q                #信息素增加強度系數
        self.Alpha=alpha        #表征信息素重要程度的參數
        self.Beta=beta          #表征啟發因子重要程度的參數
        self.Rou=rou            #信息素蒸發系數
        self.Nmax=nMax          #最大叠代次數
        self.Shortest=10e6      #初始化最短距離應該盡可能大,至少大於估算的最大城市旅行距離
        pl.show()
        random.seed()           #設置隨機種子
        #初始化全局數據結構及值
        for nCity in range(self.CityCount):#循環城市總數的次數
            BestTour.append(0)#設置最佳路徑初始值均為0
        for row in range(self.CityCount):
            pheromoneList=[]     #定義空的信息素列表
            pheromoneDeltaList=[]   #定義空的信息素列表
            for col in range(self.CityCount):
                pheromoneList.append(100)   #定義一個城市到所有城市信息素的初始值
                pheromoneDeltaList.append(0) #定義一個城市到所有城市釋放信息素的初始值
            PheromoneTraiList.append(pheromoneList)  #建立每個城市到所有城市路徑信息素的初始值列表
            PheromoneDeltaTraiList.append(pheromoneDeltaList)  #建立每個城市到所有城市路徑釋放信息素的初始值列表矩陣
    def ReadCityInfo(self,fileName):
        file=open(fileName)
        for line in file.readlines():
            cityN,cityX,cityY=line.split()
            CitySet.add(int(cityN))
            CityList.append((int(cityN),float(cityX),float(cityY)))
        for row in range(self.CityCount):
            distanceList=[]        #建立臨時存儲距離的空列表
            for col in range(self.CityCount):
                #計算每個城市到所有城市的距離值
                distance=sqrt(pow(CityList[row][1]-CityList[col][1],2)+pow(CityList[row][2]-CityList[col][2],2))
                distance=round(distance)
                distanceList.append(distance)  #追加一個城市到所有城市的距離值
            CityDistanceList.append(distanceList) #追加一個城市到所有城市的距離值,為矩陣,即包含子列表
        file.close()
    def PutAnts(self):   #定義螞蟻所選擇城市以及將城市作為參數定義螞蟻的方法和屬性
        AntList.clear()
        for antNum in range(self.AnCount):
            city=random.randint(1,self.CityCount)
            ant=ANT(city)   #螞蟻類ANT的實例化,即將每只螞蟻隨機選擇的城市作為傳入的參數,使之具有ANT螞蟻類的方法和屬性
            AntList.append(ant)   #將定義的每只螞蟻追加到列表中
    def Search(self):  #定義搜索最佳旅行路徑方法的主程序
        for iter in range(self.Nmax):
            self.PutAnts()
            for ant in AntList:
                for ttt in range(len(CityList)):
                    #執行螞蟻ant.MoveToNextCity()方法,獲取螞蟻每次旅行時的旅行路徑長度Currlen,禁忌城市列表TabuCityLsit等屬性值
                    ant.MoveToNextCity(self.Alpha,self.Beta)
                ant.two_opt_search()
                ant.UpdatePathLen()
            tmpLen=AntList[0].CurrLen  #將螞蟻列表中第一只螞蟻的旅行路徑長度賦值給新的變量tmpLen
            tmpTour=AntList[0].TabuCityList  #將獲取的螞蟻列表的第一只螞蟻的禁忌城市列表賦值給新的變量tmpTour
            for ant in AntList[1:]:   #循環遍歷螞蟻列表,從索引值1開始,除第一只外
                if ant.CurrLen < tmpLen:
                    tmpLen=ant.CurrLen
                    tmpTour=ant.TabuCityList
            if tmpLen < self.Shortest:
                self.Shortest=tmpLen
                BestTour = tmpTour
            print(iter,":",self.Shortest,":",BestTour)
            pl.clf()
            x = [];
            y = []
            for city in BestTour:
                x.append(CityList[city - 1][1])
                y.append(CityList[city - 1][2])
            x.append(x[0])
            y.append(y[0])
            pl.plot(x, y)
            pl.scatter(x, y, s=30, c=r)
            pl.pause(0.01)
            self.UpdatePheromoneTrail()

    def UpdatePheromoneTrail(self): #定義更新信息素的方法
        for ant in AntList:
            for city in ant.TabuCityList[0:-1]:
                idx=ant.TabuCityList.index(city)   #獲取當前循環,禁忌城市的索引值
                nextCity=ant.TabuCityList[idx+1]
                PheromoneDeltaTraiList[city-1][nextCity-1]+=self.Q/ant.CurrLen
                #逐次更新釋放信息索列表,註意矩陣行列索代表的意義,[city-1]為選取的子列表即當前城市與所有城市間路勁的
                #的釋放信息素值,初始值均為0,[nextCity-1]為在子列表中對應緊鄰的下一個城市,釋放信息素為Q,信息素增加強度
                #系數與螞蟻當前旅行路徑長度CurrLen的比值,路徑長度越小釋放信息素越大,反之則越小。
                PheromoneDeltaTraiList[nextCity-1][city-1]+=self.Q/ant.CurrLen
            lastCity=ant.TabuCityList[-1]
            firstCity=ant.TabuCityList[0]
            PheromoneDeltaTraiList[lastCity-1][firstCity-1]+=self.Q/ant.CurrLen
            PheromoneDeltaTraiList[firstCity-1][lastCity-1]+=self.Q/ant.CurrLen
        for(city1,city1x,city1y) in CityList:
            for(city2,city2x,city2y) in CityList:
                PheromoneTraiList[city1-1][city2-1]=(1-self.Rou)*PheromoneTraiList[city1-1][city2-1]+PheromoneDeltaTraiList[city1-1][city2-1]
                PheromoneDeltaTraiList[city1 - 1][city2 - 1]=0



class ANT:  #定義螞蟻類
    def __init__(self,currCity=0):
        self.TabuCitySet=set()
        #定義禁忌城市集合,定義集合的目的是集合本身要素不重復並且之間可以做差集運算,例如AddCity()方法中
        #self.AllowedCitySet=CitySet-self.TabuCitySet 可以方便地從城市集合中去除禁忌城市列表的城市,獲取允許的城市列表
        self.TabuCityList=[]  #定義禁忌城市空列表
        self.AllowedCitySet=set() #定義允許城市集合
        self.TransferProbabilityList=[]  #定義城市選擇可能性列表
        self.CurrCity=0        #定義當前城市初始值為0
        self.CurrLen=0.0       #定義當前旅行路徑長度
        self.AddCity(currCity)   #執行AddCity()方法,獲取每次叠代的當前城市CurrCity,禁忌城市列表TabuCityList和允許城市列表AllowedCitySet的值
    def SelectNextCity(self,alpha,beta):  #定義螞蟻選擇下一個城市的方法,需要參考前文描述的蟻群算法
        if len(self.AllowedCitySet)==0:   #如果允許城市集合為0,則返回0
            return (0)
        sumProbability=0.0   #定義概率,可能性初始值為0
        self.TransferProbabilityList=[]   #建立選擇下一個城市可能性空列表
        for city in self.AllowedCitySet: #循環遍歷允許城市集合
            sumProbability=sumProbability+(pow(PheromoneTraiList[self.CurrCity-1][city-1],alpha)*pow(1.0/CityDistanceList[self.CurrCity-1][city-1],beta))
            #螞蟻選擇下一個城市的可能性由信息素與城市間距離之間關系等綜合因素確定,其中alpha為表征信息素重要程度的參數,beta為表征啟發式因子重要程度的參數
            transferProbability=sumProbability  #根據信息素選擇公式和輪盤選擇得出概率列表,非0-1
            self.TransferProbabilityList.append((city,transferProbability))  #將城市序號和對應的轉移城市概率追加到轉移概率列表中
        threshold=sumProbability*random.random()  #將概率乘以一個0-1的隨機數,獲取輪盤制指針值
        for(cityNum,cityProb) in self.TransferProbabilityList:
            if threshold<=cityProb:
                return (cityNum)
        return (0)
    def AddCity(self,city):    #定義增加城市到禁忌城市列表中的方法
        if city<=0:
            return
        self.CurrCity=city   #更新當前城市序號
        self.TabuCityList.append(city)  #將當前城市追加到禁忌城市列表中,因為已經旅行過的城市不應該再進入
        self.TabuCitySet.add(city)      #將當前城市追加到禁忌城市集合中,用於差集運算
        self.AllowedCitySet=CitySet-self.TabuCitySet  #使用集合差集的方法獲取允許的城市列表
    def MoveToNextCity(self,alpha,beta):  #定義轉移城市方法
        nextCity=self.SelectNextCity(alpha,beta)
        if nextCity > 0:
            self.AddCity(nextCity)     #執行self.AddCity()方法
    def ClearTabu(self):
        self.TabuCityList=[]
        self.TabuCitySet.clear()
        self.AllowedCitySet=CitySet-self.TabuCitySet
    def UpdatePathLen(self):
        for city in self.TabuCityList[0:-1]:#循環遍歷禁忌城市列表
            nextCity=self.TabuCityList[self.TabuCityList.index(city)+1]     #獲取禁忌城市列表中的下一個城市序號
            self.CurrLen=self.CurrLen+CityDistanceList[city-1][nextCity-1]  #從城市間距離之中提取當前循環城市與下一個城市之間的距離,並逐次求和
        lastCity=self.TabuCityList[-1]  #提取禁列表中的最後一個城市
        firstCity=self.TabuCityList[0]  #提取禁忌列表中的第一個城市
        self.CurrLen=self.CurrLen+CityDistanceList[lastCity-1][firstCity-1]
    def two_opt_search(self):  #領域搜索
        cityNum=len(CityList)
        for i in range(cityNum):
            for j in range(cityNum-1,i,-1):
                curCity1=self.TabuCityList[i]-1
                preCity1=self.TabuCityList[(i-1)%cityNum]-1
                nextCity1=self.TabuCityList[(i+1)%cityNum]-1
                curCity2=self.TabuCityList[j]-1
                preCity2=self.TabuCityList[(j-1)%cityNum]-1
                nextCity2=self.TabuCityList[(j+1)%cityNum]-1
                CurrLen=CityDistanceList[preCity1][curCity1]+CityDistanceList[curCity2][nextCity2]
                NextLen=CityDistanceList[preCity1][curCity2]+CityDistanceList[curCity1][nextCity2]
                if NextLen < CurrLen:
                    tempList=self.TabuCityList[i:j+1]
                    self.TabuCityList[i:j+1]=tempList[::-1]
if __name__==__main__:
    theBaca=BACA()
    theBaca.ReadCityInfo(eil511.tsp)
    theBaca.Search()

技術分享圖片

蟻群算法