这几天抽空把蚁群算法用matlab实现了,感觉还是有些小问题啊。
首先介绍一下模型,很简单,如下所示,一个10*10的点阵,蚂蚁从(1,1)出发,食物在(5,10),蚂蚁每次可以走到的点为(x-1 : x+1,y-1 : y+1),比如说,现在蚂蚁在(1,1),下一步它可以走到的点有(1,2)、(2,1)以及(2,2)。另外需要注意的是,虽然蚂蚁走到(1,2)和(2,1)的路程要小于走到(2,2)的路程,此处不再加以区分,一律用一个步长表示。
用matlab实现的具体思路如下:先构建一个蚂蚁类Ant,它有很多的属性,比如说当前所在的格点、当前所走的路程、已经走到的格点、下一步可能走到的格点等等;另外还有3个方法,初始化方法Ant()、代表寻找下一个格点的方法FindNext()以及代表行走的方法Move2Next()。
好了,下面上代码。代码并不多,加起来也就100行刚出头。
=======================================
%%蚂蚁类定义
classdef Ant < handle
properties
pStart %初始格点
pEnd %结束铬点
pNow %当前格点
pNext %下一步可能的格点
pNextNumber %pNext的数目
pOccupied %已经走过的格点
tabooTable %标记格点状态,0表示没有走过,1表示走过
walkLength %走过的总步长
stateFlag %状态标记,用于结束行走判定
end
methods
function obj = Ant()
obj.pStart = [1 1];
obj.pEnd = [5 10];
obj.pNow = obj.pStart;
obj.pNextNumber = 0;
obj.pNext = [0 0];
obj.tabooTable = zeros(10, 10);
obj.walkLength = 0;
obj.stateFlag = 0;
obj.FindNext();
end
function FindNext(obj)
x = obj.pNow(1);
y = obj.pNow(2);
obj.tabooTable(x, y) = 1;
for i = (x-1) : (x+1)
for j = (y-1) : (y+1)
if(i>0 && i<11 && j>0 && j<11)
if(obj.tabooTable(i, j) == 0)
obj.pNextNumber = obj.pNextNumber + 1;
obj.pNext(obj.pNextNumber, :) = [i j];
end
end
end
end
end
function Move2Next(obj, parfum) %parfum为输入的信息素信息
pcum = zeros(obj.pNextNumber, 1);
for i = 1 : obj.pNextNumber
pcum(i) = parfum(obj.pNext(i, 1), obj.pNext(i, 2)) / DISTANCE(obj.pNext(i, :), obj.pEnd)^8;
end
pcum = pcum / sum(pcum);
for i = 2 : obj.pNextNumber
pcum(i) = pcum(i) + pcum(i-1);
end
p = rand;
picked = 0;
for i = 1 : obj.pNextNumber
if(pcum(i) > p)
picked = i;
break;
end
end
obj.walkLength = obj.walkLength + 1;
obj.pOccupied(obj.walkLength, :) = obj.pNow;
obj.pNow = obj.pNext(picked, :);
obj.pNextNumber = 0;
obj.pNext = [0 0];
obj.FindNext();
if(obj.pNow(1)==obj.pEnd(1) && obj.pNow(2)==obj.pEnd(2))
obj.stateFlag = 1;
end
if(obj.pNextNumber == 0)
obj.stateFlag = -1;
end
end
end
end
function D = DISTANCE(p1, p2)
D = sqrt((p1(1) - p2(1))^2 + (p1(2) - p2(2))^2)+0.1;%加0.1是为了防止分母出现0
end
==========================================
下面是主函数
==========================================
%%主函数
function parfum = AntWalk
parfum = ones(10, 10);
for i = 1 : 500
ant = Ant();
while(ant.stateFlag == 0)
ant.Move2Next(parfum);
end
if(ant.stateFlag == 1)
parfum = parfum * 0.1; %信息素挥发
for j = 1 : ant.walkLength
parfum(ant.pOccupied(j, 1), ant.pOccupied(j, 2)) = parfum(ant.pOccupied(j, 1), ant.pOccupied(j, 2)) + 1 / ant.walkLength;
end
parfum(ant.pEnd(1), ant.pEnd(2)) = parfum(ant.pEnd(1), ant.pEnd(2)) + 1 / ant.walkLength;
end
clear ant;
end
end
==========================================
好了,程序写完了,下面检验一下吧!
放了500只蚂蚁行走,全部走完之后信息素的分布情况如下:
0.1235 0.1235 0 0 0 0 0 0 0 0
0 0 0.1235 0 0 0 0 0 0 0
0 0 0 0.1235 0 0 0 0 0 0
0 0 0 0 0.1235 0 0 0 0 0
0 0 0 0 0 0.1235 0.1235 0 0.1235 0.1235
0 0 0 0 0 0 0 0.1235 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
看上去还可以的样子,这就是最短的路径了,数数看从起始点到终点一共走了9步,确实是最佳的选择。
接下来提升一下难度,在格点中设置一些障碍,看看还能不能得到最佳结果。
上图中的黑点表示蚂蚁不可走到的点,只要在之前的代码中将tabooTable重新初始化就可以了。在obj.tabooTable=zero(10,10)之后加入如下代码即可:
obj.tabooTable(2,8) = 1;
obj.tabooTable(3,7:8) = 1;
obj.tabooTable(4,6:7) = 1;
obj.tabooTable(5,5:6) = 1;
obj.tabooTable(6,5) = 1;
运行结果为:
0.1010 0 0 0 0 0 0 0.1010 0 0
0 0.1010 0 0 0 0 0.1010 0 0.1010 0
0 0 0.1010 0 0.1010 0.1010 0 0 0.1010 0
0 0 0 0.1010 0 0 0 0 0 0.1010
0 0 0 0 0 0 0 0 0 0.1010
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
嗯,真的很不错的样子!
好了,蚁群算法就写到这里了,从实现的结果来看效果还是可以的,能很快地找到问题的最优解。