TSP问题——ACO(蚁群算法)解法
1、蚁群算法简介
蚁群算法(Ant Colony Optimization, ACO),又称蚂蚁算法,是一种用来在图中寻找优化路径的机率型算法。它由Marco Dorigo于1992年在他的博士论文“Ant system: optimization by a colony of cooperating agents”中提出,其灵感来源于蚂蚁在寻找食物过程中发现路径的行为。蚁群算法是一种模拟进化算法,初步的研究表明该算法具有许多优良的性质。针对PID控制器参数优化设计问题,将蚁群算法设计的结果与遗传算法设计的结果进行了比较,数值仿真结果表明,蚁群算法具有一种新的模拟进化优化方法的有效性和应用价值。
更详细的蚁群算法介绍见:蚁群算法
2、蚁群算法解TSP问题的程序源码(Python)
程序源码GitHub地址:点击下载
1、Ant包:主要封装蚁群算法种群信息的AntList类和包含单个个体对象单个个体对象的信息AntUnit类
# -*- coding: utf-8 -*-
"""
基于回溯法的旅行商问题解法Python源码
Author: Greatpan
Date: 2018.10.10
"""
import numpy as np
class AntList(object):
def __init__(self,distfunc,getEtatable,numant=5,numcity=10,alpha=1,rho=0.1,Q=1):
""" 构造函数 """
self.numant = numant # 蚂蚁个数
self.numcity = numcity # 城市个数
self.alpha = alpha # 信息素重要程度因子
self.rho = rho # 信息素的挥发速度
self.Q = Q # 品质因子
self.distfunc=distfunc
self.getEtatable=getEtatable
self.bestantunit=None
self.population=[]
self.pathtable = np.zeros((self.numant,self.numcity)).astype(int) # 路径记录表
self.generation=0
def Init_eta_phe(self):
"""
函数名:Init_eta_phe(self)
函数功能: 对启发函数和信息素进行初始化
输入 1 self:类自身
输出 1 无
其他说明:无
"""
self.etatable = self.getEtatable() # 启发函数矩阵,表示蚂蚁从城市i转移到矩阵j的期望程度
self.pheromonetable = np.ones((self.numcity,self.numcity)) # 信息素矩阵
def InitStartPosition(self):
"""
函数名:InitStartPosition(self)
函数功能: 初始化蚂蚁的起始位置
输入 1 self:类自身
输出 1 无
其他说明:无
"""
# 随机产生各个蚂蚁的起点城市
if self.numant <= self.numcity: # 城市数比蚂蚁数多
self.pathtable[:,0] = np.random.permutation(range(0,self.numcity))[:self.numant]
else: # 蚂蚁数比城市数多,需要补足
self.pathtable[:self.numcity,0] = np.random.permutation(range(0,self.numcity))[:]
self.pathtable[self.numcity:,0] = np.random.permutation(range(0,self.numcity))[:self.numant-self.numcity]
def upDateInf(self):
"""
函数名:upDateInf(self)
函数功能: 对信息素进行更新
输入 1 self:类自身
输出 1 无
其他说明:无
"""
changepheromonetable = np.zeros((self.numcity,self.numcity))
if self.population:
for antunit in self.population:
for i in range(self.numcity-1):
changepheromonetable[antunit.path[i]][antunit.path[i+1]] += self.Q/antunit.length
changepheromonetable[antunit.path[self.numcity-1]][antunit.path[0]] += self.Q/antunit.length
self.pheromonetable = (1-self.rho)*self.pheromonetable + changepheromonetable
else:
self.Init_eta_phe()
def getNextCity(self,unvisited,visiting):
"""
函数名:getNextCity(self,unvisited,visiting)
函数功能: 根据信息素和启发函数矩阵,通过轮盘赌法随机选下一个城市
输入 1 self:类自身
输入 2 unvisited:未走过的城市列表
输入 2 visited:已经走过的城市列表
输出 1 k:下一个城市的编号
其他说明:无
"""
listunvisited = list(unvisited)
probtrans = np.zeros(len(listunvisited))
for k in range(len(listunvisited)):
probtrans[k] = np.power(self.pheromonetable[visiting][listunvisited[k]],self.alpha)\
*np.power(self.etatable[visiting][listunvisited[k]],self.alpha)
cumsumprobtrans = (probtrans/sum(probtrans)).cumsum()
cumsumprobtrans -= np.random.rand()
k = listunvisited[np.where(cumsumprobtrans>0)[0][0]] # 下一个要访问的城市
return k
def GoOnePath(self,i):
"""
函数名:distance(self, path)
函数功能: 第i只蚂蚁从随机点出发找到一条路径
输入 1 self:类自身
输入 2 i:当代的第i只蚂蚁
输出 1 antunit:一个蚂蚁单元类
其他说明:无
"""
visiting = self.pathtable[i,0] # 当前所在的城市
unvisited = set(range(self.numcity))# 未访问的城市
unvisited.remove(visiting) # 删除元素
for j in range(1,self.numcity): # 循环numcity-1次,访问剩余的numcity-1个城市
# 每次用轮盘法选择下一个要访问的城市
k=self.getNextCity(unvisited,visiting)
self.pathtable[i,j] = k
unvisited.remove(k)
visiting = k
antunit=AntUnit(self.pathtable[i],self.distfunc(self.pathtable[i]))
if self.bestantunit:
if self.bestantunit.length>antunit.length:
self.bestantunit=antunit
else:
self.bestantunit=antunit
return antunit
def nextGeneration(self):
"""
函数名:nextGeneration(self)
函数功能: 产生下一代
输入 1 self:类自身
输出 1 无
其他说明:无
"""
self.upDateInf()
newPopulation = [] # 新种群
for i in range(self.numant):
newPopulation.append(self.GoOnePath(i))
self.population = newPopulation
self.generation += 1
class AntUnit(object):
"""
类名:GAUnit
类说明: 遗传算法个体类
"""
def __init__(self, aPath = None,aLength = -1):
""" 构造函数 """
self.path = list(aPath) # 个体的基因序列
self.length = aLength # 初始化适配值
2、TSP类:该类封装了利用ACO算法进行对TSP问题求解的过程
# -*- encoding: utf-8 -*-
"""
TSP问题GA求解包
Author: Greatpan
Date: 2018.11.21
"""
from Ant import AntList
from MyFuncTool import GetData,ResultShow,draw
import numpy as np
class TSP(object):
def __init__(self,Position,Dist,CityNum):
""" 构造函数 """
self.citys=Position # 城市坐标
self.dist=Dist # 城市距离矩阵
self.citynum=CityNum # 城市数量
self.ant =AntList(numant=25, # 蚂蚁个数
distfunc=self.distance, # 计算距离的函数
getEtatable=self.defEtatable, # 定义启发式矩阵函数
numcity=self.citynum, # 城市个数
alpha=1, # 信息素重要程度因子
rho=0.1, # 信息素的挥发速度
Q=1) # 品质因子
def defEtatable(self):
"""
函数名:defEtatable(self)
函数功能: 在蚁群算法中定义的启发式矩阵
输入 1 self:类自身
输出 1 无
其他说明:无
"""
return 1.0/(self.dist+np.diag([1e10]*self.citynum))
def distance(self, path):
"""
函数名:distance(self, path)
函数功能: 根据路径求出总路程
输入 1 self:类自身
输入 2 path:路径
输出 1 无
其他说明:无
"""
# 计算从初始城市到最后一个城市的路程
distance = sum([self.dist[city1][city2] for city1,city2 in
zip(path[:self.citynum], path[1:self.citynum+1])])
# 计算从初始城市到最后一个城市再回到初始城市所经历的总距离
distance += self.dist[path[-1]][0]
return distance
def run(self, generate=0):
"""
函数名:run(self, n=0)
函数功能: 遗传算法解旅行商问题的运行函数
输入 1 self:类自身
2 generate:种群迭代的代数
输出 1 self.ant.bestantunit.length:最小路程
2 self.ga.best.path:最好路径
3 distance_list:每一代的最好路径列表
其他说明:无
"""
distance_list = []
while generate > 0:
self.ant.nextGeneration()
distance = self.ant.bestantunit.length
distance_list.append(distance)
generate -= 1
return self.ant.bestantunit.length,self.ant.bestantunit.path,distance_list
##############################程序入口#########################################
if __name__ == '__main__':
Position,CityNum,Dist = GetData("./data/TSP25cities.tsp")
tsp = TSP(Position,Dist,CityNum)
generate=500
Min_Path,BestPath,distance_list=tsp.run(generate)
print(BestPath)
print(tsp.distance(BestPath))
# 结果打印
BestPath.append(BestPath[0])
ResultShow(Min_Path,BestPath,CityNum,"GA")
draw(BestPath,Position,"GA",True,range(generate), distance_list)