模拟退火算法(附代码)

上一篇我们讲了旅行商问题及遗传算法来解决此类问题:遗传算法(附代码)

今天介绍另外一种解决此类NP问题的方法是模拟退火算法(Simulated Annealing, SA)

模拟退火算法的思想借鉴于固体的退火原理,当固体的温度很高的时候,内能比较大,固体的内部粒子处于快速无序运动,当温度慢慢降低的过程中,固体的内能减小,粒子的慢慢趋于有序,最终,当固体处于常温时,内能达到最小,此时,粒子最为稳定。模拟退火算法便是基于这样的原理设计而成。

那么为什么在算法开始的时候要处于不稳定的状态呢?我们先看来一下爬山法吧

爬山法的问题

爬山法是一种贪婪算法,在当前位置的附近寻找一个更大的值,不断迭代这个过程直到处于稳定状态

如图中要寻找这个函数的最大值,采用爬山法的话,如果初始点选择D点,那么爬山法能够找到最大值B点,但是如果初始值选择C或者E点,那么爬山法找到的最大值就是局部最优A点,而不是全局最优点B点

这就是爬山法的局限性,如果选择的初始点不好,那么算法很有可能会陷入局部最优解,而模拟退火引入的温度,在温度越高的时候越有机会跳到一个相对不那么优的解,从而跳出局部最优。

模拟退火的过程

  • 1.初始化一个温度T, 如T=100
  • 2.老的解损失为: old_cost, 生成一个新的解,损失为: new_cost
  • 3.计算当前是否采纳新的解概率: P = math.exp(-(new_cost-old_cost)/T)
  • 4.如果损失new_cost<old_cost或者随机一个(0,1)之间数值<P, 则接受这个新解,否则还是使用老的解
  • 5.当前的温度T下降一定的值(温度降低)
  • 6.一直迭代2~5步,直到稳定状态

可以看到一开始温度T很高的时候P也很大,那么采纳新的解(损失比老的解更大)的概率也更高,从而跳出了局部最优

随着温度T的下降P也越来越小,会越来越多的采用损失大小来评价是否采纳新的解

代码实现

# -*- encoding: utf8 -*-
import random
import math
import matplotlib.pyplot as plt
​
​
class SA:
    def __init__(self):
        self.T = 10000.
        self.cool = 0.95
​
    def new_route(self, tour, data):
        c1 = random.randint(0, len(tour['tour']) - 1)
        c2 = random.randint(0, len(tour['tour']) - 1)
​
        while c1 == c2:
            c2 = random.randint(0, len(tour['tour']) - 1)
​
        new_tour = []
        for i in range(len(tour['tour'])):
            if i == c1:
                new_tour.append(tour['tour'][c2])
            elif i == c2:
                new_tour.append(tour['tour'][c1])
            else:
                new_tour.append(tour['tour'][i])
​
        return self.get_tour_detail(new_tour, data)
​
    def get_distance(self, c1, c2):
        # 获取距离
        xd = abs(c1['x'] - c2['x'])
        yd = abs(c1['y'] - c2['y'])
        distance = math.sqrt(xd * xd + yd * yd)
​
        return distance
​
    def get_cost(self, distance):
        return distance
​
    def get_tour(self, data):
        # 随机获得一条路径
        tour = []
        for key, value in data.items():
            tour.append(key)
​
        random.shuffle(tour)
​
        return self.get_tour_detail(tour, data)
​
    def get_tour_detail(self, tour, data):
        tmp = None
        distance = 0
        for item in tour:
            if tmp is not None:
                distance_tmp = self.get_distance(data[tmp], data[item])
                distance += distance_tmp
​
            tmp = item
​
        return {'tour': tour, 'distance': distance, 'cost': self.get_cost(distance)}
​
    def run(self, data):
        route = self.get_tour(data)
        print 'before route:'
        print route
        i = 0
        while self.T > 0.1:
            new_route = self.new_route(route, data)
            old_cost, new_cost = route['cost'], new_route['cost']
​
            if new_cost < old_cost or random.random() < math.exp(-(new_cost - old_cost) / self.T):
                route = new_route
​
            self.T = self.T * self.cool
            i += 1
​
        print 'total gen:', i
        print route
        return route
​
​
def init_data(num):
    data = {}
    def get_random_point():
        # 随机生成坐标
        return {
            'x': random.randint(1, 99),
            'y': random.randint(1, 99)
        }
​
    for i in range(num):
        data[i + 1] = get_random_point()
​
    return data
​
​
def show(citys, tour):
    # 绘图
    plt.bar(left=0, height=100, width=100, color=(0, 0, 0, 0), edgecolor=(0, 0, 0, 0))
    plt.title(u'tsp')
    plt.xlabel('total distance: %s m' % tour['distance'])
​
    x = []
    y = []
    i = 0
    for item in tour['tour']:
        city = citys[item]
        x.append(city['x'])
        y.append(city['y'])
​
        i += 1
        if i == 1:
            plt.plot(city['x'], city['y'], 'or')
        else:
            plt.plot(city['x'], city['y'], 'bo')
​
    plt.plot(x, y, 'g')
    plt.xlim(0.0, 100)
    plt.ylim(0.0, 100)
    plt.show()
​
​
if __name__ == '__main__':
    scale, num, max_gen, pc, elite = 50, 10, 1000, 0.8, 0.2
    data = init_data(num)
    sa = SA()
    new_fittest = sa.run(data)
    show(data, new_fittest)
​

运行效果:

参考

[1] <<集体智慧编程>>
[2] https://www.cnblogs.com/heaad/archive/2010/12/20/1911614.html
[3] https://zhuanlan.zhihu.com/p/33184423

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,692评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,482评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,995评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,223评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,245评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,208评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,091评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,929评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,346评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,570评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,739评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,437评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,037评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,677评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,833评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,760评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,647评论 2 354

推荐阅读更多精彩内容

  • 在算法里面有一类问题叫做最优化问题,这类问题通常的特点是问题的解空间很大,用传统的算法没有办法穷举。比如时间复杂度...
    DayDayUpppppp阅读 3,803评论 0 4
  • 1.概念 介绍模拟退火前,请先了解爬山算法。因为模拟退火算法是爬山算法的改进版,它在爬山算法的基础上引入了随机化。...
    木木与呆呆阅读 1,375评论 8 12
  • ->点击访问个人博客,相互交流学习<- 一、技术论述 1.随机方法 学习在构造模式分类器中起着中心的作用。一个通常...
    JackHCC阅读 2,610评论 1 1
  • 算法思想 自然中的退火(不理解问题不大) 模拟退火算法的思想受启发于自然界中固体由高温到低温的过程中其内部分子状态...
    Cloud_J阅读 3,760评论 0 1
  • 黑色的海岛上悬着一轮又大又圆的明月,毫不嫌弃地把温柔的月色照在这寸草不生的小岛上。一个少年白衣白发,悠闲自如地倚坐...
    小水Vivian阅读 3,106评论 1 5