模拟退火算法的原理
模拟退火算法(Simulated Annealing, SA)是一种全局优化算法,其灵感来源于物理学中的退火过程。在物理退火过程中,通过逐渐降低系统温度,使物质内部的原子从高能量状态慢慢转变到低能量状态,从而达到晶体结构的优化。模拟退火算法借鉴了这种过程,通过随机搜索和逐步降低"温度"来寻找优化问题的全局最优解。
关键概念
-
温度(Temperature): 控制搜索过程中的"探索"与"开发"平衡。高温下允许较大范围的随机搜索,低温下逐渐收敛到局部优化。
-
状态(State): 问题的一个解。
-
能量(Energy): 目标函数的值,反映当前状态的质量。
-
接受概率(Acceptance Probability): 用于决定是否接受一个新的状态,即使它的能量较高,以避免陷入局部最优解。
算法步骤
-
初始化温度 TT 和初始状态 SS。
-
重复以下步骤直到满足停止条件:
-
在当前状态 S 的邻域中随机选择一个新的状态 S'。
-
计算状态 S′ 的能量差 ΔE=E(S′)−E(S)。
-
如果 ΔE≤0,接受新的状态 S′;否则,以概率接受新的状态。
-
减少温度 T。
-
-
返回找到的最优状态。
应用
模拟退火算法广泛应用于组合优化问题和实际工程中的复杂优化问题。常见的应用包括:
-
旅行商问题(TSP): 通过模拟退火算法寻找最短路径。
-
排程问题: 优化工厂生产调度、考试安排等。
-
电路设计: 优化芯片设计中的布局和连线。
-
神经网络训练: 优化神经网络参数,避免陷入局部最优解。
旅行商问题求解:
python
import numpy as np
import matplotlib.pyplot as plt
# 生成随机城市坐标
def generate_cities(num_cities):
return np.random.rand(num_cities, 2)
# 计算路径长度
def path_length(cities, path):
"""
计算给定路径的总长度
:param cities: 城市坐标的二维数组
:param path: 城市访问顺序的数组
:return: 路径的总长度
"""
return np.sum(np.linalg.norm(cities[path] - cities[np.roll(path, -1)], axis=1))
# 交换路径中的两个城市
def swap_cities(path):
"""
随机交换路径中的两个城市
:param path: 城市访问顺序的数组
"""
i, j = np.random.choice(len(path), 2, replace=False)
path[i], path[j] = path[j], path[i]
# 模拟退火算法
def simulated_annealing(cities, initial_temp, cooling_rate, num_iterations):
"""
使用模拟退火算法寻找最短路径
:param cities: 城市坐标的二维数组
:param initial_temp: 初始温度
:param cooling_rate: 降温速率
:param num_iterations: 迭代次数
:return: 最佳路径及其长度和每次迭代的路径长度
"""
# 城市数量
num_cities = len(cities)
# 初始路径为随机顺序
current_path = np.arange(num_cities)
np.random.shuffle(current_path)
# 计算初始路径的长度
current_length = path_length(cities, current_path)
# 初始化最佳路径和长度
best_path = current_path.copy()
best_length = current_length
# 初始化温度
temp = initial_temp
# 记录路径长度变化
lengths = []
# 开始迭代
for _ in range(num_iterations):
# 创建新路径,通过交换当前路径中的两个城市
new_path = current_path.copy()
swap_cities(new_path)
# 计算新路径的长度
new_length = path_length(cities, new_path)
# 计算路径长度差
delta = new_length - current_length
# 决定是否接受新路径
if delta < 0 or np.random.rand() < np.exp(-delta / temp):
current_path = new_path
current_length = new_length
# 更新最佳路径
if new_length < best_length:
best_path = new_path
best_length = new_length
# 降低温度
temp *= cooling_rate
# 记录当前路径长度
lengths.append(current_length)
return best_path, best_length, lengths
# 参数设置
num_cities = 20
initial_temp = 100
cooling_rate = 0.99
num_iterations = 1000
cities = generate_cities(num_cities)
best_path, best_length, lengths = simulated_annealing(cities, initial_temp, cooling_rate, num_iterations)
# 可视化结果
plt.figure(figsize=(10, 5))
# 绘制城市和最佳路径
plt.subplot(1, 2, 1)
plt.plot(cities[:, 0], cities[:, 1], 'o')
for i in range(num_cities):
plt.text(cities[i, 0], cities[i, 1], str(i))
for i in range(num_cities):
plt.plot([cities[best_path[i], 0], cities[best_path[(i+1) % num_cities], 0]],
[cities[best_path[i], 1], cities[best_path[(i+1) % num_cities], 1]], 'r-')
plt.title(f"Best Path (Length: {best_length:.2f})")
# 绘制路径长度随迭代次数的变化
plt.subplot(1, 2, 2)
plt.plot(lengths)
plt.xlabel('Iteration')
plt.ylabel('Path Length')
plt.title('Path Length over Iterations')
plt.tight_layout()
plt.show()