蚁群算法背景及实现方法简要介绍
背景
单只蚂蚁的行为及其简单,行为数量在10种以内,但成千上万只蚂蚁组成的蚁群却能拥有巨大的智慧,这离不开它们信息传递的方式——信息素。
蚂蚁在行走过程中会释放一种称为“信息素”的物质,用来标识自己的行走路径。在寻找食物的过程中,根据信息素的浓度选择行走的方向,并最终到达食物所在的地方。
信息素会随着时间的推移而逐渐挥发。
在一开始的时候,由于地面上没有信息素,因此蚂蚁们的行走路径是随机的。蚂蚁们在行走的过程中会不断释放信息素,标识自己的行走路径。随着时间的推移,有若干只蚂蚁找到了食物,此时便存在若干条从洞穴到食物的路径。由于蚂蚁的行为轨迹是随机分布的,因此在单位时间内,短路径上的蚂蚁数量比长路径上的蚂蚁数量要多,从而蚂蚁留下的信息素浓度也就越高。这为后面的蚂蚁们提供了强有力的方向指引,越来越多的蚂蚁聚集到最短的路径上去。
(1)高度结构化的组织——虽然蚂蚁的个体行为极其简单,但由个体组成的蚁群却构成高度结构化的社会组织,蚂蚁社会的成员有分工,有相互的通信和信息传递。
(2)自然优化——蚁群在觅食过程中,在没有任何提示下总能找到从蚁巢到食物源之间的最短路径;当经过的路线上出现障碍物时,还能迅速找到新的最优路径。
(3)信息正反馈——蚂蚁在寻找食物时,在其经过的路径上释放信息素(外激素)。蚂蚁基本没有视觉,但能在小范围内察觉同类散发的信息素的轨迹,由此来决定何去何从,并倾向于朝着信息素强度高的方向移动。
(4)自催化行为——某条路径上走过的蚂蚁越多,留下的信息素也越多(随时间蒸发一部分),后来蚂蚁选择该路径的概率也越高。
实现方法
(1)根据具体问题设置多只蚂蚁,分头并行搜索。
(2)每只蚂蚁完成一次周游后,在行进的路上释放信息素,信息素量与解的质量成正比。
(3)蚂蚁路径的选择根据信息素强度大小(初始信息素量设为相等),同时考虑两点之间的距离,采用随机的局部搜索策略。这使得距离较短的边,其上的信息素量较大,后来的蚂蚁选择该边的概率也较大。
(4)每只蚂蚁只能走合法路线(经过每个城市1次且仅1次),为此设置禁忌表来控制。
(5)所有蚂蚁都搜索完一次就是迭代一次,每迭代一次就对所有的边做一次信息素更新,原来的蚂蚁死掉,新的蚂蚁进行新一轮搜索。
(6)更新信息素包括原有信息素的蒸发和经过的路径上信息素的增加。
(7)达到预定的迭代步数,或出现停滞现象(所有蚂蚁都选择同样的路径,解不再变化),则算法结束,以当前最优解作为问题的最优解。
用途
主要用来解决路径优化问题!!!
参数
m:蚂蚁数量;
k:蚂蚁编号;
t:时刻;
n:城市数;
d i,j d_\text{i,j} di,j:城市(i,j)之间的距离;
η i,j \eta_\text{i,j} ηi,j:启发式因子(能见度)反应蚂蚁由城市i转移到城市j的启发程度;
η i,j = 1 d i,j \displaystyle\eta_\text{i,j}=\frac{1}{d_\text{i,j}} ηi,j=di,j1
τ i,j \tau_\text{i,j} τi,j:边(i,j)上的信息素;
τ i,j ( t + n ) = ( 1 − ρ ) ⋅ τ i,j ( t ) + Δ τ i,j τ i,j ( 0 ) = C \tau_\text{i,j}(t+n)=(1-\rho)\cdot\tau_\text{i,j}(t)+\Delta\tau_\text{i,j}\\ \tau_\text{i,j}(0)=C τi,j(t+n)=(1−ρ)⋅τi,j(t)+Δτi,jτi,j(0)=C
Δ τ i,j \Delta\tau_\text{i,j} Δτi,j:本次迭代边(i,j)上的信息素增量;
Δ τ i,j = ∑ k = 1 m Δ τ i,j k Δ τ i,j ( 0 ) = 0 \Delta\tau_\text{i,j}=\sum_{k=1}^m\Delta\tau_\text{i,j}^k\\ \Delta\tau_\text{i,j}(0)=0 Δτi,j=k=1∑mΔτi,jkΔτi,j(0)=0
Δ τ i,j k \Delta\tau_\text{i,j}^k Δτi,jk:第k只蚂蚁在本次迭代中留在边(i,j)上的信息素量;
Δ τ i,j k = { Q L k , 若 蚂 蚁 在 本 次 周 游 中 经 过 变 ( i , j ) 0 , 其 他 \Delta\tau_\text{i,j}^k= \left\{ \begin{array}{l} \displaystyle\frac{Q}{L_k}\ ,\ 若蚂蚁在本次周游中经过变(i,j)\\ 0\ ,\ 其他 \end{array} \right. Δτi,jk=⎩⎨⎧LkQ , 若蚂蚁在本次周游中经过变(i,j)0 , 其他
Q — — 正 常 数 ; L k — — 蚂 蚁 k 在 本 次 周 游 中 所 走 的 路 径 的 长 度 。 \begin{array}{l} Q——正常数;\\ L_k——蚂蚁k在本次周游中所走的路径的长度。 \end{array} Q——正常数;Lk——蚂蚁k在本次周游中所走的路径的长度。
ρ \rho ρ:信息素蒸发(或挥发)系数;
1 − ρ 1-\rho 1−ρ:持久性(或残留)系数,0< ρ \rho ρ<1;
P i,j k ( t ) P_\text{i,j}^k(t) Pi,jk(t):时刻t蚂蚁k由城市i转移到城市j的概率(转移概率);
P i,j k ( t ) = { [ τ i,j ( t ) ] α ⋅ [ η i,j ( t ) ] β ∑ s ∈ J k ( i ) [ τ i,s ( t ) ] α ⋅ [ η i,s ( t ) ] β P_\text{i,j}^k(t)= \left\{ \begin{array}{l} \displaystyle\frac{[\tau_\text{i,j}(t)]^{\alpha}\cdot[\eta_\text{i,j}(t)]^\beta}{\displaystyle\sum_{s\in J_k(i)}[\tau_\text{i,s}(t)]^{\alpha}\cdot[\eta_\text{i,s}(t)]^\beta} \end{array} \right. Pi,jk(t)=⎩⎨⎧s∈Jk(i)∑[τi,s(t)]α⋅[ηi,s(t)]β[τi,j(t)]α⋅[ηi,j(t)]β
α — — 信 息 素 的 相 对 重 要 程 度 ; β — — 启 发 式 因 子 的 相 对 重 要 程 度 ; J k ( i ) — — 蚂 蚁 k 下 一 步 允 许 选 择 的 城 市 合 集 \begin{array}{l} \alpha——信息素的相对重要程度;\\ \beta——启发式因子的相对重要程度;\\ J_k(i)——蚂蚁k下一步允许选择的城市合集 \end{array} α——信息素的相对重要程度;β——启发式因子的相对重要程度;Jk(i)——蚂蚁k下一步允许选择的城市合集
t a b o o k taboo_k tabook:蚂蚁k的禁忌表
算法流程
所有参数的初始化(包括城市距离表、各种系数等)
寻找每次迭代下的最佳路径
确定每只蚂蚁的初始位置和终点位置
计算每只蚂蚁该次迭代下的路径
计算每只蚂蚁走过的路程
按照当前计算出的路径更新各城市间道路的信息素
计算出该次迭代下所走路程最小的蚂蚁及其走过的路径和路程
在计算出的所有迭代次数中的最优路径寻找长度最小的一条
将结果进行打印展示
%% I. 清空环境变量
clear
clc
close all
%% II. 导入数据
x = [2, 4, 7, 13, 18, 18, 22, 24, 25, 25, 37, 41, 41, 44, 45, 54, 54, 58, 58, 62, 64, 68, 71, 71, 74, 82, 83, 83, 87, 91];
y = [99, 50, 64, 40, 40, 54, 60, 42, 38, 62, 84, 26, 94, 35, 21, 62, 67, 35, 69, 32, 60, 58, 44, 71, 78, 7, 46, 69, 76, 38];
citys = [];
for i = 1:length(x)
citys = [citys; [x(i), y(i)]];
end
%% III. 获得城市距离地图表
n = length(citys); % 城市个数
CitysDistanceTable = zeros(n, n); % 各城市之间距离矩阵
CitysNameList = 1:n; % 城市名称索引(主要给下面禁忌表构建使用)
% 计算个城市之间距离,构建距离矩阵表
for i = 1:n
for j = 1:n
if i ~= j
CitysDistanceTable(i, j) = sqrt(sum((citys(i, :) - citys(j, :)).^2));
else
CitysDistanceTable(i, j) = 0;
end
end
end
%% IV. 初始化参数
m = 200; % 蚁群数量
eta = 1 ./ CitysDistanceTable; % 可见度
tau = ones(n, n); % 信息素浓度矩阵
rho = 0.1; % 信息素挥发系数
Q = 1; % 一常数,与信息素浓度有关(个人感觉取任何数都可以)
alpha = 1; % 信息素相对重要程度
beta = 5; % 能见度相对重要程度
iter_Max = 200; % 最大迭代次数
Thre = 0.1; % 当所求最优解不变次数超过iter_Max*Thre时,终止迭代
waitbarjiange = iter_Max / 100; % 和进度条有关的一个数据
RouteBest = zeros(iter_Max, n + 1); % 每次迭代最优路径合集
LengthBest = zeros(iter_Max, 1); % 每次迭代路径最小值合集
%% V. 迭代寻找最佳路径
tic
% 添加进度条
h = waitbar(0, ['已完成:0% 搜索中... 已用时:', num2str(toc)]);
i = 1; % 迭代次数初始化
ConstantNumberOfTimes = 0; % 最优解不变次数计数初始化
% 开始迭代,迭代有两个限制条件
% 1. 迭代次数达到iter_Max
% 2. 连续iter_Max*Thre次最优解不出现变化
while (i <= iter_Max) && (ConstantNumberOfTimes < iter_Max * Thre)
RouteTable = zeros(m, n + 1); % 当前迭代次数下路径存放表初始化
RouteStart = zeros(m, 1); % 蚁群初始位置
% 初始化蚁群初始位置
for j = 1:m
temp = randperm(n);
RouteStart(j) = temp(1);
end
% 确认蚁群初始位置和最终位置
RouteTable(:, 1) = RouteStart;
RouteTable(:, end) = RouteStart;
% 计算该次迭代下,每只蚂蚁的路径
for j = 1:m
% 第j只蚂蚁的情况
for k = 2:n
% 计算第j只蚂蚁经过的第k的城市
% 计算的依据转移概率
TabooList = RouteTable(j, 1:k - 1); % 第j只蚂蚁经过了k-1座城市后的禁忌表
% 计算第j只蚂蚁第k个城市的可选项
RouteAllow_temp = ~ismember(CitysNameList, TabooList);
RouteAllow = CitysNameList(RouteAllow_temp);
% 计算第j只蚂蚁每个可选城市的转移概率
P = zeros(1, length(RouteAllow));
for l = 1:length(P)
P(l) = (tau(TabooList(end), RouteAllow(l)))^alpha * (eta(TabooList(end), RouteAllow(l)))^beta;
end
P = P ./ sum(P);
% 依据轮盘赌法确定第j只蚂蚁的下一个城市
% 为什么用轮盘赌法不清楚,但是实际证明,该方法效果明显优于寻找最大转移概率
P = cumsum(P);
target_index = find(P >= rand);
NextTarget = RouteAllow(target_index(1));
RouteTable(j, k) = NextTarget;
end
end
% 计算每只蚂蚁走过的路程
Length = zeros(m, 1);
for j = 1:m
for k = 1:n
Length(j) = Length(j) + CitysDistanceTable(RouteTable(j, k), RouteTable(j, k + 1));
end
end
% 寻找该迭代次数下,蚁群中所走过的最短路径
if i == 1
[MinLength, MinLengthRouteIndex] = min(Length);
RouteBest(i, :) = RouteTable(MinLengthRouteIndex, :);
LengthBest(i) = MinLength;
else
[MinLength, MinLengthRouteIndex] = min(Length);
% 该处判断的目的:让第二个迭代限制条件能够生效;同时使得画出的图像更加美观
if LengthBest(i - 1) < MinLength
RouteBest(i, :) = RouteBest(i - 1, :);
LengthBest(i) = LengthBest(i - 1);
ConstantNumberOfTimes = ConstantNumberOfTimes + 1;
else
RouteBest(i, :) = RouteTable(MinLengthRouteIndex, :);
LengthBest(i) = MinLength;
ConstantNumberOfTimes = 0;
end
end
% 更新信息素
Delta_Tau = zeros(n, n);
for j = 1:m
for k = 1:n
Delta_Tau(RouteTable(j, k), RouteTable(j, k + 1)) = ...
Delta_Tau(RouteTable(j, k), RouteTable(j, k + 1)) + ...
Q / Length(j);
end
end
tau = (1 - rho) * tau + Delta_Tau;
% 生成进度条
if mod(i, waitbarjiange) == 0
waitbar(i / iter_Max, h, ['已完成:', num2str(i / iter_Max * 100), '% 搜索中... 已用时:', num2str(toc)]);
end
i = i + 1;
end
close(h)
%% VI. 绘图与打印结果
% 打印最短路径和最短距离
Shortest_Length = LengthBest(i - 1);
Shortest_Route = RouteBest(i - 1, :);
disp(['最短距离', num2str(Shortest_Length)]);
disp(['最短路径', num2str(Shortest_Route)]);
% 绘制路径最优解
figure(1)
plot(citys(Shortest_Route, 1), citys(Shortest_Route, 2), 'o-');
for i = 1:n
text(citys(i, 1), citys(i, 2), [' ' num2str(i)]);
end
text(citys(Shortest_Route(1), 1), citys(Shortest_Route(1), 2), ' 起点');
text(citys(Shortest_Route(end - 1), 1), citys(Shortest_Route(end - 1), 2), ' 终点');
xlabel('城市位置横坐标')
ylabel('城市位置纵坐标')
title(['蚁群算法优化路径(最短距离:' num2str(Shortest_Length) ')'])
% 绘制最短路径长度变化曲线
figure(2)
plot(1:i - 1, LengthBest(1:i - 1), 'b')
legend('最短距离')
xlabel('迭代次数')
ylabel('距离')
title('各代最短距离')