现代优化算法-模拟退火

本文深入解析模拟退火算法,一种源于固体退火原理的优化算法,适用于解决NP类问题,如旅行商问题(TSP)。文章详细阐述了算法的基本原理、Metropolis准则、温度衰减函数及迭代终止准则,通过实例讲解算法的具体应用。
摘要由CSDN通过智能技术生成

现代优化算法-模拟退火

2020/1/19

简单理解模拟退火-求最大值

兔子们用酒将自己灌醉了,它们随机跳了很长的时间。在这期间,他们可能走向高处,也可能踏入平地。但是,随着时间的流逝,他们渐渐清醒了并朝着最高方向跳去。


模拟退火算法(SAA)来源于固体退火原理,将固体加温至充分高,再让其徐徐冷却,加温时,固体内部粒子随温升变为无序状,内能增大,而徐徐冷却时粒子渐趋有序,在每个温度都达到平衡态,最后在常温时达到基态,内能减为最小。模拟退火算法能够很好的解决NP问题。

模拟退火算法能够很好的解决NP问题。NP类问题是指一个复杂问题不能确定是否在多项式时间内找到答案,但是可以在多项式时间内验证答案是否正确。NP类问题数量很大,如完全子图问题、图着色问题、旅行商TSP问题等。


Metropolis算法

假设材料在状态 i i i下的能量为 E ( i ) E(i) E(i),那么材料在温度 T T T时从状态 i i i进入状态 j j j就遵循如下规律:

(1)如果 E ( j ) ≤ E ( i ) E(j) \leq E(i) E(j)E(i),则接受该状态被转换。

(2)如果 E ( j ) > E ( i ) E(j)>E(i) E(j)>E(i),则状态转换被概率 e E ( i ) − E ( j ) K T e^{\frac{E(i)-E(j)}{KT}} eKTEiEj接受。

其中 K K K是物理学中的玻尔兹曼常数。T是材料温度。


