蟻羣算法(ant colony algorithm) : 一種模擬進化算法
螞蟻在覓食過程中能夠在其經過的路徑留下一種稱爲信息素的物質,並在覓食的過程中能感知這種物質的強度,並指導自己的行動方向,他們總是朝着該物質強度高的方向移動,因此大量螞蟻組成的集體覓食就表現爲一種對信息素的正反饋現象。(非常符合常識對吧,這就是智能優化算法的魅力)
蟻羣算法尋優的快速性是通過正反饋式的信息傳遞和積累來保證的。而算法的早熟性收斂又可以通過其分佈計算特徵加以避免。
下面介紹五種蟻羣算法的過程:(第一種較經典,後四種均爲改進方法)
-
螞蟻系統
①初始化 : 初始時刻,m只螞蟻隨機放置,(第一次迭代)各條路徑上的信息素初始值相等,設τij(t) = τ0爲信息素初始值,可設τ0 = m/Lm,Lm是由最近鄰啓發式方法構造的路徑長度。 ②狀態轉移 : 螞蟻k(k = 1,2,...m)按照隨機比例規則選擇下一步要轉移的城市,選擇概率爲
τij(t) 爲邊(i,j)上的信息素;
ŋij(t)是啓發函數,表示螞蟻從i到j的期望程度,其表達式爲ŋij(t) = 1/dij,(dij爲i到j的距離);
allowedk爲螞蟻k下一步被允許訪問的點集合;
α爲信息啓發因子,反應螞蟻在運動過程中所積累的信息素在指導蟻羣搜索中的相對重要程度;
β爲期望啓發因子,反應啓發式信息在指導蟻羣搜索過程中的相對重要程度。
③禁忌表 : 爲了不讓螞蟻選擇已經訪問過的地方,採用禁忌表的形式來記錄螞蟻k當前所走過的地方。
④信息素更新 : 信息素揮發+信息素釋放
信息素更新公式如下
其中ρ爲信息素揮發因子,且ρ∈(0,1),ρ的大小直接影響到蟻羣的全局搜索能力及收斂速度。
ρ過小時,以前搜索過的路徑再次被選擇的可能性變大,容易出現局部收斂現象。
ρ過大時,算法有較強的隨機性和全局搜索能力,但搜索能力降低。
根據信息素更新策略的不同,Dorigo(蟻羣算法的提出者)曾給出三種不同的模型,分別稱爲Ant-Cycle模型、Ant-Quantity模型和Ant-Density模型其區別在於Δ τijk(t)的計
算方式不同。其中Ant-Cycle模型利用的是整體信息,及螞蟻完成一個循環(每個螞蟻都走過了所有地方)後更新所有路徑上的信息素(全局更新);
Ant-Quantity模型和Ant-Density模型則利用的是局部信息,即螞蟻完成一步後更新路徑上的信息素(局部更新)。
Ant-Cycle | Δ τijk(t) = Q/Lk (Lk是第k只螞蟻的路徑長度) |
---|---|
Ant-Quantity | Δ τijk(t) = Q/dij(dij是i到j的距離) |
Ant-Density | Δ τijk(t) = Q(Q爲信息素強度) |
Q爲自定義數值,其作用是充分利用全局信息反饋量,使算法在正反饋機制的作用下以合理的速度找到問題最優解。Q越大,越有利於算法的快速收斂,但當Q特別大時,雖然收斂速度很快,但其全局搜索能力變差,易限於局部最優解,故其計算性能也不穩定。
(摘自 任瑞春.基於排序加權的蟻羣算法[D].大連:大連海事大學,2006:16-17.)
我們上一章提過,智能優化算法具有隨機性,參數選擇依賴經驗,就應用最多的Ant-Cycle模型而言,最好的經驗結果是0≤α≤5;0≤β≤5;0.10≤ρ≤0.99;10≤Q≤10000(段海濱.蟻羣算法原理及其應用[M].北京:科學出版社,2005)
⑤螞蟻完成一次循環後,清空禁忌表,重新回到初始地點,準備下一次周遊(循環)。
爲了理解,附上解決相關問題的代碼
%%TSP旅行商問題%%
%%算法:蟻羣算法(螞蟻系統+蟻周模型)%%
%%算法介紹:
%%①初始化 :初始化 : 初始時刻,m只螞蟻隨機放置。
%%②狀態轉移 : 螞蟻k(k = 1,2,...m)按照隨機比例規則選擇下一步要轉移的城市。
%%③禁忌表 : 爲了不讓螞蟻選擇已經訪問過的地方,採用禁忌表的形式來記錄螞蟻k當前所走過的地方。
%%④信息素更新 : 信息素揮發+信息素釋放
%%⑤螞蟻完成一次循環後,清空禁忌表,重新回到初始地點,準備下一次周遊(循環)。
clear all;%清除工作區所有變量
%%常量設置(常量開頭字母大寫)
AntNum = 50;%%螞蟻數量
Alpha = 3;%%信息啓發因此α∈[0,5]
Beta = 3;%%期望啓發因子β∈[0,5]
Rho = 0.2;%%信息素揮發因子ρ∈[0.1,0.99]
Q = 1;%%蟻周模型信息素更新公式中參數Q∈[10,10000]
IterationTimes = 300;%%迭代(iteration)次數
%%城市的(x,y)座標
Cities = [
41 94;
37 84;
54 67;
25 62;
7 64;
2 99;
68 58;
71 44;
54 62;
83 69;
64 60;
18 54;
22 60;
83 46;
91 38;
25 38;
24 42;
58 69;
71 71;
74 78;
87 76;
18 40;
13 40;
82 7;
62 32;
58 35;
45 21;
41 26;
44 35;
4 50
];
%%相關數據準備
CityNum = size(Cities,1);
DisMatrix = zeros(CityNum,CityNum);
bestRoute = zeros(IterationTimes,CityNum);%記錄每次迭代最佳路線(其中包含全局最優解),用於蟻周模型更新信息素
bestDistance =inf.*ones(IterationTimes,1);%記錄每次迭代最佳路線距離,用於求全局最優解,然後帶入蟻周模型信息素更新模式中的Lk
for i = 1:CityNum
for j = i:CityNum %%矩陣爲對稱矩陣,故j可以從i開始,然後令disMatrix(j,i) = disMatrix(i,j)即可
if i~=j
DisMatrix(i,j) = ((Cities(i,1)-Cities(j,1))^2+(Cities(i,2)-Cities(j,2))^2)^(1/2);
else
DisMatrix(i,j) = eps;
end
DisMatrix(j,i) = DisMatrix(i,j);
end
end
EtaMatrix = 1./DisMatrix;%%ηij(t)啓發函數
PheromoneMatrix = ones(CityNum,CityNum);%%信息素(pheromone)矩陣(Matrix)
Tabu = zeros(AntNum,CityNum);%%禁忌表(tabu table)
%%迭代開始
for count = 1:IterationTimes
%%①初始化 :初始化 : 初始時刻,m只螞蟻隨機放置。
for i = 1:AntNum
Tabu(i,1) = ceil(rand*CityNum);
end
%%②狀態轉移 : 螞蟻k(k = 1,2,...m)按照隨機比例規則選擇下一步要轉移的城市。
for i = 2:CityNum
for j = 1:AntNum
visited = Tabu(j,1:i-1);
P = zeros(1,CityNum);%%初始化選擇各城市的概率
%%計算訪問各個城市的概率
for k = 1:CityNum
if isempty(find(visited == k,1))
P(k) = (PheromoneMatrix(visited(end),k)^Alpha)*(EtaMatrix(visited(end),k)^Beta);
else
P(k) = 0;%%不可訪問的城市概率爲0;
end
end
P = P/sum(P);
P = cumsum(P);
cityIndex = find(P>=rand);%%選擇常用方法:輪盤賭選擇法
%%③禁忌表 : 爲了不讓螞蟻選擇已經訪問過的地方,採用禁忌表的形式來記錄螞蟻k當前所走過的地方。
Tabu(j,i) = cityIndex(1);
end
end
dis = zeros(AntNum,1);%%準備記錄每隻螞蟻的路線長度
%%開始計算每隻螞蟻本次迭代路線長度
for i = 1:AntNum
for j = 1:CityNum-1
dis(i) = dis(i) + DisMatrix(Tabu(i,j),Tabu(i,j+1));
end
dis(i) = dis(i) + DisMatrix(CityNum,1);
end
% 求本次迭代最優解或全局最優解在螞蟻系統中不需要
disMin = min(dis);
routeIndex = find(dis==disMin);
bestRoute(count,:) = Tabu(routeIndex(1),:);
bestDistance(count) = disMin;
%%④信息素更新 : 信息素揮發+信息素釋放
deltaPhe = zeros(CityNum,CityNum);
for i = 1:AntNum
for j = 1:CityNum-1
deltaPhe(Tabu(i,j),Tabu(i,j+1)) = deltaPhe(Tabu(i,j),Tabu(i,j+1)) + Q/dis(i);
end
deltaPhe(Tabu(i,CityNum),Tabu(i,1)) = deltaPhe(Tabu(i,CityNum),Tabu(i,1)) + Q/dis(i);%%從終點到起點
end
PheromoneMatrix = (1 - Rho).* PheromoneMatrix + deltaPhe;
%%⑤螞蟻完成一次循環後,清空禁忌表,重新回到初始地點,準備下一次周遊(循環)。
Tabu = zeros(AntNum,CityNum);
end
resultDistance = min(bestDistance);%%求全局最優解,最短路徑距離
bestRouteIndex = find(bestDistance == resultDistance)
resultRoute = bestRoute(bestRouteIndex(1),:);%%求全局最優解,最短路徑索引
R = resultRoute;
C = Cities;
N=length(R);
scatter(C(:,1),C(:,2));
plot([C(R(1),1),C(R(N),1)],[C(R(1),2),C(R(N),2)],'g')
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)],'g')
hold on
end
title('旅行商問題優化結果 ');
minDis = 425.7183
%%簡單路徑規劃問題%%
%%算法:蟻羣算法(螞蟻系統+蟻周模型)%%
%%算法介紹:
%%①初始化 :初始化 : 初始時刻,m只螞蟻隨機放置。在這個問題中,m只螞蟻均放在起始點。
%%②狀態轉移 : 螞蟻k(k = 1,2,...m)按照隨機比例規則選擇下一步要轉移的地點。
%%③禁忌表 : 爲了不讓螞蟻選擇已經訪問過的地方,採用禁忌表的形式來記錄螞蟻k當前所走過的地方。
%%④信息素更新 : 信息素揮發+信息素釋放
%%⑤螞蟻完成一次循環後,清空禁忌表,重新回到初始地點,準備下一次出發。
clear all;
clc;
AntNum = 50;%%螞蟻數量
Alpha = 1;%%信息啓發因此α∈[0,5]
Beta = 3;%%期望啓發因子β∈[0,5]
Rho = 0.5;%%信息素揮發因子ρ∈[0.1,0.99]
Q = 1;%%蟻周模型信息素更新公式中參數Q∈[10,10000]
IterationTimes = 300;%%迭代(iteration)次數
%%1表示障礙物,0表示可以通過%%
Map = [0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0;
0 1 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0;
0 1 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0;
0 1 1 1 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0;
0 1 1 1 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0;
0 1 1 1 0 0 1 1 1 0 1 1 1 1 0 0 0 0 0 0;
0 1 1 1 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0;
0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0;
0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 0;
0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 0;
1 1 1 1 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 0;
1 1 1 1 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 1 1 0;
0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 1 1 0;
0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0;
];
[row,column] = size(Map);
tauMatrix = ones(row*column,row*column);%%初始化信息素矩陣
%tauMatrix = 8 .* tauMatrix;
startPoint = [1,1];
finalPoint = [row,column];
D = G2D(Map);
N = size(D,1); %%像素的個數
a = 1; %像素邊長,用於判斷點座標
startPointX = a * (startPoint(1) - 0.5);
startPointY = a * (startPoint(2) - 0.5);
finalPointX = a * (finalPoint(1) - 0.5);
finalPointY = a * (finalPoint(2) - 0.5);
start = (startPoint(1) - 1)*column + startPoint(2);
final = (finalPoint(1) - 1)*column + finalPoint(2);
Eta = zeros(N);%%啓發信息,每個點到終點的距離的導數,螞蟻傾向於走離終點近的點
for i = 1 : N
selfX = a * (mod(i,row) - 0.5); %% ---------→x
if selfX == -0.5 %%|
selfX = a * (row - 0.5); %%|
end %%|
selfY = a * (ceil(i/row) - 0.5); %%↓ y
if i ~= final
Eta(i) = 1/(((selfX - finalPointX)^2 + (selfY - finalPointY)^2)^0.5);
else
Eta(i) = 100;
end
end
tabuMatrix = ones(AntNum,N); %% 1 可達, 0 不可達
routes = cell(IterationTimes,AntNum);%%記錄每次迭代每隻螞蟻的路徑
routesDistance = zeros(IterationTimes,AntNum);
minij = inf;
mini = 0;
minj = 0;
%迭代開始
for i = 1:IterationTimes
for j = 1:AntNum
%%①初始化 :初始化 : 初始時刻,m只螞蟻隨機放置。在這個問題中,m只螞蟻均放在起始點。
position = start;
path = start;%%記錄本次迭代螞蟻j的路徑
distance = 0;%%記錄本次迭代螞蟻j的路徑距離;
tabuMatrix(j,start) = 0;%%排除初始點
%%TSP中除了禁忌表中的任意頂點都可以到達,allowedk = U - tabuk
%%但這個問題中只有相鄰八個像素可達,故要先找出八個像素
%%並查看他們是否在禁忌表中,若在,則將鄰接矩陣相應位置設置爲0(不可達);
DD = D;%%每隻螞蟻有自己的一張鄰接矩陣
DW = DD(start,:);
newIndex = find(DW);
indexLength = length(newIndex);
while position~=final && indexLength>=1%%當螞蟻走到終點或螞蟻無路可走的時候停止循環
p = zeros(1,indexLength);
%%②狀態轉移 : 螞蟻k(k = 1,2,...m)按照隨機比例規則選擇下一步要轉移的地點。
for k = 1:indexLength
p(k) = (tauMatrix(position,newIndex(k))^Alpha + Eta(newIndex(k))^Beta);
end
p = p./sum(p);
%%輪盤賭選擇法
p = cumsum(p);
toVisitIndex = find(p>=rand);
toVisit = newIndex(toVisitIndex(1));
%%記錄路徑並移動到下一個點
path = [path,toVisit];
distance = distance + DD(position,toVisit);
position = toVisit;
%%重新尋找可到達區域
DW = D(position,:);
index = find(DW);
%%③禁忌表 : 爲了不讓螞蟻選擇已經訪問過的地方,採用禁忌表的形式來記錄螞蟻k當前所走過的地方。
for c = 1:length(index)
if tabuMatrix(j,index(c)) == 0
%DD(position,index(k)) = 0;
%DD(index(k),position) = 0;
DW(index(c)) = 0;
end
end
tabuMatrix(j,position) = 0;
newIndex = find(DW);
indexLength = length(newIndex);
end
%%此時螞蟻已經走到終點或走到死角
%%記錄本次迭代螞蟻j的路徑
routes{i,j} = path;
if path(end) == final
routesDistance(i,j) = distance;
if distance < minij
mini = i;
minj = j;
minij = distance;
end
else
routesDistance(i,j) = 0;
end
end
%%此時每隻螞蟻都走完了,完成了一次迭代
%%④信息素更新 : 信息素揮發+信息素釋放(蟻周模型)
if mini~=0&&minj~=0%%如果存在有到達終點的路徑
delta = zeros(row*column,row*column);
rout = routes{mini,minj};
count = length(rout) - 1;
L = routesDistance(mini,minj);
for s = 1:count
x = rout(s);
y = rout(s+1);
delta(x,y) = Q/L;
delta(y,x) = Q/L;
end
tauMatrix = (1 - Rho).* tauMatrix + delta;
end
%%⑤螞蟻完成一次循環後,清空禁忌表,重新回到初始地點,準備下一次出發。
tabuMatrix = ones(AntNum,N);
end
%%繪製爬行圖
figure(1)
axis([0,row,0,column]);
for i = 1:row
for j = 1:column
if Map(i,j)==1
x1 = j - 1;y1 = row - i;
x2 = j;y2 = row - i;
x3 = j;y3 = row - i + 1;
x4 = j - 1;y4 = row - i + 1;
fill([x1,x2,x3,x4],[y1,y2,y3,y4],[0.2,0.2,0.2]);
hold on
else
x1 = j - 1;y1 = row - i;
x2 = j;y2 = row - i;
x3 = j;y3 = row - i + 1;
x4 = j - 1;y4 = row - i + 1;
fill([x1,x2,x3,x4],[y1,y2,y3,y4],[1,1,1]);
hold on
end
end
end
title('機器人運動軌跡');
xlabel('座標x');
ylabel('座標y');
routLength = length(rout);
rx = rout;
ry = rout;
for i = 1:routLength
rx(i) = a *(mod(rout(i),row) - 0.5);
if rx(i) == -0.5
rx(i) = a * (row - 0.5);
end
ry(i) = a*(row + 0.5 - ceil(rout(i)/row));
end
plot(rx,ry);
bestDistance = routesDistance(mini,minj);
%%由圖生成row^2個像素與row^2個像素的鄰接矩陣
function D = G2D(G)
[row,column] = size(G);
D = zeros(row*column,row*column);
for i = 1:row
for j = 1:column
if G(i,j)==0 %%此點不是障礙物
%%遍歷整個圖row^column個像素,尋找與他八聯通的八個像素
for m = 1:row
for n = 1:column
if G(m,n)==0 %%如果像素不是障礙物
im = abs(i - m);
jn = abs(j - n);
if im+jn==1||(im==1&&jn==1) %%如果在上下左右和斜着的八個方向
%%則設置鄰接矩陣的權值
D((i - 1) * row + j,(m - 1) * row + n) = (im + jn)^0.5;
end
end
end
end
end
end
end
end
當解決有障礙物的路徑規劃問題上,我一開始出現了
這種一看就不對的圖像,最終我觀察發現解收斂太快,於是我減小了Q的值,從1000變爲了1,最終便有了良好的結果。
大量仿真實驗發現,螞蟻系統在解決小規模TSP問題時性能尚可,能較快的發現最優解,但隨着測試問題規模的擴大,螞蟻系統算法的性能下降的比較嚴重,容易出現停滯現象,因此出現了針對其缺點的改進算法。
在智能優化算法之蟻羣算法(2)中詳細講解
2. 精英螞蟻系統
3. 最大-最小螞蟻系統
4. 基於排序的蟻羣算法
5. 蟻羣系統