智能算法之Ant Colony Optimization蟻羣算法解決TSP問題

AntColonyOptimization蟻羣算法


前言:本文主要圍繞解決TSP旅行商問題展開,對於機器人的路線規劃以及非線性方程求解的問題等解決方案大家可以直接參考github源碼地址
對於一些其他優化算法例如遺傳算法解決一些現實問題都有實現!! 歡迎小夥伴的star哦~~ 🤭

先看一下效果圖:

蟻羣算法解決TSP問題:

TSP問題

蟻羣算法解決機器人路徑規劃問題:

路徑規劃

1、什麼是蟻羣算法

1.1、蟻羣算法的來源

  同遺傳算法相似,都來自於大自然的啓迪。蟻羣算法就來自於螞蟻尋找食物過程中發現路徑的行爲。
  螞蟻並沒有視覺卻可以尋找到食物,這得益於螞蟻分泌的信息素,螞蟻之間相互獨立,彼此之間通過信息素進行交流,從而實現羣體行爲。

1.2、蟻羣算法的基本原理

  基本原理的過程就是螞蟻覓食的過程。首先,螞蟻在覓食的過程中會在路徑上留下信息素的物質,並在尋找食物的過程中感知這種物質的強度,並指導自己的行爲方向,他們總會朝着濃度高的方向前進。因此可以看得出來,螞蟻覓食的過程是一個正反饋的過程,該路段經過的螞蟻越多,信息素留下的就越多,濃度越高,更多的螞蟻都會選擇這個路段。

2、蟻羣算法的實現原理

2.1、蟻羣算法實現的重要規則(細品)

1. 避障規則
  如果螞蟻要移動的方向有障礙物擋住,他會隨機的選擇另外一個方向,如果有信息素指引的話,會按照信息素的指引前進。
2. 散播信息素規則
  每隻螞蟻在剛找到食物的時候散發出來的信息素最多,並隨着走選的距離,散播的信息越少。
3. 範圍
  螞蟻觀察的範圍有限,只能在局部的範圍內進行選擇。例如螞蟻觀察的範圍爲3*3,那麼它能夠移動的範圍也就是在這個3*3區域內。
4. 移動規則
  前面也說過,螞蟻的前進方向的選擇依賴於信息素的濃度,回朝向信息素高的方向移動。當週圍沒有信息素或者信息素相同的時候,那麼螞蟻就會按照原來的方向繼續前進,並且在前進方向上受到一個隨機的擾動,爲了避免再原地轉圈,他會記住之前經過的點,下一次遇到的時候就會避開這個已經經過的點。
5. 覓食規則
  如果螞蟻在感知範圍內找到食物則直接過去,加速模型的收斂,否則朝着信息素高的方向前進,並且每隻螞蟻都有小概率的犯錯誤,從而不是信息素最多的點移動,打破局部最優解的情況。
6. 環境
  每隻螞蟻之間相互獨立,他們依賴環境中的信息素進行交流。每隻螞蟻都僅僅能感知到環境內的信息。並且隨機信息素會隨着時間逐漸減少。如果這條路上經過的螞蟻越來越少,那麼信息素也會越來越少。

2.2、蟻羣算法解決TSP問題的過程

  旅行商問題(Traveling saleman problem, TSP)是物流配送的典型問題,他的求解有十分重要的理論和現實意義。

  旅行商問題傳統的解決方法都是遺傳算法,但是遺傳算法的收斂速度慢,具有一定的缺陷。

  在求解TSP蟻羣算法中,每隻螞蟻相互獨立,用於構造不同的路線,螞蟻之間通過信息素進行交流,合作求解。

基本過程如下:

  1. 初始化,設置迭代次數;
  2. 將 ants 只螞蟻放置到 cities 個城市上;
  3. ants只螞蟻按照概率函數選擇下一個城市,並完成所有城市的周遊;
  4. 記錄本次迭代的最優路線;
  5. 全局更新信息素。
  6. 終止。本例終止條件是迭代次數,也可以設置運行時間或最短路徑的下限。
  7. 輸出結果

  應用全局更新信息素來改變路徑上信息素的值。當ants螞蟻生成了ants個解,其中最短路徑的是本代最優解,將屬於這條路線上的所有關聯的路線進行信息素更新。

  之所以使用全局信息素,是爲了讓最優路徑上有格外的信息素支持,這樣後面的螞蟻會優先選擇這條路線。並且伴隨着信息素的揮發,全局最短路徑關聯路線信息素得到進一步增強。

3、蟻羣算法TSP程序實現

3.1、程序中矩陣大小以及含義

程序中矩陣說明(首字母大寫):

矩陣 大小 含義
Distance (城市數量,城市數量) 表徵各個城市之間的距離信息
Eta (城市數量,城市數量) 表徵各個城市之間的啓發因子
Tau (城市數量,城市數量) 表徵各個城市之間信息素的值
Route (螞蟻個數,城市數量) 每隻螞蟻周遊城市的記錄矩陣
R_best (迭代次數,城市數量) 每次迭代的最優路線
L_best (迭代次數,1) 每次迭代的最短距離
L_ave (迭代次數,1) 每次迭代的平均距離

3.2、整體架構

'3.3、初始化變量參數'
'3.4、初始化矩陣參數'

while '迭代次數'
    '3.5、安排螞蟻初始位置'
    '3.6、螞蟻周遊'
    '3.7、記錄最優路線以及最短距離'
    '3.8、更新信息素'
end
'3.9、結果輸出'

3.3、初始化變量參數

初始化主要對程序當中重要參數進行聲明。
程序實現:

