Python + 模拟退火

模拟退火(Simulated Annealing,SA)是一种用于全局优化问题的随机化算法,受到物理中“退火”过程的启发。退火是金属从高温慢慢冷却到低温的过程,其中金属分子从混乱的状态逐渐变得有序。模拟退火利用类似的策略来找到一个优化问题的最优解。


一、工作原理


模拟退火的核心思想是通过模拟金属退火的过程,在搜索空间中逐渐寻找最优解。具体步骤如下:

1.初始状态和温度设定:从一个随机解开始,设定一个较高的初始温度(类似于物理过程中的温度)。
2.生成邻域解:通过小的随机变化生成当前解的邻域解(即稍微改变当前解的某些参数)。
3.接受准则:

  • 如果邻域解比当前解更好(即目标函数值更小或更大,取决于优化方向),则接受该邻域解。

4.降温过程:逐步降低温度(“冷却”过程)。温度的下降通常是指数型的,即每次降温的幅度逐渐减小。温度的降低意味着接受更差解的概率变小,从而收敛到一个最优解。
5.终止条件:当温度降到某个较低值,或达到预定的最大迭代次数时,停止搜索,最终得到一个解。

# 1、设定一个初始温度T(这个温度很高)
# 2、每次循环都退火一次
# 3、然后降低T的温度,我们通过让和 T 一个降温系数 dT(一个接近1的小数)相乘,达到慢慢降低温度的效果,直接接近于0((我们用eps来代表一个接近0的数)只要 T < eps 就可以退出循环)

T = 2000    # 初始温度
dT = 0.99   # 降温系数 delta T
eps = 1e-14 # 温度下限阈值

while T > eps:  # 循环条件:当温度高于阈值时继续退火
    # 这里写每次的退火操作

    T = T * dT  # 温度按系数下降

二、模拟退火的优点

  • 全局搜索能力强:模拟退火通过接受较差解避免了陷入局部最优解,增加了找到全局最优解的可能性。
  • 简单易实现:算法的结构简单,且不需要复杂的数学推导,易于实现。

三、模拟退火的缺点

  • 计算时间较长:尤其是在需要多次降温或温度下降较慢时,算法可能需要较长的时间才能找到较好的解。
  • 调参困难:温度的初始值、降温速率等参数的选择可能对结果有较大影响,往往需要多次实验进行调整。

四、应用领域

  • 组合优化问题:如旅行商问题、图着色问题、生产调度问题等。
  • 机器学习与数据挖掘:比如特征选择、模型参数调优等。
  • 物理和化学领域:如蛋白质折叠问题、材料设计等。

五、代码演示部分

列题1:找到这个函数的最小值

from __future__ import division
import numpy as np
import math


# 定义目标函数(待优化的函数)
def aimFunction(x):
    y = x ** 3 - 60 * x ** 2 - 4 * x + 6
    return y


# 模拟退火算法参数初始化
T = 1000  # 初始温度
Tmin = 10  # 终止温度(温度下限)
x = np.random.uniform(low=0, high=100)  # 随机初始化自变量x
k = 50  # 内循环次数(每个温度下的迭代次数)
y = 0  # 目标函数值初始化
t = 0  # 迭代计数

# 模拟退火主循环:当温度大于等于终止温度时继续迭代
while T >= Tmin:
    for i in range(k):
        # 计算当前解的目标函数值
        y = aimFunction(x)

        # 在当前解的邻域内生成一个新解(扰动)
        # 邻域大小与温度T成正比,随着温度降低,搜索范围逐渐缩小
        xNew = x + np.random.uniform(low=-0.055, high=0.055) * T

        # 检查新解是否在定义域[0, 100]内
        if (0 <= xNew and xNew <= 100):
            yNew = aimFunction(xNew)

            # 如果新解更优(目标函数值更小),则接受新解
            if yNew - y < 0:
                x = xNew
            else:
                # 否则,依据Metropolis准则以一定概率接受较差解
                # 这个概率随着温度降低而减小
                p = math.exp(-(yNew - y) / T) # 注意负号
                r = np.random.uniform(low=0, high=1)
                if r < p:
                    x = xNew

    # 温度更新(降温)
    t += 1
    print(f"迭代次数: {t}, 当前温度: {T:.2f}")
    T = 1000 / (1 + t)  # 降温函数,随迭代次数增加温度逐渐降低 可以自己定义一个dT降温系数: T = T * dT

# 输出最优解及其对应的目标函数值
print(f"最优解 x = {x:.6f}, 目标函数值 y = {aimFunction(x):.6f}")

控制台展示: 

E:\python\python.exe D:\compiler\python\建模\模拟退火test\1.py 
迭代次数: 1, 当前温度: 1000.00
迭代次数: 2, 当前温度: 500.00
迭代次数: 3, 当前温度: 333.33
迭代次数: 4, 当前温度: 250.00
迭代次数: 5, 当前温度: 200.00
迭代次数: 6, 当前温度: 166.67
迭代次数: 7, 当前温度: 142.86
迭代次数: 8, 当前温度: 125.00
迭代次数: 9, 当前温度: 111.11
迭代次数: 10, 当前温度: 100.00
迭代次数: 11, 当前温度: 90.91
迭代次数: 12, 当前温度: 83.33
迭代次数: 13, 当前温度: 76.92
迭代次数: 14, 当前温度: 71.43
迭代次数: 15, 当前温度: 66.67
迭代次数: 16, 当前温度: 62.50
迭代次数: 17, 当前温度: 58.82
迭代次数: 18, 当前温度: 55.56
迭代次数: 19, 当前温度: 52.63
迭代次数: 20, 当前温度: 50.00
迭代次数: 21, 当前温度: 47.62
迭代次数: 22, 当前温度: 45.45
迭代次数: 23, 当前温度: 43.48
迭代次数: 24, 当前温度: 41.67
迭代次数: 25, 当前温度: 40.00
迭代次数: 26, 当前温度: 38.46
迭代次数: 27, 当前温度: 37.04
迭代次数: 28, 当前温度: 35.71
迭代次数: 29, 当前温度: 34.48
迭代次数: 30, 当前温度: 33.33
迭代次数: 31, 当前温度: 32.26
迭代次数: 32, 当前温度: 31.25
迭代次数: 33, 当前温度: 30.30
迭代次数: 34, 当前温度: 29.41
迭代次数: 35, 当前温度: 28.57
迭代次数: 36, 当前温度: 27.78
迭代次数: 37, 当前温度: 27.03
迭代次数: 38, 当前温度: 26.32
迭代次数: 39, 当前温度: 25.64
迭代次数: 40, 当前温度: 25.00
迭代次数: 41, 当前温度: 24.39
迭代次数: 42, 当前温度: 23.81
迭代次数: 43, 当前温度: 23.26
迭代次数: 44, 当前温度: 22.73
迭代次数: 45, 当前温度: 22.22
迭代次数: 46, 当前温度: 21.74
迭代次数: 47, 当前温度: 21.28
迭代次数: 48, 当前温度: 20.83
迭代次数: 49, 当前温度: 20.41
迭代次数: 50, 当前温度: 20.00
迭代次数: 51, 当前温度: 19.61
迭代次数: 52, 当前温度: 19.23
迭代次数: 53, 当前温度: 18.87
迭代次数: 54, 当前温度: 18.52
迭代次数: 55, 当前温度: 18.18
迭代次数: 56, 当前温度: 17.86
迭代次数: 57, 当前温度: 17.54
迭代次数: 58, 当前温度: 17.24
迭代次数: 59, 当前温度: 16.95
迭代次数: 60, 当前温度: 16.67
迭代次数: 61, 当前温度: 16.39
迭代次数: 62, 当前温度: 16.13
迭代次数: 63, 当前温度: 15.87
迭代次数: 64, 当前温度: 15.62
迭代次数: 65, 当前温度: 15.38
迭代次数: 66, 当前温度: 15.15
迭代次数: 67, 当前温度: 14.93
迭代次数: 68, 当前温度: 14.71
迭代次数: 69, 当前温度: 14.49
迭代次数: 70, 当前温度: 14.29
迭代次数: 71, 当前温度: 14.08
迭代次数: 72, 当前温度: 13.89
迭代次数: 73, 当前温度: 13.70
迭代次数: 74, 当前温度: 13.51
迭代次数: 75, 当前温度: 13.33
迭代次数: 76, 当前温度: 13.16
迭代次数: 77, 当前温度: 12.99
迭代次数: 78, 当前温度: 12.82
迭代次数: 79, 当前温度: 12.66
迭代次数: 80, 当前温度: 12.50
迭代次数: 81, 当前温度: 12.35
迭代次数: 82, 当前温度: 12.20
迭代次数: 83, 当前温度: 12.05
迭代次数: 84, 当前温度: 11.90
迭代次数: 85, 当前温度: 11.76
迭代次数: 86, 当前温度: 11.63
迭代次数: 87, 当前温度: 11.49
迭代次数: 88, 当前温度: 11.36
迭代次数: 89, 当前温度: 11.24
迭代次数: 90, 当前温度: 11.11
迭代次数: 91, 当前温度: 10.99
迭代次数: 92, 当前温度: 10.87
迭代次数: 93, 当前温度: 10.75
迭代次数: 94, 当前温度: 10.64
迭代次数: 95, 当前温度: 10.53
迭代次数: 96, 当前温度: 10.42
迭代次数: 97, 当前温度: 10.31
迭代次数: 98, 当前温度: 10.20
迭代次数: 99, 当前温度: 10.10
迭代次数: 100, 当前温度: 10.00
最优解 x = 40.215724, 目标函数值 y = -32152.060650

进程已结束,退出代码为 0
 

 

 列题2:找到 n 的算数平方根

from __future__ import division
import numpy as np
import math
import matplotlib.pyplot as plt


# 获取用户输入
n = float(input("Enter a positive number: "))

# 目标函数:|x^2 - n|
def aimFunction(x):
    return math.fabs(x * x - n)

# 模拟退火参数
T = max(100, n)  # 初始温度
Tmin = 1e-14     # 终止温度
dT = 0.995       # 降温系数
x = np.random.uniform(low=0, high=np.sqrt(n)*2)  # 初始解
k = 30           # 内循环次数
history = []     # 记录迭代过程

# 主循环
while T >= Tmin:
    for i in range(k):
        y = aimFunction(x)
        # 生成新解(扰动)
        xNew = x + np.random.uniform(-1, 1) * T * 0.1
        if xNew >= 0:  # 确保非负
            yNew = aimFunction(xNew)
            # 接受准则
            if yNew < y or np.random.random() < math.exp(-(yNew - y)/T):
                x = xNew
    history.append((T, x, aimFunction(x)))
    T *= dT  # 降温
    # 打印进度
    if len(history) % 100 == 0:
        print(f"Iteration: {len(history)}, Temperature: {T:.6f}, Current Best: {x:.6f}")

# 输出结果
print(f"\nInput Value: {n}")
print(f"Calculated Square Root: {x:.10f}")
print(f"Actual Square Root: {math.sqrt(n):.10f}")
print(f"Absolute Error: {abs(x - math.sqrt(n)):.10f}")

# 提取绘图数据
iterations = range(1, len(history)+1)
temperatures = [h[0] for h in history]
objective_values = [h[2] for h in history]

# 绘图(使用英文标签,避免中文)
plt.figure(figsize=(10, 8))

# 子图1:目标函数随迭代次数变化
plt.subplot(2, 1, 1)  # 创建2行1列的子图布局,选择第1个子图(上方)
plt.plot(iterations, objective_values, 'b-', linewidth=1)  # 绘制蓝色实线
plt.xlabel('Iterations')  # x轴标签:迭代次数
plt.ylabel('Objective Function |x^2 - n|')  # y轴标签:目标函数值
plt.title('Objective Function vs. Iterations')  # 子图标题
plt.grid(True, linestyle='--', alpha=0.7)  # 添加虚线网格(透明度70%)

# 子图2:目标函数随温度变化
plt.subplot(2, 1, 2)  # 选择第2个子图(下方)
plt.plot(temperatures, objective_values, 'r-', linewidth=1)  # 绘制红色实线
plt.xscale('log')  # 设置x轴为对数尺度(因为温度指数下降)
plt.xlabel('Temperature (Log Scale)')  # x轴标签:温度(对数尺度)
plt.ylabel('Objective Function |x^2 - n|')  # y轴标签:目标函数值
plt.title('Objective Function vs. Temperature')  # 子图标题
plt.grid(True, linestyle='--', alpha=0.7)  # 添加虚线网格

plt.tight_layout()  # 自动调整子图参数,避免标签重叠
plt.show()  # 显示图形

 控制台展示:

