python 矩阵保留四位小数_python第三方库|解TSP问题神器elkai

01

简介

01

    elkai是python的第三方库,专门用于解决TSP问题,目前已知能够在规模达到315个节点的问题中求解出最优方案。elkai本身的实现基于大名鼎鼎的LKH算法,该算法被认为是目前解决TSP问题最有效的算法。

    elkai可在Windows、Linux、OS X等系统的python3.5及以上版本中使用,安装很简单,且不需要外部依赖,只需在命令提示符中运行以下命令即可:

pip install elkai

    elkai官方网址传送门:https://pypi.org/project/elkai/

    关于TSP问题我们在往期文章中已经介绍过,可参考文章如下:

python实现 | 模拟退火(SA)算法解决TSP问题

python实现 | 禁忌搜索(TS)算法解决TSP问题

python实现 | 遗传算法(GA)解决TSP问题

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

02

调用过程

0‍2

    elkai的调用过程也很简单,只需要构建好并传入各节点的距离矩阵,就能返回最优解决方案,这里我们同样用往期文章中的例子(规模为31)来演示,首先导入需要的库(完整代码及数据见文末):

import numpy as npimport elkaiimport mathimport matplotlib.pyplot as pltimport scipy as spimport scipy.spatial as ssp

然后给出实例并计算各节点的距离矩阵:

"""data.txt数据载入"""city_name = []city_condition = []with open('data.txt','r',encoding='UTF-8') as f:    lines = f.readlines()    for line in lines:        line = line.split('\n')[0]        line = line.split(',')        city_name.append(line[0])        city_condition.append([float(line[1]), float(line[2])])city_condition = np.array(city_condition)#利用scipy计算距离矩阵def genDistanceMat(x,y):    X=np.array([x,y])    distMat=ssp.distance.pdist(X.T)    sqdist=ssp.distance.squareform(distMat)    return sqdistx,y = city_condition[:,0],city_condition[:,1]#计算距离矩阵distance = genDistanceMat(x, y)

然后将计算好的距离矩阵distance传入elkai函数就能得到最优解方案了:

#传入解方案,计算解方案的总距离def cal_fitness(solutionnew):    valuenew = np.sum(distance[solutionnew[:-1],solutionnew[1:len(solutionnew)]])    return valuenewsolutionbest = elkai.solve_int_matrix(distance)solutionbest.append(0)print("最优解方案:",solutionbest)print("最优解总长度:",cal_fitness(solutionbest))#最优解方案:[0, 26, 28, 1, 2, 11, 24, 3, 25, 13, 10, 9, 4, 6, 7, 8, 12, 15, 14, 16, 22, 17, 18, 20, 19, 21, 29, 30, 23, 5, 27, 0]#最优解总长度: 151.78775827153964

注意,这个函数计算出的是有回路的TSP问题,但返回的解方案solutionbest没有给出完整解方案(少一个终点0),故我们在代码中在解方案最末尾加上了编号0。

    官方网站上还有种解决方式是使用函数elkai.solve_float_matrix(),但这种方法精度不够,计算出的结果不稳定,不建议使用。

    最终解方案图示如下:

9e2c5605748be1738bdd3dacf0a46630.png

    调用elkai解TSP不仅能够得到非常好的解方案,同样用时也很少(其中一个原因是该库用的C语言编译封装实现的),在我的台式机上运行100次上述代码,规模31的问题平均用时只有0.05秒。

03

补充说明

03

    对于调用elkai其实存在一个坑,常出现在距离矩阵内部存在较多浮点数的算例中,这会导致哪怕在很多该类小规模的问题中都算不出最优解,举例如下:

def main(city_condition):    #计算距离矩阵    def genDistanceMat(x,y):        X=np.array([x,y])        distMat=ssp.distance.pdist(X.T)        sqdist=ssp.distance.squareform(distMat)        return sqdist    x,y = city_condition[:,0],city_condition[:,1]    #计算距离矩阵    distance = genDistanceMat(x, y)        def cal_fitness(solutionnew):        valuenew = np.sum(distance[solutionnew[:-1],solutionnew[1:len(solutionnew)]])        return valuenew                solutionbest = elkai.solve_int_matrix(distance)    # solutionbest = elkai.solve_float_matrix(distance,runs=10)#允许浮点距离    solutionbest.append(0)    print("最优解方案:",solutionbest)    print("最优解总长度:",cal_fitness(solutionbest))

如上,我们首先将调用的过程写到一个函数中,然后给出一个实例,并调用计算:

city_condition = np.array([[82., 76.],       [20., 70.],       [19., 32.],       [14., 24.],       [ 2., 39.],       [ 5., 42.],       [ 1., 65.],       [ 3., 82.],       [ 9., 97.],       [29., 89.],       [50., 93.]])main(city_condition)#输出#最优解方案: [0, 2, 3, 4, 5, 6, 1, 7, 8, 9, 10, 0]#最优解总长度: 268.8398159965181

得到结果为268.84。此时我们将各节点的坐标缩小一百倍,即city_condition/100:

city_condition = np.array([[82., 76.],       [20., 70.],       [19., 32.],       [14., 24.],       [ 2., 39.],       [ 5., 42.],       [ 1., 65.],       [ 3., 82.],       [ 9., 97.],       [29., 89.],       [50., 93.]])city_condition /= 100main(city_condition)#输出#最优解方案: [0, 3, 10, 5, 2, 9, 8, 7, 1, 6, 4, 0]#最优解总长度: 4.988332119353135

按照预期总长度应该为2.6884,但实际算出的结果为4.98833,解方案的顺序也差别较大,导致这个结果的可能原因是elkai库对浮点数的小数部分不敏感,所以想要避开这个坑的话,我们就需要将输入elkai的距离矩阵乘上一个较大的倍数,例如10000,迫使减小传入的数据小数部分对整个解方案的影响(其实如果将之前算例代码部分在传入距离矩阵时乘上较大的数,得出的结果能达到150.98959,优于之前的结果)。

04

小结

04

    上述我们介绍了调用elkai第三方库解决TSP问题的方法,在计算效果、计算时间及实现简易程度上都远优于我们自己手动实现的一些解TSP的基础算法,所以如果就实用角度而言,非常推荐大家调用这个包来解决TSP问题,但同时也要注意在输入距离矩阵时乘上一个较大数来避免elkai库的坑。

    完整代码及数据可在公众号后台回复  20200828  获取

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值