之前两三个星期都在不间断地准备期末考试,今天终于把模拟退火算法的代码搞定了!
from random import *
from math import *
import numpy as np
import matplotlib.pyplot as plt
f=lambda x:x+10*np.sin(3*x)+np.cos(x)#目标函数
#模拟退火算法有总共5个要素
t=20000#初始温度
end_t=10**(-7)#结束温度
alpha=0.98#衰减系数
mirkiv_len=1000#马尔可夫链长
s=3#初始解
#给定求函数最优值考虑到的区间
a=0
b=9
#外层循环:退火,直到温度小于等于结束温度
x=[]
y=[]
z=0
while t>end_t:
#内层循环:马尔可夫扰动
ins=0 #记录迭代次数
while ins<=mirkiv_len:
if a<s<b:
snew=s+0.01*(2*random()-1)
elif s<=a:
snew=s+0.01*random()
elif s>=b:
snew=s-0.01*random()
if f(snew)<f(s):
s=snew
else:
p=random()
if p<e**((f(s)-f(snew))/t):
s=snew
else:
pass
ins+=1
z+=1
x.append(z)
y.append(f(s))
t=t*alpha
#这里是原来的函数图像,读者可以去掉#号自己查看
x2=np.linspace(0,9,10000)
y2=f(x2)
#plt.figure()
#plt.plot(x2,y2)
#plt.show()
y1=[min(y2) for i in range(0,len(y))]
print(f(s))
plt.figure()
plt.plot(x,y,'b-',label='SA')
plt.plot(x,y1,'r-',label='min(f)')
plt.legend()
plt.show()
下面是效果图:
很好地与真正地最小值重合了,说明算法成功了!但是偶尔也会有下面的小差错:
“不小心”跳出了全局最优,找到另一个局部最优了~~
所以在使用模拟退火算法的时候要多运行几次程序找到最优的解,当然有时候也需要调整马尔科夫链长(即迭代次数),初始解,以及衰减系数找到最适合目标函数的模拟退火参数。
关于模拟退火算法的原理介绍,请移步《模拟退火算法及马尔科夫链》~~