蚂蚁算法简介
目錄
定義
編輯 各個螞蟻在沒有事先告訴他們食物在什么地方的前提下開始尋找食物。當一只找到食物以后,它會向環境釋放一種揮發性分泌物pheromone (稱為信息素,該物質隨著時間的推移會逐漸揮發消失,信息素濃度的大小表征路徑的遠近)來實現的,吸引其他的螞蟻過來,這樣越來越多的螞蟻會找到食物。有些螞蟻并沒有像其它螞蟻一樣總重復同樣的路,他們會另辟蹊徑,如果另開辟的道路比原來的其他道路更短,那么,漸漸地,更多的螞蟻被吸引到這條較短的路上來。最后,經過一段時間運行,可能會出現一條最短的路徑被大多數螞蟻重復著。原理
編輯 設想,如果我們要為螞蟻設計一個人工智能的程序,那么這個程序要多么復雜呢?首先,你要讓螞蟻能夠避開障礙物,就必須根據適當的地形給它編進指令讓他們能夠巧妙的避開障礙物,其次,要讓螞蟻找到食物,就需要讓他們遍歷空間上的所有點;再次,如果要讓螞蟻找到最短的路徑,那么需要計算所有可能的路徑并且比較它們的大小,而且更重要的是,你要小心翼翼地編程,因為程序的錯誤也許會讓你前功盡棄。這是多么不可思議的程序!太復雜了,恐怕沒人能夠完成這樣繁瑣冗余的程序。 然而,事實并沒有你想得那么復雜,上面這個程序每個螞蟻的核心程序編碼不過100多行!為什么這么簡單的程序會讓螞蟻干這樣復雜的事情?答案是:簡單規則的涌現。事實上,每只螞蟻并不是像我們想象的需要知道整個世界的信息,他們其實只關心很小范圍內的眼前信息,而且根據這些局部信息利用幾條簡單的規則進行決策,這樣,在蟻群這個集體里,復雜性的行為就會凸現出來。這就是人工生命、復雜性科學解釋的規律!那么,這些簡單規則是什么呢?問題
編輯 螞蟻究竟是怎么找到食物的呢?在沒有螞蟻找到食物的時候,環境沒有有用的信息素,那么螞蟻為什么會相對有效的找到食物呢?這要歸功于螞蟻的移動規則,尤其是在沒有信息素時候的移動規則。首先,它要能盡量保持某種慣性,這樣使得螞蟻盡量向前方移動(開始,這個前方是隨機固定的一個方向),而不是原地無謂的打轉或者震動;其次,螞蟻要有一定的隨機性,雖然有了固定的方向,但它也不能像粒子一樣直線運動下去,而是有一個隨機的干擾。這樣就使得螞蟻運動起來具有了一定的目的性,盡量保持原來的方向,但又有新的試探,尤其當碰到障礙物的時候它會立即改變方向,這可以看成一種選擇的過程,也就是環境的障礙物讓螞蟻的某個方向正確,而其他方向則不對。這就解釋了為什么單個螞蟻在復雜的諸如迷宮的地圖中仍然能找到隱蔽得很好的食物。 當然,在有一只螞蟻找到了食物的時候,大部分螞蟻會沿著信息素很快找到食物的。但不排除會出現這樣的情況:在最初的時候,一部分螞蟻通過隨機選擇了同一條路徑,隨著這條路徑上螞蟻釋放的信息素越來越多,更多的螞蟻也選擇這條路徑,但這條路徑并不是最優(即最短)的,所以,導致了迭代次數完成后,螞蟻找到的不是最優解,而是次優解,這種情況下的結果可能對實際應用的意義就不大了。 螞蟻如何找到最短路徑的?這一是要歸功于信息素,另外要歸功于環境,具體說是計算機時鐘。信息素多的地方顯然經過這里的螞蟻會多,因而會有更多的螞蟻聚集過來。假設有兩條路從窩通向食物,開始的時候,走這兩條路的螞蟻數量同樣多(或者較長的路上螞蟻多,這也無關緊要)。當螞蟻沿著一條路到達終點以后會馬上返回來,這樣,短的路螞蟻來回一次的時間就短,這也意味著重復的頻率就快,因而在單位時間里走過的螞蟻數目就多,灑下的信息素自然也會多,自然會有更多的螞蟻被吸引過來,從而灑下更多的信息素……;而長的路正相反,因此,越來越多地螞蟻聚集到較短的路徑上來,最短的路徑就近似找到了。也許有人會問局部最短路徑和全局最短路的問題,實際上螞蟻逐漸接近全局最短路的,為什么呢?這源于螞蟻會犯錯誤,也就是它會按照一定的概率不往信息素高的地方走而另辟蹊徑,這可以理解為一種創新,這種創新如果能縮短路途,那么根據剛才敘述的原理,更多的螞蟻會被吸引過來。詳細說明
編輯范圍
螞蟻觀察到的范圍是一個方格世界,螞蟻有一個參數為速度半徑(一般是3),那么它能觀察到的范圍就是3*3個方格世界,并且能移動的距離也在這個范圍之內。環境
螞蟻所在的環境是一個虛擬的世界,其中有障礙物,有別的螞蟻,還有信息素,信息素有兩種,一種是找到食物的螞蟻灑下的食物信息素,一種是找到窩的螞蟻灑下的窩的信息素。每個螞蟻都僅僅能感知它范圍內的環境信息。環境以一定的速率讓信息素消失。覓食規則
在每只螞蟻能感知的范圍內尋找是否有食物,如果有就直接過去。否則看是否有信息素,并且比較在能感知的范圍內哪一點的信息素最多,這樣,它就朝信息素多的地方走,并且每只螞蟻都會以小概率犯錯誤,從而并不是往信息素最多的點移動。螞蟻找窩的規則和上面一樣,只不過它對窩的信息素做出反應,而對食物信息素沒反應。移動規則
每只螞蟻都朝向信息素最多的方向移,并且,當周圍沒有信息素指引的時候,螞蟻會按照自己原來運動的方向慣性的運動下去,并且,在運動的方向有一個隨機的小的擾動。為了防止螞蟻原地轉圈,它會記住剛才走過了哪些點,如果發現要走的下一點已經在之前走過了,它就會盡量避開。避障規則
如果螞蟻要移動的方向有障礙物擋住,它會隨機的選擇另一個方向,并且有信息素指引的話,它會按照覓食的規則行為。信息素規則
每只螞蟻在剛找到食物或者窩的時候撒發的信息素最多,并隨著它走遠的距離,播撒的信息素越來越少。 根據這幾條規則,螞蟻之間并沒有直接的關系,但是每只螞蟻都和環境發生交互,而通過信息素這個紐帶,實際上把各個螞蟻之間關聯起來了。比如,當一只螞蟻找到了食物,它并沒有直接告訴其它螞蟻這兒有食物,而是向環境播撒信息素,當其它的螞蟻經過它附近的時候,就會感覺到信息素的存在,進而根據信息素的指引找到了食物。相關研究
編輯引申
跟著螞蟻的蹤跡,你找到了什么?通過上面的原理敘述和實際操作,我們不難發現螞蟻之所以具有智能行為,完全歸功于它的簡單行為規則,而這些規則綜合起來具有下面兩個方面的特點: 1、多樣性 2、正反饋 多樣性保證了螞蟻在覓食的時候不至走進死胡同而無限循環,正反饋機制則保證了相對優良的信息能夠被保存下來。我們可以把多樣性看成是一種創造能力,而正反饋是一種學習強化能力。正反饋的力量也可以比喻成權威的意見,而多樣性是打破權威體現的創造性,正是這兩點小心翼翼的巧妙結合才使得智能行為涌現出來了。 引申來講,大自然的進化,社會的進步、人類的創新實際上都離不開這兩樣東西,多樣性保證了系統的創新能力,正反饋保證了優良特性能夠得到強化,兩者要恰到好處的結合。如果多樣性過剩,也就是系統過于活躍,這相當于螞蟻會過多的隨機運動,它就會陷入混沌狀態;而相反,多樣性不夠,正反饋機制過強,那么系統就好比一潭死水。這在蟻群中來講就表現為,螞蟻的行為過于僵硬,當環境變化了,螞蟻群仍然不能適當的調整。 既然復雜性、智能行為是根據底層規則涌現的,既然底層規則具有多樣性和正反饋特點,那么也許你會問這些規則是哪里來的?多樣性和正反饋又是哪里來的?我本人的意見:規則來源于大自然的進化。而大自然的進化根據剛才講的也體現為多樣性和正反饋的巧妙結合。而這樣的巧妙結合又是為什么呢?為什么在你眼前呈現的世界是如此栩栩如生呢?答案在于環境造就了這一切,之所以你看到栩栩如生的世界,是因為那些不能夠適應環境的多樣性與正反饋的結合都已經死掉了,被環境淘汰了!搜索引擎算法
蟻群算法的由來:螞蟻是地球上最常見、數量最多的昆蟲種類之一,常常成群結隊地出現在人類的日常生活環境中。這些昆蟲的群體生物智能特征,引起了一些學者的注意。意大利學者M.Dorigo,V.Maniezzo等人在觀察螞蟻的覓食習性時發現,螞蟻總能找到巢穴與食物源之間的最短路徑。經研究發現,螞蟻的這種群體協作功能是通過一種遺留在其來往路徑上的叫做信息素(Pheromone)的揮發性化學物質來進行通信和協調的。化學通信是螞蟻采取的基本信息交流方式之一,在螞蟻的生活習性中起著重要的作用。通過對螞蟻覓食行為的研究,他們發現,整個蟻群就是通過這種信息素進行相互協作,形成正反饋,從而使多個路徑上的螞蟻都逐漸聚集到最短的那條路徑上。 這樣,M.Dorigo等人于1991年首先提出了蟻群算法。其主要特點就是:通過正反饋、分布式協作來尋找最優路徑。這是一種基于種群尋優的啟發式搜索算法。它充分利用了生物蟻群能通過個體間簡單的信息傳遞,搜索從蟻巢至食物間最短路徑的集體尋優特征,以及該過程與旅行商問題求解之間的相似性。得到了具有NP難度的旅行商問題的最優解答。同時,該算法還被用于求解Job-Shop調度問題、二次指派問題以及多維背包問題等,顯示了其適用于組合優化類問題求解的優越特征。 多年來世界各地研究工作者對蟻群算法進行了精心研究和應用開發,該算法現已被大量應用于數據分析、機器人協作問題求解、電力、通信、水利、采礦、化工、建筑、交通等領域。 蟻群算法之所以能引起相關領域研究者的注意,是因為這種求解模式能將問題求解的快速性、全局優化特征以及有限時間內答案的合理性結合起來。其中,尋優的快速性是通過正反饋式的信息傳遞和積累來保證的。而算法的早熟性收斂又可以通過其分布式計算特征加以避免,同時,具有貪婪啟發?圖3蟻群在障礙物前經過一段時間后的情形式搜索特征的蟻群系統又能在搜索過程的早期找到可以接受的問題解答。這種優越的問題分布式求解模式經過相關領域研究者的關注和努力,已經在最初的算法模型基礎上得到了很大的改進和拓展。 經過一定時間,從食物源返回的螞蟻到達D點同樣也碰到障礙物,也需要進行選擇。此時A, B兩側的信息素濃度相同,它們仍然一半向左,一半向右。但是當A側的螞蟻已經完全繞過障礙物到達C點時,B側的螞蟻由于需走的路徑更長,還不能到達C點,圖3表示蟻群在障礙物前經過一段時間后的情形。 此時對于從蟻巢出發來到C點的螞蟻來說,由于A側的信息素濃度高,B側的信息素較低,就傾向于選擇A側的路徑。這樣的結果是A側的螞蟻越來越多,最終所有螞蟻都選擇這條較短的路徑,圖4 表示蟻群最終選擇的路徑圖4 蟻群最終選擇的路徑 上述過程,很顯然是由螞蟻所留下的信息素的“正反饋”過程而導致的。螞蟻個體就是通過這種信息的交流來達到搜索食物的目的。蟻群算法的基本思想也是從這個過程轉化而來的。 蟻群算法的特點: 1)蟻群算法是一種自組織的算法。在系統論中,自組織和它組織是組織的兩個基本分類,其區別在于組織力或組織指令是來自于系統的內部還是來自于系統的外部,來自于系統內部的是自組織,來自于系統外部的是他組織。如果系統在獲得空間的、時間的或者功能結構的過程中,沒有外界的特定干預,我們便說系統是自組織的。在抽象意義上講,自組織就是在沒有外界作用下使得系統熵減小的過程(即是系統從無序到有序的變化過程)。蟻群算法充分體現了這個過程,以螞蟻群體優化為例子說明。當算法開始的初期,單個的人工螞蟻無序的尋找解,算法經過一段時間的演化,人工螞蟻間通過信息激素的作用,自發的越來越趨向于尋找到接近最優解的一些解,這就是一個無序到有序的過程。 2)蟻群算法是一種本質上并行的算法。每只螞蟻搜索的過程彼此獨立,僅通過信息激素進行通信。所以蟻群算法則可以看作是一個分布式的多agent系統,它在問題空間的多點同時開始進行獨立的解搜索,不僅增加了算法的可靠性,也使得算法具有較強的全局搜索能力。 3)蟻群算法是一種正反饋的算法。從真實螞蟻的覓食過程中我們不難看出,螞蟻能夠最終找到最短路徑,直接依賴于最短路徑上信息激素的堆積,而信息激素的堆積卻是一個正反饋的過程。對蟻群算法來說,初始時刻在環境中存在完全相同的信息激素,給予系統一個微小擾動,使得各個邊上的軌跡濃度不相同,螞蟻構造的解就存在了優劣,算法采用的反饋方式是在較優的解經過的路徑留下更多的信息激素,而更多的信息激素又吸引了更多的螞蟻,這個正反饋的過程使得初始的不同得到不斷的擴大,同時又引導整個系統向最優解的方向進化。因此,正反饋是螞蟻算法的重要特征,它使得算法演化過程得以進行。 4)蟻群算法具有較強的魯棒性。相對于其它算法,蟻群算法對初始路線要求不高,即蟻群算法的求解結果不依賴于初始路線的選擇,而且在搜索過程中不需要進行人工的調整。其次,蟻群算法的參數數目少,設置簡單,易于蟻群算法應用到其它組合優化問題的求解。 蟻群算法的應用進展以蟻群算法為代表的蟻群智能已成為當今分布式人工智能研究的一個熱點,許多源于蜂群和蟻群模型設計的算法己越來越多地被應用于企業的運轉模式的研究。美國五角大樓正在資助關于群智能系統的研究工作-群體戰略(Swarm Strategy),它的一個實戰用途是通過運用成群的空中無人駕駛飛行器和地面車輛來轉移敵人的注意力,讓自己的軍隊在敵人后方不被察覺地安全進行。英國電信公司和美國世界通信公司以電子螞蟻為基礎,對新的電信網絡管理方法進行了試驗。群智能還被應用于工廠生產計劃的制定和運輸部門的后勤管理。美國太平洋西南航空公司采用了一種直接源于螞蟻行為研究成果的運輸管理軟件,結果每年至少節約了1000萬美元的費用開支。英國聯合利華公司己率先利用群智能技術改善其一家牙膏廠的運轉情況。美國通用汽車公司、法國液氣公司、荷蘭公路交通部和美國一些移民事務機構也都采用這種技術來改善其運轉的機能。鑒于群智能廣闊的應用前景,美國和歐盟均于近幾年開始出資資助基于群智能模擬的相關研究項目,并在一些院校開設群體智能的相關課程。國內,國家自然科學基金”十五”期間學科交叉類優先資助領域中的認知科學及其信息處理的研究內容中也明確列出了群智能領域的進化、自適應與現場認知主題。 蟻群優化算法最初用于解決TSP問題,經過多年的發展,已經陸續滲透到其他領域中,比如圖著色問題、大規模集成電路設計、通訊網絡中的路由問題以及負載平衡問題、車輛調度問題等。蟻群算法在若干領域己獲得成功的應用,其中最成功的是在組合優化問題中的應用。 在網絡路由處理中,網絡的流量分布不斷變化,網絡鏈路或結點也會隨機地失效或重新加入。蟻群的自身催化與正向反饋機制正好符合了這類問題的求解特點,因而,蟻群算法在網絡領域得到一定應用。蟻群覓食行為所呈現出的并行與分布特性使得算法特別適合于并行化處理。因而,實現算法的并行化執行對于大量復雜的實際應用問題的求解來說是極具潛力的。 在某群體中若存在眾多無智能的個體,它們通過相互之間的簡單合作所表現出來的智能行為即稱為集群智能(Swarm Intelligence)。互聯網上的交流,不過是更多的神經元連接(人腦)通過互聯網相互作用的結果,光纜和路由器不過是軸突和突觸的延伸。從自組織現象的角度上看,人腦的智能和蟻群也沒有本質上的區別,單個神經元沒有智能可言,單個螞蟻也沒有,但是通過連接形成的體系,是一個智能體。(作者: 李精靈 編選:中國電子商務研究中心)1. 蟻群算法簡介
???? 蟻群算法(Ant Clony Optimization, ACO)是一種群智能算法,它是由一群無智能或有輕微智能的個體(Agent)通過相互協作而表現出智能行為,從而為求解復雜問題提供了一個新的可能性。蟻群算法最早是由意大利學者Colorni A., Dorigo M. 等于1991年提出。經過20多年的發展,蟻群算法在理論以及應用研究上已經得到巨大的進步。
????? 蟻群算法是一種仿生學算法,是由自然界中螞蟻覓食的行為而啟發的。在自然界中,螞蟻覓食過程中,蟻群總能夠按照尋找到一條從蟻巢和食物源的最優路徑。圖(1)顯示了這樣一個覓食的過程。
圖(1)螞蟻覓食
?
???? 在圖1(a)中,有一群螞蟻,假如A是蟻巢,E是食物源(反之亦然)。這群螞蟻將沿著蟻巢和食物源之間的直線路徑行駛。假如在A和E之間突然出現了一個障礙物(圖1(b)),那么,在B點(或D點)的螞蟻將要做出決策,到底是向左行駛還是向右行駛?由于一開始路上沒有前面螞蟻留下的信息素(pheromone),螞蟻朝著兩個方向行進的概率是相等的。但是當有螞蟻走過時,它將會在它行進的路上釋放出信息素,并且這種信息素會議一定的速率散發掉。信息素是螞蟻之間交流的工具之一。它后面的螞蟻通過路上信息素的濃度,做出決策,往左還是往右。很明顯,沿著短邊的的路徑上信息素將會越來越濃(圖1(c)),從而吸引了越來越多的螞蟻沿著這條路徑行駛。
2. TSP問題描述
????? 蟻群算法最早用來求解TSP問題,并且表現出了很大的優越性,因為它分布式特性,魯棒性強并且容易與其它算法結合,但是同時也存在這收斂速度慢,容易陷入局部最優(local optimal)等缺點。
????? TSP問題(Travel Salesperson Problem,即旅行商問題或者稱為中國郵遞員問題),是一種,是一種NP-hard問題,此類問題用一般的算法是很大得到最優解的,所以一般需要借助一些啟發式算法求解,例如遺傳算法(GA),蟻群算法(ACO),微粒群算法(PSO)等等。
????? TSP問題可以分為兩類,一類是對稱TSP問題(Symmetric TSP),另一類是非對稱問題(Asymmetric TSP)。所有的TSP問題都可以用一個圖(Graph)來描述:
令
是所有城市的集合.?表示第i個城市,?為城市的數目;
是所有城市之間連接的集合;
是所有城市之間連接的成本度量(一般為城市之間的距離);
如果, 那么該TSP問題為對稱的,否則為非對稱的。
一個TSP問題可以表達為:
求解遍歷圖,所有的節點一次并且回到起始節點,使得連接這些節點的路徑成本最低。
3. 蟻群算法原理
????? 假如蟻群中所有螞蟻的數量為m,所有城市之間的信息素用矩陣pheromone表示,最短路徑為bestLength,最佳路徑為bestTour。每只螞蟻都有自己的內存,內存中用一個禁忌表(Tabu)來存儲該螞蟻已經訪問過的城市,表示其在以后的搜索中將不能訪問這些城市;還有用另外一個允許訪問的城市表(Allowed)來存儲它還可以訪問的城市;另外還用一個矩陣(Delta)來存儲它在一個循環(或者迭代)中給所經過的路徑釋放的信息素;還有另外一些數據,例如一些控制參數,該螞蟻行走玩全程的總成本或距離(tourLength),等等。假定算法總共運行MAX_GEN次,運行時間為t。
蟻群算法計算過程如下:
(1)初始化
設t=0,初始化bestLength為一個非常大的數(正無窮),bestTour為空。初始化所有的螞蟻的Delt矩陣所有元素初始化為0,Tabu表清空,Allowed表中加入所有的城市節點。隨機選擇它們的起始位置(也可以人工指定)。在Tabu中加入起始節點,Allowed中去掉該起始節點。
(2)為每只螞蟻選擇下一個節點。
為每只螞蟻選擇下一個節點,該節點只能從Allowed中以某種概率(公式1)搜索到,每搜到一個,就將該節點加入到Tabu中,并且從Allowed中刪除該節點。該過程重復n-1次,直到所有的城市都遍歷過一次。遍歷完所有節點后,將起始節點加入到Tabu中。此時Tabu表元素數量為n+1(n為城市數量),Allowed元素數量為0。接下來按照(公式2)計算每個螞蟻的Delta矩陣值。最后計算最佳路徑,比較每個螞蟻的路徑成本,然后和bestLength比較,若它的路徑成本比bestLength小,則將該值賦予bestLength,并且將其Tabu賦予BestTour。
(公式1)
(公式2)
其中表示選擇城市j的概率,表示第個螞蟻,表示城市在第時刻的信息素濃度,表示從城市i到城市j的可見度,
,表示城市之間的成本(或距離)。由此可見越小,越大,也就是從城市到的可見性就越大。表示螞蟻在城市與之間留下的信息素。
表示螞蟻經過一個循環(或迭代)鎖經過路徑的總成本(或距離),即tourLength.?均為控制參數。
(3)更新信息素矩陣
令t,按照(公式3)更新信息素矩陣phermone。
(公式3)
為時刻城市與之間的信息素濃度。為控制參數,為城市與之間信息素經過一個迭代后的增量。并且有
(公式4)
其中由公式計算得到。
(4)檢查終止條件
如果達到最大代數MAX_GEN,算法終止,轉到第(5)步;否則,重新初始化所有的螞蟻的Delt矩陣所有元素初始化為0,Tabu表清空,Allowed表中加入所有的城市節點。隨機選擇它們的起始位置(也可以人工指定)。在Tabu中加入起始節點,Allowed中去掉該起始節點,重復執行(2),(3),(4)步。
(5)輸出最優值
4. Java實現
????? 在該java實現中我們選擇使用tsplib上的數據att48,這是一個對稱tsp問題,城市規模為48,其最優值為10628.其距離計算方法如圖(2)所示:
圖(2)att48距離計算方法
????? 實現中,使用了兩個java類,一個Ant類,一個ACO類。
具體實現代碼如下(此代碼借鑒了蟻群優化算法的JAVA實現):
Ant類:
1: import java.util.Random; 2: import java.util.Vector; 3: 4: /** 5: * 6: * @author BIAO YU 7: * 8: */ 9: public class Ant implements Cloneable { 10: 11: private Vector<Integer> tabu; //禁忌表 12: private Vector<Integer> allowedCities; //允許搜索的城市 13: private float[][] delta; //信息數變化矩陣 14: private int[][] distance; //距離矩陣 15: 16: private float alpha; 17: private float beta; 18: 19: private int tourLength; //路徑長度 20: private int cityNum; //城市數量 21: 22: private int firstCity; //起始城市 23: private int currentCity; //當前城市 24: 25: public Ant(){ 26: cityNum = 30; 27: tourLength = 0; 28: 29: } 30: 31: /** 32: * Constructor of Ant 33: * @param num 螞蟻數量 34: */ 35: public Ant(int num){ 36: cityNum = num; 37: tourLength = 0; 38: 39: } 40: 41: /** 42: * 初始化螞蟻,隨機選擇起始位置 43: * @param distance 距離矩陣 44: * @param a alpha 45: * @param b beta 46: */ 47: public void init(int[][] distance, float a, float b){ 48: alpha = a; 49: beta = b; 50: allowedCities = new Vector<Integer>(); 51: tabu = new Vector<Integer>(); 52: this.distance = distance; 53: delta = new float[cityNum][cityNum]; 54: for (int i = 0; i < cityNum; i++) { 55: Integer integer = new Integer(i); 56: allowedCities.add(integer); 57: for (int j = 0; j < cityNum; j++) { 58: delta[i][j] = 0.f; 59: } 60: } 61: 62: Random random = new Random(System.currentTimeMillis()); 63: firstCity = random.nextInt(cityNum); 64: for (Integer i:allowedCities) { 65: if (i.intValue() == firstCity) { 66: allowedCities.remove(i); 67: break; 68: } 69: } 70: 71: tabu.add(Integer.valueOf(firstCity)); 72: currentCity = firstCity; 73: } 74: 75: /** 76: * 選擇下一個城市 77: * @param pheromone 信息素矩陣 78: */ 79: public void selectNextCity(float[][] pheromone){ 80: float[] p = new float[cityNum]; 81: float sum = 0.0f; 82: //計算分母部分 83: for (Integer i:allowedCities) { 84: sum += Math.pow(pheromone[currentCity][i.intValue()], alpha)*Math.pow(1.0/distance[currentCity][i.intValue()], beta); 85: } 86: //計算概率矩陣 87: for (int i = 0; i < cityNum; i++) { 88: boolean flag = false; 89: for (Integer j:allowedCities) { 90: 91: if (i == j.intValue()) { 92: p[i] = (float) (Math.pow(pheromone[currentCity][i], alpha)*Math.pow(1.0/distance[currentCity][i], beta))/sum; 93: flag = true; 94: break; 95: } 96: } 97: 98: if (flag == false) { 99: p[i] = 0.f; 100: } 101: } 102: 103: //輪盤賭選擇下一個城市 104: Random random = new Random(System.currentTimeMillis()); 105: float sleectP = random.nextFloat(); 106: int selectCity = 0; 107: float sum1 = 0.f; 108: for (int i = 0; i < cityNum; i++) { 109: sum1 += p[i]; 110: if (sum1 >= sleectP) { 111: selectCity = i; 112: break; 113: } 114: } 115: 116: //從允許選擇的城市中去除select city 117: for (Integer i:allowedCities) { 118: if (i.intValue() == selectCity) { 119: allowedCities.remove(i); 120: break; 121: } 122: } 123: //在禁忌表中添加select city 124: tabu.add(Integer.valueOf(selectCity)); 125: //將當前城市改為選擇的城市 126: currentCity = selectCity; 127: 128: } 129: 130: /** 131: * 計算路徑長度 132: * @return 路徑長度 133: */ 134: private int calculateTourLength(){ 135: int len = 0; 136: for (int i = 0; i < cityNum; i++) { 137: len += distance[this.tabu.get(i).intValue()][this.tabu.get(i+1).intValue()]; 138: } 139: return len; 140: } 141: 142: 143: 144: public Vector<Integer> getAllowedCities() { 145: return allowedCities; 146: } 147: 148: public void setAllowedCities(Vector<Integer> allowedCities) { 149: this.allowedCities = allowedCities; 150: } 151: 152: public int getTourLength() { 153: tourLength = calculateTourLength(); 154: return tourLength; 155: } 156: public void setTourLength(int tourLength) { 157: this.tourLength = tourLength; 158: } 159: public int getCityNum() { 160: return cityNum; 161: } 162: public void setCityNum(int cityNum) { 163: this.cityNum = cityNum; 164: } 165: 166: public Vector<Integer> getTabu() { 167: return tabu; 168: } 169: 170: public void setTabu(Vector<Integer> tabu) { 171: this.tabu = tabu; 172: } 173: 174: public float[][] getDelta() { 175: return delta; 176: } 177: 178: public void setDelta(float[][] delta) { 179: this.delta = delta; 180: } 181: 182: public int getFirstCity() { 183: return firstCity; 184: } 185: 186: public void setFirstCity(int firstCity) { 187: this.firstCity = firstCity; 188: } 189: 190: } 191:ACO類:
1: import java.io.BufferedReader; 2: import java.io.FileInputStream; 3: import java.io.IOException; 4: import java.io.InputStreamReader; 5: 6: /** 7: * 8: * @author BIAO YU 9: * 10: * 11: */ 12: public class ACO { 13: 14: private Ant[] ants; //螞蟻 15: private int antNum; //螞蟻數量 16: private int cityNum; //城市數量 17: private int MAX_GEN; //運行代數 18: private float[][] pheromone; //信息素矩陣 19: private int[][] distance; //距離矩陣 20: private int bestLength; //最佳長度 21: private int[] bestTour; //最佳路徑 22: 23: //三個參數 24: private float alpha; 25: private float beta; 26: private float rho; 27: 28: 29: public ACO(){ 30: 31: } 32: /** constructor of ACO 33: * @param n 城市數量 34: * @param m 螞蟻數量 35: * @param g 運行代數 36: * @param a alpha 37: * @param b beta 38: * @param r rho 39: * 40: **/ 41: public ACO(int n, int m, int g, float a, float b, float r) { 42: cityNum = n; 43: antNum = m; 44: ants = new Ant[antNum]; 45: MAX_GEN = g; 46: alpha = a; 47: beta = b; 48: rho = r; 49: 50: } 51: 52: @SuppressWarnings("resource") 53: /** 54: * 初始化ACO算法類 55: * @param filename 數據文件名,該文件存儲所有城市節點坐標數據 56: * @throws IOException 57: */ 58: private void init(String filename) throws IOException{ 59: //讀取數據 60: int[] x; 61: int[] y; 62: String strbuff; 63: BufferedReader data = new BufferedReader(new InputStreamReader(new FileInputStream(filename))); 64: 65: distance = new int[cityNum][cityNum]; 66: x = new int[cityNum]; 67: y = new int[cityNum]; 68: for (int i = 0; i < cityNum; i++) { 69: strbuff = data.readLine(); 70: String[] strcol = strbuff.split(""); 71: x[i] = Integer.valueOf(strcol[1]); 72: y[i] = Integer.valueOf(strcol[2]); 73: } 74: //計算距離矩陣 ,針對具體問題,距離計算方法也不一樣,此處用的是att48作為案例,它有48個城市,距離計算方法為偽歐氏距離,最優值為10628 75: for (int i = 0; i < cityNum - 1; i++) { 76: distance[i][i] = 0; //對角線為0 77: for (int j = i + 1; j < cityNum; j++) { 78: double rij = Math.sqrt(((x[i] - x[j]) * (x[i] - x[j])+ (y[i] - y[j]) * (y[i] - y[j]))/10.0); 79: int tij = (int) Math.round(rij); 80: if (tij < rij) { 81: distance[i][j] = tij + 1; 82: distance[j][i] = distance[i][j]; 83: }else { 84: distance[i][j] = tij; 85: distance[j][i] = distance[i][j]; 86: } 87: } 88: } 89: distance[cityNum - 1][cityNum - 1] = 0; 90: 91: //初始化信息素矩陣 92: pheromone=new float[cityNum][cityNum]; 93: for(int i=0;i<cityNum;i++) 94: { 95: for(int j=0;j<cityNum;j++){ 96: pheromone[i][j]=0.1f; //初始化為0.1 97: } 98: } 99: bestLength=Integer.MAX_VALUE; 100: bestTour=new int[cityNum+1]; 101: //隨機放置螞蟻 102: for(int i=0;i<antNum;i++){ 103: ants[i]=new Ant(cityNum); 104: ants[i].init(distance, alpha, beta); 105: } 106: } 107: 108: public void solve(){ 109: 110: for (int g = 0; g < MAX_GEN; g++) { 111: for (int i = 0; i < antNum; i++) { 112: for (int j = 1; j < cityNum; j++) { 113: ants[i].selectNextCity(pheromone); 114: } 115: ants[i].getTabu().add(ants[i].getFirstCity()); 116: if (ants[i].getTourLength() < bestLength) { 117: bestLength = ants[i].getTourLength(); 118: for (int k = 0; k < cityNum + 1; k++) { 119: bestTour[k] = ants[i].getTabu().get(k).intValue(); 120: } 121: } 122: for (int j = 0; j < cityNum; j++) { 123: ants[i].getDelta()[ants[i].getTabu().get(j).intValue()][ants[i].getTabu().get(j+1).intValue()] = (float) (1./ants[i].getTourLength()); 124: ants[i].getDelta()[ants[i].getTabu().get(j+1).intValue()][ants[i].getTabu().get(j).intValue()] = (float) (1./ants[i].getTourLength()); 125: } 126: } 127: 128: //更新信息素 129: updatePheromone(); 130: 131: //重新初始化螞蟻 132: for(int i=0;i<antNum;i++){ 133: 134: ants[i].init(distance, alpha, beta); 135: } 136: } 137: 138: //打印最佳結果 139: printOptimal(); 140: } 141: 142: //更新信息素 143: private void updatePheromone(){ 144: //信息素揮發 145: for(int i=0;i<cityNum;i++) 146: for(int j=0;j<cityNum;j++) 147: pheromone[i][j]=pheromone[i][j]*(1-rho); 148: //信息素更新 149: for(int i=0;i<cityNum;i++){ 150: for(int j=0;j<cityNum;j++){ 151: for (int k = 0; k < antNum; k++) { 152: pheromone[i][j] += ants[k].getDelta()[i][j]; 153: } 154: } 155: } 156: } 157: 158: private void printOptimal(){ 159: System.out.println("The optimal length is: " + bestLength); 160: System.out.println("The optimal tour is: "); 161: for (int i = 0; i < cityNum + 1; i++) { 162: System.out.println(bestTour[i]); 163: } 164: } 165: 166: public Ant[] getAnts() { 167: return ants; 168: } 169: 170: public void setAnts(Ant[] ants) { 171: this.ants = ants; 172: } 173: 174: public int getAntNum() { 175: return antNum; 176: } 177: 178: public void setAntNum(int m) { 179: this.antNum = m; 180: } 181: 182: public int getCityNum() { 183: return cityNum; 184: } 185: 186: public void setCityNum(int cityNum) { 187: this.cityNum = cityNum; 188: } 189: 190: public int getMAX_GEN() { 191: return MAX_GEN; 192: } 193: 194: public void setMAX_GEN(int mAX_GEN) { 195: MAX_GEN = mAX_GEN; 196: } 197: 198: public float[][] getPheromone() { 199: return pheromone; 200: } 201: 202: public void setPheromone(float[][] pheromone) { 203: this.pheromone = pheromone; 204: } 205: 206: public int[][] getDistance() { 207: return distance; 208: } 209: 210: public void setDistance(int[][] distance) { 211: this.distance = distance; 212: } 213: 214: public int getBestLength() { 215: return bestLength; 216: } 217: 218: public void setBestLength(int bestLength) { 219: this.bestLength = bestLength; 220: } 221: 222: public int[] getBestTour() { 223: return bestTour; 224: } 225: 226: public void setBestTour(int[] bestTour) { 227: this.bestTour = bestTour; 228: } 229: 230: public float getAlpha() { 231: return alpha; 232: } 233: 234: public void setAlpha(float alpha) { 235: this.alpha = alpha; 236: } 237: 238: public float getBeta() { 239: return beta; 240: } 241: 242: public void setBeta(float beta) { 243: this.beta = beta; 244: } 245: 246: public float getRho() { 247: return rho; 248: } 249: 250: public void setRho(float rho) { 251: this.rho = rho; 252: } 253: 254: 255: /** 256: * @param args 257: * @throws IOException 258: */ 259: public static void main(String[] args) throws IOException { 260: ACO aco = new ACO(48, 100, 1000, 1.f, 5.f, 0.5f); 261: aco.init("c://data.txt"); 262: aco.solve(); 263: } 264: 265: } 266:5. 總結
????? 蟻群算法和其它的啟發式算法一樣,在很多場合都得到了應用,并且取得了很好的結果。但是同樣存在著很多的缺點,例如收斂速度慢,容易陷入局部最優,等等。對于這些問題,還需要進一步的研究和探索,另外蟻群算法的數學機理至今還沒有得到科學的解釋,這也是當前研究的熱點和急需解決的問題之一。
總結
- 上一篇: 财务系统专用服务器中标公告,东南大学财务
- 下一篇: centos7加入第二块网卡无法识别