Python實(shí)現(xiàn)蟻群算法
1、引言
在自然界中各種生物群體顯現(xiàn)出來(lái)的智能近幾十年來(lái)得到了學(xué)者們的廣泛關(guān)注,學(xué)者們通過(guò)對(duì)簡(jiǎn)單生物體的群體行為進(jìn)行模擬,進(jìn)而提出了群智能算法。其中,模擬蟻群覓食過(guò)程的蟻群優(yōu)化算法(Ant Colony Optimization, ACO)和模擬鳥(niǎo)群運(yùn)動(dòng)方式的粒子群算法(Particle Swarm Optimization, PSO)是兩種最主要的群智能算法。
蟻群算法是一種源于大自然生物世界的新的仿生進(jìn)化算法,由意大利學(xué)者M(jìn). Dorigo, V. Maniezzo和A.Colorni等人于20世紀(jì)90年代初期通過(guò)模擬自然界中螞蟻集體尋徑行為而提出的一種基于種群的啟發(fā)式隨機(jī)搜索算法"。螞蟻有能力在沒(méi)有任何提示的情形下找到從巢穴到食物源的最短路徑,并且能隨環(huán)境的變化,適應(yīng)性地搜索新的路徑,產(chǎn)生新的選擇。其根本原因是螞蟻在尋找食物時(shí),能在其走過(guò)的路徑上釋放一種特殊的分泌物——信息素(也稱外激素),隨著時(shí)間的推移該物質(zhì)會(huì)逐漸揮發(fā),后來(lái)的螞蟻選擇該路徑的概率與當(dāng)時(shí)這條路徑上信息素的強(qiáng)度成正比。當(dāng)一條路徑上通過(guò)的螞蟻越來(lái)越多時(shí),其留下的信息素也越來(lái)越多,后來(lái)螞蟻選擇該路徑的概率也就越高,從而更增加了該路徑上的信息素強(qiáng)度。而強(qiáng)度大的信息素會(huì)吸引更多的螞蟻,從而形成一種正反饋機(jī)制。通過(guò)這種正反饋機(jī)制,螞蟻?zhàn)罱K可以發(fā)現(xiàn)最短路徑。
最早的蟻群算法是螞蟻系統(tǒng)(Ant System,AS),研究者們根據(jù)不同的改進(jìn)策略對(duì)螞蟻系統(tǒng)進(jìn)行改進(jìn)并開(kāi)發(fā)了不同版本的蟻群算法,并成功地應(yīng)用于優(yōu)化領(lǐng)域。用該方法求解旅行商(TSP)問(wèn)題、分配問(wèn)題、車(chē)間作業(yè)調(diào)度(job-shop)問(wèn)題,取得了較好的試驗(yàn)結(jié)果。蟻群算法具有分布式計(jì)算、無(wú)中心控制和分布式個(gè)體之間間接通信等特征,易于與其他優(yōu)化算法相結(jié)合,它通過(guò)簡(jiǎn)單個(gè)體之間的協(xié)作表現(xiàn)出了求解復(fù)雜問(wèn)題的能力,已被廣泛應(yīng)用于求解優(yōu)化問(wèn)題。蟻群算法相對(duì)而言易于實(shí)現(xiàn),且算法中并不涉及復(fù)雜的數(shù)學(xué)操作,其處理過(guò)程對(duì)計(jì)算機(jī)的軟硬件要求也不高,因此對(duì)它的研究在理論和實(shí)踐中都具有重要的意義。
目前,國(guó)內(nèi)外的許多研究者和研究機(jī)構(gòu)都開(kāi)展了對(duì)蟻群算法理論和應(yīng)用的研究,蟻群算法已成為國(guó)際計(jì)算智能領(lǐng)域關(guān)注的熱點(diǎn)課題。雖然目前蟻群算法沒(méi)有形成嚴(yán)格的理論基礎(chǔ),但其作為一種新興的進(jìn)化算法已在智能優(yōu)化等領(lǐng)域表現(xiàn)出了強(qiáng)大的生命力。
2 蟻群算法理論
蟻群算法是對(duì)自然界螞蟻的尋徑方式進(jìn)行模擬而得出的一種仿生算法。螞蟻在運(yùn)動(dòng)過(guò)程中,能夠在它所經(jīng)過(guò)的路徑上留下信息素進(jìn)行信息傳遞,而且螞蟻在運(yùn)動(dòng)過(guò)程中能夠感知這種物質(zhì),并以此來(lái)指導(dǎo)自己的運(yùn)動(dòng)方向。因此,由大量螞蟻組成的蟻群的集體行為便表現(xiàn)出一種信息正反饋現(xiàn)象:某一路徑上走過(guò)的螞蟻越多,則后來(lái)者選擇該路徑的概率就越大。
3 算法理論圖解
(1)在自然界中,螞蟻的食物源總是隨機(jī)分散于蟻巢周?chē)?,在蟻群協(xié)調(diào)、分工、合作后總能找到一條通往食物源的最短路徑。現(xiàn)實(shí)中,我們能觀察到大量螞蟻在巢穴與食物源之間形成近乎直線的路徑,而不是曲線、圓等其他形狀,如圖(a)。
(2)螞蟻群體不僅能完成復(fù)雜的任務(wù),并且還能適應(yīng)環(huán)境的變化,如在蟻群運(yùn)動(dòng)路線上突然出現(xiàn)障礙物時(shí),一開(kāi)始各只螞蟻分布是均勻的,不管路徑長(zhǎng)短,螞蟻總是先按同等概率選擇各條路徑,如圖(b)。
(3)螞蟻在運(yùn)動(dòng)過(guò)程中,能在其經(jīng)過(guò)的路徑上留下信息素,并且能感知到這種物質(zhì)的存在及其強(qiáng)度,并以此指導(dǎo)自己運(yùn)動(dòng)的方向,螞蟻傾向于信息素濃度高的方向移動(dòng)。在相同時(shí)間內(nèi)較短路徑上的信息素量就遺留得較多,則選擇較短路徑得螞蟻也隨即增多,如圖(c)。
(4)不難看出,由于大量螞蟻組成得蟻群集體行為表現(xiàn)出的一種信息正反饋現(xiàn)象,在某一路徑上走過(guò)的螞蟻越多,則后來(lái)者選擇該路徑的概率就越大,螞蟻個(gè)體質(zhì)檢就是通過(guò)這種信息交流機(jī)制來(lái)搜索食物,并最終沿著最短路徑行進(jìn),如圖(d)。
4 人工蟻群優(yōu)化過(guò)程
基于以上真實(shí)蟻群尋找食物時(shí)的最優(yōu)路徑選擇問(wèn)題,可以構(gòu)造人工蟻群,來(lái)解決最優(yōu)化問(wèn)題,如TSP問(wèn)題。人工蟻群中把具有簡(jiǎn)單功能的工作單元看作螞蟻。二者的相似之處在于都是優(yōu)先選擇信息素濃度大的路徑。較短路徑的信息素濃度高,所以能夠最終被所有螞蟻選擇,也就是最終的優(yōu)化結(jié)果。兩者的區(qū)別在于人工蟻群有一定的記憶能力,能夠記憶已經(jīng)訪問(wèn)過(guò)的節(jié)點(diǎn)。同時(shí),人工蟻群再選擇下一條路徑的時(shí)候是按一定算法規(guī)律有意識(shí)地尋找最短路徑,而不是盲目的。例如在TSP問(wèn)題中,可以預(yù)先知道當(dāng)前城市到下一個(gè)目的地的距離。
在TSP問(wèn)題的人工蟻群算法中,假設(shè)m只螞蟻在圖的相鄰節(jié)點(diǎn)間移動(dòng),從而協(xié)作異步地得到問(wèn)題的解。每只螞蟻的一步轉(zhuǎn)移概率由圖中的每條邊上的兩類參數(shù)決定:一是信息素值,也稱信息素痕跡;二是可見(jiàn)度,即先驗(yàn)值。
信息素的更新方式有兩種:一是揮發(fā),也就是所有路徑上的信息素以一定的比率減少,模擬自然蟻群的信息素隨時(shí)間揮發(fā)的過(guò)程;二是增強(qiáng),給評(píng)價(jià)值“好”(有螞蟻?zhàn)哌^(guò))的邊增加信息素。
螞蟻向下一個(gè)目標(biāo)的運(yùn)動(dòng)是通過(guò)一個(gè)隨機(jī)原則來(lái)實(shí)現(xiàn)的,也就是運(yùn)用當(dāng)前所在節(jié)點(diǎn)存儲(chǔ)的信息,計(jì)算出下一步可達(dá)節(jié)點(diǎn)的概率,并按此概率實(shí)現(xiàn)一步移動(dòng),如此往復(fù),越來(lái)越接近最優(yōu)解。
螞蟻在尋找過(guò)程中,或在找到一個(gè)解后,會(huì)評(píng)估該解或解的一部分的優(yōu)化程度,并把評(píng)價(jià)信息保存在相關(guān)連接的信息素中。
這種算法有別于傳統(tǒng)編程模式,其優(yōu)勢(shì)在于,避免了冗長(zhǎng)的編程和籌劃,程序本身是基于一定規(guī)則的隨機(jī)運(yùn)行來(lái)尋找最佳配置。也就是說(shuō),當(dāng)程序最開(kāi)始找到目標(biāo)的時(shí)候,路徑可能不是最優(yōu)的。但是,程序可以通過(guò)螞蟻尋找食物的時(shí)候的信息素原理,不斷地去修正原來(lái)的路線,使整個(gè)路線越來(lái)越短,也就是說(shuō),程序執(zhí)行的時(shí)間越長(zhǎng)(在程序中也就是迭代次數(shù)不能太少,同時(shí)還要保證一定的螞蟻數(shù)量),所獲得的路徑就越可能接近最優(yōu)路徑。這看起來(lái)很類似與我們所見(jiàn)的由無(wú)數(shù)例子進(jìn)行歸納概括形成最佳路徑的過(guò)程。實(shí)際上好似是程序的一個(gè)自我學(xué)習(xí)的過(guò)程。
這種優(yōu)化過(guò)程的本質(zhì)在于:
選擇機(jī)制:信息素越多的路徑,被選擇的概率越大。
更新機(jī)制:路徑上面的信息素會(huì)隨螞蟻的經(jīng)過(guò)而增長(zhǎng),而且同時(shí)也隨時(shí)間的推移逐漸揮發(fā)消失。
協(xié)調(diào)機(jī)制:螞蟻間實(shí)際上是通過(guò)分泌物來(lái)互相通信、協(xié)同工作的。
蟻群算法正是充分利用了選擇、更新和協(xié)調(diào)的優(yōu)化機(jī)制,即通過(guò)個(gè)體之間的信息交流與相互協(xié)作最終找到最優(yōu)解,使它具有很強(qiáng)的發(fā)現(xiàn)較優(yōu)解的能力。
事實(shí)上,每只螞蟻并不是像我們想象的需要知道整個(gè)世界的信息,他們其實(shí)只關(guān)心很小范圍內(nèi)的眼前信息,而且根據(jù)這些局部信息利用幾條簡(jiǎn)單的規(guī)則進(jìn)行決策,但是,當(dāng)集群里有無(wú)數(shù)螞蟻的時(shí)候,復(fù)雜性的行為就會(huì)凸現(xiàn)出來(lái)。這就是人工生命、復(fù)雜性科學(xué)解釋的規(guī)律!那么,這些簡(jiǎn)單規(guī)則是什么呢?下面詳細(xì)說(shuō)明:
1、范圍:
螞蟻觀察到的范圍是一個(gè)方格世界,螞蟻有一個(gè)參數(shù)為速度半徑(一般是3),那么它能觀察到的范圍就是3*3個(gè)方格世界,并且能移動(dòng)的距離也在這個(gè)范圍之內(nèi)。
2、環(huán)境:
螞蟻所在的環(huán)境是一個(gè)虛擬的世界,其中有障礙物,有別的螞蟻,還有信息素,信息素有兩種,一種是找到食物的螞蟻灑下的食物信息素,一種是找到窩的螞蟻灑下的窩的信息素。每個(gè)螞蟻都僅僅能感知它范圍內(nèi)的環(huán)境信息。環(huán)境以一定的速率讓信息素消失。
3、覓食規(guī)則:
在每只螞蟻能感知的范圍內(nèi)尋找是否有食物,如果有就直接過(guò)去。否則看是否有信息素,并且比較在能感知的范圍內(nèi)哪一點(diǎn)的信息素最多,這樣,它就朝信息素多的地方走,并且每只螞蟻多會(huì)以小概率犯錯(cuò)誤,從而并不是往信息素最多的點(diǎn)移動(dòng)。螞蟻找窩的規(guī)則和上面一樣,只不過(guò)它對(duì)窩的信息素做出反應(yīng),而對(duì)食物信息素沒(méi)反應(yīng)。
4、移動(dòng)規(guī)則:
每只螞蟻都朝向信息素最多的方向移,并且,當(dāng)周?chē)鷽](méi)有信息素指引的時(shí)候,螞蟻會(huì)按照自己原來(lái)運(yùn)動(dòng)的方向慣性的運(yùn)動(dòng)下去,并且,在運(yùn)動(dòng)的方向有一個(gè)隨機(jī)的小的擾動(dòng)。為了防止螞蟻原地轉(zhuǎn)圈,它會(huì)記住最近剛走過(guò)了哪些點(diǎn),如果發(fā)現(xiàn)要走的下一點(diǎn)已經(jīng)在最近走過(guò)了,它就會(huì)盡量避開(kāi)。
5、避障規(guī)則:
如果螞蟻要移動(dòng)的方向有障礙物擋住,它會(huì)隨機(jī)的選擇另一個(gè)方向,并且有信息素指引的話,它會(huì)按照覓食的規(guī)則行為。
6、播撒信息素規(guī)則:
每只螞蟻在剛找到食物或者窩的時(shí)候撒發(fā)的信息素最多,并隨著它走遠(yuǎn)的距離,播撒的信息素越來(lái)越少。
根據(jù)這幾條規(guī)則,螞蟻之間并沒(méi)有直接的關(guān)系,但是每只螞蟻都和環(huán)境發(fā)生交互,而通過(guò)信息素這個(gè)紐帶,實(shí)際上把各個(gè)螞蟻之間關(guān)聯(lián)起來(lái)了。比如,當(dāng)一只螞蟻找到了食物,它并沒(méi)有直接告訴其它螞蟻這兒有食物,而是向環(huán)境播撒信息素,當(dāng)其它的螞蟻經(jīng)過(guò)它附近的時(shí)候,就會(huì)感覺(jué)到信息素的存在,進(jìn)而根據(jù)信息素的指引找到了食物。
那么,螞蟻究竟是怎么找到食物的呢?
在沒(méi)有螞蟻找到食物的時(shí)候,環(huán)境沒(méi)有有用的信息素,那么螞蟻為什么會(huì)相對(duì)有效的找到食物呢?這要?dú)w功于螞蟻的移動(dòng)規(guī)則,尤其是在沒(méi)有信息素時(shí)候的移動(dòng)規(guī)則。首先,它要能盡量保持某種慣性,這樣使得螞蟻盡量向前方移動(dòng)(開(kāi)始,這個(gè)前方是隨機(jī)固定的一個(gè)方向),而不是原地?zé)o謂的打轉(zhuǎn)或者震動(dòng);其次,螞蟻要有一定的隨機(jī)性,雖然有了固定的方向,但它也不能像粒子一樣直線運(yùn)動(dòng)下去,而是有一個(gè)隨機(jī)的干擾。這樣就使得螞蟻運(yùn)動(dòng)起來(lái)具有了一定的目的性,盡量保持原來(lái)的方向,但又有新的試探,尤其當(dāng)碰到障礙物的時(shí)候它會(huì)立即改變方向,這可以看成一種選擇的過(guò)程,也就是環(huán)境的障礙物讓螞蟻的某個(gè)方向正確,而其他方向則不對(duì)。這就解釋了為什么單個(gè)螞蟻在復(fù)雜的諸如迷宮的地圖中仍然能找到隱蔽得很好的食物。當(dāng)然,在有一只螞蟻找到了食物的時(shí)候,其他螞蟻會(huì)沿著信息素很快找到食物的。
螞蟻如何找到最短路徑的?
這一是要?dú)w功于信息素,另外要?dú)w功于環(huán)境,具體說(shuō)是計(jì)算機(jī)時(shí)鐘。信息素多的地方顯然經(jīng)過(guò)這里的螞蟻會(huì)多,因而會(huì)有更多的螞蟻聚集過(guò)來(lái)。假設(shè)有兩條路從窩通向食物,開(kāi)始的時(shí)候,走這兩條路的螞蟻數(shù)量同樣多(或者較長(zhǎng)的路上螞蟻多,這也無(wú)關(guān)緊要)。當(dāng)螞蟻沿著一條路到達(dá)終點(diǎn)以后會(huì)馬上返回來(lái),這樣,短的路螞蟻來(lái)回一次的時(shí)間就短,這也意味著重復(fù)的頻率就快,因而在單位時(shí)間里走過(guò)的螞蟻數(shù)目就多,灑下的信息素自然也會(huì)多,自然會(huì)有更多的螞蟻被吸引過(guò)來(lái),從而灑下更多的信息素……;而長(zhǎng)的路正相反,因此,越來(lái)越多地螞蟻聚集到較短的路徑上來(lái),最短的路徑就近似找到了。也許有人會(huì)問(wèn)局部最短路徑和全局最短路的問(wèn)題,實(shí)際上螞蟻逐漸接近全局最短路的,為什么呢?這源于螞蟻會(huì)犯錯(cuò)誤,也就是它會(huì)按照一定的概率不往信息素高的地方走而另辟蹊徑,這可以理解為一種創(chuàng)新,這種創(chuàng)新如果能縮短路途,那么根據(jù)剛才敘述的原理,更多的螞蟻會(huì)被吸引過(guò)來(lái)。
5 基本蟻群算法及其流程
5.1 蟻群算法公式
蟻群算法實(shí)際上是正反饋原理和啟發(fā)式算法相結(jié)合的一種算法。在選擇路徑時(shí),螞蟻不僅利用了路徑上的信息素,而且用到了城市間距離的倒數(shù)作為啟發(fā)式因子。實(shí)驗(yàn)結(jié)果表明,ant-cycle模型比ant-quantity和ant-density模型有更好的性能。這是因?yàn)閍nt-cycle模型利用全局信息更新路徑上的信息素量,而ant-quantity和ant-density模型使用局部信息。
5.2 蟻群算法程序概括
(1)參數(shù)初始化
在尋最短路錢(qián),需對(duì)程序各個(gè)參數(shù)進(jìn)行初始化,蟻群規(guī)模m、信息素重要程度因子α、啟發(fā)函數(shù)重要程度因子β、信息素會(huì)發(fā)因子、最大迭代次數(shù)ddcs_max,初始迭代值為ddcs=1。
(2)構(gòu)建解空間
將每只螞蟻隨機(jī)放置在不同的出發(fā)地點(diǎn),對(duì)螞蟻訪問(wèn)行為按照公式計(jì)算下一個(gè)訪問(wèn)的地點(diǎn),直到所有螞蟻訪問(wèn)完所有地點(diǎn)。
(3)更新信息素
計(jì)算每只螞蟻經(jīng)過(guò)的路徑總長(zhǎng)Lk,記錄當(dāng)前循環(huán)中的最優(yōu)路徑,同時(shí)根據(jù)公式對(duì)各個(gè)地點(diǎn)間連接路徑上的信息素濃度進(jìn)行更新。
(4)判斷終止
迭代次數(shù)達(dá)到最大值前,清空螞蟻經(jīng)過(guò)的記錄,并返回步驟2。
5.3 流程圖
6 案例實(shí)現(xiàn)
6.1 案例1
求解函數(shù):的最小值,其中x的取值范圍為[-5,5], y的取值范圍為[-5, 5]。這是一個(gè)有多個(gè)局部極值的函數(shù)。
6.2 Python實(shí)現(xiàn)
import numpy as np from tqdm import tqdm#進(jìn)度條設(shè)置 import matplotlib.pyplot as plt import matplotlib as mpl import matplotlib; matplotlib.use('TkAgg') mpl.rcParams['font.sans-serif'] = ['SimHei'] # 指定默認(rèn)字體 mpl.rcParams['axes.unicode_minus'] = False # 解決保存圖像是負(fù)號(hào)'-'顯示為方塊的問(wèn)題 #============蟻群算法求函數(shù)極值================ #=======適應(yīng)度函數(shù)===== def func(x,y): value = 20*np.power(x*x-y*y,2)-np.power(1-y,2)-3*np.power(1+y,2)+0.3 return value #=======初始化參數(shù)==== m=20 #螞蟻個(gè)數(shù) G_max=200 #最大迭代次數(shù) Rho=0.9 #信息素蒸發(fā)系數(shù) P0=0.2 #轉(zhuǎn)移概率常數(shù) XMAX= 5 #搜索變量x最大值 XMIN= -5 #搜索變量x最小值 YMAX= 5 #搜索變量y最大值 YMIN= -5 #搜索變量y最小值 X=np.zeros(shape=(m,2)) #蟻群 shape=(20, 2) Tau=np.zeros(shape=(m,)) #信息素 P=np.zeros(shape=(G_max,m)) #狀態(tài)轉(zhuǎn)移矩陣 fitneess_value_list=[] #迭代記錄最優(yōu)目標(biāo)函數(shù)值 #==隨機(jī)設(shè)置螞蟻初始位置== for i in range(m):#遍歷每一個(gè)螞蟻 X[i,0]=np.random.uniform(XMIN,XMAX,1)[0] #初始化x X[i,1]=np.random.uniform(YMIN,YMAX,1)[0] #初始化y Tau[i]=func(X[i,0],X[i,1]) step=0.1; #局部搜索步長(zhǎng) for NC in range(G_max):#遍歷每一代 lamda=1/(NC+1) BestIndex=np.argmin(Tau) #最優(yōu)索引 Tau_best=Tau[BestIndex] #最優(yōu)信息素 #==計(jì)算狀態(tài)轉(zhuǎn)移概率=== for i in range(m):#遍歷每一個(gè)螞蟻 P[NC,i]=np.abs((Tau_best-Tau[i]))/np.abs(Tau_best)+0.01 #即例最優(yōu)信息素的距離 #=======位置更新========== for i in range(m): # 遍歷每一個(gè)螞蟻 #===局部搜索==== if P[NC,i]<P0: temp1 = X[i, 0] + (2 * np.random.random() - 1) * step * lamda # x(2 * np.random.random() - 1) 轉(zhuǎn)換到【-1,1】區(qū)間 temp2 = X[i,1] + (2 * np.random.random() - 1) * step * lamda #y #===全局搜索==== else: temp1 = X[i, 0] + (XMAX - XMIN) * (np.random.random() - 0.5) temp2 = X[i, 0] + (YMAX - YMIN) * (np.random.random() - 0.5) #=====邊界處理===== if temp1 < XMIN: temp1 =XMIN if temp1 > XMAX: temp1 =XMAX if temp2 < XMIN: temp2 =XMIN if temp2 > XMAX: temp2 =XMAX #==判斷螞蟻是否移動(dòng)(選更優(yōu)=== if func(temp1, temp2) < func(X[i, 0], X[i, 1]): X[i, 0] = temp1 X[i, 1]= temp2 #=====更新信息素======== for i in range(m): # 遍歷每一個(gè)螞蟻 Tau[i] = (1 - Rho) * Tau[i] + func(X[i, 0], X[i, 1]) #(1 - Rho) * Tau[i] 信息蒸發(fā)后保留的 index=np.argmin(Tau)#最小值索引 value=Tau[index]#最小值 fitneess_value_list.append(func(X[index,0],X[index,1])) #記錄最優(yōu)目標(biāo)函數(shù)值 #==打印結(jié)果=== min_index=np.argmin(Tau)#最優(yōu)值索引 minX=X[min_index,0] #最優(yōu)變量x minY=X[min_index,1] #最優(yōu)變量y minValue=func(X[min_index,0],X[min_index,1]) #最優(yōu)目標(biāo)函數(shù)值 print('最優(yōu)變量x',minX,end='') print('最優(yōu)變量y',minY,end='\n') print('最優(yōu)目標(biāo)函數(shù)值',minValue) plt.plot(fitneess_value_list,label='迭代曲線') plt.legend() plt.show()
6.3 結(jié)果
最優(yōu)變量x 5.0最優(yōu)變量y 5.0 最優(yōu)目標(biāo)函數(shù)值 -123.7
6.4 案例2
6.5 Python實(shí)現(xiàn)
#====================導(dǎo)入相關(guān)庫(kù)============================= import pandas as pd import numpy as np from tqdm import tqdm#進(jìn)度條設(shè)置 import matplotlib.pyplot as plt import matplotlib; matplotlib.use('TkAgg') from pylab import * mpl.rcParams['font.sans-serif'] = ['SimHei'] mpl.rcParams['axes.unicode_minus'] = False #=======================定義函數(shù)========================== #=======目標(biāo)函數(shù)===== def calc_f(X): """計(jì)算粒子的的適應(yīng)度值,也就是目標(biāo)函數(shù)值,X 的維度是 size * 2 """ A = 10 pi = np.pi x = X[0] y = X[1] return 2 * A + x ** 2 - A * np.cos(2 * pi * x) + y ** 2 - A * np.cos(2 * pi * y) #====懲罰項(xiàng)函數(shù)====== def calc_e(X): """計(jì)算螞蟻的懲罰項(xiàng),X 的維度是 size * 2 """ ee = 0 """計(jì)算第一個(gè)約束的懲罰項(xiàng)""" e1 = X[0] + X[1] - 6 ee += max(0, e1) """計(jì)算第二個(gè)約束的懲罰項(xiàng)""" e2 = 3 * X[0] - 2 * X[1] - 5 ee += max(0, e2) return ee #===子代和父輩之間的選擇操作==== def update_best(parent,parent_fitness,parent_e,child,child_fitness,child_e): """ 針對(duì)不同問(wèn)題,合理選擇懲罰項(xiàng)的閾值。本例中閾值為0.00001 :param parent: 父輩個(gè)體 :param parent_fitness:父輩適應(yīng)度值 :param parent_e :父輩懲罰項(xiàng) :param child: 子代個(gè)體 :param child_fitness 子代適應(yīng)度值 :param child_e :子代懲罰項(xiàng) :return: 父輩 和子代中較優(yōu)者、適應(yīng)度、懲罰項(xiàng) """ # 規(guī)則1,如果 parent 和 child 都沒(méi)有違反約束,則取適應(yīng)度小的 if parent_e <= 0.00001 and child_e <= 0.00001: if parent_fitness <= child_fitness: return parent,parent_fitness,parent_e else: return child,child_fitness,child_e # 規(guī)則2,如果child違反約束而parent沒(méi)有違反約束,則取parent if parent_e < 0.00001 and child_e >= 0.00001: return parent,parent_fitness,parent_e # 規(guī)則3,如果parent違反約束而child沒(méi)有違反約束,則取child if parent_e >= 0.00001 and child_e < 0.00001: return child,child_fitness,child_e # 規(guī)則4,如果兩個(gè)都違反約束,則取適應(yīng)度值小的 if parent_fitness <= child_fitness: return parent,parent_fitness,parent_e else: return child,child_fitness,child_e #=======================初始化參數(shù)========================== m=20 #螞蟻個(gè)數(shù) G_max=200 #最大迭代次數(shù) Rho=0.9 #信息素蒸發(fā)系數(shù) P0=0.2 #轉(zhuǎn)移概率常數(shù) XMAX= 2 #搜索變量x最大值 XMIN= 1 #搜索變量x最小值 YMAX= 0 #搜索變量y最大值 YMIN= -1 #搜索變量y最小值 step=0.1 #局部搜索步長(zhǎng) P=np.zeros(shape=(G_max,m)) #狀態(tài)轉(zhuǎn)移矩陣 fitneess_value_list=[] #迭代記錄最優(yōu)目標(biāo)函數(shù)值 #=======================初始化螞蟻群體位置和信息素========================== def initialization(): """ :return: 初始化蟻群和初始信息素 """ X = np.zeros(shape=(m, 2)) # 蟻群 shape=(20, 2) Tau = np.zeros(shape=(m,)) # 信息素 for i in range(m): # 遍歷每一個(gè)螞蟻 X[i, 0] = np.random.uniform(XMIN, XMAX, 1)[0] # 初始化x X[i, 1] =np.random.uniform(YMIN, YMAX, 1)[0] # 初始化y Tau[i] = calc_f(X[i])#計(jì)算信息素 return X,Tau #===位置更新==== def position_update(NC,P,X): """ :param NC: 當(dāng)前迭代次數(shù) :param P: 狀態(tài)轉(zhuǎn)移矩陣 :param X: 蟻群 :return: 蟻群X """ lamda = 1 / (NC + 1) # =======位置更新========== for i in range(m): # 遍歷每一個(gè)螞蟻 # ===局部搜索=== if P[NC, i] < P0: temp1 = X[i, 0] + (2 * np.random.random() - 1) * step * lamda # x(2 * np.random.random() - 1) 轉(zhuǎn)換到【-1,1】區(qū)間 temp2 = X[i, 1] + (2 * np.random.random() - 1) * step * lamda # y # ===全局搜索=== else: temp1 = X[i, 0] + (XMAX - XMIN) * (np.random.random() - 0.5) temp2 = X[i, 0] + (YMAX - YMIN) * (np.random.random() - 0.5) # =====邊界處理===== if (temp1 < XMIN) or (temp1 > XMAX): temp1 = np.random.uniform(XMIN, XMAX, 1)[0] # 初始化x if (temp2 < YMIN) or (temp2 > YMAX): temp2 = np.random.uniform(YMIN, YMAX, 1)[0] # 初始化y #=====判斷螞蟻是否移動(dòng)(選更優(yōu))===== #==子代螞蟻== children=np.array([temp1,temp2])#子代個(gè)體螞蟻 children_fit=calc_f(children) #子代目標(biāo)函數(shù)值 children_e=calc_e(children) #子代懲罰項(xiàng) parent=X[i]#父輩個(gè)體螞蟻 parent_fit=calc_f(parent)#父輩目標(biāo)函數(shù)值 parent_e=calc_e(parent)#父輩懲罰項(xiàng) pbesti, pbest_fitness, pbest_e = update_best(parent, parent_fit, parent_e, children, children_fit,children_e) X[i]=pbesti return X #======信息素更新============ def Update_information(Tau,X): """ :param Tau: 信息素 :param X: 螞蟻群 :return: Tau信息素 """ for i in range(m): # 遍歷每一個(gè)螞蟻 Tau[i] = (1 - Rho) * Tau[i] + calc_f(X[i]) #(1 - Rho) * Tau[i] 信息蒸發(fā)后保留的 return Tau #=============主函數(shù)====================== def main(): X,Tau=initialization() #初始化螞蟻群X 和信息素 Tau for NC in tqdm(range(G_max)): # 遍歷每一代 BestIndex = np.argmin(Tau) # 最優(yōu)索引 Tau_best = Tau[BestIndex] # 最優(yōu)信息素 # 計(jì)算狀態(tài)轉(zhuǎn)移概率 for i in range(m): # 遍歷每一個(gè)螞蟻 P[NC, i] = np.abs((Tau_best - Tau[i])) / np.abs(Tau_best) + 0.01 # 即離最優(yōu)信息素的距離 # =======位置更新========== X=position_update(NC,P,X) #X.shape=(20, 2) # =====更新信息素======== Tau=Update_information(Tau, X) # =====記錄最優(yōu)目標(biāo)函數(shù)值======== index = np.argmin(Tau) # 最小值索引 value = Tau[index] # 最小值 fitneess_value_list.append(calc_f(X[index])) # 記錄最優(yōu)目標(biāo)函數(shù)值 #=====打印結(jié)果======= min_index = np.argmin(Tau) # 最優(yōu)值索引 minX = X[min_index, 0] # 最優(yōu)變量x minY = X[min_index, 1] # 最優(yōu)變量y minValue = calc_f(X[min_index]) # 最優(yōu)目標(biāo)函數(shù)值 print('最優(yōu)變量x', minX, end='') print('最優(yōu)變量y', minY, end='\n') print('最優(yōu)目標(biāo)函數(shù)值', minValue) print('最優(yōu)變量對(duì)應(yīng)的懲罰項(xiàng)',calc_e(X[min_index])) #=====可視化======= plt.plot(fitneess_value_list, label='迭代曲線') plt.legend() plt.show() if __name__=='__main__': main()
6.6 結(jié)果
100%|██████████| 200/200 [00:00<00:00, 220.49it/s]
最優(yōu)變量x 1.0000085699291246最優(yōu)變量y -0.0040192755525732165
最優(yōu)目標(biāo)函數(shù)值 1.0032219250172503
最優(yōu)變量對(duì)應(yīng)的懲罰項(xiàng) 0
到此這篇關(guān)于Python實(shí)現(xiàn)蟻群算法的文章就介紹到這了,更多相關(guān)Python 蟻群算法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python Xarray處理設(shè)置二維數(shù)組作為coordinates方式
這篇文章主要介紹了python Xarray處理設(shè)置二維數(shù)組作為coordinates方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07pyinstaller生成的exe文件啟動(dòng)時(shí)間漫長(zhǎng)的原因
本文主要介紹了pyinstaller生成的exe文件啟動(dòng)時(shí)間漫長(zhǎng)的原因,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-01-01python 3利用Dlib 19.7實(shí)現(xiàn)攝像頭人臉檢測(cè)特征點(diǎn)標(biāo)定
這篇文章主要為大家詳細(xì)介紹了python 3利用Dlib 19.7實(shí)現(xiàn)攝像頭人臉檢測(cè)特征點(diǎn)標(biāo)定,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-02-02對(duì)python 多線程中的守護(hù)線程與join的用法詳解
今天小編就為大家分享一篇對(duì)python 多線程中的守護(hù)線程與join的用法詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-02-02Python命令行參數(shù)解析之a(chǎn)rgparse模塊詳解
這篇文章主要介紹了Python命令行參數(shù)解析之a(chǎn)rgparse模塊詳解,argparse?是?Python?的一個(gè)標(biāo)準(zhǔn)庫(kù),用于命令行參數(shù)的解析,這意味著我們無(wú)需在代碼中手動(dòng)為變量賦值,而是可以直接在命令行中向程序傳遞相應(yīng)的參數(shù),再由變量去讀取這些參數(shù),需要的朋友可以參考下2023-08-08Python中map和列表推導(dǎo)效率比較實(shí)例分析
這篇文章主要介紹了Python中map和列表推導(dǎo)效率比較,實(shí)例分析了Python中的map與列表的推導(dǎo)效率,需要的朋友可以參考下2015-06-06