% 隨機產生40個城市的座標
position = 50 * randn(40, 2);
epochs = 50;  % 迭代次數
% 螞蟻個數最好大於等於城市個數,保證每個城市都有一個螞蟻
ants = 40;  
alpha = 1.4;  % 表徵信息素重要程度參數
beta = 2.2;  % 表徵啓發因子重要程度參數
rho = 0.15;  % 信息素揮發參數
Q = 10^6;  % 信息素增強係數
cities = size(position, 1);  % 城市個數

3.4、初始化矩陣參數

主要實現了重要矩陣聲明以及初始化。
程序實現:

% 城市之間的距離矩陣
Distance = ones(cities, cities);
for i = 1: cities
    for j = 1: cities
        if i ~= j
            % 座標點歐氏距離
            Distance(i, j) = ((position(i, 1) - position(j, 1))^2 + (position(i, 2) - position(j, 2))^2)^0.5;
        else
            % 因爲後面要取倒數,所以取一個浮點數精度大小
            Distance(i, j) = eps;
        end
        Distance(j, i) = Distance(i, j);
    end
end
% 啓發因子矩陣
Eta = 1./Distance;
% 信息素初始值每個路線均相同爲 1
Tau = ones(cities, cities);
% 每隻螞蟻的路線圖
Route = zeros(ants, cities);
epoch = 1;
% 記錄每回合最優城市
R_best = zeros(epochs, cities);
% 記錄每回合最短距離
L_best = inf .* ones(epochs, 1);
% 記錄每回合平均距離
L_ave = zeros(epochs, 1);

3.5、安排螞蟻初始位置

主要是將所有的螞蟻安置在所有的城市當中,螞蟻個數 >= 城市個數。並且保證均勻分佈。

% 初始隨機位置
RandPos = [];
for i = 1: ceil(ants / cities)
    RandPos = [RandPos, randperm(cities)];
end
% 初始位置轉置就對應了Route矩陣中每隻螞蟻的初始位置
Route(:, 1) = (RandPos(1, 1:ants))';

3.6、螞蟻周遊

由於螞蟻的初始位置已經確定,所有主要就是周遊剩餘的所有城市,循環(cities-1)次。裏面的循環就是將所有的螞蟻進行周遊一次。

對於每隻螞蟻的周遊主要是對剩餘的城市進行周遊,不能重複拜訪同一個城市。NoVisited矩陣存儲着該螞蟻未訪問的城市。然後在所有沒有訪問過城市中選擇一個。選擇的方式也是類似於輪盤賭法。概率函數表徵信息素和啓發因子,兩者有着不同的重要程度。
P=[τij(t)]α[ηij]β P = [\tau_{ij}(t)]^\alpha · [\eta_{ij}]^\beta
其中τij(t)\tau_{ij}(t)爲路線上(i,j)(i, j)上的信息素濃度;ηij\eta_{ij}爲路線上(i,j)(i, j)上的啓發式信息;
程序實現:

for j = 2: cities
        for i = 1: ants
            Visited = Route(i, 1:j-1);
            NoVisited = zeros(1, (cities - j + 1));
            P = NoVisited;
            num = 1;
            for k = 1: cities
                if length(find(Visited == k)) == 0
                    NoVisited(num) = k;
                    num = num + 1;
                end
            end
            for k = 1: length(NoVisited)
                P(k) = (Tau(Visited(end), NoVisited(k))^alpha) * (Eta(Visited(end), NoVisited(k))^beta);
            end
            P = P / sum(P);
            Pcum = cumsum(P);
            select = find(Pcum >= rand);
            to_visit = NoVisited(select(1));
            Route(i, j) = to_visit;
        end
    end

3.7、記錄最優路線以及最短距離

計算每個回合每隻螞蟻走過的距離。並記錄該回合最短路徑,最短距離和平均距離。

Distance_epoch = zeros(ants, 1);
for i = 1: ants
    R = Route(i, :);
    for j = 1: cities - 1
        Distance_epoch(i) = Distance_epoch(i) + Distance(R(j), R(j + 1));
    end
    Distance_epoch(i) = Distance_epoch(i) + Distance(R(1), R(cities));
end
L_best(epoch) = min(Distance_epoch);
pos = find(Distance_epoch == L_best(epoch));
R_best(epoch, :) = Route(pos(1), :);
L_ave(epoch) = mean(Distance_epoch);
epoch = epoch + 1;

3.8、更新信息素

更新信息素主要保證獲得最優距離的那條路線的信息素得到最大的增強。

Delta_Tau = zeros(cities, cities);
for i = 1: ants
    for j = 1: (cities - 1)
        Delta_Tau(Route(i, j), Route(i, j + 1)) = Delta_Tau(Route(i, j), Route(i, j + 1)) + Q / Distance_epoch(i);
    end
    Delta_Tau(Route(i, 1), Route(i, cities)) = Delta_Tau(Route(i, 1), Route(i, cities)) + Q / Distance_epoch(i);
end
Tau = (1 - rho) .* Tau + Delta_Tau;
Route = zeros(ants, cities);

3.9、結果輸出

迭代完成後,在R_best矩陣中得到最短路徑的最小路線,最後輸出最優的結果。
結果輸出實現:

Pos = find(L_best == min(L_best));
Short_Route = R_best(Pos(1), :);
Short_Length = L_best(Pos(1), :);
figure
subplot(121);
DrawRoute(position, Short_Route);
subplot(122);
plot(L_best);
hold on
plot(L_ave, 'r');
title('平均距離和最短距離');

畫圖函數實現:

function DrawRoute(C, R)
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)], '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('旅行商規劃');

4、結果

結果展示

爲了說明方便將代碼直接拆開展示,如果想要全部的代碼歡迎大家直接到 Github源碼

最後

更多精彩內容,大家可以轉到我的主頁:曲怪曲怪的主頁

源碼地址github地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章