ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Python实现粒子群优化算法求解方程:从原理到实践

Python实现粒子群优化算法求解方程:从原理到实践 1. 项目概述当优化算法遇上方程求解在工程优化、参数拟合乃至一些基础的科学计算场景里我们常常会遇到需要求解方程根的问题。对于简单的一元一次、二次方程我们有现成的求根公式对于复杂的非线性方程牛顿法、二分法等数值方法也是经典选择。但今天我想聊点不一样的用粒子群优化算法来解方程。这听起来可能有点“杀鸡用牛刀”但恰恰是这种跨界应用能让我们更深刻地理解PSO算法的核心思想与灵活性也为解决那些难以求导或定义域不明确的方程提供了一种全新的思路。这个项目就是用Python实现基础PSO算法并将其应用于求解一元方程和二元方程组的根。粒子群优化本质上是一种基于群体智能的随机搜索算法。它的灵感来源于鸟群或鱼群的社会行为。想象一下你在一个漆黑的房间里寻找一个声音源方程的解你有一群朋友粒子分散在房间各处。每个人只能听到声音的大小适应度值即方程绝对值的大小并且会记住自己听到声音最响的那个位置个体最优同时大家还会互相通信知道谁目前的位置声音最响全局最优。接下来每个人都会根据自己过去的“最佳记忆”和群体的“最佳发现”来调整自己下一步移动的方向和速度。经过多次迭代整个群体就会逐渐向声源方程的解聚集。这就是PSO求解方程的基本逻辑——将方程f(x)0的求解转化为寻找使|f(x)|最小化的x值问题。对于一元方程x是一个标量对于二元方程组{f1(x,y)0, f2(x,y)0}我们则需要寻找一组(x, y)使得|f1(x,y)| |f2(x,y)|或其它形式的组合值最小。通过PSO我们无需计算梯度也无需假设函数连续或可导只要能够计算函数值就能进行搜索。这种方法特别适合教学演示、算法验证以及处理那些形式怪异、传统方法容易失效的“丑陋”方程。2. 核心思路将方程求解转化为优化问题2.1 问题转化与适应度函数设计使用PSO求解方程的第一步也是最关键的一步是将方程求根问题重新定义为函数最小化问题。对于一个一元方程f(x) 0它的根x*满足f(x*) 0。因此我们可以构造一个适应度函数Fitness(x) |f(x)|。显然当Fitness(x)的值越接近0对应的x就越接近方程的真实根。PSO算法的目标就是找到能使Fitness(x)最小化的x。对于二元方程组情况稍微复杂一点。假设我们有方程组f1(x, y) 0 f2(x, y) 0我们需要找到一对(x*, y*)同时满足两个方程。一种直接且常用的方法是构造一个综合适应度函数将两个方程的偏离程度结合起来。最常见的形式是绝对值和或平方和Fitness(x, y) |f1(x, y)| |f2(x, y)|或者Fitness(x, y) [f1(x, y)]^2 [f2(x, y)]^2平方和的形式在数学上更光滑对优化算法更友好因为它避免了绝对值函数在零点不可导的问题虽然PSO不依赖梯度。我们的代码将采用平方和的形式。注意适应度函数的设计直接影响搜索效率和精度。如果方程间的量级差异很大例如一个方程值域在[-1,1]另一个在[-1000,1000]直接相加可能导致量级大的方程主导搜索过程。此时需要考虑对函数进行归一化处理或者为每个方程赋予权重。2.2 基础PSO算法原理速览在深入代码前我们快速回顾一下标准PSOGlobal Best PSO的更新公式。每个粒子i在D维空间中的位置表示为X_i (x_i1, x_i2, ..., x_iD)速度表示为V_i (v_i1, v_i2, ..., v_iD)。在每一次迭代中粒子的速度和位置按以下公式更新速度更新公式v_id(t1) w * v_id(t) c1 * r1 * (pbest_id - x_id(t)) c2 * r2 * (gbest_d - x_id(t))位置更新公式x_id(t1) x_id(t) v_id(t1)其中t代表当前迭代次数。w是惯性权重控制粒子保持原有速度的倾向。较大的w利于全局探索较小的w利于局部开发。c1和c2是加速常数认知系数和社会系数通常设为2.0左右。r1和r2是[0, 1]区间内的随机数。pbest_i是粒子i迄今为止找到的个体最优位置。gbest是整个粒子群迄今为止找到的全局最优位置。对于一元方程搜索空间是1维D1对于二元方程组搜索空间是2维D2。算法的流程可以概括为初始化在给定的搜索范围内随机初始化一群粒子的位置和速度。评估计算每个粒子当前位置的适应度值即方程偏差的绝对值或平方和。更新个体与全局最优比较每个粒子当前适应度与其历史最优pbest更新pbest。找出所有粒子中适应度最好的更新全局最优gbest。更新速度与位置根据上述公式更新每个粒子的速度和位置。迭代重复步骤2-4直到达到最大迭代次数或适应度值满足精度要求。3. Python代码实现与逐行解析接下来我们将实现一个通用的基础PSO类然后分别应用于一元和二元方程的求解。我会先给出完整代码块再对其中的关键部分进行详细拆解。3.1 基础PSO求解器类实现import numpy as np import matplotlib.pyplot as plt from typing import Callable, Tuple, List, Optional class BasicPSOSolver: 基础粒子群优化PSO求解器。 用于求解最小化问题可适配一元或多元函数。 def __init__(self, objective_func: Callable, dim: int, bounds: List[Tuple[float, float]], num_particles: int 30, max_iter: int 100, w: float 0.8, c1: float 2.0, c2: float 2.0, tol: float 1e-6): 初始化PSO求解器。 参数 objective_func: 目标函数适应度函数输入为位置向量输出为标量越小越好。 dim: 搜索空间的维度。解一元方程dim1解二元方程组dim2。 bounds: 每个维度的搜索边界列表例如 [(x_low, x_high), (y_low, y_high)]。 num_particles: 粒子数量。 max_iter: 最大迭代次数。 w: 惯性权重。 c1: 个体学习因子。 c2: 社会学习因子。 tol: 收敛容忍度。当全局最优适应度小于tol时提前停止。 self.objective_func objective_func self.dim dim self.bounds np.array(bounds) # 转换为数组便于计算 self.num_particles num_particles self.max_iter max_iter self.w w self.c1 c1 self.c2 c2 self.tol tol # 初始化粒子位置和速度 self.positions np.random.uniform(lowself.bounds[:, 0], highself.bounds[:, 1], size(self.num_particles, self.dim)) # 速度初始化为搜索范围宽度的10%~20% bound_ranges self.bounds[:, 1] - self.bounds[:, 0] self.velocities np.random.uniform(-0.2 * bound_ranges, 0.2 * bound_ranges, size(self.num_particles, self.dim)) # 初始化个体最优位置和适应度 self.pbest_positions self.positions.copy() self.pbest_values np.array([self.objective_func(pos) for pos in self.positions]) # 初始化全局最优 self.gbest_idx np.argmin(self.pbest_values) self.gbest_position self.pbest_positions[self.gbest_idx].copy() self.gbest_value self.pbest_values[self.gbest_idx] # 记录历史最优值用于绘图和分析 self.history_gbest_value [self.gbest_value] def _update_velocity(self): 更新所有粒子的速度。 r1 np.random.rand(self.num_particles, self.dim) r2 np.random.rand(self.num_particles, self.dim) cognitive self.c1 * r1 * (self.pbest_positions - self.positions) social self.c2 * r2 * (self.gbest_position - self.positions) self.velocities self.w * self.velocities cognitive social def _update_position(self): 更新所有粒子的位置并进行边界处理。 self.positions self.velocities # 边界吸收处理如果粒子飞出边界将其拉回边界并反转速度方向 for d in range(self.dim): low, high self.bounds[d] # 超出下界 below_mask self.positions[:, d] low self.positions[below_mask, d] low self.velocities[below_mask, d] * -0.5 # 反转并阻尼速度 # 超出上界 above_mask self.positions[:, d] high self.positions[above_mask, d] high self.velocities[above_mask, d] * -0.5 def optimize(self): 执行优化主循环。 for iter in range(self.max_iter): # 1. 更新速度和位置 self._update_velocity() self._update_position() # 2. 计算新位置的适应度 current_values np.array([self.objective_func(pos) for pos in self.positions]) # 3. 更新个体最优 improved_mask current_values self.pbest_values self.pbest_positions[improved_mask] self.positions[improved_mask] self.pbest_values[improved_mask] current_values[improved_mask] # 4. 更新全局最优 current_best_idx np.argmin(self.pbest_values) current_best_value self.pbest_values[current_best_idx] if current_best_value self.gbest_value: self.gbest_value current_best_value self.gbest_position self.pbest_positions[current_best_idx].copy() # 5. 记录历史 self.history_gbest_value.append(self.gbest_value) # 6. 收敛检查 if self.gbest_value self.tol: print(f迭代 {iter1} 次后提前收敛适应度: {self.gbest_value:.2e}) break return self.gbest_position, self.gbest_value def plot_convergence(self): 绘制全局最优适应度随迭代次数的收敛曲线。 plt.figure(figsize(10, 6)) plt.plot(self.history_gbest_value, linewidth2) plt.yscale(log) # 使用对数坐标更清晰地观察收敛 plt.xlabel(迭代次数, fontsize12) plt.ylabel(全局最优适应度 (log scale), fontsize12) plt.title(PSO收敛曲线, fontsize14) plt.grid(True, whichboth, ls--, alpha0.5) plt.show()代码关键点解析边界处理策略(_update_position方法中)粒子在更新位置后可能飞出预设的搜索边界。这里采用了“边界吸收”策略将粒子位置设置为边界值并将其在该维度上的速度反向并减半*-0.5。这是一种简单有效的处理方式避免了粒子卡在边界外同时速度阻尼有助于粒子在边界附近探索。另一种常见策略是“随机重置”将越界粒子随机放回搜索空间内。适应度评估的向量化在optimize方法中我们使用列表推导式[self.objective_func(pos) for pos in self.positions]来计算所有粒子的适应度。对于简单的目标函数这已经足够。如果目标函数计算量极大可以考虑使用numpy的向量化操作或并行计算来提升效率。个体最优更新逻辑我们使用布尔掩码improved_mask current_values self.pbest_values来一次性找出所有适应度得到改善的粒子然后批量更新它们的pbest_positions和pbest_values。这比在循环中逐个判断更高效。收敛判断除了设置最大迭代次数max_iter我们还增加了一个基于容忍度tol的提前终止条件。当全局最优适应度gbest_value小于tol时我们认为已经找到了足够精确的解提前退出循环。这对于求解方程根目标是f(x)0非常实用。3.2 一元方程求解应用实例假设我们要求解方程x^3 - 2x^2 - 5x 6 0。我们知道它有三个实根分别约为-2,1,3。我们用PSO来寻找其中一个根。def equation_1d(x): 定义一元方程: x^3 - 2x^2 - 5x 6 0 return x**3 - 2*x**2 - 5*x 6 def fitness_1d(x): 适应度函数方程绝对值的平方。平方可以使函数更平滑利于优化。 return equation_1d(x)**2 # 设置搜索范围我们尝试寻找[-3, 0]区间内的根即根-2 bounds_1d [(-3, 0)] dim_1d 1 # 创建并运行PSO求解器 pso_solver_1d BasicPSOSolver(objective_funcfitness_1d, dimdim_1d, boundsbounds_1d, num_particles20, max_iter50, w0.7, c11.5, c21.5) best_solution_1d, best_fitness_1d pso_solver_1d.optimize() print(f找到的最优解 x {best_solution_1d[0]:.6f}) print(f对应的方程值 f(x) {equation_1d(best_solution_1d[0]):.6e}) print(f适应度值 (f(x)^2) {best_fitness_1d:.6e}) # 可视化收敛过程 pso_solver_1d.plot_convergence() # 可视化函数曲线与找到的解 x_plot np.linspace(-3, 0, 400) y_plot equation_1d(x_plot) plt.figure(figsize(10, 6)) plt.plot(x_plot, y_plot, labelf(x) x^3 - 2x^2 - 5x 6, linewidth2) plt.axhline(y0, colork, linestyle--, alpha0.3) # 绘制y0参考线 plt.scatter(best_solution_1d, equation_1d(best_solution_1d), colorred, s100, zorder5, labelfPSO找到的根: x≈{best_solution_1d[0]:.4f}) plt.xlabel(x) plt.ylabel(f(x)) plt.title(一元方程求解结果可视化) plt.legend() plt.grid(True) plt.show()运行结果分析在我的多次运行中算法通常在10-20次迭代内收敛到适应度小于1e-12的水平找到的解x ≈ -2.000000。收敛曲线在对数坐标下呈现典型的快速下降后趋于平稳的特征。可视化图中红色的点准确地落在了函数曲线与x轴y0虚线的交点处。实操心得搜索范围的重要性对于一元高次方程PSO可能收敛到搜索范围内的任何一个根。如果你知道根的大致区间将搜索范围bounds设在该区间内可以显著提高找到目标根的效率和准确性。如果搜索范围包含多个根PSO最终找到哪个根带有一定的随机性取决于粒子初始化和随机因子的影响。这既是缺点也是优点——通过多次运行或使用多个粒子群你有可能找到方程的所有实根。3.3 二元方程组求解应用实例现在我们升级难度求解一个二元非线性方程组f1(x, y) x^2 y^2 - 4 0 # 一个半径为2的圆 f2(x, y) exp(x) y - 1 0 # 一条指数曲线这个方程组的解是圆与曲线的交点。我们可以通过几何想象在第一象限和第二象限各有一个交点。def equations_2d(vars): 定义二元方程组 x, y vars[0], vars[1] f1 x**2 y**2 - 4 # 圆方程 f2 np.exp(x) y - 1 # 指数曲线方程 return np.array([f1, f2]) def fitness_2d(vars): 适应度函数两个方程偏差的平方和 f equations_2d(vars) return np.sum(f**2) # 设置搜索范围我们尝试寻找第一象限的解 (x0, y0) bounds_2d [(-1, 3), (-1, 3)] # x和y的范围 dim_2d 2 # 创建并运行PSO求解器 pso_solver_2d BasicPSOSolver(objective_funcfitness_2d, dimdim_2d, boundsbounds_2d, num_particles50, # 二元问题需要更多粒子 max_iter100, w0.6, # 略微降低惯性权重加强局部搜索 c11.8, c21.8) best_solution_2d, best_fitness_2d pso_solver_2d.optimize() best_x, best_y best_solution_2d print(f找到的最优解: x {best_x:.6f}, y {best_y:.6f}) print(f方程1的值: f1 {best_x**2 best_y**2 - 4:.6e}) print(f方程2的值: f2 {np.exp(best_x) best_y - 1:.6e}) print(f总适应度值 (平方和) {best_fitness_2d:.6e}) # 可视化收敛过程 pso_solver_2d.plot_convergence() # 可视化方程组曲线与找到的解 xx, yy np.meshgrid(np.linspace(-1, 3, 400), np.linspace(-1, 3, 400)) F1 xx**2 yy**2 - 4 F2 np.exp(xx) yy - 1 plt.figure(figsize(12, 10)) # 绘制f10的等高线即圆 plt.contour(xx, yy, F1, levels[0], colorsblue, linewidths2, labelx^2 y^2 4) # 绘制f20的等高线即曲线 plt.contour(xx, yy, F2, levels[0], colorsgreen, linewidths2, labelexp(x) y 1) # 标记PSO找到的解 plt.scatter(best_x, best_y, colorred, s150, zorder5, labelfPSO解: ({best_x:.3f}, {best_y:.3f})) plt.xlabel(x) plt.ylabel(y) plt.title(二元方程组求解可视化) plt.legend() plt.grid(True) plt.axis(equal) # 保证x,y轴比例相同圆看起来才是圆 plt.show()运行结果分析由于我们将搜索范围设定在第一象限[(-1,3), (-1,3)]算法稳定地收敛到第一象限的交点大约在(x≈0.537, y≈1.647)附近。适应度值可以达到1e-15量级说明找到了非常精确的解。收敛曲线显示算法在初期快速下降随后进入精细调整阶段。可视化图中红点清晰地落在蓝色圆和绿色曲线的交点处。注意事项粒子数与搜索维度对于二元或更高维的问题搜索空间呈指数级增长。num_particles20对于一元问题可能足够但对于二元问题就显得有些稀疏可能导致搜索效率低下或陷入局部最优。我通常将粒子数设置为10*dim到30*dim之间作为起点。本例中dim2我选择了50个粒子以确保有足够的覆盖率。4. 参数调优与性能提升技巧基础PSO的性能很大程度上依赖于参数的选择。没有一套参数能适应所有问题但有一些经验法则和调优策略。4.1 关键参数影响分析惯性权重w这是最重要的参数之一。高值 (如 0.9~1.2)粒子保持高速运动探索能力强适合在迭代初期进行全局搜索但后期可能因速度过快而错过精细解。低值 (如 0.4~0.6)粒子速度衰减快开发能力强适合在迭代后期进行局部精细搜索。动态调整策略最常用的策略是线性递减即w w_max - (w_max - w_min) * (iter / max_iter)。例如从0.9线性降到0.4。这能让算法在初期广泛探索在后期精细开发。加速常数c1和c2c1认知系数控制粒子向自身历史最优位置移动的倾向。值越大粒子越“自信”倾向于独立探索。c2社会系数控制粒子向群体历史最优位置移动的倾向。值越大粒子越“从众”收敛速度越快但可能过早陷入局部最优。经典设置是c1 c2 2.0。有时为了平衡探索与开发可以设置c1从大到小递减c2从小到大递增。粒子数量num_particles粒子越多搜索能力越强但每次迭代的计算成本也越高。对于简单的一元或二元问题20-50个粒子通常足够。对于高维复杂问题可能需要数百个粒子。一个实用的启发式是num_particles 10 * dim。搜索边界bounds这是最容易被忽视但至关重要的参数。不合理的边界会直接导致算法失败。尽可能根据问题先验知识缩小边界。例如如果你知道方程的根大致在正数范围就不要将边界设为(-100, 100)。如果对根的位置一无所知可以先进行一次大范围的、低精度的PSO搜索来定位根的大致区域然后在该区域进行第二次高精度的搜索。4.2 实现动态惯性权重让我们改进之前的BasicPSOSolver加入线性递减的惯性权重。class DynamicWeightPSOSolver(BasicPSOSolver): 带有线性递减惯性权重的PSO求解器。 def __init__(self, objective_func: Callable, dim: int, bounds: List[Tuple[float, float]], num_particles: int 30, max_iter: int 100, w_max: float 0.9, # 初始惯性权重 w_min: float 0.4, # 最终惯性权重 c1: float 2.0, c2: float 2.0, tol: float 1e-6): self.w_max w_max self.w_min w_min # 在父类初始化时传入一个中间值实际更新在optimize中动态计算 super().__init__(objective_func, dim, bounds, num_particles, max_iter, w_max, c1, c2, tol) def optimize(self): 执行优化主循环并动态更新惯性权重w。 for iter in range(self.max_iter): # 动态计算当前迭代的惯性权重 self.w self.w_max - (self.w_max - self.w_min) * (iter / self.max_iter) # 其余步骤与父类相同 self._update_velocity() self._update_position() current_values np.array([self.objective_func(pos) for pos in self.positions]) improved_mask current_values self.pbest_values self.pbest_positions[improved_mask] self.positions[improved_mask] self.pbest_values[improved_mask] current_values[improved_mask] current_best_idx np.argmin(self.pbest_values) current_best_value self.pbest_values[current_best_idx] if current_best_value self.gbest_value: self.gbest_value current_best_value self.gbest_position self.pbest_positions[current_best_idx].copy() self.history_gbest_value.append(self.gbest_value) if self.gbest_value self.tol: print(f迭代 {iter1} 次后提前收敛适应度: {self.gbest_value:.2e}) break return self.gbest_position, self.gbest_value # 使用动态权重求解器测试之前的二元方程组 pso_dynamic DynamicWeightPSOSolver(objective_funcfitness_2d, dimdim_2d, boundsbounds_2d, num_particles30, max_iter80, w_max0.9, w_min0.4) best_sol_dynamic, best_fit_dynamic pso_dynamic.optimize() print(f动态权重PSO解: ({best_sol_dynamic[0]:.6f}, {best_sol_dynamic[1]:.6f}), 适应度: {best_fit_dynamic:.2e}) pso_dynamic.plot_convergence()对比基础版本和动态权重版本的收敛曲线你通常会发现动态权重版本在迭代初期下降速度可能略慢因为初始w更大探索更强但在中后期能更稳定、更彻底地收敛到更优的值减少了在最优解附近的震荡。4.3 处理多解与局部最优问题PSO是一种随机算法并且倾向于收敛到全局最优解附近。但对于多峰函数对应方程的多解问题标准PSO很可能只找到其中一个解。如何用PSO寻找方程的所有根这里提供两种思路多次独立运行这是最简单的方法。利用PSO的随机性每次从不同的随机初始种群开始运行。由于每次运行是独立的有可能收敛到不同的解。你需要记录每次运行找到的最优解然后通过聚类或设置最小距离阈值来去除重复的解。小生境PSO这是一种更高级的变体。其核心思想是让粒子群内形成多个“小生境”每个小生境围绕一个潜在的局部最优解进行搜索。实现起来比较复杂需要在标准PSO的基础上修改粒子间的信息共享机制让粒子更多地与“邻居”中的最优粒子交流而不是全局最优粒子。对于大多数“找方程的一个根”的应用场景多次独立运行结合合理的搜索范围划分是性价比最高的策略。5. 常见问题、调试技巧与扩展方向5.1 常见问题排查表问题现象可能原因排查与解决思路算法不收敛适应度值居高不下1. 搜索边界设置错误根本不在边界内。2. 粒子数太少或迭代次数不足。3. 惯性权重w太小粒子过早失去探索能力。4. 适应度函数设计有误例如不是求最小值。1. 绘制函数图像确认根的大致位置调整bounds。2. 增加num_particles和max_iter。3. 尝试增大w或使用动态递减权重。4. 检查objective_func确保返回的是|f(x)|或f(x)^2。算法早熟很快陷入一个局部最优1. 加速常数c2远大于c1社会因素过强。2. 惯性权重w下降太快。3. 粒子多样性过早丧失。1. 尝试减小c2或增大c1例如设c12.5, c21.5。2. 使用动态权重并设置较高的初始值w_max。3. 引入速度钳制或随机重置策略保持粒子活性。每次运行结果差异很大这是随机算法的正常现象尤其是对于多解问题或在平坦区域。1. 增加粒子数量使搜索更稳定。2. 多次运行取最好结果或所有不重复的结果。3. 如果追求确定性结果可以固定随机数种子np.random.seed(42)。找到的“解”对应的函数值并不接近01. 收敛容忍度tol设置过大。2. 算法确实收敛到了局部最优该点函数值不是零。3. 方程可能无实根。1. 减小tol例如1e-10。2. 检查收敛曲线看适应度是否已平稳。尝试不同的初始参数。3. 对于复数根PSO无法直接处理。需将问题转化为实部虚部分别处理。高维问题求解速度慢目标函数计算复杂且粒子数*维度数很大。1. 优化objective_func的代码使用向量化计算。2. 考虑使用更高效的PSO变种如带收缩因子的PSO。3. 如果可能降低搜索维度或缩小边界。5.2 调试与可视化技巧绘制收敛曲线这是最重要的诊断工具。一个健康的收敛曲线应该在前1/3迭代次数内快速下降之后缓慢逼近极限。如果曲线很早就变平可能是早熟如果曲线一直缓慢下降可能需要增加迭代次数或调整参数。绘制粒子轨迹动画对于一元或二元问题可以实时绘制每一代粒子的位置。这能直观地看到粒子是如何探索和聚集的。对于教学演示尤其有用。输出中间信息在optimize循环中每隔一定代数打印当前的最优解和适应度观察其变化趋势。固定随机种子在调试阶段使用np.random.seed(某个固定数)可以确保每次运行结果相同便于复现问题和比较参数调整的效果。5.3 扩展方向这个基础项目可以朝多个方向扩展使其功能更强大、更实用求解更复杂的方程/方程组只需修改objective_func。可以处理超越方程、微分方程转化为优化问题、甚至方程组中方程个数大于未知数个数的超定系统使用最小二乘作为适应度。集成到更大的项目中PSO求根可以作为参数估计、曲线拟合、机器学习模型超参数优化中的一个步骤。例如在拟合一个非线性模型时其参数可能需要通过求解一个方程组来确定。实现更高级的PSO变种带收缩因子的PSO引入一个收缩因子来保证收敛性通常参数设置更鲁棒。自适应PSO根据种群的分布情况动态调整w、c1、c2等参数。多种群PSO使用多个子种群并行搜索定期交换信息有助于避免局部最优并寻找多解。与经典求根方法结合可以先用PSO进行“粗搜索”找到一个根的近似位置然后以此作为初始值调用scipy.optimize.fsolve或牛顿法进行“精搜索”结合两者的优点。这个用PSO求解方程的项目更像是一个理解群体智能优化算法的“沙盒”。它剥离了复杂应用的外壳让我们能清晰地看到粒子如何通过简单的规则协作解决一个明确的数学问题。当你亲手调参、观察收敛曲线、并最终看到粒子群精准地聚集在方程的根上时对算法“感觉”的理解会比读任何教科书都来得深刻。
返回列表