蟻群演算法matlab
(一)蟻群演算法的由來
蟻群演算法最早是由Marco Dorigo等人在1991年提出,他們在研究新型演算法的過程中,發現蟻群在尋找食物時,通過分泌一種稱為資訊素的生物激素交流覓食資訊從而能快速的找到目標,據此提出了基於資訊正反饋原理的蟻群演算法。
蟻群演算法的基本思想來源於自然界螞蟻覓食的最短路徑原理,根據昆蟲科學家的觀察,發現自然界的螞蟻雖然視覺不發達,但它們可以在沒有任何提示的情況下找到從食物源到巢穴的最短路徑,並在周圍環境發生變化後,自適應地搜尋新的最佳路徑。
螞蟻在尋找食物源的時候,能在其走過的路徑上釋放一種叫資訊素的激素,使一定範圍內的其他螞蟻能夠察覺到。當一些路徑上通過的螞蟻越來越多時,資訊素也就越來越多,螞蟻們選擇這條路徑的概率也就越高,結果導致這條路徑上的資訊素又增多,螞蟻走這條路的概率又增加,生生不息。這種選擇過程被稱為螞蟻的自催化行為。對於單個螞蟻來說,它並沒有要尋找最短路徑,只是根據概率選擇;對於整個蟻群系統來說,它們卻達到了尋找到最優路徑的客觀上的效果。這就是群體智慧。
(二)蟻群演算法能做什麼
蟻群演算法根據模擬螞蟻尋找食物的最短路徑行為來設計的仿生演算法,因此一般而言,蟻群演算法用來解決最短路徑問題,並真的在旅行商問題(TSP,一個尋找最短路徑的問題)上取得了比較好的成效。目前,也已漸漸應用到其他領域中去,在圖著色問題、車輛排程問題、積體電路設計、通訊網路、資料聚類分析等方面都有所應用。
(三)蟻群演算法的流程步驟
這裡以TSP問題為例,演算法設計的流程如下:
步驟1:對相關引數進行初始化,包括蟻群規模、資訊素因子、啟發函式因子、資訊素揮發因子、資訊素常數、最大迭代次數等,以及將資料讀入程式,並進行預處理:比如將城市的座標資訊轉換為城市間的距離矩陣。
步驟2:隨機將螞蟻放於不同出發點,對每個螞蟻計算其下個訪問城市,直到有螞蟻訪問完所有城市。
步驟3:計算各螞蟻經過的路徑長度Lk,記錄當前迭代次數最優解,同時對路徑上的資訊素濃度進行更新。
步驟4:判斷是否達到最大迭代次數,若否,返回步驟2;是,結束程式。
步驟5:輸出結果,並根據需要輸出尋優過程中的相關指標,如執行時間、收斂迭代次數等。
要用到的符號說明:
m:整個螞蟻群體中螞蟻數量;
n:城市的數量;
dij:城市i與城市j的距離
βij(t):t時刻城市i和城市j連線路徑上的資訊素;
pkij(t):t時刻螞蟻k從城市i轉移到城市j的概率;
初始時刻螞蟻被放在不同的城市,且各城市路徑上的資訊素濃度為0。
由於蟻群演算法涉及到的引數蠻多的,且這些引數的選擇對程式又都有一定的影響,所以選擇合適的引數組合很重要。蟻群演算法有個特點就是在尋優的過程中,帶有一定的隨機性,這種隨機性主要體現在出發點的選擇上。蟻群演算法正是通過這個初始點的選擇將全域性尋優慢慢轉化為區域性尋優的。引數設定的關鍵就在於在“全域性”和“區域性”之間建立一個平衡點。
(四)蟻群演算法的關鍵引數
在蟻群演算法的發展中,關鍵引數的設定有一定的準則,一般來講遵循以下幾條:
儘可能在全域性上搜索最優解,保證解的最優性;
演算法儘快收斂,以節省尋優時間;
儘量反應客觀存在的規律,以保證這類仿生演算法的真實性。
螞蟻數量:
設M表示城市數量,m表示螞蟻數量。m的數量很重要,因為m過大時,會導致搜尋過的路徑上資訊素變化趨於平均,這樣就不好找出好的路徑了;m過小時,易使未被搜尋到的路徑資訊素減小到0,這樣可能會出現早熟,沒找到全域性最優解。一般上,在時間等資源條件緊迫的情況下,螞蟻數設定為城市數的1.5倍較穩妥。
資訊素因子:
資訊素因子反映了螞蟻在移動過程中所積累的資訊量在指導蟻群搜尋中的相對重要程度,其值過大,螞蟻選擇以前走過的路徑概率大,搜尋隨機性減弱;值過小,等同於貪婪演算法,使搜尋過早陷入區域性最優。實驗發現,資訊素因子選擇[1,4]區間,效能較好。
啟發函式因子:
啟發函式因子反映了啟發式資訊在指導蟻群搜尋過程中的相對重要程度,其大小反映的是蟻群尋優過程中先驗性和確定性因素的作用強度。過大時,雖然收斂速度會加快,但容易陷入區域性最優;過小時,容易陷入隨機搜尋,找不到最優解。實驗研究發現,當啟發函式因子為[3,4.5]時,綜合求解效能較好。
資訊素揮發因子:
資訊素揮發因子表示資訊素的消失水平,它的大小直接關係到蟻群演算法的全域性搜尋能力和收斂速度。實驗發現,當屬於[0.2,0.5]時,綜合性能較好。
資訊素常數:
這個引數為資訊素強度,表示螞蟻迴圈一週時釋放在路徑上的資訊素總量,其作用是為了充分利用有向圖上的全域性資訊反饋量,使演算法在正反饋機制作用下以合理的演化速度搜索到全域性最優解。值越大,螞蟻在已遍歷路徑上的資訊素積累越快,有助於快速收斂。實驗發現,當值屬於[10,1000]時,綜合性能較好。
最大迭代次數:
最大迭代次數值過小,可能導致演算法還沒收斂就已結束;過大則會導致資源浪費。一般最大迭代次數可以取100到500次。一般來講,建議先取200,然後根據執行程式檢視演算法收斂的軌跡來修改取值。
組合引數設計策略:
通常可以按照以下策略來進行引數組合設定:
1. 確定螞蟻數目,螞蟻數目與城市規模之比約為1.5;
2. 引數粗調,即調整取值範圍較大的α,β及Q;
3. 引數微調,即調整取值範圍較小的ρ
%設定初始化引數
C=[1,2;70,90;80,60;10,100;800,200;800,100;90,80;200,600;230,4;500,90];
NC_max=100;
m=18;
Alpha=1;
Beta=5;
Rho=0.5;
Q=1;
%%-------------------------------------------------------------------------
%% 主要符號說明
%% C n個城市的座標,n×2的矩陣
%% NC_max 最大迭代次數
%% m 螞蟻個數
%% Alpha 表徵資訊素重要程度的引數
%% Beta 表徵啟發式因子重要程度的引數
%% Rho 資訊素蒸發係數
%% Q 資訊素增加強度係數
%% R_best 各代最佳路線
%% L_best 各代最佳路線的長度
%%=========================================================================
%%第一步:變數初始化
n=size(C,1);%n表示問題的規模(城市個數)
D=zeros(n,n);%D表示完全圖的賦權鄰接矩陣
for i=1:n
for j=1:n
if i~=j
D(i,j)=((C(i,1)-C(j,1))^2+(C(i,2)-C(j,2))^2)^0.5;
else
D(i,j)=eps; %i=j時不計算,應該為0,但後面的啟發因子要取倒數,用eps(浮點相對精度)表示
end
D(j,i)=D(i,j); %對稱矩陣
end
end
%{
1.C就是城市座標
x y
城市1 0 120
城市2 120 0
城市n 100 230
2.執行後這裡D變成了一個n*n的矩陣,每個元素代表兩個城市之間的距離,比如當城市數目為3時:
D= 城市1 城市2 城市3
城市1 0 120 100
城市2 120 0 230
城市3 100 230 0
這裡D是個對角線為0的對稱矩陣,因為城市1,2間距離等於城市2,1的距離,城市n與n距離設定為0
%}
Eta=1./D; %Eta為啟發因子矩陣,這裡設為距離的倒數
Tau=ones(n,n); %Tau為資訊素矩陣
Tabu=zeros(m,n); %儲存並記錄路徑的生成,禁忌表
NC=1; %迭代計數器,記錄迭代次數
R_best=zeros(NC_max,n); %各代最佳路線
L_best=inf.*ones(NC_max,1); %各代最佳路線的長度
L_ave=zeros(NC_max,1); %各代路線的平均長度
while NC<=NC_max %停止條件之一:達到最大迭代次數,停止
%%第二步:將m只螞蟻放到n個城市上
Randpos=[]; %隨機存取
for i=1:(ceil(m/n))
Randpos=[Randpos,randperm(n)];
end
Tabu(:,1)=(Randpos(1,1:m))'; %此句不太理解?
%{
1.ceil(m/n)
假如有 10只螞蟻,3個城市,ceil(m/n)=ceil(10/3)=4,需要安排四次,才能把這十隻螞蟻全部放到到三個城市,
每次都在行向量Randpos加入如新的元素,randperm(3)表示就是1 3 2,或者3 1 2這種隨機組合,4次迴圈之後,
那麼Randpos =
2 3 1 1 2 3 3 1 2 3 2 1
2.Tabu(:,1)=(Randpos(1,1:m))'
總共m螞蟻,只這裡m為10,Tabu(:,1)表示Tabu第一行就是初始10只螞蟻被隨機分到所三個城市中的一個
Tabu =
2
3
1
1
2
3
3
1
2
3
這裡只取m=10個數,因為Tabu第一列表示m只螞蟻初始的時候隨機被分在的城市,比如第一個2代表,第一隻螞蟻
最開始放在了城市2,以此類推
%}
%%第三步:m只螞蟻按概率函式選擇下一座城市,完成各自的周遊
for j=2:n %所在城市不計算
for i=1:m
visited=Tabu(i,1:(j-1)); %記錄已訪問的城市,避免重複訪問
J=zeros(1,(n-j+1)); %待訪問的城市
P=J; %待訪問城市的選擇概率分佈
Jc=1; %訪問的城市個數
for k=1:n
if length(find(visited==k))==0 %開始時置0
J(Jc)=k; %這時記錄沒有訪問的城市到J中
Jc=Jc+1; %訪問的城市個數自加1
end
end
%{
1.visited=Tabu(i,1:(j-1)); 向量visited記錄已訪問的城市,比如第一次Tabu中第一行第一個的城市2
2.J=zeros(1,(n-j+1)) 向量J記錄待訪問的城市,已結訪問城市2,還沒訪問1和3城市放入J向量中
3.if length(find(visited==k))==0
判斷語句,find()語句找到visited中等於k的元素在陣列visited中的位置,例如陣列a=[1 2 3 4 5 2],
find(a==2)=[2,6],find(a==6)=[],則
length(find(a==6))=0
length()==0判斷length()是否為零
如果為零就是visited中沒有k元素,即沒有訪問過k城市。
這時記錄沒有訪問的城市到J中。
%}
%下面計算待選城市的概率分佈
for k=1:length(J)
P(k)=(Tau(visited(end),J(k))^Alpha)*(Eta(visited(end),J(k))^Beta);
end
P=P/(sum(P));
%按概率原則選取下一個城市
Pcum=cumsum(P); %cumsum,元素累加即求和
Select=find(Pcum>=rand); %若計算的概率大於原來的就選擇這條路線%要選擇其中總概率大於等於某一個隨機數,找到大於等於這個隨機數的城市的在J中的位置
to_visit=J(Select(1)); %提取這些城市的編號到to_visit中
Tabu(i,j)=to_visit;
end
end
%{
1. %visited(end)表示螞蟻現在所在城市編號,J(k)表示下一步要訪問的城市編號
2.P=P/(sum(P));把各個路徑概率統一到和為1
3.Pcum=cumsum(P); cumsum,元素累加即求和,比如P=[0.1 0.5 0.4],cumsum(P)= [0.1000 0.6000 1.0000]
有一點要特別說明,用到cumsum(P),螞蟻要選擇的下一個城市不是按最大概率,就是要用到輪盤法則,不然影響全域性收縮能力,
所以用到累積函式,Pcum=cumsum(P)
4.Select=find(Pcum>=rand); to_visit=J(Select(1))
輪盤法則,Select(1),1保證可以選到最大概率的城市,具體自己可以用matlab試一下:
p=[0.1 0.6 0.3] 中間那個城市概率最大
此時Pcum=[0.1 0.7 1], Select =[2 3]; Select(1)=2,中間那個城市概率最大
%}
if NC>=2
Tabu(1,:)=R_best(NC-1,:);
end
%%第四步:記錄本次迭代最佳路線
L=zeros(m,1); %開始距離為0,m*1的列向量
for i=1:m
R=Tabu(i,:);
for j=1:(n-1)
L(i)=L(i)+D(R(j),R(j+1)); %原距離加上第j個城市到第j+1個城市的距離
end
L(i)=L(i)+D(R(1),R(n)); %一輪下來後走過的距離,加上第一個和最後一個城市的距離
end
%{
1.L=zeros(m,1) 記錄本次迭代最佳路線的長度,每個螞蟻都有自己走過的長度記錄在向量L中
%}
L_best(NC)=min(L); %最佳距離取最小
pos=find(L==L_best(NC)); %找到路徑最短的那條螞蟻所在的行編號
R_best(NC,:)=Tabu(pos(1),:); %此輪迭代後的最佳路線
L_ave(NC)=mean(L); %此輪迭代後的平均距離
NC=NC+1 %迭代繼續
%{
1.R_best(NC,:)=Tabu(pos(1),:):找到路徑最短的那條螞蟻所在的城市先後順序,pos(1)中1表示萬一有長度一樣的兩條螞蟻,那就選第一個
%}
%%第五步:更新資訊素
Delta_Tau=zeros(n,n); %開始時資訊素為n*n的0矩陣
for i=1:m
for j=1:(n-1)
Delta_Tau(Tabu(i,j),Tabu(i,j+1))=Delta_Tau(Tabu(i,j),Tabu(i,j+1))+Q/L(i);
%此次迴圈在路徑(i,j)上的資訊素增量
end
Delta_Tau(Tabu(i,n),Tabu(i,1))=Delta_Tau(Tabu(i,n),Tabu(i,1))+Q/L(i); %加上第一個到最後一個城市的資訊素增量
%此次迴圈在整個路徑上的資訊素增量
end
Tau=(1-Rho).*Tau+Delta_Tau; %考慮資訊素揮發,更新後的資訊素
%%第六步:禁忌表清零
Tabu=zeros(m,n); %%直到最大迭代次數
end
%{
1.R_best(NC,:)=Tabu(pos(1),:):找到路徑最短的那條螞蟻所在的城市先後順序,pos(1)中1表示萬一有長度一樣的兩條螞蟻,那就選第一個
%}
%%第七步:輸出結果
Pos=find(L_best==min(L_best)); %找到最佳路徑(非0為真)
Shortest_Route=R_best(Pos(1),:) %最大迭代次數後最佳路徑
Shortest_Length=L_best(Pos(1)) %最大迭代次數後最短距離
subplot(1,2,1) %繪製第一個子圖形
N=length(R);
scatter(C(:,1),C(:,2));
hold on
plot([C(R(1),1),C(R(N),1)],[C(R(1),2),C(R(N),2)],'r')
hold on
for ii=2:N
plot([C(R(ii-1),1),C(R(ii),1)],[C(R(ii-1),2),C(R(ii),2)],'r')
hold on
end
title('旅行商問題優化結果 ')
subplot(1,2,2) %繪製第二個子圖形
plot(L_best)
hold on %保持圖形
plot(L_ave,'r')
title('平均距離和最短距離') %標題
%{
這部分沒什麼太大問題,多看幾遍就好
%}