蚂蚁算法的应用(01背包、函数极值、TSP)
笔者是一位大一的萌新,这篇算法是自己查阅文献以及参考别人的博客再加上自身的理解写出来的。有错误的地方希望及时指正。这篇文章我使用的是Matlab,后续会给出python版本。以后会陆续出其他的优化算法以及人工智能算法,机器学习,深度学习等。
这是我在b站的详细讲解
目录:
1. 原理
背景介绍
在了解蚂蚁算法前,首先当然是了解一下算法的背景。 在自然界中,蚂蚁总能找到一条从蚂蚁洞到食物的最短路径,这是人们观察出来的结果。这是为什么呢,因为有一个叫信息素的物质的存在。蚂蚁在运动过程中,能够感知这种物质的存在和这个物质的浓度,同时也会释放这种物质。
原理简介
在初始阶段,环境中的信息素浓度为0,此时,蚂蚁会随机选择路径到食物。如下图所示:
随后的蚂蚁,根据之前路径上的信息素,选择自己走哪一条路。
划重点!信息素是一个随时间挥发的物质。假设每只蚂蚁在单位时间留下的信息素相同,那么,路径越短,残留的信息素也就越多。蚂蚁选择这条路的概率也就越大。这条路上的蚂蚁也就越来越多,产生的信息素也越来越多了。因此形成了正反馈。最终得出最优路径。基本蚂蚁算法的参数和公式
以TSP问题为例子来讲解。
首先是初始化参数:
m:蚂蚁数量,约为城市数量的1.5倍。如果蚂蚁数量过大,则每条路径上的信息素浓度趋于平均,正反馈作用减弱,从而导致收敛速度减慢;如果过小,则可能导致一些从未搜索过的路径信息素浓度减小为0,导致过早收敛,解的全局最优性降低
alpha:信息素因子,反映了蚂蚁运动过程中积累的信息量在指导蚁群搜索中的相对重要程度,取值范围通常在[1, 4]之间。如果信息素因子值设置过大,则容易使随机搜索性减弱;其值过小容易过早陷入局部最优。这是为什么呢?看一下下面的公式1,alpha越大,那么信息素所占的比例也就越大,也就是信息素的重要性也就越大,那么蚂蚁就更倾向于走以前走过的最短路径,如果该路径,如下图所示:
那么,就会陷入局部最优解。反之,如果alpha值越小,那么信息素的重要新也就越小,结果就会倾向于局部最优解。
belta:启发函数因子,反映了启发式信息在指导蚁群搜索中的相对重要程度,取值范围在[3, 5]之间。如果值设置过大,虽然收敛速度加快,但是易陷入局部最优;其值过小,蚁群易陷入纯粹的随机搜索,很难找到最优解。同样,参照一下下面的公式1。belta越大,那么启发函数的重要新也就越大,蚂蚁在某个局部点的时候,选择局部最优解的概率也就越大,但是局部最优不代表着全局最优,所以容易陷入局部最优解。
rho:信息素挥发因子,反映了信息素的消失水平,相反的反映了信息素的保持水平,取值范围通常在[0.2, 0.5]之间。当取值过大时,容易影响随机性和全局最优性;反之,收敛速度降低
Q:信息素常数,表示蚂蚁遍历一次所有城市所释放的信息素总量。越大则收敛速度越快,但是容易陷入局部最优;反之会影响收敛速度
n:城市数量
d:城市i到城市j之间的距离
tau:t时刻,城市i与城市j之间的信息素浓度
pc:t时刻,蚂蚁k从城市i向城市j转移的概率
Heu_F:启发函数,表示蚂蚁从城市i转移到城市j的期望程度,这里我们取值为距离的倒数。(很好理解)
allow:蚂蚁k待访城市的集合,初始时刻中有个元素,即排除掉蚂蚁一开始所在城市以外的其他城市,随着时间推移,其中的城市越来越少,直到为空,表示遍历完所有的城市
:表示在所有蚂蚁遍历完所有城市时,第k只蚂蚁对城市i与城市j之间信息素浓度总增加量的贡献量
:表示所有蚂蚁遍历完所有城市时,城市i与城市j之间信息素浓度的累积增加量
:表示蚂蚁k遍历完所有城市后经历的总路程长度
然后给出三个重要的公式:
公式1:
从公式中可以看出信息素因子为信息素浓度的指数,启发函数因子为启发函数的指数,这样便很好理解这两个参数所起到的作用了,分别决定了信息素浓度以及转移期望对于蚂蚁k从城市i转移到城市j的可能性的贡献程度。
公式2:
这个公式反映了信息素浓度的迭代更新规律,可以看出,所有蚂蚁遍历完一次所有城市后,当前信息素浓度由两部分组成,第一部分即上次所有蚂蚁遍历完所有城市后路径上信息素的残留,第二部分为本次所有蚂蚁遍历完所有城市后每条路径上的信息素的新增量。
公式3:
公式三反映了每只蚂蚁对于自己经过的城市之间路径上信息素浓度的贡献量,可以看出,其经历的路程越长,则对于沿途上信息素浓度的贡献量也就越低,如果尽力的路程越短,则对于沿途上信息素浓度的贡献量也就越高,结合公式二可以看出,信息素浓度累积贡献量大的路径被选择的概率也就大,这就是为什么能够选出最短路径的原因。关于的计算还有一些其他模型,这里就不详细介绍了,我们这里给出的是ant cycle system模型,也是TSP问题中常用的一种模型。
基本蚂蚁算法的流程
2. 应用
TSP
clear;
close all;
clc;
n = 31;
x = rand(1,n)*100; %
y = rand(1,n)*100; %
D = zeros(n,n);
for i = 1:n
for j = 1:n
if i~=j
D(i,j) = sqrt(power(x(i)-x(j),2)+power(y(i)-y(j),2));
else
D(i,j) = 1e-3;
end
end
end
m = 75;
Alpha = 1;
Beta = 5;
Rho = 0.2;
Q = 10;
Heu_F = 1./D;
Tau = ones(n,n);
Table = zeros(m,n);
iter = 1;
iter_max = 500; %
Route_best = zeros(iter_max,n);
Length_best = zeros(iter_max,1);
while iter <= iter_max
start = zeros(m,1);
for i = 1:m
temp = randperm(n);
start(i) = temp(1);
end
Table(:,1) = start;
city_index = 1:n;
for i = 1:m
for j = 2:n
has_visited = Table(i,1:(j-1)); %
allow_index = ~ismember(city_index,has_visited);
allow = city_index(allow_index);
P = allow;
for k = 1:length(allow)
P(k) = Tau(has_visited(end),allow(k))^Alpha * Heu_F(has_visited(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
[min_Length,min_index] = min(Length);
if iter > 1
if min_Length > Length_best(iter - 1)
Length_best(iter) = Length_best(iter-1);
Route_best(iter,:) = Route_best(iter-1,:);
else
Length_best(iter) = min_Length;
Route_best(iter,:) = Table(min_index,:);
end
else
Length_best(iter) = min_Length;
Route_best(iter,:) = Table(min_index,:);
end
iter
iter = iter + 1;
Delta_Tau = zeros(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
end
Tau = (1-Rho)*Tau + Delta_Tau;
Table = zeros(m,n);
end
plot(Length_best);
函数极值
clear;
close all;
clc;
m = 20;
Dimension = 2;
iter_max = 500;
Rho = 0.9;
Q = 10;
Alpha = 1;
Belta = 5;
Upper = [5;5];
Lower = [-5;-5];
X = zeros(m,Dimension);
for i = 1:m
X(i,:) = rand(2,1).*(Upper-Lower)+Lower;
Tau(i) = func(X(i,:));
if Tau(i) == 0
Tau(i) = 1e-3;
end
end
Heu_F = 1./Tau;
step = 0.1;
iter = 1;
while iter <= iter_max
P = zeros(m,1);
for i = 1:m
P(i) = P(i) + Tau(i)^Alpha * Heu_F(i)^Belta;
end
P = P / sum(P);
Pc = cumsum(P);
t = rand;
jubu_index = find(Pc >= t);
quanju_index = find(Pc < t);
for i = 1:length(jubu_index)
t = jubu_index(i);
temp1 = X(i,1) + (2*rand-1)*step;
temp2 = X(i,2) + (2*rand-1)*step;
if temp1 > Upper(1)
temp1 = Upper(1);
end
if temp1 < Lower(1)
temp1 = Lower(1);
end
if temp2 > Upper(2)
temp2 = Upper(2);
end
if temp2 < Lower(2)
temp2 = Lower(2);
end
if func([temp1,temp2]) < func(X(t,:))
X(t,:) = [temp1,temp2]
end
end
for i = 1:length(quanju_index)
t = quanju_index(i);
temp1 = rand*(Upper(1)-Lower(1))+Lower(1);
temp2 = rand*(Upper(2)-Lower(2))+Lower(2);
if temp1 > Upper(1)
temp1 = Upper(1);
end
if temp1 < Lower(1)
temp1 = Lower(1);
end
if temp2 > Upper(2)
temp2 = Upper(2);
end
if temp2 < Lower(2)
temp2 = Lower(2);
end
if func([temp1,temp2]) < func(X(t,:))
X(t,:) = [temp1,temp2]
end
end
iter
iter = iter + 1;
for i = 1:m
Tau(i) = (1-Rho)*Tau(i) + func(X(i,:));
end
[Value,index] = min(Tau);
trace(iter) = func(X(index,:));
end
plot(trace)
function results = func(x)
results = 20*(x(1)^2-x(2)^2)^2 - (1-x(2))^2 -3*(1+x(2))^2 + 0.3;
end
01背包
clear;
close all;
clc;
n = 50;
V = 1000;
u = [80 82 85 70 72 70 66 50 55 25 50 55 40 48 50 32 22 60 30 32 40 38 35 32 25 28 30 22 25 30 45 30 60 50 20 65 20 25 30 10 20 25 15 10 10 10 4 4 2 1];
p = [220 208 198 192 180 180 165 162 160 15 8 155 130 125 122 120 118 115 110 105 101 100 100 98 9 6 95 90 88 82 80 77 75 73 72 70 69 66 65 63 60 58 56 5 0 30 20 15 10 8 5 3 1 ];
Alpha = 0.7;
Beta = 0.3;
iter_max = 200;
Q = 1;
m = 10;
Rho = 0.1;
Tau = ones(1,n);
Table = zeros(m,n);
Route_best = zeros(iter_max,n);
Value_best = zeros(iter_max,1);
Heu_F = zeros(1,n);
for i = 1:n
Heu_F(i) = p(i) / u(i);
end
iter =1;
while iter <= iter_max
start = zeros(m,1);
for i = 1:m
temp = randperm(n);
start(i) = temp(1);
end
Table(:,1) = start;
city_index = 1:n;
for i = 1:m
for j = 2:n
if Table(i,j-1) == 0
continue;
end
has_visited = Table(i,1:(j-1));
temp = 0;
allow_index = ~ismember(city_index,has_visited);
allow = city_index(allow_index);
temp = 0;
for l = 1:length(has_visited)
temp = temp + u(has_visited(l));
end
for l = 1:length(allow)
if temp + u(allow(l)) > V
allow(l) = 0;
end
end
allow(allow == 0) = [];
if isempty(allow)
continue;
end
P = allow;
for k = 1:length(allow)
P(k) = (Tau(allow(k))^Alpha)*(Heu_F(allow(k))^Beta);
end
if P == 0
P = 0;
else
P = P / sum(P);
Pc = cumsum(P);
target_index = find(Pc >= rand);
target = allow(target_index(1));
Table(i,j) = target;
end
end
end
Value = zeros(m,1);
for i = 1:m
Route = Table(i,:);
for j = 1:n
if Route(j) > 0
Value(i) = Value(i) + p(Route(j));
end
end
end
[max_Value,max_index] = max(Value);
if iter == 1
Value_best(iter) = max_Value;
Route_best(iter,:) = Table(max_index,:);
else
if max_Value < Value_best(iter-1)
Value_best(iter) = Value_best(iter-1);
Route_best(iter,:) = Route_best(iter-1,:);
else
Value_best(iter) = max_Value;
Route_best(iter,:) = Table(max_index,:);
end
end
iter = iter + 1;
Delta_Tau = zeros(n,n);
for i = 1:m
for j = 1:(n-1)
if Table(i,j) > 0 && Table(i,j+1)>0
Delta_Tau(Table(i,j),Table(i,j+1)) = Delta_Tau(Table(i,j),Table(i,j+1)) + Q/Value(i);
end
end
end
Tau = (1-Rho)*Tau + Delta_Tau;
Table = zeros(m,n);
end
plot(Value_best)