模擬退火算法


一、什么是模擬退火算法

1、爬山算法

在了解模擬退火算法之前,先來看一下爬山算法:爬山算法是一種貪心算法,該算法每次從當前的解空間中選取一個解作為最優解,直到達到一個局部最優解。假設函數f(x)的圖像如下圖:

現在使用爬山算法來求f(x)的最大值,若C為當前最優解,則爬山算法搜索到A就會停止搜索,這會獲得一個局部最優解,而不是全局最優解。

2、模擬退火算法

繼續考慮尋找f(x)最大值的問題,爬山算法搜索到A點時就會停止搜索,原因是A點左右的值均小於A點的值。模擬退火算法采用的解決辦法是以一定的概率選擇A兩邊的點,盡管A兩邊的點並不是局部最優解,這樣就有一定的概率搜索到D點,從而搜索到B點,最終獲得了全局最優解。
上文中的一定概率來自於固體退火原理:當固體溫度較高時,物質內能較大,固體內部分子運動劇烈;當溫度逐漸降低時,物體內能也隨之降低,分子運動趨於平穩;當固體溫度降到常溫時,固體內部分子運動最終平穩。根據Metropolis准則,粒子在溫度T時趨於平衡的概率為e^(-ΔE/(kT)),其中E為溫度T時的內能,ΔE為其改變量,k為Boltzmann常數。

二、模擬退火算法步驟

三、模擬退火算法流程圖

四、模擬退火算法偽代碼

/*
* J(y):在狀態y時的評價函數值
* Y(i):表示當前狀態
* Y(i+1):表示新的狀態
* r: 用於控制降溫的快慢
* T: 系統的溫度,系統初始應該要處於一個高溫的狀態
* T_min :溫度的下限,若溫度T達到T_min,則停止搜索
*/
while( T > T_min )
{
  dE = J( Y(i+1) ) - J( Y(i) ) ; 

  if ( dE >=0 ) //表達移動后得到更優解,則總是接受移動
       Y(i+1) = Y(i) ; //接受從Y(i)到Y(i+1)的移動
  else
  {
       // 函數exp( dE/T )的取值范圍是(0,1) ,dE/T越大,則exp( dE/T )也
      if ( exp( -dE/T ) > random( 0 , 1 ) )
      Y(i+1) = Y(i) ; //接受從Y(i)到Y(i+1)的移動
  }
  T = r * T ; //降溫退火 ,0<r<1 。r越大,降溫越慢;r越小,降溫越快
  /*
  * 若r過大,則搜索到全局最優解的可能會較高,但搜索的過程也就較長。若r過小,則搜索的過程會很快,但最終可能會達到一個局部最優值
  */
  i ++ ;
}

五、使用模擬退火算法解決旅行商問題

旅行商問題(TravelingSalesmanProblem,TSP)是一個經典的組合優化問題。經典的TSP可以描述為:一個商品推銷員要去若干個城市推銷商品,該推銷員從一個城市出發,需要經過所有城市后,回到出發地。應如何選擇行進路線,以使總的行程最短。
該問題可以使用模擬退火算法解決,python代碼如下:

import math
import time
import random

# 初始溫度
T = 50000
# 最低溫度
T_end = 1e-8
# 在每個溫度下的迭代次數
L = 100
# 退火系數
delta = 0.98

# 31個城市的坐標
citys = [[1304,2312],[3639,1315],[4177,2244],[3712,1399],[3488,1535],[3326,1556],[3238,1229],[4196,1004],[4312,790],[4386,570],[3007,1970],[2562,1756],[2788,1491],[2381,1676],[1332,695],[3715,1678],[3918,2179],[4061,2370],[3780,2212],[3676,2578],[4029,2838],[4263,2931],[3429,1908],[3507,2367],[3394,2643],[3439,3201],[2935,3240],[3140,3550],[2545,2357],[2778,2826],[2370,2975]]
# 存儲兩個城市之間的距離
d = [[0 for i in range(31)] for j in range(31)]
# 存儲一條路徑
ans = []

# 計算降溫次數
cnt=0

# 計算兩個城市之間的距離
def get_city_distance():
    for i in range(len(citys)):
        for j in range(i, len(citys)):
            d[i][j] = d[j][i] = math.sqrt((citys[i][0]-citys[j][0])**2 + (citys[i][1]-citys[j][1])**2)

# 使用隨機交換路徑中兩個城市的位置來產生一條新路徑
def create_new(a):
    i = random.randint(0, len(a)-1)
    j = random.randint(0, len(a)-1)
    a[i], a[j] = a[j], a[i]
    return a

# 獲取路徑的長度
def get_route_distance(a):
    dist = 0
    for i in range(len(a)-1):
        dist+=d[a[i]][a[i+1]]
    return dist
    
def saa():
    get_city_distance()
    cnt = 0
    ans = range(0, len(citys))
    t = T
    result = 0
    while t >= T_end:
        for i in range(0, L):
            ans_new = create_new(ans)
            d1, d2 = get_route_distance(ans), get_route_distance(ans_new)
            de = d2 - d1
            result = d1
            if de<0:
                ans = ans_new
                result = d2
            else:
                if(math.e**(-de/T) > random.random()):
                    ans = ans_new
                    result = d2
        t = t * delta
        cnt+=1
    print "路徑如下:"
    print ans
    print "路徑長度:"
    print result
    print "降溫次數:"
    print cnt
    
start = time.time()
saa()
end = time.time()
print "運行耗時:" + str(end-start) + "s"

輸出:

路徑如下:
[5, 18, 29, 28, 6, 24, 12, 17, 15, 27, 21, 1, 22, 9, 8, 23, 19, 25, 30, 16, 26, 13, 14, 7, 11, 20, 4, 2, 3, 0, 10]
路徑長度:
40605.6088359
降溫次數:
1448
運行耗時:2.93400001526s

六、參考

1、http://www.cnblogs.com/heaad/archive/2010/12/20/1911614.html
2、https://www.cnblogs.com/lyrichu/p/6688459.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM