模拟退火算法与其python实现(二)——TSP问题

模拟退火算法与其python实现(二)——TSP问题

上一篇文章介绍了模拟退火算法的基本原理(模拟退火算法与其python实现(一)),这篇文章介绍一下模拟退火算法在数学建模中最常应用的一类问题——Traveling salesman problem,也就是旅行商问题,这类问题的描述如下:

 

一个旅行商从城市1 出发,需要到其它城市n去推销货物,最后返回城市1 。若任意两个城市间的距离已知,旅行商如何选择最佳行走路线?

 

这种问题也就是上篇提到的NP-hard问题中很典型的一类,如果使用枚举法,随着城市数目的增多,计算量将几何倍数的递增。那么,如何使用SA算法来求近似最优解呢,首先我们这个问题转化为数学模型:

模拟退火算法与其python实现(二)——TSP问题_第1张图片

 

 

我们所求即为函数Z的最小值,下面我们便使用python来构建TSP问题的SA模型并尝试求得近似最优解

首先导入问题数据并处理:

 

from __future__ import division
import pandas as pd
import utils
import numpy as np
import math
import matplotlib.pyplot as plt
citys=pd.read_table('./data/tsp100.txt',sep='\t',header=None)
citys.columns=['x']
citys['y']=None

for i in range(len(citys)):
    coordinate=citys['x'][i].split()
    citys['x'][i]=float(coordinate[0])
    citys['y'][i]=float(coordinate[1])

print citys.head(5)

其中:

1.string.split()可以剪切字符串,其用法如下:

模拟退火算法与其python实现(二)——TSP问题_第2张图片

接着看下数据长什么样

 模拟退火算法与其python实现(二)——TSP问题_第3张图片

数据集存储了各个城市的坐标,我们把第一个城市作为我们的起点,同时也是我们的终点。接着在数据集中除去这个城市以便于计算。

 

start=list(citys.iloc[0])
end=list(citys.iloc[0])
citys=citys.drop([0])
citys.index=[i for i in range(len(citys))]

 

接着我们便可以初始化我们的行走路线了,我们直接将数据集中城市存储的顺序做为我们最初的行走路线

 

paths=[i for i in range(len(citys))]# initiate path

 

通过matplotlib可以得到初始路径的路线图:

 

模拟退火算法与其python实现(二)——TSP问题_第4张图片

然后我们按照在上文提到的规则设置初始温度,即随机选择几组状态,计算能量差值最大的一组,以此为依据得到初始温度,我们设接受概率为0.5。

'''
random path and calculate distance to sreach for optimal initiate temperature
'''

distance1=0
distance2=0
dif=0
for i in range(10):  
    #np.random.shuffle(path)
    newPaths1=list(np.random.permutation(paths))
    newPaths2=list(np.random.permutation(paths))
    distance1=utils.CalLength(citys,newPaths1,start,end)
    distance2=utils.CalLength(citys,newPaths2,start,end)
    difNew=abs(distance1-distance2)
    if difNew>=dif:
        dif=difNew

Pr=0.5 #initiate accept possibility
T0=dif/Pr#initiate terperature

1.其中计算距离的函数定义在utils模块中:

import math
def CalDistance(x,y):
    return math.sqrt(x**2+y**2)

def CalLength(citys, paths,start,end):
    length=0
    n=1
    for i in range(len(paths)):
        if i==0:
            length+=CalDistance(start[0]-citys['x'][paths[i]],start[1]-citys['y'][paths[i]])
            n+=1
        elif n

 

2.np.random.permutation(list)可以打乱数据在list中的排序,但不会直接替换原list,而np.random.shuffle(list)会直接替换。

 

 

现在我们可以初始化其它参数:

Pr=0.5 #initiate accept possibility
T0=dif/Pr#initiate terperature
T=T0
Tmin=T/50
k=10*len(paths) #times of internal circulation
initialPath=paths.copy()
length=utils.CalLength(citys,initialPath,start,end)
print (length)

 

计算得到初始路径所需要走的距离为:

 

然后执行降温过程,这里,关于邻域函数的设置,我们首先设置为调换路径中某对节点的位置。

t=0
optimalPath=initialPath.copy()
optimalLength=length
while T>Tmin:
    for i in range(k):
        a=0
        b=0
        newPaths=optimalPath.copy()
        while a==b:
            a=np.random.randint(0,len(paths))
            b=np.random.randint(0,len(paths))
        te=newPaths[a]
        newPaths[a]=newPaths[b]
        newPaths[b]=te
        newLength=utils.CalLength(citys,newPaths,start,end)
        if newLength

最后执行结果如下

路径图为下:

 模拟退火算法与其python实现(二)——TSP问题_第5张图片

 

现在我们尝试一下改进SA算法:

首先,我们更改初始路径,使初始路径也随机生成:

initialPath=list(np.random.permutation(paths))
length=utils.CalLength(citys,initialPath,start,end)

 

接着,我们改进一下邻域函数,将函数设置为根据温度的大小,调换多对节点的位置,这样,能够增加遍历整体的概率。

 

for j in range(int(T0/500)):
    a=0
    b=0
    while a==b:
        a=np.random.randint(0,len(paths))
        b=np.random.randint(0,len(paths))
    te=newPaths[a]
    newPaths[a]=newPaths[b]
    newPaths[b]=te
newLength=utils.CalLength(citys,newPaths,start,end)

 

接着我们可以设置一个增温过程,即有一定概率重新升温,以避免算法在局部最小值处停滞不前。我们设置重升温的概率为0.15。

 

back=np.random.uniform(low=0,high=1)
if back>=0.85:
    T=T*2
    continue

 

最终,我们SA模型如下:

 

initialPath=list(np.random.permutation(paths))
length=utils.CalLength(citys,initialPath,start,end)
optimalPath = initialPath.copy()
optimalLength=length
t=0
while T>Tmin:
    for i in range(k):
        newPaths=optimalPath.copy()
        for j in range(int(T0/500)):
            a=0
            b=0
            while a==b:
                a=np.random.randint(0,len(paths))
                b=np.random.randint(0,len(paths))
            te=newPaths[a]
            newPaths[a]=newPaths[b]
            newPaths[b]=te
        newLength=utils.CalLength(citys,newPaths,start,end)
        if newLength=0.85:
        T=T*2
        continue
    t+=1
    print (t)
    T=T0/(1+t)
print (optimalLength)

 

执行算法,得到结果:

 

 

代码与数据已上传至github:https://github.com/JiaruiFeng/Simulated-Annealing-solving-TSP-with-python

你可能感兴趣的:(智能算法)