资讯动态

模拟退火算法原理与Python实现:从物理退火到全局优化

发布时间:2026/8/28 9:26:53 来源:尧图企业网站定制
1. 项目概述从“烧铁淬火”到“寻优爬山”在数学建模和优化领域我们常常会遇到一个令人头疼的问题面对一个复杂、崎岖、拥有无数个“山峰”和“山谷”的多元函数如何找到那个全局最优解而不是一头栽进最近的局部最优解里出不来这就像在一片连绵起伏的山脉中寻找海拔最低点你从某个地方出发如果只遵循“下坡”策略很容易就掉进一个山坳里以为到了最低点殊不知远处还有更深的峡谷。模拟退火算法Simulated Annealing, SA就是为了解决这类全局优化问题而诞生的一个绝妙灵感。它的思想源于固体退火过程将金属加热到高温使其内部粒子处于高能、无序状态然后缓慢降温粒子逐渐趋于有序最终在常温下达到能量最低的稳定状态。把这个物理过程抽象成算法就成了我们寻找函数最优解的利器。简单来说它允许我们在搜索过程中以一定的概率接受一个“更差”的解从而有机会跳出局部最优的陷阱去探索更广阔的解空间最终逼近全局最优。这个项目就是带你亲手用模拟退火算法去求解一个多元函数的最值问题。无论你是正在备战数学建模竞赛的学生还是对优化算法感兴趣的开发者通过这个从原理到代码的完整实践你不仅能掌握SA的核心思想更能获得一套可以直接用于解决实际问题的工具箱。我们将从最基础的原理讲起一步步推导并用Python实现一个清晰、可扩展的SA求解器最后用它去攻克几个经典的测试函数。相信我当你看到算法成功跳出局部最优、一步步逼近全局最优解时那种感觉就像亲手完成了一次精密的物理实验。2. 算法核心原理与物理隐喻拆解2.1 退火过程的数学抽象能量、温度与概率要理解模拟退火必须先吃透它的三个核心概念状态、能量和温度。在算法中它们分别对应着优化问题的解、目标函数值和控制参数。状态 (State) / 解 (Solution) 就是我们要求解的问题的一个可能答案。对于多元函数求最小值一个状态就是函数定义域内的一个点比如(x1, x2, ..., xn)。能量 (Energy) / 目标函数值 (Objective Value) 评价一个状态“好坏”的指标。在求最小值问题中函数值f(x1, x2, ..., xn)越小意味着该状态的能量越低也就越“好”。我们的目标就是找到能量最低的状态。温度 (Temperature) 这是整个算法的灵魂参数。它不是一个物理量而是一个控制算法“探索”与“利用”行为的控制变量。高温时算法倾向于大胆探索更容易接受差解低温时算法趋于保守更像一个传统的局部搜索只接受更好的解。算法的精髓体现在状态转移准则即如何从一个当前状态S_old转移到下一个状态S_new。这里引入了Metropolis准则如果新状态的能量更低E_new E_old即找到了更好的解那么无条件接受这个新状态。如果新状态的能量更高E_new E_old即找到了一个更差的解那么以一定的概率P接受它。这个概率P由以下公式决定P exp(-(E_new - E_old) / T)其中T是当前温度。这个公式是理解SA的关键。(E_new - E_old)是能量增量变差的幅度T是当前温度。当温度T很高时即使(E_new - E_old)较大-(E_new - E_old) / T也会是一个较小的负数exp()函数的值仍然相对较大接近1。这意味着算法有很高的概率接受一个差解从而能够跳出当前的“能量洼地”局部最优在解空间中进行大范围的“勘探”。当温度T逐渐降低时同样的能量增量(E_new - E_old)除以一个变小的T会得到一个很大的负数exp()函数的值会急剧变小接近0。这意味着算法接受差解的概率变得极低行为越来越像“下山法”只在当前解的附近进行精细的“开采”最终稳定在某个低能状态。注意这个接受差解的概率正是SA区别于贪婪算法如梯度下降的核心。贪婪算法只走下坡路注定会陷入局部最优。而SA通过“偶尔的上坡”获得了逃离局部最优的可能。2.2 算法流程全景与关键参数解析一个完整的模拟退火算法流程可以概括为以下几个步骤我将其比喻为一次“受控的登山探险”初始化随机生成一个初始解S设定一个较高的初始温度T0并确定降温计划退火策略。迭代搜索内循环在当前温度T下进行L次尝试L称为马尔可夫链长度或迭代次数。a.产生新解在当前解S的附近通过某种机制如随机扰动产生一个新解S‘。b.计算能量差计算新解与旧解的目标函数值之差ΔE f(S’) - f(S)。c.Metropolis判别若ΔE 0接受S‘作为新的当前解。若ΔE 0则以概率P exp(-ΔE / T)接受S‘。d. 重复步骤a-c共L次。降温外循环按照预设的降温策略降低温度T。例如T α * T其中α是降温系数0 α 1。终止检查判断是否满足终止条件如温度低于某个极小值T_min或连续若干次迭代解未改进。若未终止则返回步骤2否则输出当前找到的最优解。在这个过程中有几个关键参数决定了算法的性能和效果初始温度T0 必须足够高以确保在初期几乎所有移动都被接受让算法能充分探索解空间。一个经验法则是让初始接受概率对于某个典型的正ΔE大于0.8。可以通过少量实验来估计。降温系数α 控制温度下降的速度。通常取值在[0.8, 0.99]之间。α越接近1降温越慢搜索越细致但耗时越长α越小降温越快可能收敛迅速但容易陷入局部最优。对于复杂问题慢退火α0.95~0.99效果更好。每个温度的迭代次数L 也称为马尔可夫链长度。它决定了在每个温度下算法进行充分搜索的程度。L太小可能在该温度下还未达到平衡就降温了L太大会增加不必要的计算开销。一个常见策略是L与问题维度或定义域大小相关。终止温度T_min 当温度低于此值时认为系统已“冻结”停止搜索。通常设为一个非常小的正数如1e-7。实操心得参数设置没有银弹需要针对具体问题调整。一个实用的调参顺序是先确定一个较大的T0和较小的α如0.85进行快速测试观察收敛趋势。如果发现算法很早就停滞了可能是T0不够高或α太小导致“淬火”太快。然后再逐步调高α增加L进行更精细的搜索。记录每次参数下的最优解和收敛曲线是调参的关键。3. 面向多元函数求解的SA实现细节3.1 解的表达与新解生成策略对于多元函数f(x1, x2, ..., xn)一个解自然就是一个n维向量。在编程实现中我们用一个列表或NumPy数组来表示它例如solution [x1, x2, ..., xn]。如何从当前解S产生一个新解S‘是影响算法性能的关键操作这被称为“邻域结构”设计。对于连续函数优化最常用也最直接的方法是随机扰动import numpy as np def generate_new_solution(current_solution, bounds, step_scale): 通过随机扰动产生新解。 :param current_solution: 当前解n维数组。 :param bounds: 每个变量的取值范围列表形如[(min1, max1), (min2, max2), ...]。 :param step_scale: 扰动步长的缩放因子与温度相关。 :return: 新解。 n_dim len(current_solution) new_solution current_solution.copy() # 随机选择一个或多个维度进行扰动 # 方式一扰动所有维度更激进 # perturbation np.random.uniform(-step_scale, step_scale, n_dim) # new_solution perturbation # 方式二随机扰动一个维度更精细推荐 dim_to_change np.random.randint(0, n_dim) perturbation np.random.uniform(-step_scale, step_scale) new_solution[dim_to_change] perturbation # 确保新解在边界内 for i in range(n_dim): if new_solution[i] bounds[i][0]: new_solution[i] bounds[i][0] elif new_solution[i] bounds[i][1]: new_solution[i] bounds[i][1] return new_solution这里有几个设计点需要注意扰动幅度step_scale 这个值最好能与当前温度T关联。温度高时扰动可以大一些进行全局探索温度低时扰动应小一些进行局部微调。一种常见的做法是step_scale (bounds[i][1] - bounds[i][0]) * ratio其中ratio随温度降低而减小。扰动维度 每次扰动所有维度变化剧烈探索性强但可能不够精细。每次只扰动一个随机维度变化更平滑更容易在低温下进行精细搜索。后者在实际中更常用效果也往往更稳定。边界处理 当扰动使解超出定义域时必须进行处理。除了上面代码中的“反射”或“夹紧”方法也可以让解在边界上随机重置或者采用周期性边界条件如果问题允许。简单的“夹紧”处理对于大多数问题已经足够。3.2 温度衰减策略的选择与实践降温策略即温度T如何随时间迭代次数下降直接影响算法的收敛速度和最终解的质量。除了最常用的等比降温T_{k1} α * T_k还有以下几种常见策略经典指数降温T(k) T0 * α^k其中k是外循环迭代次数。这是最标准、最常用的方法实现简单效果可靠。快速模拟退火T(k) T0 / (1 k)。这种降温方式初期降温快后期降温慢可以在初期快速定位到有希望的区域后期再进行精细搜索。对于某些问题能加快收敛。对数降温T(k) T0 / log(1 k)。理论上如果每个温度下的迭代次数足够多这种策略能以概率1收敛到全局最优解但降温极慢实际计算成本很高较少使用。在代码实现中我们通常采用经典指数降温因为它易于控制参数意义明确。def update_temperature(T, cooling_rate): 更新温度指数降温 return T * cooling_rate # 或者将冷却率作为参数传入 # cooling_rate 通常取 0.8 ~ 0.993.3 算法终止条件的合理设定不能让算法无限运行下去我们需要设定合理的停止条件。常见的终止条件有温度条件 当温度T低于某个预设的极小值T_min如1e-7时停止。这是最直接的条件。解质量条件 当连续N个温度循环中找到的最优解都没有任何改进时停止。这表明算法可能已经收敛。迭代次数条件 当外循环降温次数达到一个最大值max_iter时停止。这是为了防止在参数设置不当时程序长时间运行。时间条件 运行时间超过某个阈值时停止。在实际编程中通常采用组合条件。例如同时判断T T_min和连续无改进次数 N。stop False no_improve_count 0 best_value_history [] # 记录历史最优值 while not stop: # ... SA 主循环 ... # 检查当前循环是否改进了全局最优解 current_best min(best_value_history[-L:]) if best_value_history else float(inf) # 假设求最小值 if current_best global_best_value: global_best_value current_best no_improve_count 0 else: no_improve_count 1 # 更新温度 T update_temperature(T, cooling_rate) # 检查终止条件 if T T_min or no_improve_count max_no_improve: stop True4. Python代码实现一个可复用的SA求解器下面我将呈现一个结构清晰、注释完整、易于扩展的模拟退火算法Python实现。这个实现将上述所有原理和细节都囊括其中你可以直接用它来求解你的多元函数优化问题。import numpy as np import matplotlib.pyplot as plt import time class SimulatedAnnealing: 模拟退火算法求解器针对连续函数最小化问题 def __init__(self, func, bounds, T0100, T_min1e-7, alpha0.95, L100, max_stay50): 初始化SA求解器。 :param func: 目标函数接受一个n维数组作为输入返回标量。 :param bounds: 变量边界列表形如[(min1, max1), (min2, max2), ...]。 :param T0: 初始温度。 :param T_min: 终止温度。 :param alpha: 降温系数。 :param L: 每个温度下的迭代次数马尔可夫链长度。 :param max_stay: 最优解连续无改进的最大次数用于辅助终止。 self.func func self.bounds np.array(bounds) self.n_dim len(bounds) self.T0 T0 self.T_min T_min self.alpha alpha self.L L self.max_stay max_stay # 记录历史 self.best_solution_history [] self.best_value_history [] self.temperature_history [] self.current_value_history [] # 内部状态 self.current_solution None self.current_value None self.best_solution None self.best_value float(inf) def _initialize(self): 随机初始化一个解 self.current_solution np.random.uniform(self.bounds[:, 0], self.bounds[:, 1]) self.current_value self.func(self.current_solution) # 初始化解也是当前最优解 self.best_solution self.current_solution.copy() self.best_value self.current_value def _generate_new_solution(self, T): 基于当前温度和当前解生成一个新解。 扰动步长与当前温度成正比实现自适应搜索。 new_solution self.current_solution.copy() # 随机选择一个维度进行扰动 dim np.random.randint(0, self.n_dim) # 计算当前温度下的相对扰动幅度 # 温度高时扰动范围大温度低时扰动范围小。 range_width self.bounds[dim, 1] - self.bounds[dim, 0] # 扰动幅度与温度成正比并乘以一个缩放因子这里取0.1 step_scale 0.1 * range_width * (T / self.T0) perturbation np.random.uniform(-step_scale, step_scale) new_solution[dim] perturbation # 边界处理若超出边界则将其拉回边界 new_solution[dim] np.clip(new_solution[dim], self.bounds[dim, 0], self.bounds[dim, 1]) return new_solution def _metropolis(self, old_value, new_value, T): Metropolis准则决定是否接受新解 delta new_value - old_value if delta 0: return True # 新解更好接受 else: # 以概率 exp(-delta/T) 接受差解 p np.exp(-delta / T) return np.random.rand() p def solve(self, seedNone): 执行模拟退火算法。 :param seed: 随机种子用于复现结果。 :return: 最优解最优值。 if seed is not None: np.random.seed(seed) self._initialize() T self.T0 stay_count 0 # 记录最优解未改进的次数 print(f开始模拟退火优化...) print(f初始解: {self.current_solution}, 初始值: {self.current_value:.6f}) iteration 0 while T self.T_min and stay_count self.max_stay: for _ in range(self.L): # 生成新解 new_solution self._generate_new_solution(T) new_value self.func(new_solution) # 根据Metropolis准则决定是否接受新解 if self._metropolis(self.current_value, new_value, T): self.current_solution new_solution self.current_value new_value # 更新历史最优解 if new_value self.best_value: self.best_solution new_solution.copy() self.best_value new_value stay_count 0 # 找到更优解重置计数器 else: stay_count 1 # 记录当前值用于绘图 self.current_value_history.append(self.current_value) # 记录本温度轮次的最优情况 self.best_solution_history.append(self.best_solution.copy()) self.best_value_history.append(self.best_value) self.temperature_history.append(T) # 降温 T * self.alpha iteration 1 # 每10轮打印一次进度 if iteration % 10 0: print(fIter {iteration:4d}, T{T:.4e}, Best Value{self.best_value:.6f}) print(f优化结束。共进行 {iteration} 轮降温。) print(f最优解: {self.best_solution}) print(f最优值: {self.best_value:.10f}) return self.best_solution, self.best_value def plot_results(self): 绘制优化过程曲线 fig, axes plt.subplots(2, 2, figsize(12, 8)) # 1. 最优值随迭代次数的变化 axes[0, 0].plot(self.best_value_history, b-, linewidth1) axes[0, 0].set_xlabel(Annealing Iteration) axes[0, 0].set_ylabel(Best Function Value) axes[0, 0].set_title(Best Value History) axes[0, 0].grid(True, linestyle--, alpha0.7) # 2. 当前值随搜索步数的变化可以看到接受差解的过程 axes[0, 1].plot(self.current_value_history, r-, linewidth0.5, alpha0.7) axes[0, 1].set_xlabel(Search Step) axes[0, 1].set_ylabel(Current Function Value) axes[0, 1].set_title(Current Value History (All Steps)) axes[0, 1].grid(True, linestyle--, alpha0.7) # 3. 温度衰减曲线 axes[1, 0].plot(self.temperature_history, g-, linewidth2) axes[1, 0].set_xlabel(Annealing Iteration) axes[1, 0].set_ylabel(Temperature) axes[1, 0].set_title(Temperature Decay) axes[1, 0].set_yscale(log) # 对数坐标更清晰 axes[1, 0].grid(True, linestyle--, alpha0.7) # 4. 最优值随温度的变化散点图 scatter axes[1, 1].scatter(self.temperature_history, self.best_value_history, crange(len(self.temperature_history)), cmapviridis, s20) axes[1, 1].set_xlabel(Temperature) axes[1, 1].set_ylabel(Best Function Value) axes[1, 1].set_title(Best Value vs. Temperature) axes[1, 1].set_xscale(log) axes[1, 1].grid(True, linestyle--, alpha0.7) plt.colorbar(scatter, axaxes[1, 1], labelIteration) plt.tight_layout() plt.show() # 示例定义测试函数和边界 def sphere_function(x): Sphere函数全局最小值在(0,0,...,0)最小值为0。最简单的单峰函数。 return np.sum(x**2) def rastrigin_function(x): Rastrigin函数多峰函数全局最小值在(0,0,...,0)最小值为0。是著名的难优化函数。 A 10 n len(x) return A * n np.sum(x**2 - A * np.cos(2 * np.pi * x)) # 使用示例 if __name__ __main__: # 设置问题维度 n_dim 2 bounds [(-5.12, 5.12)] * n_dim # Rastrigin函数的常用定义域 # 创建求解器实例 sa_solver SimulatedAnnealing( funcrastrigin_function, boundsbounds, T0100.0, # 初始温度 T_min1e-7, # 终止温度 alpha0.95, # 降温系数 L200, # 每个温度迭代200次 max_stay30 # 最优解连续30轮无改进则停止 ) # 运行求解设置随机种子以便复现 start_time time.time() best_sol, best_val sa_solver.solve(seed42) end_time time.time() print(f\n计算耗时: {end_time - start_time:.2f} 秒) print(f理论最优值: 0.0) print(f算法找到的最优值: {best_val:.10f}) print(f误差: {best_val - 0.0:.10f}) # 可视化优化过程 sa_solver.plot_results()这段代码是一个功能完整的SA求解器框架。SimulatedAnnealing类封装了算法的所有逻辑。_generate_new_solution方法实现了自适应步长的扰动_metropolis方法实现了状态转移准则。solve方法是主流程plot_results方法则提供了直观的收敛过程可视化。5. 实战测试挑战经典优化函数理论说得再多不如跑个例子看看。我们选取两个经典的测试函数来检验我们SA求解器的威力。5.1 测试案例一Sphere函数Sphere函数是一个简单的凸函数没有局部最优只有一个全局最小值点。它常用来检验算法的基本功能是否正常。# 测试Sphere函数 (2维) print( 测试 Sphere 函数 ) bounds_sphere [(-5, 5), (-5, 5)] sa_sphere SimulatedAnnealing(sphere_function, bounds_sphere, T050, alpha0.9, L100) best_sol_sphere, best_val_sphere sa_sphere.solve(seed123) print(f找到的最优解: {best_sol_sphere}) print(f对应的函数值: {best_val_sphere:.6f}) print(f理论最优解: [0, 0], 最优值: 0.0)对于Sphere函数SA应该能非常轻松且精确地找到原点附近的最优解。这个测试主要用来验证我们的代码没有逻辑错误参数设置基本合理。5.2 测试案例二Rastrigin函数Rastrigin函数才是SA算法真正的试金石。它是一个高度多峰的函数在定义域内存在大量的局部最优点其函数图像像一片布满“鸡蛋盒”的崎岖山地。对于传统的梯度下降法几乎百分之百会陷入某个局部最优。这正是SA大显身手的地方。# 测试Rastrigin函数 (2维) print(\n 测试 Rastrigin 函数 ) bounds_rastrigin [(-5.12, 5.12), (-5.12, 5.12)] sa_rastrigin SimulatedAnnealing(rastrigin_function, bounds_rastrigin, T0100, alpha0.95, L200, max_stay50) best_sol_rast, best_val_rast sa_rastrigin.solve(seed456) print(f找到的最优解: {best_sol_rast}) print(f对应的函数值: {best_val_rast:.6f}) print(f理论最优解: [0, 0], 最优值: 0.0) sa_rastrigin.plot_results() # 观察收敛过程运行这段代码你会看到算法初期在函数值上剧烈震荡高温接受差解随后震荡幅度逐渐减小最终收敛到一个非常接近0的值。通过plot_results生成的图表你可以清晰地看到最优值历史图曲线总体呈下降趋势但中间可能有小幅回升接受了差解但最终找到了更好的区域。当前值历史图密密麻麻的折线充满了上下跳跃这正是Metropolis准则在起作用——接受差解。温度衰减图一条平滑下降的曲线。最优值vs温度图可以看到在高温区最优值波动大在低温区最优值稳定在最低点附近。5.3 参数调优实验与结果分析SA的性能很大程度上依赖于参数。下面我们设计一个小实验观察关键参数alpha降温系数和L链长对结果的影响。def parameter_test(func, bounds, param_grid): 参数网格搜索测试 :param param_grid: 字典例如 {alpha: [0.85, 0.9, 0.95, 0.99], L: [50, 100, 200]} results [] for alpha in param_grid[alpha]: for L in param_grid[L]: run_times 5 # 每个参数组合运行5次取平均 best_vals [] for _ in range(run_times): solver SimulatedAnnealing(func, bounds, T0100, T_min1e-7, alphaalpha, LL) _, best_val solver.solve() best_vals.append(best_val) avg_best np.mean(best_vals) std_best np.std(best_vals) results.append({ alpha: alpha, L: L, avg_best: avg_best, std_best: std_best }) print(falpha{alpha:.3f}, L{L:3d} - 平均最优值: {avg_best:.6f} ± {std_best:.6f}) return results # 对Rastrigin函数进行参数测试 param_grid {alpha: [0.85, 0.9, 0.95, 0.99], L: [50, 100, 200, 500]} print(开始参数调优实验...) test_results parameter_test(rastrigin_function, bounds_rastrigin, param_grid) # 简单分析找出平均最优值最小的参数组合 best_result min(test_results, keylambda x: x[avg_best]) print(f\n最佳参数组合: alpha{best_result[alpha]}, L{best_result[L]}) print(f对应的平均最优值: {best_result[avg_best]:.6f})通过这样的实验你可能会发现对于像Rastrigin这样的复杂函数较大的alpha如0.99慢退火和较大的L如200或500往往能获得更稳定、更好的结果但代价是更长的计算时间。而对于简单函数或对精度要求不高的场景较小的alpha和L可以更快得到可接受的解。6. 常见问题、避坑指南与进阶技巧在实际使用SA算法时你肯定会遇到各种各样的问题。下面是我总结的一些典型问题和解决方案。6.1 算法不收敛或收敛到错误解问题表现 最优值曲线早早持平或者在一个很差的水平上波动无法接近理论最优。可能原因与解决初始温度T0太低 算法从一开始就缺乏“探索”能力。解决提高T0。可以写一个小程序测试初始接受率随机产生大量新解计算在初始温度下的接受概率确保它大于0.8。降温太快α太小 系统还没来得及在每个温度下达到平衡就冷却了相当于“淬火”而非“退火”。解决增大α到0.95以上尝试慢退火。每个温度的迭代次数L不足 在每个温度下搜索不充分。解决增加L。L可以与问题维度挂钩例如L 100 * n_dim。新解生成策略不佳 扰动步长太大或太小。解决实现自适应步长如我们代码中那样让步长与当前温度成正比。或者引入更复杂的邻域搜索如Cauchy分布扰动比均匀分布有更长的拖尾有利于跳出局部最优。问题本身过于复杂 SA毕竟是一种概率算法不能保证100%找到全局最优。解决多次运行算法取最好的结果。或者考虑与其他算法如局部搜索结合。6.2 算法运行速度太慢问题表现 程序运行时间过长尤其是对于高维问题。优化策略向量化目标函数 确保你的func能够利用NumPy的向量运算避免在Python层进行低效的循环。这是最大的性能瓶颈。减少不必要的计算 在_metropolis判断中如果delta 0就直接接受只有delta 0时才计算exp(-delta/T)。计算指数函数相对耗时。调整参数 在可接受的精度损失下减小L或增大α让降温慢但每步迭代次数少找到速度与质量的平衡点。设定合理的终止条件 除了T_min一定要加上max_stay最优解无改进次数或最大运行时间限制防止在已经收敛后空转。6.3 如何将SA应用于离散或组合优化问题我们的实现是针对连续函数的。SA同样广泛应用于旅行商问题TSP、调度问题等组合优化。关键在于新解生成策略和目标函数。新解生成 对于TSP新解可以通过“2-opt”交换两段路径、“节点插入”等操作产生。目标函数 就是路径总长度。 代码框架几乎不用变只需要重写_generate_new_solution方法和目标函数func即可。这体现了我们代码设计良好的扩展性。6.4 进阶技巧混合策略与重启机制混合局部搜索 在SA的低温阶段或者每次接受一个新解后可以嵌入一个快速的局部搜索如梯度下降、爬山法来快速“爬”到当前邻域的最低点。这能显著提高收敛精度和速度。这种算法称为“模拟退火-局部搜索混合算法”。重启机制 如果算法陷入某个平台期过久可以强行将温度重置到一个较高的值但低于初始温度并从一个新的随机解或当前最优解附近开始重新进行退火过程。这能增加找到全局最优的概率。自适应参数调整 根据搜索过程中的反馈动态调整参数。例如如果接受率过低可以适当放慢降温速度如果接受率一直很高可以加快降温。模拟退火算法是一个充满魅力的“古老”而强大的优化工具。它原理直观实现灵活对目标函数的要求极低不要求可导、连续使其在工程优化、参数调优、组合优化等领域始终占有一席之地。通过这个项目我希望你不仅获得了一个可用的代码工具更建立起对“探索”与“利用”这一核心优化思想的深刻理解。下次当你面对一个复杂的、多峰的优化难题时不妨试试模拟退火给它一个“跳出去”的机会也许惊喜就在那里等着你。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价