蚁群算法是对自然界蚂蚁的寻径方式进行模似而得出的一种仿生算法。蚂蚁在运动过程中,能够在它所经过的路径上留下一种称之为外激素(pheromone)的物质进行信息传递,而且蚂蚁在运动过程中能够感知这种物质,并以此指导自己的运动方向,因此由大量蚂蚁组成的蚁群集体行为便表现出一种信息正反馈现象:某一路径上走过的蚂蚁越多,则后来者选择该路径的概率就越大。
在蚁群寻找食物时,它们总能找到一条从食物到巢穴之间的最优路径。这是因为蚂蚁在寻找路径时会在路径上释放出一种特殊的信息素。当它们碰到一个还没有走过的路口时.就随机地挑选一 条路径前行。与此同时释放出与路径长度有关的信息素。路径越长, 释放的激索浓度越低.当后来的蚂蚁再次碰到这个路口的时候.选择 激素浓度较高路径概率就会相对较大。这样形成一个正反馈。最优路径上的激索浓度越来越大.而其它的路径上激素浓度却会随着时间的流逝而消减。最终整个蚁群会找出最优路径。
ACO算法的实现要分析几个要素,分别是构建图、约束、信息素和启发式信息、解的构建、信息素更新等。
对TSP问题而言:
构建图与问题的描述相一致,即且每一条边都带有一个权值代表点之间的距离,问题的状态就是旅行商在游历过程中出现的 所有可能的状态的集合。
约束:在TSP中唯一的约束就是在旅行商游历的 过程中,所有城市都要被访问且每一个城市最多只能被访问一次。
信息素和启发式信息:TSP中的信息素表示在访问城市 i 后直接访问城市 j 的期望度。启发式信息代表蚂蚁随机选择下一城市的概率,要根据实际情况进行取值,一般直接取两城市之间距离的倒数。
解的构建:每一只蚂蚁最初都从随机选择出来的起点城市出发,每经过一次迭代蚂蚁就向解中添加 一个还没有访问过的城市,当所有城市都被蚂蚁访问过之后,解的构建就终止。在解的构建过中, 蚂蚁都是利用信息素和启发式信息以一定的概率P从候选城市中选择。
在参数α和β的作用如下:如果α=0,则最靠近 的城市最有可能被选出,这相当于一种经典的随机贪心算法;如果 β=0,那么就只有信息素的放大系数在起作用,也就是说,算法只使用了信息素而没有利用任何启发式信息带来的偏向性,特别是当α>1时算法很快就会陷入停滞状态。
信息素更新:当所有蚂蚁都构建好路径后,各边上的信息素将会被更新。首先,所有边上的信息素都会减少一 个常量因子的大小,然后在蚂蚁经过的边上增加信息素。信息素的蒸发根据下面的式子执行:
其中ρ是信息素蒸发率,有0<ρ<1 。参数ρ的作用是避免信息素的无限积累,而且还可以使算法“忘记”之前较差的路径。
在信息素的蒸发步骤之后,所有蚂蚁都在它们经过的边上释放信息素:
其中C代表了第k只蚂蚁建立的路径的长度。
根据上式我们可以看到,蚂蚁构建的路径越好,路径上的各条边就会获得更多的信息素。 一般而言,如果一条边被更多蚂蚁选择,而该边所在的路径总长度越短,那么这条边就会获得越多的信息素,在以后的迭代中它就更有可能被蚂蚁选择。
下面是用ACO解决TSP问题的python代码。
#蚁群优化解TSP问题
import numpy as np
import random as rd
def lengthCal(antPath,distmat): #计算距离
length =[]
dis = 0
for i in range(len(antPath)):
for j in range(len(antPath[i]) - 1):
dis += distmat[antPath[i][j]][antPath[i][j + 1]]
dis += distmat[antPath[i][-1]][antPath[i][0]]
length.append(dis)
dis = 0
return length
distmat = np.array([[0,35,29,67,60,50,66,44,72,41,48,97],
[35,0,34,36,28,37,55,49,78,76,70,110],
[29,34,0,58,41,63,79,68,103,69,78,130],
[67,36,58,0,26,38,61,80,87,110,100,110],
[60,28,41,26,0,61,78,73,103,100,96,130],
[50,37,63,38,61,0,16,64,50,95,81,95],
[66,55,79,61,78,16,0,49,34,82,68,83],
[44,49,68,80,73,64,49,0,35,43,30,62],
[72,78,103,87,103,50,34,35,0,47,32,48],
[41,76,69,110,100,95,82,43,47,0,26,74],
[48,70,78,100,96,81,68,30,32,26,0,58],
[97,110,130,110,130,95,83,62,48,74,58,0]])
antNum = 12 #蚂蚁数量
alpha = 1 #信息素重要程度因子
beta = 3 #启发函数重要程度因子
pheEvaRate = 0.3 #信息素蒸发率
cityNum = distmat.shape[0]
pheromone = np.ones((cityNum,cityNum)) #信息素矩阵
heuristic = 1 / (np.eye(cityNum) + distmat) - np.eye(cityNum) #启发式信息矩阵,取1/dismat
iter,itermax = 1,100 #迭代次数
while iter < itermax:
antPath = np.zeros((antNum, cityNum)).astype(int) - 1 #蚂蚁的路径
firstCity = [i for i in range(12)]
rd.shuffle(firstCity) #随机为每只蚂蚁分配起点城市
unvisted = []
p = []
pAccum = 0
for i in range(len(antPath)):
antPath[i][0] = firstCity[i]
for i in range(len(antPath[0]) - 1): #逐步更新每只蚂蚁下一个要去的城市
for j in range(len(antPath)):
for k in range(cityNum):
if k not in antPath[j]:
unvisted.append(k)
for m in unvisted:
pAccum += pheromone[antPath[j][i]][m] ** alpha * heuristic[antPath[j][i]][m] ** beta
for n in unvisted:
p.append(pheromone[antPath[j][i]][n] ** alpha * heuristic[antPath[j][i]][n] ** beta / pAccum)
roulette = np.array(p).cumsum() #生成轮盘
r = rd.uniform(0, max(roulette))
for x in range(len(roulette)):
if roulette[x] >= r: #使用轮盘法选择下一个要去的城市
antPath[j][i + 1] = unvisted[x]
break
unvisted = []
p = []
pAccum = 0
pheromone = (1 - pheEvaRate) * pheromone #信息素挥发
length = lengthCal(antPath,distmat)
for i in range(len(antPath)):
for j in range(len(antPath[i]) - 1):
pheromone[antPath[i][j]][antPath[i][j + 1]] += 1 / length[i] #信息素更新
pheromone[antPath[i][-1]][antPath[i][0]] += 1 / length[i]
iter += 1
print("最短距离为:")
print(min(length))
print("最短路径为:")
print(antPath[length.index(min(length))])