elkai是python的第三方库,专门用于解决TSP问题,目前已知能够在规模达到315个节点的问题中求解出最优方案。elkai本身的实现基于大名鼎鼎的LKH算法,该算法被认为是目前解决TSP问题最有效的算法之一。
elkai的调用过程很简单,只需要构建好并传入各节点的距离矩阵,就能返回最优解决方案
下载方式:
cmd中输入:pip install elkai
本文利用规模为101个点的TSP问题做例子进行介绍
点的数据如下:
id | x_coord | y_coord |
1 | 40 | 50 |
2 | 25 | 85 |
…… | …… | …… |
101 | 31 | 67 |
各点示意图如下:
编写函数计算各点间的距离矩阵:
# 计算距离矩阵,此处用坐标直接计算距离,实际交通规划中可能会有现成的距离矩阵
def genDistanceMat(x, y):
X = np.array([x, y])
distMat = ssp.distance.pdist(X.T)
distMat = ssp.distance.squareform(distMat)
return distMat
编写函数计算整个路线的总长度:
# 计算所得方案的线路总长度
def cal_fitness(sol):
tot_len = np.sum(distance[sol[:-1], sol[1:len(sol)]])
return tot_len
主程序如下:
def main(city_condition):
# 计算距离矩阵,此处用坐标直接计算最短距离,实际交通规划中可能会有现成的最短距离矩阵
def genDistanceMat(x, y):
X = np.array([x, y])
distMat = ssp.distance.pdist(X.T)
distMat = ssp.distance.squareform(distMat)
return distMat
x, y = city_condition[:, 0], city_condition[:, 1]
distance = genDistanceMat(x, y)
# 计算所得方案的线路总长度
def cal_fitness(sol):
tot_len = np.sum(distance[sol[:-1], sol[1:len(sol)]])
return tot_len
sol = elkai.solve_int_matrix(distance)
# sol = elkai.solve_float_matrix(distance,runs=10)#允许浮点距离
sol.append(0)
'''这个函数计算出的是有回路的TSP问题,但返回的解方案sol没有给出完整解方案(少一个终点0),故我们在代码中在解方案最末尾加上了编号0'''
print("最优解方案:", sol)
print("最优解总长度:", cal_fitness(sol))
return sol,cal_fitness(sol)
主程序输入城市的x,y坐标,输出即为TSP问题的解方案和总长度,输入无误则可直接跑,使用十分方便。调用elkai解TSP不仅能够得到非常好的解方案,同样用时也很少(其中一个原因是该库用的C语言编译封装实现的)。
求解结果如下图:
所有程序代码:
'利用elkai求解TSP问题'
'2022.6.22 北京交通大学 韬会'
import numpy as np
import elkai
import math
import matplotlib.pyplot as plt
import scipy as sp
import scipy.spatial as ssp
import pandas as pd
data = pd.read_excel('cvrp.xlsx')
num_node = len(data.id)
loc=[[data.x_coord[i],data.y_coord[i]] for i in range(num_node)]
loc=np.array(loc)
print(loc)
x,y = loc[:,0],loc[:,1]
plt.scatter(list(x),list(y))
def main(city_condition):
# 计算距离矩阵,此处用坐标直接计算最短距离,实际交通规划中可能会有现成的最短距离矩阵
def genDistanceMat(x, y):
X = np.array([x, y])
distMat = ssp.distance.pdist(X.T)
distMat = ssp.distance.squareform(distMat)
return distMat
x, y = city_condition[:, 0], city_condition[:, 1]
distance = genDistanceMat(x, y)
# 计算所得方案的线路总长度
def cal_fitness(sol):
tot_len = np.sum(distance[sol[:-1], sol[1:len(sol)]])
return tot_len
sol = elkai.solve_int_matrix(distance)
# sol = elkai.solve_float_matrix(distance,runs=10)#允许浮点距离
sol.append(0)
'''这个函数计算出的是有回路的TSP问题,但返回的解方案sol没有给出完整解方案(少一个终点0),故在解方案最末尾加上了编号0'''
print("最优解方案:", sol)
print("最优解总长度:", cal_fitness(sol))
return sol,cal_fitness(sol)
sol,lenth=main(loc)
# 绘图部分
plt.scatter(x,y)
for i in range(len(x)):
plt.annotate(sol[i], xy = (x[i], y[i]), xytext = (x[i]+0.3, y[i]+0.3)) # 这里xy是需要标记的坐标,xytext是对应的标签坐标
plt.plot(x,y)
plt.show()
参考文献: