python实现蚁群算法解决TSP问题


蚁群算法简单介绍

蚁群算法 模仿蚂蚁集体寻径行为 提出的算法,属于种群启发式搜索算法。算法通过蚂蚁在路径上留下信息素和大量蚂蚁的引入,诱使蚂蚁在选择 路径时 容易对更优的路径进行选择。 蚂蚁的选择属于随机选择,目的地路径上的信息素和长度决定了选择该路径的可能性(概率),在路径长度固定的情况下,路径上信息素越多,蚂蚁选择该路径的概率越大。 从而形成正反馈的效果,最终致使算法收敛。

蚁群算法概念

概念符号解释
人工蚂蚁ant搜索解的单元,本身具有记忆(存储)解的能力,自身的行为就是在探索可行解
禁忌表tabu记录蚂蚁已经走过的城市(体现蚂蚁的记忆功能)
信息素蚂蚁在两城市路径之间留下的标记,可以理解为一种权重
信息素蒸发系数ρ反映信息素在路径上随时间的蒸发速度(在算法中是每一次迭代之后,信息素丢失的比例)
转移概率Pij蚂蚁从 i 城市向 j 城市 转移时所依据的概率阈值

转移概率

第k只蚂蚁,Sk是第k只蚂蚁没有去过的城市集合,从城市 i 向城市 j 转移的概率定义为
τ是信息素,表示群体探索解的经验
η是路径的度量,一般采用距离的导数,表示先验经验

