繁体   English   中英

为什么这种应用于 TSP 的模拟退火算法不收敛?

Why is this simulated annealing algorithm applied to the TSP not converging?

提示:本站收集StackOverFlow近2千万问答,支持中英文搜索,鼠标放在语句上弹窗显示对应的参考中文或英文, 本站还提供   中文繁体   英文版本   中英对照 版本,有任何建议请联系yoyou2525@163.com。

对于一个练习,我必须找到这个旅行推销员问题的最佳解决方案,唯一的区别是推销员可能不会两次访问第一个坐标。 最佳值应该在给出的 1200 左右。 我不明白为什么这不会收敛。 另外一个重要的注意事项是使用曼哈顿距离度量而不是欧几里得距离。

def shuffle_coords(coords):
     x0 = coords[0]
     coords = shuffle(coords[1:])
     return np.insert(coords,0,x0,axis = 0)

def distance(x,y):
    return abs(x[1] - y[1]) + abs(x[0] - y[0])

这里坐标随机打乱。

def shuffle(array):
    df = pd.DataFrame(array)
    return df.sample(len(array)).to_numpy() 


def path_distance(path):
    dist     = []
    for i in range(1,len(path)):
        dist.append(distance(path[i],path[i-1]))
    return np.sum(dist)

这里初始化模拟退火算法。

def SA_distance(path, T_0,T_min, alpha):
    T = T_0
    dist = path_distance(path)
    
    while T >  T_min:
        new_path = gen_subtour(path)
        diffF = path_distance(new_path) - dist
        if diffF < 0:
            path = new_path
            dist = path_distance(path)
 
        elif np.exp(-(diffF/T)) > random.uniform(0,1):
            path = new_path
            dist = path_distance(path)
      
        T = T * alpha
        print(dist,T)
    return dist,path

在这里生成随机子游,同时保持 x0 就位。

def gen_subtour(path):
    subset = shuffle(np.delete(path,0,axis =0))
    subset = shuffle(path)
    if random.uniform(0,1) < 0.5:
        subset = np.flipud(subset)
    else:
        j = random.randint(1,(len(subset)-1))
        p = subset[j-1]
        q = subset[j]
        subset = np.delete(subset,[j-1,j],axis = 0)
        subset = np.insert(subset,0,p,axis = 0)
        subset = np.insert(subset,len(subset),q,axis = 0)
 
    return np.insert(subset,0,path[0],axis = 0)

def main():
    T_0     = 12
    T_min   = 10**-9
    alpha   =  0.999
    coords = np.array([[375, 375],[161, 190], [186, 169],[185, 124],
                       [122, 104],[109, 258], [55, 153] ,[120, 49],
                       [39, 85]  ,[59, 250] , [17, 310] ,[179, 265],
                       [184, 198]])
    path , distance = SA_distance(coords,T_0,T_min,alpha)
1 个回复

我已经测试过了,我的第一直觉是gen_subtour()工作不正常,可能是因为步数太多而改变了路线。

我会尝试不同的版本并检查效果如何。 SA 计划似乎运作良好,我认为错误是提案。

无论如何,这里有一些代码希望能帮助你更好地测试。

我使用pdist预先计算曼哈顿距离,即;

import numpy as np
from scipy.spatial.distance import pdist, cdist, squareform

coords = np.array([[375, 375],[161, 190], [186, 169],[185, 124],
                   [122, 104],[109, 258], [55, 153] ,[120, 49],
                   [39, 85]  ,[59, 250] , [17, 310] ,[179, 265],
                   [184, 198]])

Y = pdist(coords, 'cityblock')

distance_matrix = squareform(Y)
nodes_count = coords.shape[0]

并定义开始

def random_start():
    """
        Random start, returns a state
    """
    a = np.arange(0,nodes_count)
    np.random.shuffle(a)
    return a

目标函数,我们有不返回原点的版本;

def objective_function( route ):
    # uncomment when testing new/modify neighbors
    # assert check_all_nodes_visited(route)

    return np.sum( distance_matrix[route[1:],route[:-1]] )

我这里有 3 种建议,基于一条路线;

def random_swap( route ):
    """
        Random Swap - a Naive neighbour function

        Will only work for small instances of the problem
    """
    route_copy = route.copy()

    random_indici = np.random.choice( route , 2, replace = False)
    route_copy[ random_indici[0] ] = route[ random_indici[1] ]
    route_copy[ random_indici[1] ] = route[ random_indici[0] ]

    return route_copy

def vertex_insert( route, nodes=1 ):
    """
        Vertex Insert Neighbour, inspired by

        http://www.sciencedirect.com/science/article/pii/S1568494611000573
    """
    route_copy = route.copy()
    random_indici = np.random.choice( route , 2, replace = False)
    index_of_point_to_reroute = random_indici[0]
    value_of_point_to_reroute = route[ random_indici[0] ]
    index_of_new_place = random_indici[1]
    route_copy = np.delete(route_copy, index_of_point_to_reroute)
    route_copy = np.insert(route_copy, index_of_new_place, values=value_of_point_to_reroute)
    return route_copy

