TSP问题——ACO(蚁群算法)解法(附源代码)

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)

你可能感兴趣的:(TSP问题)