p i j k = { τ i j α ⋅ η i j β ∑ s ∈ S k [ τ i s α ⋅ η i s β ] , j 不 在 t a b u 中 0 , j 在 t a b u 中 p_{ij}^{k} = \begin{cases} \frac{τ_{ij}^{α}·η_{ij}^{β}}{\sum_{s∈S_k}[τ_{is}^{α}·η_{is}^{β}]}&,j不在tabu中\\ \\ 0&,j在tabu中\\ \end{cases} pijk=sSk[τisαηisβ]τijαηijβ0,jtabu,jtabu

该概率其实就是通往城市 j 路径的权重在所有可选路径权重中所占的比例
	比如下图中蚂蚁从城市i转移至城市j的概率,Sk = {h,j,l}

w i j = τ i j α ⋅ η i j β w i h = τ i h α ⋅ η i h β w i h = τ i l α ⋅ η i l β p i j k = w i j w i h + w i j + w i l \begin{array}{lcl} w_{ij} = τ_{ij}^{α}·η_{ij}^{β}\\ w_{ih} = τ_{ih}^{α}·η_{ih}^{β}\\ w_{ih} = τ_{il}^{α}·η_{il}^{β}\\ \\ p_{ij}^{k} = \frac{w_{ij}}{w_{ih}+w_{ij}+w_{il}} \end{array} wij=τijαηijβwih=τihαηihβwih=τilαηilβpijk=wih+wij+wilwij

蚂蚁转移概率

算法流程

流程图

信息素更新

信息素更新公式

假设m只蚂蚁,n座城市,t时刻 到 t+n时刻信息素的更新
τ i j ( t + n ) = ( 1 − ρ ) τ i j ( t ) + ∑ k = 1 m Δ τ i j k τ_{ij}(t+n) = (1-ρ)τ_{ij}(t) + \sum_{k=1}^{m}Δτ_{ij}^{k} τij(t+n)=(1ρ)τij(t)+k=1mΔτijk

Δτ_{ij}^{k}表示第k只蚂蚁从城市i到城市j 在路径上留下的信息素

τ_{ij}是城市i到城市j路径上的信息素

ρ的大小影响着算法的收敛速度和搜索能力
	ρ越小算法的全局搜索和随机搜索能力越好,但是算法也越不容易收敛
	ρ越大算法的全局搜索能力减弱,算法收敛能力增强,但同时算法也容易陷入局部最优解
三种信息素更新模型
Lk 表示 蚂蚁走完全部30个城市之后的路径长度,dij是城市i到城市j之间的路径长度,Q为常数
蚁周模型

Δ τ i j k = { Q L k , 若 蚂 蚁 k 由 城 市 i 转 移 至 城 市 j ( 也 可 以 理 解 为 经 过 路 径 i j ) 0 , 蚂 蚁 未 经 过 Δτ_{ij}^{k} = \begin{cases} \frac{Q}{L_k} ,若蚂蚁k由城市i 转移至城市j(也可以理解为经过路径ij) \\ \\ 0,蚂蚁未经过 \end{cases} Δτijk=LkQkijij0

蚁密模型

Δ τ i j k = { Q , 若 蚂 蚁 k 由 城 市 i 转 移 至 城 市 j ( 也 可 以 理 解 为 经 过 路 径 i j ) 0 , 蚂 蚁 未 经 过 Δτ_{ij}^{k} = \begin{cases} Q,若蚂蚁k由城市i 转移至城市j(也可以理解为经过路径ij) \\ \\ 0,蚂蚁未经过 \end{cases} Δτijk=Qkijij0

蚁量模型

Δ τ i j k = { Q d i j , 若 蚂 蚁 k 由 城 市 i 转 移 至 城 市 j ( 也 可 以 理 解 为 经 过 路 径 i j ) 0 , 蚂 蚁 未 经 过 Δτ_{ij}^{k} = \begin{cases} \frac{Q}{d_{ij}} ,若蚂蚁k由城市i 转移至城市j(也可以理解为经过路径ij) \\ \\ 0,蚂蚁未经过 \end{cases} Δτijk=dijQkijij0

TSP问题简介

TSP,全称Travelling Salesman Problem (旅行商问题)
给出城市坐标,求解旅行商 如何每个城市仅经过一次就可以遍历所有城市,而且要求路径长度最短

城市坐标

城市坐标城市坐标城市坐标
0(18,54)10(71,44)20(7,64)
1(87,76)11(64,60)21(22,60)
2(74,78)12(68,58)22(25,62)
3(71,71)13(83,69)23(62,32)
4(25,38)14(58,69)24(87,7)
5(58,35)15(54,62)25(91,38)
6(4,50)16(51,67)26(83,46)
7(13,40)17(37,84)27(41,26)
8(18,40)18(41,94)28(45,21)
9(24,42)19(2,99)29(44,35)

编码

城市编号从0至29,而且需要记录30个城市的顺序,所以采用实数编码
	具体形式如下:
			编码空间中的一个编码,也就是解空间中的一个解,也是种群中的一个个体
			用向量表示
					path = [20, 1, 3, 7, 14, 25, 10, 2, 27, 24, 8, 0, 16, 26, 22, 5, 18, 28, 4, 19, 13, 12, 11, 21, 6, 23, 29, 9, 17, 15]
			该向量含义:
			从城市20开始,经历城市1,3,7, 14, 25, 10, 2, 27, 24, 8, 0, 16, 26, 22, 5, 18, 28, 4, 19, 13, 12, 11, 21, 6, 23, 29, 9, 17 ,到城市15再回到20结束

目标函数

将路径长度函数作为目标函数,两城市间 距离按照欧式距离(向量差的二范数)计算
定义城市 i 和城市 j 之间的距离,用Xi代表第i个城市的坐标,Xj代表第j个城市的坐标

d i s t ( i , j ) = ∥ X i − X j ∥ 2 dist(i,j)= \left\|Xi-Xj\right\|_2 dist(i,j)=XiXj2

定义推销员走过的路径总长度,path[i]代表路径中经过的第i个城市的编号,数据可以参考上一段中编码的内容
path作为一个可行解

t a r g e t f u n c ( p a t h ) = ∑ i = 0 28 d i s t ( p a t h [ i ] , p a t h [ i + 1 ] ) + d i s t ( p a t h [ 29 ] , p a t h [ 0 ] ) targetfunc(path) = \sum_{i=0}^{28} dist(path[i],path[i+1]) + dist(path[29],path[0]) targetfunc(path)=i=028dist(path[i],path[i+1])+dist(path[29],path[0])

编程实现

编程思路

给每一只蚂蚁定义一个字典储存信息,三个键tabu(禁忌表)、Lk(剩余城市)和L(当前路径长度)
字典类型dict,三个键数据类型str,tabu的值数据类型是list,Lk的值的数据类型是list,L的值的数据类型是float

城市间距离先计算好,之后计算距离时仅加运算以减小不必要的消耗
信息素和距离计算时,从信息素储存矩阵和城市距离矩阵中取出,存入数据类型为numpy.array的向量中(主要是方便计算转移概率时的幂运算)

代码

jupyter文件代码
In[1]:
	import numpy as np
	import random
	from copy import deepcopy
In[2]:
	#位置信息
	locations = [
	    [18,54],[87,76],[74,78],[71,71],[25,38],
	    [58,35],[4,50],[13,40],[18,40],[24,42],
	    [71,44],[64,60],[68,58],[83,69],[58,69],
	    [54,62],[51,67],[37,84],[41,94],[2,99],
	    [7,64],[22,60],[25,62],[62,32],[87,7],
	    [91,38],[83,46],[41,26],[45,21],[44,35]
	]
In[3]:
	#快速幂运算
	def pow_mat(mat,p):
	    tmp = deepcopy(mat)
	    if p==1:
	        return tmp
	    j = 1
	    while j<p:
	        j = j<<1
	        tmp *= tmp
	        if p-j==1:
	            tmp *= mat
	            break
	    return tmp
In[4]:
	def dist(x,y):
	    return round(((x[0]-y[0])**2+(x[1]-y[1])**2)**0.5,2)
	#轮盘赌选择实现
	def choice(rs):
	    p = random.random()
	    i = 0
	    while p>0:
	        p -= rs[i]
	        i += 1
	    return i-1
In[5]:
	#城市间距离矩阵
	cities_dis = np.array([0.1 for i in range(30)]*30).reshape(30,30)
	for i in range(30):
	    for j in range(i+1,30):
	        tmp = dist(locations[i],locations[j])
	        cities_dis[i][j] = tmp
	        cities_dis[j][i] = tmp
	#城市间距离倒数矩阵
	cities_dis_recip = 1/cities_dis    
In[6]:
	#蚂蚁决策
	def decision(city_now,jk,alp,beta):
	    global cities_phernomones
	    global cities_dis_recip
	    tmp_recip = []
	    tmp_pheno = []
	    for item in jk:
	        tmp_recip.append(cities_dis_recip[city_now][item])
	        tmp_pheno.append(cities_phernomones[city_now][item])
	    tmp_recip = np.array(tmp_recip)
	    tmp_pheno = np.array(tmp_pheno)
	    tmp_recip = pow_mat(tmp_recip,beta)
	    tmp_pheno = pow_mat(tmp_pheno,alp)
	    p = tmp_recip*tmp_pheno
	    s = np.sum(p)
	    p /= s
	    id = choice(p)
	    return jk[id]
In[7]:
	#蚂蚁周游
	def walk_cycle(ant,alpha,beta):
	    global cities_dis
	    while ant['Jk'] != []:
	        id = decision(ant['tabu'][-1],ant['Jk'],alpha,beta)
	        ant['Jk'].remove(id)
	        ant['L'] += cities_dis[ant['tabu'][-1],id]
	        ant['tabu'].append(id)
	    ant['L'] += cities_dis[ant['tabu'][-1],0]
In[8]:
	#重置函数
	def reset_ant(ant):
	    start = random.randint(0,29)
	    ant['tabu'] = [start]
	    ant['Jk'] = [i for i in range(30) if i!=start]
	    ant['L'] = 0
In[9]:
	#初始化蚂蚁群
	ants = []
	for i in range(50):
	    start = random.randint(0,29)
	    tmp = {'tabu':[start],'Jk':[i for i in range(30) if i!=start],'L':0}
	    ants.append(tmp)
In[10]:
	#参数
	Np = 50
	alpha = 1
	beta = 3
	Q = 1
	rho = 0.1
In[11]:
	G = 200
	cities_order = []
	#蚁周模型
	#info_c = {}
	#蚁密模型
	#info_d = {}
	#蚁量模型
	info_q = {}
	path_q = {}
	best = 1e5
	
	#城市间路径信息素矩阵
	cities_phernomones = np.array([1 for i in range(30)]*30).reshape(30,30)
	
	while G>0:
	    G -= 1
	    tmp = 1e5
	    #蚂蚁周游 并记录最优路径
	    for i in range(Np):
	        walk_cycle(ants[i],alpha,beta)
	        if ants[i]['L']<best:
	            best = ants[i]['L']
	            cities_order = ants[i]['tabu']
	        if ants[i]['L']<tmp:
	            tmp = ants[i]['L']
	            path_q[200-G] = deepcopy(ants[i]['tabu'])
	    info_q[200-G] = tmp
	    #信息素挥发
	    cities_phernomones = (1-rho)*cities_phernomones
	    #按照蚁周模型更新信息素
	    for i in range(Np):
	        for j in range(30):
	            m,n = ants[i]['tabu'][j-1],ants[i]['tabu'][j]
	            #蚁量模型
	            # cities_phernomones[m][n] += Q/cities_dis[m][n]
	            # cities_phernomones[n][m] += Q/cities_dis[m][n]
	            #蚁密模型
	            '''cities_phernomones[m][n] += Q
	            cities_phernomones[n][m] += Q'''
	            #蚁周模型
	            cities_phernomones[m][n] += Q/ants[i]['L']
	            cities_phernomones[n][m] += Q/ants[i]['L']
	    #清空蚂蚁禁忌表并随机开始城市
	    for i in range(Np):
	        reset_ant(ants[i])
    
In[12]:
	import matplotlib.pyplot as plt
	plt.rcParams['figure.figsize'] = (20,8)
In[13]:
	qun_x = list(info_q.keys())
	qun_y = list(info_q.values())
	plt.xlabel('G')
	plt.ylabel('distance')
	plt.title('G=200 Np={} alpha={} beta={} Q={} rho={} min_dist={}'.format(Np,alpha,beta,Q,rho,best))
	plt.plot(qun_x,qun_y)
	#plt.savefig('./result/ants/ants{}_{}_{}_{}_{}.png'.format(Np,alpha,beta,Q,rho))
Out[13]:
	

antsresult

求解路径可视化

antspaths

  • 1
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
蚁群算法是一种模拟蚂蚁觅食行为的优化算法,常用于求解TSP问题。以下是Python实现蚁群算法求解TSP问题的示例代码: ``` python import numpy as np import random # TSP距离矩阵 distance_matrix = [[0, 1, 2, 3, 4], [1, 0, 3, 2, 5], [2, 3, 0, 4, 6], [3, 2, 4, 0, 7], [4, 5, 6, 7, 0]] # 蚂蚁数量 ant_count = 10 # 蚂蚁移动距离的影响因子 alpha = 1 # 蚂蚁信息素浓度的影响因子 beta = 5 # 信息素的挥发系数 rho = 0.1 # 初始信息素浓度 tau0 = 1 # 迭代次数 iteration_count = 100 # 初始化信息素浓度矩阵 tau = np.zeros((5, 5)) + tau0 # 计算路径长度 def path_length(path): length = 0 for i in range(len(path) - 1): length += distance_matrix[path[i]][path[i + 1]] length += distance_matrix[path[-1]][path[0]] return length # 选择下一个节点 def select_next_node(current_node, visited_nodes): # 计算当前节点到其他节点的信息素浓度和启发式因子 probabilities = [] for i in range(len(distance_matrix)): if i not in visited_nodes: tau_ij = tau[current_node][i] eta_ij = 1 / distance_matrix[current_node][i] p = (tau_ij ** alpha) * (eta_ij ** beta) probabilities.append(p) else: probabilities.append(0) # 根据概率选择下一个节点 probabilities = probabilities / np.sum(probabilities) next_node = np.random.choice(range(len(distance_matrix)), p=probabilities) return next_node # 更新信息素浓度 def update_pheromone(ant_paths): global tau # 挥发信息素 tau = (1 - rho) * tau # 更新信息素 for path in ant_paths: length = path_length(path) for i in range(len(path) - 1): tau[path[i]][path[i + 1]] += 1 / length tau[path[-1]][path[0]] += 1 / length # 蚁群算法主函数 def ant_colony_optimization(): global tau shortest_path_length = float('inf') shortest_path = [] for i in range(iteration_count): # 初始化蚂蚁位置 ant_positions = [random.randint(0, len(distance_matrix) - 1) for _ in range(ant_count)] ant_paths = [] # 蚂蚁移动 for j in range(len(distance_matrix) - 1): for k in range(ant_count): current_node = ant_positions[k] visited_nodes = ant_positions[:k] + ant_positions[k + 1:j + 1] next_node = select_next_node(current_node, visited_nodes) ant_positions[k] = next_node ant_paths.append(ant_positions.copy()) # 更新信息素浓度 update_pheromone(ant_paths) # 记录最短路径 min_path_index = np.argmin([path_length(path) for path in ant_paths]) if path_length(ant_paths[min_path_index]) < shortest_path_length: shortest_path_length = path_length(ant_paths[min_path_index]) shortest_path = ant_paths[min_path_index] return shortest_path, shortest_path_length # 测试 shortest_path, shortest_path_length = ant_colony_optimization() print('Shortest path:', shortest_path) print('Shortest path length:', shortest_path_length) ``` 注:该示例代码中的TSP距离矩阵为一个简单的5个节点的例子,实际使用时需根据具体问题进行修改。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值