模拟退火算法

  • T = T 0 T=T_0 T=T0,随机生成一个初始解 x 0 x_0 x0

  • T T T等于冷却进度表中的下一个值 T i T_i Ti。(温度T的变化服从某种递减函数)。

  • 根据当前解 x i x_i xi进行扰动,产生一个新的解 x j x_j xj。计算相应的目标函数值 f ( x j ) f(x_j) f(xj)

  • f ( x j ) < f ( x i ) f(x_j)<f(x_i) f(xj)<f(xi),则接受新解。

    f ( x j ) > f ( x i ) f(x_j)>f(x_i) f(xj)>f(xi),若 r a n d < p rand<p rand<p,则接受新解 x j x_j xj r a n d rand rand是随机生成数。

    Metropolis准则:
    p = { ​ ​ 1 , f ( x j ) < f ( x i ) ​ e − f ( x i ) − f ( x j ) T , f ( x j ) > f ( x i ) ​ p=\left\{​\begin{aligned}​1, f(x_j)<f(x_i) \\​e^{-\tfrac{f(x_i)-f(x_j)}{T}},f(x_j)>f(x_i)\\\end{aligned}​\right. p=1,f(xj)<f(xi)eTf(xi)f(xj),f(xj)>f(xi)

扰动的方式有许多种,可以自行确定。

  • 在温度 T i T_i Ti下,重复 L k L_k Lk次的扰动和接受过程。也就是上述过程中的3、4.
  • 判断T是否已经达到 T f T_f Tf,如果是,则终止算法。否则继续下一个 T T T值。

符号说明

符号意义备注
T 0 T_0 T0冷却开始时的温度
T ( t ) T(t) T(t)温度衰减函数将连续的温度点转换为离散点
T f T_f Tf控制参数T的终值停止准则
L k L_k Lk马尔科夫链长度任何一个温度的迭代次数

温度衰减函数 T ( t ) T(t) T(t)

常用的简单下降方式:
t k + 1 = α t k , 其 中 ( 0 < α < 1 ) t_{k+1}=\alpha t_{k},其中(0<\alpha<1) tk+1=αtk0<α<1
经典模拟退火算法的降温方式:
T ( t ) = T 0 1 g ( 1 + t ) T(t)=\cfrac{T_0}{1g(1+t)} T(t)=1g(1+t)T0
快速模拟退火算法的降温方式
T ( t ) = T 0 1 + α t T(t)=\frac{T_0}{1+\alpha t} T(t)=1+αtT0

内、外循环终止准则(最大迭代次数)

内循环

也称Metropolis抽样稳定准则。用于决定在各温度下产生候选解的数目。

(1)固定长度:在每一个温度迭代相同的步数,步数的选取同问题的大小有关。

(2)随着温度的下降,将同一温度的迭代步数增加。(由接受和拒绝的比率来控制迭代步数。)

外循环

零度法:设置终止温度的阀值。很小的正数 ξ \xi ξ。如0.000001.

循环总数控制法:设置外循环迭代次数。 T m a x T_{max} Tmax=100;

不改进规则的控制法:算法搜索到的最优值连续若干步保持不变。


总结

整个优化过程就是不断寻找新解和缓慢降低温度的交替过程。

最终的解是对该问题寻优的结果。

缺点:如果降温速度过缓,求解过程因为算法太慢而效率减小。相对于简单的搜索算法不具有明显的优势。如果降温速度过快,很可能最终得不到全局最优解。

  • 要确定在每一温度下状态转换的结束准则。 也就是零度法或者不改进规则法。

  • 初始温度的选择还有确定某个可行解的邻域的方法也要恰当。


题目解析

题目原文:https://blog.csdn.net/astandoffish/article/details/77189620

我方有一个基地,经度和纬度为(70,40)。假设我方飞机的速度为1000公里/小时。我方派一架飞机从基地出发,侦察完敌方所有目标,再返回原来的基地。在敌方每一目标点的侦察时间不计,求该架飞机所花费的时间(假设我方飞机巡航时间可以充分长)。

代码符号含义备注
d i j d_{ij} dij i i i与点 j j j的距离对称矩阵
p a t h path path路径各点排列组成的路径
l o n g long long总路程同时作为判断条件,判断新解是否被接受
d j dj dj代价函数值代价函数计算的是变动路程 Δ d \Delta d Δd

S = [ 1 , 2 , 3 , ⋯   , 102 ] S=[1,2,3,\cdots,102] S=[1,2,3,,102]

是所有路径点标签的集合。

(共有100个敌方基地,飞机需要从我方基地出发与降落,因此初始点1和中止点102均为我方基地。)

而每一个路径点都可能会被第二次,第三次,…,第101次观察。记 π i = j \large\pi_{i}=j πi=j 表示第i次经过j点, ( j ∈ 1 , 2 , ⋯   , 102 ) (j \in 1,2,\cdots,102) (j1,2,,102)

其中,初始点和终止点 π 1 , π 102 \large\pi_{1},\large\pi_{102} π1,π102必等于1和102。

产生初始解

程序用蒙特卡洛法产生初始解,具体操作见代码部分。

产生新解

随机生成两个序号 u 、 v u、v uv

现有解:
π 1 ⋯ π u − 1 π u π u + 1 ⋯ π v − 1 π v π v + 1 ⋯ π 102 \pi_1 \cdots \pi_{u-1} \pi_u \pi_{u+1} \cdots\pi_{v-1}\pi_{v}\pi_{v+1} \cdots \pi_{102} π1πu1πuπu+1πv1πvπv+1π102
使用两点变换法,即颠倒 u , v u,v u,v之间的路径顺序:
π 1 ⋯ π u − 1 π v π v − 1 ⋯ π u + 1 π u π v + 1 ⋯ π 102 \pi_1 \cdots \pi_{u-1} \pi_v \pi_{v-1} \cdots\pi_{u+1}\pi_{u}\pi_{v+1} \cdots \pi_{102} π1πu1πvπv1πu+1πuπv+1π102
这样便产生了新的解。注意,解的含义是路径。

退火过程

产生新解的过程中,实际距离变化的只有 u 、 v u、v uv改变的边界处变动。

因此,代价函数可以表示为:
Δ d = ( d π u − 1 π v + d π u π v + 1 ) − ( d π u − 1 π u + d π v π v + 1 ) \Delta d =(d_{\pi_{u-1}\pi_{v}}+d_{\pi_{u}\pi_{v+1}})-(d_{\pi_{u-1}\pi_u}+d_{\pi_{v}\pi_{v+1}}) Δd=(dπu1πv+dπuπv+1)(dπu1πu+dπvπv+1)
通过这个代价函数,结合metropolis接受准则,判断是否降温。

最终温度达到设定的值(极小),算法结束。

这里给出的是python代码,参考了matlab代码修改而成。

import pandas as pd
import matplotlib.pyplot as plt
import math
import numpy as np
import random
import matplotlib.pyplot as plt

pp = open('路径数据文件')
data = pd.read_table(pp,header=None,sep=' ')

df = pd.DataFrame(data)

# ### 转换为单列,便于合并

x = df.iloc[:, 0:8:2]
x = pd.DataFrame(x.values.reshape(-1,1))
y = df.iloc[:, 1:8:2]
y = pd.DataFrame(y.values.reshape(-1,1))

sj = pd.concat([x,y],axis=1,ignore_index=True)
sj = sj.rename(columns=({0:'x',1:'y'}))
sj = sj.values

loc0 = [70,40]
sj = np.insert(sj, 0 ,values=loc0,axis=0)
sj = np.insert(sj, len(sj) ,values=loc0,axis=0)
#增加初始列


length = len(sj)
length


sj=sj*math.pi/180 #角度化弧度


#距离计算
d = np.zeros([length,length])
for i in range(0,length-1):
    for j in range(i+1,length):
        temp = math.cos(sj[i,0]-sj[j,0])*math.cos(sj[i,1])*math.cos(sj[j,1])+math.sin(sj[i,1])*math.sin(sj[j,1])#计算余弦值
        d[i,j]=6370*math.acos(temp)
d = d+d.T #做成对称阵


path = []
long = np.inf
for i in range(1000): #蒙特卡洛法设定初始解
    array_rand = list(range(2,length))
    np.random.shuffle(array)
    path_0 = [1]+array_rand+[length]
    #产生介于1与长度之间的随机整数。
    temp = 0
    for j in range(length-2):
        temp+=d[path_0[j],path_0[j+1]]
    if temp<long:
        path = path_0
        long = temp
e=0.1**30 #极小值(零度法)
L=200000 #(迭代次数)
at=0.999
T=1; 


# ### 退火过程


#产生新解
for i in range(L):
    c = 1+np.floor((length-2)*np.random.rand(1,2))
    c = c.astype(np.int)
    c.sort()
    c1 = c[0,0]
    c2 = c[0,1]
    #计算代价函数值
    dj=d[path[c1-1]-1,path[c2]-1]+d[path[c1]-1,path[c2+1]-1]-d[path[c1-1]-1,path[c1]-1]-d[path[c2]-1,path[c2+1]-1]
    #接受准则
    if dj<0:
        tt = path[c1:c2+1]
        tt = tt[::-1]
        path=path[0:c1]+tt+path[c2+1:length]#将中间段倒置得到新路径
        long = long + dj
        T = T*at #接受并降温
    elif np.exp(-dj/T)>np.random.rand(1):#路径没有变短,以一定概率接受
        tt = path[c1:c2+1]
        tt = tt[::-1]
        path=path[0:c1]+tt+path[c2+1:length]
        long = long + dj
        T = T*at #接受并降温
    if T<e:
        break


xx = []
yy = []
for i in path:
    xx.append(sj[i-1,0])
    yy.append(sj[i-1,1])


plt.figure(figsize=(8,8),dpi=200)
plt.style.use("ggplot")  
plt.title('Total distance: '+ str(long))
plt.plot(xx, yy,'o-')
plt.show()

输出结果如下:
路径图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值