def block_reverse( route, nodes=1 ):
    """
        Block Reverse Neighbour, inspired by

        http://www.sciencedirect.com/science/article/pii/S1568494611000573

        Note that this is a random 2-opt operation.
    """
    route_copy = route.copy()
    random_indici = np.random.choice( route , 2, replace = False)
    index_of_cut_left = np.min(random_indici)
    index_of_cut_right = np.max(random_indici)
    route_copy[ index_of_cut_left:index_of_cut_right ] = np.flip(route_copy[ index_of_cut_left:index_of_cut_right ])

    return route_copy

或者,您可以在 SA 之后进行 2-opt 回合,以确保没有交叉。

def swap_for_2opt( route, i, k):
    """
        Helper for 2-opt search
    """
    route_copy = route.copy()
    index_of_cut_left = i
    index_of_cut_right = k
    route_copy[ index_of_cut_left:index_of_cut_right ] = np.flip(route_copy[ index_of_cut_left:index_of_cut_right ])

    return route_copy

def local_search_2opt( route ):
    """
        Local Optimum with 2-opt

        https://en.wikipedia.org/wiki/2-opt

    """
    steps_since_improved = 0
    still_improving = True

    route = route.copy()

    while still_improving :
        for i in range( route.size - 1 ):
            for k in np.arange( i + 1, route.size ):
                alt_route = swap_for_2opt(route, i, k)

                if objective_function(alt_route) < objective_function(route):
                    route = alt_route.copy()
                    steps_since_improved = 0

            steps_since_improved += 1

            if steps_since_improved > route.size + 1:
                still_improving = False
                break

    return route

并使用 frigidum 进行 SA

import frigidum


local_opt = frigidum.sa(random_start=random_start,
           objective_function=objective_function,
           neighbours=[random_swap, vertex_insert, block_reverse],
           copy_state=frigidum.annealing.naked,
           T_start=10**5,
           alpha=.95,
           T_stop=0.001,
           repeats=10**2,
           post_annealing = local_search_2opt)

返回的路由几乎总是 1145。

我已经在frigidum主页上发布了一般提示和技巧。

1 模拟退火TSP

我正在寻找在Java中实现模拟退火算法的方法,以为Traveling Salesman问题找到一条最佳路线,到目前为止,我已经实现了蛮力,并希望修改该代码以使用模拟退火。 显然,蛮力和模拟退火非常不同,并且使用的功能也非常不同。 我了解模拟退火使用一个称为温度的变量,该变量在算法运行时冷 ...

2 模拟退火算法

我在C ++中实现了模拟退火,以将(x-2)^2+(y-1)^2最小化。 我得到各种各样的输出,这对于这种启发式方法是不可接受的。 似乎解决方案正在收敛,但从未完全接近解决方案。 我的代码: 如何获得解决方案? ...

3 如何在节点上实现模拟退火(TSP)

我需要编写类似旅行推销员问题的程序,但需要使用节点。我需要获得较少错位的金额。 我不知道如何使用玻尔兹曼常数实现模拟退火算法。 我已经编码了第一部分: `导入 java.util.ArrayList; 导入 java.util.Random; 公共类数量 { 私有 ArrayList 数量 ...

5 为什么我的模拟退火算法会生成越来越差的解决方案并尽早收敛?

为什么我的程序会产生越来越差的解决方案并这么早收敛? 我一直在优化和各种启发式技术,读了最近和我最近决定尝试如实现模拟退火这一职位。 我相信我对理论足够了解。 接受概率受以下函数指导 成本差是当前解决方案的“成本”与新随机生成的建议解决方案的成本之间的差。 成本 ...

9 矩形嵌套-使用模拟退火收敛到最优解

我正在使用“ 模拟退火”解决矩形嵌套问题。 我能够取得良好的结果,但是我得到的解决方案是DISCRETE。 甚至不能始终获得全局最优。 问题描述: 目标 -通过更改零件放置的顺序,最大程度地减少无限片材的长度(宽度恒定)。 我面临的问题: 我得到的输出结果是DISCR ...

10 用于图形着色的模拟退火

我正在研究用于图着色的模拟退火算法。 我正在遵循这个模型,但是我很难理解冷却时间表,更具体地说,是变量M的部分。在我的理解中,M表示应该改变温度之后的迭代次数。 此外,据我所知,该算法侧重于找到适当的颜色分布,给定色数而不是找到它的值。 由于没有专注于找到色数,而是关注成本足够低的着色 ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2022 STACKOOM.COM