大数跨境
0
0

退火算法与旅行推销员问题

退火算法与旅行推销员问题 数据皮皮侠
2020-01-03
2
导读:旅行推销员问题(Travelling Salesman Problem, TSP)是组合数学中一个古老而困难

旅行推销员问题Travelling Salesman Problem, TSP)是组合数学中一个古老而困难的问题,至今尚未彻底解决,是组合优化中的一个NP-完备问题类。这个问题描述的是:有一货物推销员要去若干个城市推销货物,从城市1出发,经其余各城市至少一次,各城市间的距离已知,然后回到城市1,问图和选择行走路线,才能使得总行程最短。显而易见,城市的数量越多,该问题就越困难。针对这个问题并没有通用的解决办法,尽管目前已经有一些指数级的算法(具体见文末)可精确的求解TSP,但对于大规模的问题会出现组合爆炸的现象,故而人们退而求其次,转向寻找近似算法或启发式算法,并取得了相当的进展。本文将重点用模拟退火地方法解决旅行推销员问题。

%=====================================================================%

   模拟退火方法Simulated Annealing Algorithm)是一种源于五十年代、基于Monte Carlo迭代求解思想的随机搜索算法,其出发点是将组合优化问题与统计力学的热平衡做类比,把优化的目标函数作为能量函数,模拟物理学中固体物质的退火处理,先加温使之具有足够高的能量,再使系统处于等温过程,是自由能达到最小值,系统处于平衡状态,最后再逐渐降温,其内部能量也相应下降,在热平衡条件下,物体内部处于不同状态的概率服从Boltzman分布(描述一定温度下微观粒子运动速度的概率分布)。若退火步骤恰当,则最终会行程最低能量的基态。这种算法思想在求解优化问题时,不但接受对目标函数有改进的状态,还能以某种概率接受使目标函数恶化的状态,从而可使之避免过早收敛到某个局部极值点,也正是这种概率性的扰动能够使之跳出局部极值点,故而得到的解常常很好。

   模拟退火法所得解的好坏与初始状态、温度函数等都有一定的联系,降温较快的效果不一定很好,效果好的,其降温过程又极其缓慢。但由于该方法适用范围广,并可认为控制迭代次数反复求解,因此具有很强的实用性。

%========================================================================%

下面我们开始讨论如何用模拟退火方法求解TSP

记住两条重要的规则:

1.每个城市有且仅能访问一次

2.必须返回起始城市

数学模型:


 

模拟退火算法的进行过程:

1、选择初始状态H(初始解)、初始温度、降温次数;

2、生成H的领域状态H,并计算Z(H’)-Z(H)

3、按接收概率置换H

4、重复步骤2直到停机条件满足。

 

创建模拟退火算法:

①导入一些常见的包

import numpy as np

import random

import matplotlib.pyplot as plt

import os

import shutil

import imageio

   其中,osoperation system(操作系统),封装了常见的文件和目录操作;shutil为高级的文件、文件夹、压缩包的处理模块;imageio用于gif的绘制。

   ②为了使数据更具有一般性,在具体算法之前,我们首先随机生成各城市坐标(假设共50个城市),并定义需要的数据。

i>随机生成各点并定义各城市间的距离

def create_data(N, xu=25, yu=25, xd=-25, yd=-25):

    fx = lambda: random.random() * (xu - xd) + xd

    fy = lambda: random.random() * (yu - yd) + yd

    calDistance = lambda x, y: np.sqrt((x[0] - y[0]) ** 2 + (x[1] - y[1]) ** 2)

    points = [(0, 0)] * N

    for i in range(N):

        points[i] = (fx(), fy())

    Mat = np.zeros((N, N))

    for i in range(N):

        for j in range(i + 1, N):

            dv = calDistance(points[i], points[j])

            Mat[i][j], Mat[j][i] = dv, dv

return points, Mat

 

我们可以得到随机生成的各城市的坐标以及其距离矩阵(由于随机性每一次生成的城市坐标均不一样)


ii>定义推销员所走过的总距离,即为每个城市之间的距离总和

def calpathValue(path):

    global Mat

    temp = Mat[0][path[0]]

    for i in range(len(path) - 1):

        temp += Mat[path[i]][path[i + 1]]

    temp += Mat[path[-1]][0]

return temp

 

③创建模拟退火算法

i>创建目录并设定城市数目,设置初始温度、更新温度、每个温度下的迭代次数

if __name__ == '__main__':

    # N, Mat = read_data()

    TIMESIT = 0

    PNGFILE = './png/'

    PNGLIST = []

    if not os.path.exists(PNGFILE): #判断PNGFILE是否存在

        os.mkdir(PNGFILE) #创建目录

    else:

        shutil.rmtree(PNGFILE) #递归的去删除文件

        os.mkdir(PNGFILE)

    N = 50

    points, Mat = create_data(N)

 

    T = 500  # 起始温度

    alpha = 0.995  # T_{k+1} = alpha * T_k方式更新温度

    limitedT = 1.  # 最小值的T

    iterTime = 1000  # 每个温度下迭代的次数

ii>遍历H的领域状态H,计算路程长度并设置停机条件

while T > limitedT:

        print(T)

        for i in range(iterTime):

            tempPath = path.copy()

            tx = random.randint(0, N - 2)

            ty = random.randint(0, N - 2)

            if tx != ty:

                tempPath[tx], tempPath[ty] = tempPath[ty], tempPath[tx]

                tempValue = calpathValue(tempPath)

                if tempValue <= value:

                    path = tempPath.copy()

                    value = tempValue.copy()

                else:

                    p = np.exp((value - tempValue) / (K * T))

                    if random.random() < p:

                        path = tempPath.copy()

                        value = tempValue.copy()

        if value < global_Best:

            global_Best = value

            draw(path, value)

        T *= alpha

④输出结果并做动态图

  path, value = initial()

  tempPath, tempValue = [], 0

  global_Best = value  # 画图

print(value)

    print(0, end='-->')

    for i in path:

        print(i, end='-->')

generated_images = []

    for png_path in PNGLIST:

        generated_images.append(imageio.imread(png_path))

    generated_images = generated_images + [generated_images[-1]] * 5

    imageio.mimsave('tsp.gif', generated_images, 'GIF', duration=0.5)

结果输出:

共保存58张静态图;

将这些静态图绘制成gif,则可得到(插入tsp.gif)

且我们得到的结果为:

 

结语:

运行过程中深刻的感受到收敛速度慢执行时间较长,且对参数的依赖性较大。但整个SAA创建过程以及输出结果都较有趣。tsp本身作为一个较为经典的NP问题,目前求解的方法也有很多:精确算法如线性规划方法、动态规划方法、分支定界方法;近似方法有插入法、最近邻算法、生成树法;近年来也有一些新的尝试如遗传算法、蚁群算法等,不同的方法都有不同的优缺点。感兴趣的同学可以做进一部分了解。


参考网站

github.com/DiegoVicen/som-tsp

blog.csdn.net/a19990412/article/details/84978612

【声明】内容源于网络
0
0
数据皮皮侠
社科数据综合服务中心,立志服务百千万社科学者
内容 2137
粉丝 0
数据皮皮侠 社科数据综合服务中心,立志服务百千万社科学者
总阅读615
粉丝0
内容2.1k