模拟退火算法

模拟退火算法

一,基本概念

​ 模拟退火算法(Simulated Annealing,SA)是一种模拟固体降温过程的最优化算法。其模拟的过程是首先将固体加温至某一温度,固体内部的粒子随温度上升慢慢变为无序的状态,内能增大,然后让其慢慢冷却,温度下降时,内部的粒子慢慢趋于有序,达到一种平衡态,最后达到常温时成为基态,此时内能减为最小,算法模拟这样一个过程期望能达到最优化的目的。

二,算法原理

模拟退火算法分为三部分:初始解,解空间和目标函数.

​ 1)初始解:初始解释算法迭代的起点,试验表明,模拟退火算法是健壮的,即最终解的求得最优解并不十分依赖初始解的选取,从而可任意选择一个初始解。当然,如果初始解选择得当可以加快找到全局最优解。

​ 2)解空间:一般是离散的可行解的集合。

​ 3)目标函数:对优化目标的量化描述,是解空间到某个数集的一个映射,通常表示为若干优化目标的一个和式,应正确体现问题的整体优化要求且较易计算,当解空间包含不可行解时还应包括罚函数。

​ 算法从初始解开始,在解空间中进行随机搜索,最终搜索到最终目标值

假定初始解为左边蓝色点A,模拟退火算法会快速搜索到局部最优解B,但在搜索到局部最优解后,不是就此结束,而是会以一定的概率接受到左边的移动。也许经过几次这样的不是局部最优的移动后会到达全局最优点D,于是就跳出了局部最小值

根据热力学的原理,在温度为TT时,出现能量差为dEdE的降温的概率为p(dE)p(dE),表示为

算法的基本过程如下:

1.初始化:设定初始温度T,初始解状态S,终止温度T0;

2.降温过程:在T>T0的时候,循环以下步骤;

3.在解空间中随机搜索一个新解S’;

4.计算增量△E=E(S’)-E(S),其中C(S)为解S对应的目标函数值或称为评价函数;

5.若△E<0 则接受S’作为新的当前解,否则以概论exp(-△E/T)接受S’为当前解;

6.如果满足终止条件则输出当前解为最优解,结束程序.终止条件有两种情况,一是温度达到了最低温度T0;二是连续取若干个新解都没有跳出当前最优解;

三、模拟退火算法的优缺点

模拟退火算法的应用很广泛,可以高效地求解NP完全问题,如货郎担问题(Travelling Salesman Problem,简记为TSP)、最大截问题(Max Cut Problem)、0-1背包问题(Zero One Knapsack Problem)、图着色问题(Graph Colouring Problem)等等,但其参数难以控制,不能保证一次就收敛到最优值,一般需要多次尝试才能获得(大部分情况下还是会陷入局部最优值)。观察模拟退火算法的过程,发现其主要存在如下三个参数问题:

(1) 温度T的初始值设置问题
  温度TT的初始值设置是影响模拟退火算法全局搜索性能的重要因素之一、初始温度高,则搜索到全局最优解的可能性大,但因此要花费大量的计算时间;反之,则可节约计算时间,但全局搜索性能可能受到影响。

(2) 退火速度问题,即每个TT值的迭代次数
  模拟退火算法的全局搜索性能也与退火速度密切相关。一般来说,同一温度下的“充分”搜索是相当必要的,但这也需要计算时间。循环次数增加必定带来计算开销的增大。

(3) 温度管理问题
  温度管理问题也是模拟退火算法难以处理的问题之一。实际应用中,由于必须考虑计算复杂度的切实可行性等问题,常采用如下所示的降温方式:
T=α×T.α∈(0,1).
T=α×T.α∈(0,1).

注:为了保证较大的搜索空间,αα一般取接近于1的值,如0.95、0.9。

算法实践:

import numpy as np
import matplotlib.pyplot as plt

def inputfun(x):
    return (x-2)*(x+3)*(x+8)*(x-9)

initT = 1000 #初始温度
minT = 1 #温度下限
iterL = 1000 #每个T值的迭代次数
delta = 0.95 #温度衰减系数
k = 1

initx = 10*(2*np.random.rand()-1)
nowt = initT
print("初始解:",initx)

xx = np.linspace(-10,10,300)
yy = inputfun(xx)
plt.figure()
plt.plot(xx,yy)
plt.plot(initx,inputfun(initx),'o')

#模拟退火算法寻找最小值过程
while nowt>minT:
    for i in np.arange(1,iterL,1):
        funVal = inputfun(initx)
        xnew = initx+(2*np.random.rand()-1)
        if xnew>=-10 and xnew<=10:
            funnew = inputfun(xnew)
            res = funnew-funVal
            if res<0:
                initx = xnew
            else:
                p = np.exp(-(res)/(k*nowt))
                if np.random.rand()<p:
                    initx = xnew

    nowt = nowt*delta

print("最优解:",initx)
print("最优值:",inputfun(initx))
plt.plot(initx,inputfun(initx),'*r')
plt.show()

你可能感兴趣的:(模拟退火)