蚁群算法

蚁群算法

​ 蚁群算法由Marco Dorigo于1992年提出,该算法模拟了自然界中蚂蚁的觅食行为。蚂蚁在寻找食物源时,会在其经过的路径上释放一种信息素,并能够感知其他蚂蚁释放的信息素。信息素浓度的大小表征路径的远近,信息素浓度越高,表示对应的路径距离越短。通常蚂蚁会以较大的概率优先选择信息素浓度较高的路径,并释放一定量的信息素,以增强该条路径上的信息素浓度,这样,会形成一个正反馈。最终,蚂蚁能够找到一条从巢穴到食物源的最佳路径,即距离最短。生物学家发现,路径上的信息素浓度会随着时间的推进而逐渐衰减。

基本思路

​ 蚁群算法的基本思路为:用蚂蚁的行走路径表示待优化问题的可行解,整个蚂蚁群体的所有路径构成待优化问题的解空间。路径较短的蚂蚁释放的信息素量较多,随着时间的推进,较短的路径上累积的信息素浓度逐渐增高,选择该路径的蚂蚁个数也愈来愈多。最终,整个蚂蚁会在正反馈的作用下集中到最佳的路径上,此时对应的便是待优化问题的最优解。

蚁群算法的数学模型

​ 蚁群搜索食物的过程与TSP问题的求解过程非常相似,这里以TSP问题作为背景来介绍基本蚁群算法。所谓TSP问题就是求一条遍历所有n个城市且每个城市仅经过一次的最短路径。在ACO算法中,首先将m个蚂蚁随机分配到n个不同的城市中,通常m不大于n;然后m只蚂蚁同时由一个城市运动到另一个城市,逐步完成他们的搜索过程。蚂蚁k根据各个城市间的连接路径上的信息素浓度决定其访问的下一个城市,设p_ij\^k (t)表示t时刻蚂蚁k从城市i转移到城市j的概率:

其中τ_ij\^α (t)表示信息素浓度,它代表的是从i到j的后延效应;η_ij\^β (t)为启发式信息,一般为启发式函数,它代表从i到j的先验效应。

启发式信息η_ij增加了对有潜力解的倾向性,它通常是与问题有关的独立函数。最小化路径长度问题的启发式信息:

​ η~ij~=1/d~ij~

信息素浓度更新公式:

其中1-ρ表示信息素残留因子,∆τ~ij~^k^表示第k只蚂蚁在城市i与城市j连接路径上释放的信息素浓度。

蚁群算法的三种模型

算法流程

​ 步骤1:初始化相关参数,如需遍历的城市数n、蚂蚁数m、初始时各路径信息素τ、m只蚂蚁遍历循环的次数最大值T~max~、信息素发挥p以及\\alpha\\beta、Q等。建立禁忌列表J^k^,并保证此时表中未存任何城市信息。

​ 步骤2:将m只蚂蚁随机放在各个城市中,每个城市中至多分布一只蚂蚁;将m只蚂蚁所存在城市存入禁忌列表J^k^。

​ 步骤3:所有蚂蚁根据概率转换规则选择下一城市,并将选择城市存入禁忌列表。

​ 步骤4:所有蚂蚁遍历完n个城市后在所经过的路径上依据信息素更新公式更新信息素,并记录本次迭代过程中的最优路径和最优路径长度。

​ 步骤5:清空禁忌列表J^k^,重复步骤3和步骤4,直到每只蚂蚁均完成T~max~次遍历为止,最后输出的路径即为最优路径。

代码实例

%% 清空环境变量

clear all

clc

%% 导入数据

load citys_data.mat % 从名为 'citys_data.mat' 的文件中加载数据

%% 计算城市间的相互距离

n = size(citys,1); % 获取城市数量

D = zeros(n,n); % 创建一个用于存储城市间距离的零矩阵

for i = 1:n

​ for j = 1:n

​ if i ~= j

​ D(i,j) = sqrt(sum((citys(i,:) - citys(j,:)) .^ 2)); %勾股定理

​ else

​ D(i,j) = 1 * 10^-4; % 对角线上的距离设置一个很小的值,避免出现零值

​ end

​ end

end

%% 初始化参数

m = 50; %蚂蚁数量

alpha = 1; %信息素重要程度因子

beta = 5; %启发函数重要程度因子

rho = 0.1; %信息素挥发因子

Q = 1; %蚁周模型中的常系数

Eta = 1 ./ D; %启发函数

Tau = ones(n,n); %信息素矩阵,初始化为n行n列的全1方阵

Table = zeros(m,n); %路径记录表,m只蚂蚁所以有m行记录,每只蚂蚁经过n个城市的次序所以是n列

iter = 1; %迭代次数初值

iter_max = 200; %最大迭代次数

Route_best = zeros(iter_max,n); %各代最佳路径

Length_best = zeros(iter_max,1);%各代最佳路径的长度

Length_ave = zeros(iter_max,1); %各代路径的平均长度

%% 迭代寻找最佳路径

while iter <= iter_max

​ %随机产生各个蚂蚁的起点城市

