通过上面这个视频可以了解到模拟退火算法的基础概念,这个视频也是我看过最通俗易懂的讲解了。
灵活运用视频的方法,用python代码实现一元五次方程的求解,方程如下:
对于这个方程,要将其转变为函数,才能进行求解:
将这个问题转为求解函数f的最小值问题,注意这里加了一个绝对值符号,这样f最小值的解,才是这个方程的根
然后把函数用代码敲出来:
import numpy as np
def fun(x: float):
x = x ** 5 + 10 * (x ** 3) + 20 * x - 4
return np.fabs(x)
定义解的随机获取方式和更新方式(通过random随机得到一个解):
import random
x = random.uniform(-100000, 100000) #得到一个随机浮点数
dx = x + random.uniform(-100000, 100000) * t #每次更新x都受到t都受到温度的影响,温度越高x的变化越大,温度越低x的变化范围越小
做好这两步,就可以带入的模拟退火的框架里求解了,完整代码如下:
import random
import numpy as np
import matplotlib.pyplot as plt
t = 200000
dt = 0.993
eps = 1e-14
def fun(x: float):
x = x ** 5 + 10 * (x ** 3) + 20 * x - 4
return np.fabs(x)
n = 0
x = random.uniform(-100000, 100000)
x = float(x)
f = fun(x)
f_values = [] # 存储每次循环后的 f 值
x_values = [] # 存储每次循环后的 x 值
while (t > eps):
dx = x + random.uniform(-100000, 100000) * t
df = fun(dx)
if df < f:
f = df
x = dx
elif np.exp((f - df) / t) * 100000 > random.randint(0, 100000):
f = df
x = dx
t = t * dt
n += 1
f_values.append(f)
x_values.append(x)
print(f"f = {f},x = {x},第{n}次循环")
# 绘制折线图
plt.figure()
plt.plot(range(1, n + 1), f_values, label='f value')
plt.plot(range(1, n + 1), x_values, label='x value')
plt.xlabel('Iterations')
plt.ylabel('Value')
plt.legend()
plt.show()
我们运行代码,查看结果,并输出折线图:
那么我们看到电脑算到的结果为x=0.1962,这个时候f的值就非常接近与零了,那么在误差允许的范围内,我们就可以认为f等于零
总结
通过模拟退火算法求解函数最小值是具有通用性的,理论上只要把函数f改成你想求的任意一个函数,都能求出最小值(前提,x不受约束的条件下),那么在x受约束的条件下该如何写退火算法进行求解呢?可以看我后续更新