E:\python\python.exe D:\compiler\python\建模\模拟退火test\2.py 
Enter a positive number: 2
Iteration: 100, Temperature: 60.577044, Current Best: 1.384569
Iteration: 200, Temperature: 36.695782, Current Best: 6.986883
Iteration: 300, Temperature: 22.229220, Current Best: 1.302009
Iteration: 400, Temperature: 13.465804, Current Best: 3.457651
Iteration: 500, Temperature: 8.157186, Current Best: 1.348156
Iteration: 600, Temperature: 4.941382, Current Best: 1.481375
Iteration: 700, Temperature: 2.993343, Current Best: 1.213146
Iteration: 800, Temperature: 1.813279, Current Best: 1.414416
Iteration: 900, Temperature: 1.098431, Current Best: 1.683188
Iteration: 1000, Temperature: 0.665397, Current Best: 1.431369
Iteration: 1100, Temperature: 0.403078, Current Best: 1.260856
Iteration: 1200, Temperature: 0.244173, Current Best: 1.497106
Iteration: 1300, Temperature: 0.147913, Current Best: 1.270650
Iteration: 1400, Temperature: 0.089601, Current Best: 1.335943
Iteration: 1500, Temperature: 0.054278, Current Best: 1.426471
Iteration: 1600, Temperature: 0.032880, Current Best: 1.429626
Iteration: 1700, Temperature: 0.019918, Current Best: 1.416934
Iteration: 1800, Temperature: 0.012066, Current Best: 1.413867
Iteration: 1900, Temperature: 0.007309, Current Best: 1.417952
Iteration: 2000, Temperature: 0.004428, Current Best: 1.414231
Iteration: 2100, Temperature: 0.002682, Current Best: 1.414696
Iteration: 2200, Temperature: 0.001625, Current Best: 1.414136
Iteration: 2300, Temperature: 0.000984, Current Best: 1.414561
Iteration: 2400, Temperature: 0.000596, Current Best: 1.414203
Iteration: 2500, Temperature: 0.000361, Current Best: 1.414287
Iteration: 2600, Temperature: 0.000219, Current Best: 1.414233
Iteration: 2700, Temperature: 0.000133, Current Best: 1.414250
Iteration: 2800, Temperature: 0.000080, Current Best: 1.414256
Iteration: 2900, Temperature: 0.000049, Current Best: 1.414253
Iteration: 3000, Temperature: 0.000029, Current Best: 1.414216
Iteration: 3100, Temperature: 0.000018, Current Best: 1.414218
Iteration: 3200, Temperature: 0.000011, Current Best: 1.414227
Iteration: 3300, Temperature: 0.000007, Current Best: 1.414215
Iteration: 3400, Temperature: 0.000004, Current Best: 1.414216
Iteration: 3500, Temperature: 0.000002, Current Best: 1.414212
Iteration: 3600, Temperature: 0.000001, Current Best: 1.414214
Iteration: 3700, Temperature: 0.000001, Current Best: 1.414215
Iteration: 3800, Temperature: 0.000001, Current Best: 1.414214
Iteration: 3900, Temperature: 0.000000, Current Best: 1.414213
Iteration: 4000, Temperature: 0.000000, Current Best: 1.414214
Iteration: 4100, Temperature: 0.000000, Current Best: 1.414214
Iteration: 4200, Temperature: 0.000000, Current Best: 1.414214
Iteration: 4300, Temperature: 0.000000, Current Best: 1.414214
Iteration: 4400, Temperature: 0.000000, Current Best: 1.414214
Iteration: 4500, Temperature: 0.000000, Current Best: 1.414214
Iteration: 4600, Temperature: 0.000000, Current Best: 1.414214
Iteration: 4700, Temperature: 0.000000, Current Best: 1.414214
Iteration: 4800, Temperature: 0.000000, Current Best: 1.414214
Iteration: 4900, Temperature: 0.000000, Current Best: 1.414214
Iteration: 5000, Temperature: 0.000000, Current Best: 1.414214
Iteration: 5100, Temperature: 0.000000, Current Best: 1.414214
Iteration: 5200, Temperature: 0.000000, Current Best: 1.414214
Iteration: 5300, Temperature: 0.000000, Current Best: 1.414214
Iteration: 5400, Temperature: 0.000000, Current Best: 1.414214
Iteration: 5500, Temperature: 0.000000, Current Best: 1.414214
Iteration: 5600, Temperature: 0.000000, Current Best: 1.414214
Iteration: 5700, Temperature: 0.000000, Current Best: 1.414214
Iteration: 5800, Temperature: 0.000000, Current Best: 1.414214
Iteration: 5900, Temperature: 0.000000, Current Best: 1.414214
Iteration: 6000, Temperature: 0.000000, Current Best: 1.414214
Iteration: 6100, Temperature: 0.000000, Current Best: 1.414214
Iteration: 6200, Temperature: 0.000000, Current Best: 1.414214
Iteration: 6300, Temperature: 0.000000, Current Best: 1.414214
Iteration: 6400, Temperature: 0.000000, Current Best: 1.414214
Iteration: 6500, Temperature: 0.000000, Current Best: 1.414214
Iteration: 6600, Temperature: 0.000000, Current Best: 1.414214
Iteration: 6700, Temperature: 0.000000, Current Best: 1.414214
Iteration: 6800, Temperature: 0.000000, Current Best: 1.414214
Iteration: 6900, Temperature: 0.000000, Current Best: 1.414214
Iteration: 7000, Temperature: 0.000000, Current Best: 1.414214
Iteration: 7100, Temperature: 0.000000, Current Best: 1.414214
Iteration: 7200, Temperature: 0.000000, Current Best: 1.414214
Iteration: 7300, Temperature: 0.000000, Current Best: 1.414214

Input Value: 2.0
Calculated Square Root: 1.4142135624
Actual Square Root: 1.4142135624
Absolute Error: 0.0000000000

生成图展示:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值