​ start = zeros(m,1); % 创建一个初始城市编号的数组

​ for i = 1:m

​ temp = randperm(n); %把1到n这些数随机打乱得到的一个数字序列

​ start(i) = temp(1); %每只蚂蚁的起始位置是随机的

​ end

​ Table(:,1) = start; %路径记录表的第一列记为开始出发的城市

​ %构建解空间

​ citys_index = 1:n; %生成了一个1至31的一维数组

​ %逐个蚂蚁路径选择

​ for i = 1 : m

​ %逐个城市路径选择

​ for j = 2 : n

​ tabu = Table(i,1:(j - 1)); %已访问的城市集合(禁忌表)

​ allow_index = ~ismember(citys_index,tabu);

​ %找到尚未访问的城市,判断前一矩阵是否在后一矩阵中的逻辑值,并取反

​ allow = citys_index(allow_index); %待访问的城市集合

​ P = allow; % 创建概率数组,用于存储城市间转移概率

​ %计算城市间转移概率

​ for k = 1:length(allow)

​ P(k) = Tau(tabu(end),allow(k)) ^ alpha * Eta(tabu(end),allow(k)) ^ beta;

​ end

​ P = P / sum(P); % 归一化概率

​ %轮盘赌法选择下一个访问城市

​ Pc = cumsum(P);

​ target_index = find(Pc >= rand); % 选择满足条件的城市编号

​ target = allow(target_index(1)); % 获得下一个访问的城市编号

​ Table(i,j) = target; % 将下一个城市编号放入路径记录表

​ end

​ end

​ %计算各个蚂蚁的路径距离

​ Length = zeros(m,1); % 创建数组,用于存储各个蚂蚁的路径距离

​ for i = 1:m

​ Route = Table(i,:);

​ for j = 1:(n-1)

​ Length(i) = Length(i) + D(Route(j),Route(j+1));% 计算路径长度

​ end

​ Length(i) = Length(i) + D(Route(n),Route(1)); % 考虑最后一个城市回到起点的距离

​ end

​ %计算最短路径距离及平均距离

​ if iter == 1

​ [min_Length,min_index] = min(Length); % 获取最短路径长度及其索引(走出了最短路径的那只蚂蚁编号)

​ Length_best(iter) = min_Length; % 存储本次迭代中的最短路径长度

​ Length_ave(iter) = mean(Length); % 计算本次迭代产生所有值的平均路径长度

​ Route_best(iter,:) = Table(min_index); % 存储最佳路径

​ else

​ [min_Length,min_index] = min(Length); % 获取最短路径长度及其索引

​ Length_best(iter) = min(Length_best(iter - 1),min_Length);

​ % 更新最短路径长度,第一个参数是矩阵,第二个参数是标量,凡矩阵中的元素大于标量的,都用标量值替代

​ Length_ave(iter) = mean(Length); % 计算平均路径长度

​ if Length_best(iter) == min_Length

​ Route_best(iter,:) = Table(min_index,:); % 存储最佳路径

​ else

​ Route_best(iter,:) = Route_best((iter-1)😅;% 若未找到更优路径,保持上一代的最佳路径

​ end

​ end

​ %更新信息素

​ Delta_Tau = zeros(n,n); % 创建用于存储信息素增量的矩阵,n个城市所以是n阶

​ %逐个蚂蚁计算

​ for i = 1:m

​ %逐个城市计算

​ for j = 1:(n-1)

​ Delta_Tau(Table(i,j),Table(i,j+1)) = Delta_Tau(Table(i,j),Table(i,j+1)) + Q / Length(i);

​ % 计算信息素增量

​ end

​ Delta_Tau(Table(i,n),Table(i,1)) = Delta_Tau(Table(i,n),Table(i,1)) + Q/Length(i);

​ % 考虑回到起点的信息素增量

​ end

​ Tau = (1-rho) * Tau + Delta_Tau; % 更新信息素

​ %迭代次数+1,清空路径记录表

​ iter = iter + 1;

​ Table = zeros(m,n);

end

%% 结果显示

[Shortest_Length,index] = min(Length_best); % 获取最短路径长度及其索引

Shortest_Route = Route_best(index,:); % 获取最短路径

disp(['最短距离:' num2str(Shortest_Length)]);% 显示最短路径长度

disp(['最短路径:' num2str([Shortest_Route Shortest_Route(1)])]);% 显示最短路径

%% 绘图

figure(1)

plot([citys(Shortest_Route,1);citys(Shortest_Route(1),1)],...

​ [citys(Shortest_Route,2);citys(Shortest_Route(1),2)],'o-');

grid on

for i = 1:size(citys,1)

​ 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),citys(Shortest_Route(end),2),' 终点');

xlabel('城市位置横坐标')

ylabel('城市位置纵坐标')

title(['蚁群算法优化路径(最短距离:' num2str(Shortest_Length) ')'])

figure(2)

plot(1:iter_max,Length_best,'b',1:iter_max,Length_ave,'r:')

legend('最短距离','平均距离')

xlabel('迭代次数')

ylabel('距离')

title('各代最短距离与平均距离对比')