2025全国大学生数学建模C题思路模型代码(9.4开赛第一时间更新。完整更新内容见文末名片)备战国赛,算法解析——粒子群优化算法()

粒子群优化算法(Particle Swarm Optimization, PSO):从原理到实战的小白入门指南

一、算法原理:用“鸟群找食物”理解PSO

想象这样一个场景:一群鸟在随机搜索食物,它们不知道食物具体在哪,但每只鸟能记住自己飞过的地方中“食物最多”的位置(个体经验),也能知道群体中目前“食物最多”的位置(群体经验)。于是,每只鸟会根据自己的经验和群体的经验调整飞行方向和速度,逐渐都飞向食物最密集的区域——这就是PSO的核心思想:通过个体与群体的协作,逐步逼近最优解

二、核心概念:PSO的“四大基本要素”

为了将“鸟群觅食”转化为数学模型,我们需要定义4个关键概念,用表格直观对比:

概念通俗理解数学定义作用
粒子(Particle)一只“找食物的鸟”,代表一个候选解DDD维向量xi=(xi1,xi2,...,xiD)\boldsymbol{x}_i=(x_{i1},x_{i2},...,x_{iD})xi=(xi1,xi2,...,xiD)i=1,2,...,Ni=1,2,...,Ni=1,2,...,NNNN为粒子总数)每个粒子的位置对应优化问题的一个潜在解
速度(Velocity)鸟的飞行方向和距离(“下一步飞多远、往哪飞”)DDD维向量vi=(vi1,vi2,...,viD)\boldsymbol{v}_i=(v_{i1},v_{i2},...,v_{iD})vi=(vi1,vi2,...,viD)决定粒子下一时刻的移动趋势
个体最优(pbest)鸟自己飞过的“食物最多”的位置pi=(pi1,pi2,...,piD)\boldsymbol{p}_i=(p_{i1},p_{i2},...,p_{iD})pi=(pi1,pi2,...,piD)(粒子iii历史最优位置)粒子的“个人经验”
全局最优(gbest)整个群体目前找到的“食物最多”的位置pg=(pg1,pg2,...,pgD)\boldsymbol{p}_g=(p_{g1},p_{g2},...,p_{gD})pg=(pg1,pg2,...,pgD)(所有粒子中最优的位置)粒子的“群体经验”

三、数学模型:粒子如何“调整飞行”?(核心公式详解)

PSO的核心是速度更新公式(决定粒子怎么飞)和位置更新公式(决定粒子飞到哪)。我们用“鸟飞行”的例子拆解每个公式:

1. 速度更新公式:三部分合力决定飞行方向和速度

粒子的速度由三部分组成,就像鸟飞行时受三种力的影响:
vid(t+1)=ω⋅vid(t)⏟惯性项+c1⋅r1⋅(pid−xid(t))⏟认知项+c2⋅r2⋅(pgd−xid(t))⏟社会项 v_{id}(t+1) = \underbrace{\omega \cdot v_{id}(t)}_{\text{惯性项}} + \underbrace{c_1 \cdot r_1 \cdot (p_{id} - x_{id}(t))}_{\text{认知项}} + \underbrace{c_2 \cdot r_2 \cdot (p_{gd} - x_{id}(t))}_{\text{社会项}} vid(t+1)=惯性项ωvid(t)+认知项c1r1(pidxid(t))+社会项c2r2(pgdxid(t))

组成部分通俗解释数学意义
惯性项鸟保持当前飞行趋势的“惯性”(比如你骑车时不蹬脚蹬,车会因惯性继续前进)。ω⋅vid(t)\omega \cdot v_{id}(t)ωvid(t):保留上一时刻速度的一部分,ω\omegaω是“惯性权重”。
认知项鸟根据自己记忆中“最好位置”调整方向(“我之前在A点找到过很多食物,往A点飞一点”)。c1r1(pid−xid(t))c_1 r_1 (p_{id} - x_{id}(t))c1r1(pidxid(t))pid−xid(t)p_{id} - x_{id}(t)pidxid(t)是当前位置到个体最优的“距离差”,c1c_1c1是“个体学习强度”,r1r_1r1是[0,1]随机数(增加随机性)。
社会项鸟根据群体中“最好位置”调整方向(“大家都说B点食物最多,我也往B点飞一点”)。c2r2(pgd−xid(t))c_2 r_2 (p_{gd} - x_{id}(t))c2r2(pgdxid(t))pgd−xid(t)p_{gd} - x_{id}(t)pgdxid(t)是当前位置到全局最优的“距离差”,c2c_2c2是“群体学习强度”,r2r_2r2是[0,1]随机数。
2. 位置更新公式:“飞了多远,就挪多远”

速度决定了“飞行的方向和距离”,位置则根据速度更新:
xid(t+1)=xid(t)+vid(t+1) x_{id}(t+1) = x_{id}(t) + v_{id}(t+1) xid(t+1)=xid(t)+vid(t+1)
通俗理解:就像你现在站在位置xxx,以速度vvv走了1秒,新位置就是x+vx + vx+v(比如现在在x=3x=3x=3,速度v=2v=2v=2,下一步就到3+2=53+2=53+2=5)。

3. 关键参数:如何让粒子“飞得更聪明”?
参数作用如何设置?
惯性权重ω\omegaω控制“惯性项”的强度,平衡全局搜索(大范围找解)和局部搜索(精细优化)。- 较大ω\omegaω(如0.9):惯性强,适合全局探索(像开车高速行驶,快速扫过多个区域);
- 较小ω\omegaω(如0.4):惯性弱,适合局部精细搜索(像开车低速行驶,仔细观察细节);
- 常用策略:线性递减ω(t)=ωmax−ωmax−ωminTmax⋅t\omega(t)=\omega_{\text{max}} - \frac{\omega_{\text{max}} - \omega_{\text{min}}}{T_{\text{max}}} \cdot tω(t)=ωmaxTmaxωmaxωmint(从0.9减到0.4,先全局后局部)。
学习因子c1,c2c_1,c_2c1,c2c1c_1c1:个体学习强度(“相信自己”);c2c_2c2:群体学习强度(“相信大家”)。- 典型值:c1=c2=2c_1=c_2=2c1=c2=2(经验平衡值);
- c1c_1c1太大:粒子太固执,可能陷入“自己的局部最优”;
- c2c_2c2太大:粒子太盲从,可能快速收敛但错过更好解。
速度边界vmin,vmaxv_{\text{min}},v_{\text{max}}vmin,vmax防止速度过大导致粒子“飞过最优解”(像开车超速冲过目的地)。通常设为vmax=k⋅(xmax,d−xmin,d)v_{\text{max}}=k \cdot (x_{\text{max},d} - x_{\text{min},d})vmax=k(xmax,dxmin,d)kkk取0.1~0.2,xmax,xminx_{\text{max}},x_{\text{min}}xmax,xmin是位置边界),超出时截断为vminv_{\text{min}}vminvmaxv_{\text{max}}vmax

四、算法步骤:手把手教你“实现PSO”

PSO的迭代流程就像“鸟群找食物的过程”,分6步循环执行,直到找到“食物最多”的位置(最优解):

Step 1:初始化粒子群(“鸟群刚出发,随机找方向”)
  • 确定基本参数

    • 问题维度DDD(变量个数,如优化f(x,y)f(x,y)f(x,y)D=2D=2D=2);
    • 粒子数量NNN(鸟的数量,通常取20~100,太少搜索慢,太多计算量大);
    • 最大迭代次数TmaxT_{\text{max}}Tmax(最多找多少次,如100次);
    • 位置边界[xmin,d,xmax,d][x_{\text{min},d},x_{\text{max},d}][xmin,d,xmax,d](变量范围,如x,y∈[−5,5]x,y \in [-5,5]x,y[5,5]);
    • 速度边界[vmin,d,vmax,d][v_{\text{min},d},v_{\text{max},d}][vmin,d,vmax,d](如vmax=0.2×(5−(−5))=2v_{\text{max}}=0.2 \times (5 - (-5))=2vmax=0.2×(5(5))=2)。
  • 随机初始化

    • 位置:每个粒子的初始位置xi(0)\boldsymbol{x}_i(0)xi(0)[xmin,d,xmax,d][x_{\text{min},d},x_{\text{max},d}][xmin,d,xmax,d]内随机生成(如xi(0)=(2.3,−1.5)x_i(0)=(2.3,-1.5)xi(0)=(2.3,1.5));
    • 速度:每个粒子的初始速度vi(0)\boldsymbol{v}_i(0)vi(0)[vmin,d,vmax,d][v_{\text{min},d},v_{\text{max},d}][vmin,d,vmax,d]内随机生成(如vi(0)=(1.2,−0.8)v_i(0)=(1.2,-0.8)vi(0)=(1.2,0.8));
    • 个体最优pip_ipi:初始时设为当前位置(“刚开始飞,自己最好的位置就是现在的位置”);
    • 全局最优pgp_gpg:从所有pip_ipi中选适应度最好的位置(“大家刚开始,先选目前最好的那个”)。
Step 2:计算适应度值(“评估当前位置食物多少”)
  • 适应度函数:即优化目标函数f(x)f(\boldsymbol{x})f(x)(如极小化问题f(x,y)=x2+y2f(x,y)=x^2+y^2f(x,y)=x2+y2,值越小“食物越多”);
  • 计算:对每个粒子的位置xi(t)\boldsymbol{x}_i(t)xi(t),代入f(x)f(\boldsymbol{x})f(x)得到适应度值(如xi=(2,3)\boldsymbol{x}_i=(2,3)xi=(2,3),适应度f=22+32=13f=2^2+3^2=13f=22+32=13)。
Step 3:更新个体最优pbest(“我之前飞过的地方,这里是不是更好?”)
  • 对每个粒子iii,比较当前位置的适应度f(xi(t))f(\boldsymbol{x}_i(t))f(xi(t))和自己历史最优适应度f(pi)f(p_i)f(pi)
    • f(xi(t))<f(pi)f(\boldsymbol{x}_i(t)) < f(p_i)f(xi(t))<f(pi)(极小化问题,当前位置“食物更多”),则更新pi=xi(t)p_i = \boldsymbol{x}_i(t)pi=xi(t)
    • 否则,保持pip_ipi不变(“还是之前的位置更好”)。
Step 4:更新全局最优gbest(“大家目前找到的位置,谁的最好?”)
  • 遍历所有粒子的pip_ipi,找到适应度最小的pip_ipi作为新的pgp_gpg
    • 若某个粒子的pip_ipi适应度比当前pgp_gpg更小,则更新pg=pip_g = p_ipg=pi
    • 否则,保持pgp_gpg不变(“目前还没人超过这个最好位置”)。
Step 5:更新速度和位置(“根据经验调整飞行,飞向更好的地方”)
  • 更新速度:用速度公式计算vid(t+1)v_{id}(t+1)vid(t+1),并检查是否超出[vmin,vmax][v_{\text{min}},v_{\text{max}}][vmin,vmax](超出则截断,如v=3v=3v=3vmax=2v_{\text{max}}=2vmax=2,则取v=2v=2v=2);
  • 更新位置:用位置公式计算xid(t+1)x_{id}(t+1)xid(t+1),并检查是否超出[xmin,xmax][x_{\text{min}},x_{\text{max}}][xmin,xmax](超出则截断,如x=6x=6x=6xmax=5x_{\text{max}}=5xmax=5,则取x=5x=5x=5)。
Step 6:判断终止条件(“找到满意的食物了吗?”)
  • 若满足以下任一条件,则停止迭代,输出pgp_gpg(最优解):
    • 迭代次数t=Tmaxt=T_{\text{max}}t=Tmax(达到最大搜索次数);
    • 全局最优适应度f(pg)<ϵf(p_g) < \epsilonf(pg)<ϵ(达到预设精度,如ϵ=10−6\epsilon=10^{-6}ϵ=106,即“食物足够多了”)。
  • 否则,返回Step 2,继续下一次迭代。

五、算法流程图:一目了然的迭代过程

graph TD
    A[初始化粒子群:位置、速度、pbest、gbest] --> B[计算所有粒子适应度值]
    B --> C[更新个体最优pbest:比较当前位置与自己历史最好]
    C --> D[更新全局最优gbest:比较所有pbest,选最好的]
    D --> E[更新速度:惯性项+认知项+社会项(截断速度边界)]
    E --> F[更新位置:当前位置+新速度(截断位置边界)]
    F --> G{达到最大迭代次数或精度?}
    G -- 是 --> H[输出全局最优解gbest]
    G -- 否 --> B[回到计算适应度]

六、为什么PSO适合数模小白?

  • 原理简单:模拟鸟群协作,无需复杂数学推导;
  • 参数少:核心参数仅ω,c1,c2,N,Tmax\omega,c_1,c_2,N,T_{\text{max}}ω,c1,c2,N,Tmax,调参容易;
  • 通用性强:可解决函数优化、参数估计、路径规划等多种问题(如数学建模中的“最优分配”“最小成本”问题)。

总结

PSO的本质是:让每个“粒子”(候选解)通过“自己的经验”(pbest)和“群体的经验”(gbest)不断调整方向,像鸟群一样协作找到最优解。记住核心公式的三部分(惯性+认知+社会),理解参数如何平衡“全局探索”和“局部优化”,你就能快速上手用PSO解决数模问题啦!

Python实现代码:

粒子群算法(PSO)Python实现代码检查与优化

一、代码检查结果

原代码整体符合Python3语法规范,逻辑清晰,变量命名规范(英文命名),无未定义变量或类型不匹配问题。核心优化流程(初始化→速度更新→位置更新→pbest/gbest更新)完整正确,边界裁剪、参数设置(如w=0.7、c1=c2=1.5)符合PSO经验值。主要可优化点为补充关键步骤的行内注释,使每一行代码的作用更明确。

二、优化后完整代码
import numpy as np  # 导入数值计算库,用于矩阵运算和随机数生成
import matplotlib.pyplot as plt  # 导入绘图库,用于绘制收敛曲线


# -------------------------- 适应度函数定义 --------------------------
def sphere_function(position):
    """
    计算Sphere函数的适应度值(测试函数,用于评估粒子位置优劣)
    Sphere函数公式:f(x) = sum(x_i^2),最小值在x=0处,f(x)=0
    参数:
        position: 粒子位置向量 (numpy数组,形状为[dim,])
    返回:
        float: 适应度值(函数计算结果)
    """
    return np.sum(position ** 2)  # 计算位置向量各维度的平方和,作为适应度值


# -------------------------- 粒子群初始化 --------------------------
def initialize_particles(n_particles, dim, pos_bounds, vel_bounds):
    """
    初始化粒子群的位置、速度、个体最优位置和个体最优值
    参数:
        n_particles: 粒子数量 (int)
        dim: 问题维度 (int)
        pos_bounds: 位置边界 [min, max] (list),控制粒子搜索空间范围
        vel_bounds: 速度边界 [min, max] (list),控制粒子移动步长范围
    返回:
        particle_positions: 粒子位置矩阵 (n_particles x dim numpy数组)
        particle_velocities: 粒子速度矩阵 (n_particles x dim numpy数组)
        pbest_positions: 个体最优位置矩阵 (n_particles x dim numpy数组)
        pbest_values: 个体最优值数组 (n_particles x 1 numpy数组)
    """
    # 初始化位置:在[pos_bounds[0], pos_bounds[1]]内均匀随机生成,确保覆盖整个搜索空间
    particle_positions = np.random.uniform(
        low=pos_bounds[0],  # 位置下界(如Sphere函数常用-10)
        high=pos_bounds[1],  # 位置上界(如Sphere函数常用10)
        size=(n_particles, dim)  # 生成n_particles个粒子,每个粒子dim维
    )
    
    # 初始化速度:在[vel_bounds[0], vel_bounds[1]]内均匀随机生成,控制初始移动能力
    particle_velocities = np.random.uniform(
        low=vel_bounds[0],  # 速度下界(通常为位置范围的-10%~-20%)
        high=vel_bounds[1],  # 速度上界(通常为位置范围的10%~20%)
        size=(n_particles, dim)  # 与位置矩阵维度一致
    )
    
    # 个体最优位置初始化为初始位置(初始时刻每个粒子的历史最优就是当前位置)
    pbest_positions = np.copy(particle_positions)  # 使用np.copy避免浅拷贝
    
    # 个体最优值初始化为初始位置的适应度值(计算每个粒子初始位置的Sphere函数值)
    pbest_values = np.array([sphere_function(pos) for pos in particle_positions])  # 列表推导式计算后转为数组
    
    return particle_positions, particle_velocities, pbest_positions, pbest_values


# -------------------------- 速度更新函数 --------------------------
def update_velocities(particle_positions, particle_velocities, pbest_positions, gbest_position, w, c1, c2, vel_bounds):
    """
    根据PSO速度更新公式更新粒子速度(核心步骤,控制粒子移动方向和步长)
    速度公式:v = w*v + c1*r1*(pbest - pos) + c2*r2*(gbest - pos)
    参数:
        particle_positions: 当前粒子位置矩阵 (n_particles x dim)
        particle_velocities: 当前粒子速度矩阵 (n_particles x dim)
        pbest_positions: 个体最优位置矩阵 (n_particles x dim),每个粒子的历史最佳位置
        gbest_position: 全局最优位置向量 (dim,),整个种群的历史最佳位置
        w: 惯性权重 (float),控制对当前速度的保留程度(平衡探索与利用)
        c1: 认知学习因子 (float),控制个体经验的影响权重
        c2: 社会学习因子 (float),控制群体经验的影响权重
        vel_bounds: 速度边界 [min, max] (list),防止速度过大导致粒子跳出搜索空间
    返回:
        updated_velocities: 更新后的速度矩阵 (n_particles x dim)
    """
    n_particles, dim = particle_positions.shape  # 获取粒子数量和问题维度(从位置矩阵形状推断)
    r1 = np.random.rand(n_particles, dim)  # 认知项随机因子矩阵(每个粒子每个维度独立生成[0,1)随机数)
    r2 = np.random.rand(n_particles, dim)  # 社会项随机因子矩阵(同上)
    
    # 速度更新三部分拆解(便于理解物理意义):
    inertia_term = w * particle_velocities  # 惯性项:保留当前速度的一部分(w越大,探索能力越强)
    cognitive_term = c1 * r1 * (pbest_positions - particle_positions)  # 认知项:向个体最优位置移动的趋势
    social_term = c2 * r2 * (gbest_position - particle_positions)  # 社会项:向全局最优位置移动的趋势
    
    updated_velocities = inertia_term + cognitive_term + social_term  # 合并三项得到新速度
    
    # 速度边界裁剪:确保速度不超出设定范围(防止粒子因速度过大冲出搜索空间)
    updated_velocities = np.clip(updated_velocities, vel_bounds[0], vel_bounds[1])
    
    return updated_velocities


# -------------------------- 位置更新函数 --------------------------
def update_positions(particle_positions, particle_velocities, pos_bounds):
    """
    根据速度更新粒子位置,并进行边界裁剪(确保粒子在有效搜索空间内移动)
    参数:
        particle_positions: 当前粒子位置矩阵 (n_particles x dim)
        particle_velocities: 当前粒子速度矩阵 (n_particles x dim)
        pos_bounds: 位置边界 [min, max] (list),搜索空间的范围限制
    返回:
        updated_positions: 更新后的位置矩阵 (n_particles x dim)
    """
    updated_positions = particle_positions + particle_velocities  # 位置更新公式:新位置 = 旧位置 + 速度
    # 位置边界裁剪:若位置超出[pos_bounds[0], pos_bounds[1]],则强制拉回边界(确保搜索有效区域)
    updated_positions = np.clip(updated_positions, pos_bounds[0], pos_bounds[1])
    return updated_positions


# -------------------------- PSO主函数 --------------------------
def particle_swarm_optimization(n_particles, dim, pos_bounds, vel_bounds, max_iter, w, c1, c2):
    """
    粒子群优化算法主流程(协调各模块完成迭代优化)
    参数:
        n_particles: 粒子数量 (int),影响搜索多样性和计算效率
        dim: 问题维度 (int),优化变量的数量(如5维Sphere函数有5个变量)
        pos_bounds: 位置边界 [min, max] (list),搜索空间范围
        vel_bounds: 速度边界 [min, max] (list),移动步长限制
        max_iter: 最大迭代次数 (int),算法终止条件(迭代次数足够大时收敛)
        w: 惯性权重 (float),平衡探索(全局搜索)与利用(局部搜索)
        c1: 认知学习因子 (float),个体经验权重
        c2: 社会学习因子 (float),群体经验权重
    返回:
        gbest_position: 全局最优位置 (dim numpy数组),算法找到的最优解
        gbest_value: 全局最优值 (float),最优解对应的适应度值
        gbest_history: 每代全局最优值记录 (max_iter numpy数组),用于绘制收敛曲线
    """
    # 1. 初始化粒子群(位置、速度、个体最优)
    particle_positions, particle_velocities, pbest_positions, pbest_values = initialize_particles(
        n_particles, dim, pos_bounds, vel_bounds
    )
    
    # 2. 初始化全局最优(从初始个体最优中选取最优值对应的位置和值)
    gbest_index = np.argmin(pbest_values)  # 找到pbest_values中最小值的索引(适应度越小越优)
    gbest_position = np.copy(pbest_positions[gbest_index])  # 全局最优位置初始化为该粒子的位置
    gbest_value = pbest_values[gbest_index]  # 全局最优值初始化为该粒子的适应度值
    
    # 记录每代全局最优值(用于后续绘制收敛曲线,观察算法收敛过程)
    gbest_history = np.zeros(max_iter)  # 初始化长度为max_iter的数组
    
    # 3. 迭代优化(核心循环,重复更新速度、位置、适应度、pbest、gbest)
    for iter in range(max_iter):  # 从0到max_iter-1迭代
        # 3.1 更新粒子速度(根据当前位置、速度、pbest、gbest计算新速度)
        particle_velocities = update_velocities(
            particle_positions, particle_velocities, pbest_positions, 
            gbest_position, w, c1, c2, vel_bounds
        )
        
        # 3.2 更新粒子位置(根据新速度计算新位置,并裁剪边界)
        particle_positions = update_positions(
            particle_positions, particle_velocities, pos_bounds
        )
        
        # 3.3 计算当前所有粒子的适应度值(评估新位置的优劣)
        current_values = np.array([sphere_function(pos) for pos in particle_positions])
        
        # 3.4 更新个体最优pbest(若当前位置适应度优于历史pbest,则更新)
        for i in range(n_particles):  # 遍历每个粒子
            if current_values[i] < pbest_values[i]:  # 当前值更小(更优)
                pbest_values[i] = current_values[i]  # 更新个体最优值
                pbest_positions[i] = np.copy(particle_positions[i])  # 更新个体最优位置
        
        # 3.5 更新全局最优gbest(若当前pbest中的最优值优于历史gbest,则更新)
        current_gbest_index = np.argmin(pbest_values)  # 找到当前pbest中的最优索引
        current_gbest_value = pbest_values[current_gbest_index]  # 当前pbest中的最优值
        if current_gbest_value < gbest_value:  # 当前pbest最优值更优
            gbest_value = current_gbest_value  # 更新全局最优值
            gbest_position = np.copy(pbest_positions[current_gbest_index])  # 更新全局最优位置
        
        # 3.6 记录当前代的全局最优值(用于收敛曲线)
        gbest_history[iter] = gbest_value
        
        # 打印迭代信息(每10代打印一次,监控优化进度)
        if (iter + 1) % 10 == 0:  # iter从0开始,+1转为1-based计数
            print(f"迭代次数: {iter+1}/{max_iter} | 当前最优值: {gbest_value:.6f}")  # 保留6位小数
    
    return gbest_position, gbest_value, gbest_history


# -------------------------- 主程序 --------------------------
if __name__ == "__main__":  # 确保该代码块仅在直接运行脚本时执行
    # -------------------------- 参数设置 --------------------------
    n_particles = 30  # 粒子数量:经验值20-40(太少多样性不足,太多计算量大)
    dim = 5  # 问题维度:测试5维Sphere函数(即优化5个变量x1,x2,x3,x4,x5)
    pos_bounds = [-10, 10]  # 位置边界:Sphere函数常用[-10,10](覆盖最小值0)
    vel_bounds = [-2, 2]  # 速度边界:位置范围的±20%(10*20%=2,平衡移动步长)
    max_iter = 100  # 最大迭代次数:经验值100-500(100代足以收敛到Sphere函数最小值)
    w = 0.7  # 惯性权重:经验值0.5-0.9(0.7平衡探索与利用,w大→探索强,w小→利用强)
    c1 = 1.5  # 认知因子:经验值1-2(1.5表示中等个体经验权重)
    c2 = 1.5  # 社会因子:经验值1-2(1.5表示中等群体经验权重,c1=c2时个体与群体同等重要)
    
    # -------------------------- 运行PSO算法 --------------------------
    print("粒子群算法开始优化...")
    gbest_position, gbest_value, gbest_history = particle_swarm_optimization(
        n_particles, dim, pos_bounds, vel_bounds, max_iter, w, c1, c2
    )
    
    # -------------------------- 输出结果 --------------------------
    print("\n优化结束!")
    print(f"全局最优位置: {np.round(gbest_position, 6)}")  # 保留6位小数,应接近[0,0,...,0]
    print(f"全局最优值: {gbest_value:.8f}")  # 保留8位小数,应接近0(Sphere函数最小值)
    
    # -------------------------- 收敛曲线可视化 --------------------------
    plt.figure(figsize=(10, 6))  # 设置图像大小
    plt.plot(range(1, max_iter+1), gbest_history, 'b-', linewidth=2)  # 蓝色实线绘制收敛曲线
    plt.xlabel('迭代次数', fontsize=12)  # x轴标签
    plt.ylabel('全局最优值', fontsize=12)  # y轴标签
    plt.title('PSO算法收敛曲线 (Sphere函数)', fontsize=14)  # 图像标题
    plt.grid(True, linestyle='--', alpha=0.7)  # 添加网格线(虚线,透明度0.7)
    plt.show()  # 显示图像
三、代码逐一讲解(含参数设置说明)
1. 核心模块与功能

代码分为适应度函数、初始化模块、速度更新、位置更新、PSO主函数、主程序六个部分,各模块职责明确,通过函数解耦,结构清晰。

2. 关键参数设置与意义

以下是影响PSO性能的核心参数及其设置依据:

参数名含义代码中设置值选择依据(经验值/原理)
n_particles粒子数量30经验值20-40:太少(如<10)会导致搜索多样性不足,易陷入局部最优;太多(如>50)会增加计算量,性价比低。30是平衡多样性和效率的常用值。
dim问题维度5测试5维Sphere函数(可根据实际问题调整,如优化10个变量则设为10)。
pos_bounds位置边界 [min, max][-10, 10]Sphere函数最小值在0处,[-10,10]覆盖足够大的搜索空间,确保初始粒子能分布在最优解附近。其他函数(如Rastrigin)可能需要更大范围(如[-50,50])。
vel_bounds速度边界 [min, max][-2, 2]通常设为位置范围的±10%~20%:10*20%=2,防止速度过大导致粒子跳出搜索空间(如速度>10会直接从-10跳到10,错过中间最优解)。
max_iter最大迭代次数100经验值100-500:Sphere函数简单,100代足以收敛;复杂函数(如多峰函数)可能需要200-500代。迭代次数过少收敛不充分,过多浪费计算资源。
w惯性权重0.7平衡探索(全局搜索)与利用(局部搜索):w=0.7为经典经验值(w>0.9→探索强,适合初期;w<0.5→利用强,适合后期,也可动态调整w从0.9线性降至0.4)。
c1/c2认知/社会学习因子1.5/1.5经验值1-2:c1控制个体经验(粒子自身历史最优的影响),c2控制群体经验(全局最优的影响)。c1=c2=1.5表示个体与群体同等重要;若c1>c2,粒子更依赖自身经验,探索性更强。
3. 核心流程讲解
  1. 初始化initialize_particles生成随机位置(覆盖搜索空间)和速度(控制初始移动),并将初始位置设为个体最优(pbest)。
  2. 速度更新update_velocities通过惯性项(保留当前趋势)、认知项(向pbest移动)、社会项(向gbest移动)计算新速度,裁剪边界防止越界。
  3. 位置更新update_positions根据速度更新位置,裁剪边界确保粒子在有效空间内。
  4. pbest/gbest更新:每次迭代计算当前位置适应度,若优于历史pbest则更新pbest;再从pbest中选最优更新gbest。
  5. 收敛监控:记录每代gbest值,迭代结束后输出最优解并绘制收敛曲线(应随迭代下降至0附近)。
4. 运行结果预期
  • 全局最优位置:接近[0, 0, 0, 0, 0](Sphere函数最小值点)。
  • 全局最优值:接近0(如0.00012345,受随机初始化影响略有波动)。
  • 收敛曲线:从初始较高值(如100-500,因初始位置平方和)快速下降,100代后趋于平缓(收敛到最小值)。

通过以上参数设置和流程设计,PSO算法能高效找到Sphere函数的最优解,代码可直接用于其他优化问题(只需替换sphere_function为目标函数,并调整dimpos_bounds等参数)。

Matlab实现代码:

粒子群算法(PSO)Matlab代码实现优化与讲解

一、常见错误预判及避免措施

常见错误避免措施
参数设置不当导致收敛问题惯性权重w设为0.4-0.9,加速系数c1、c2设为1-2,粒子数20-100,迭代次数100-1000
速度更新公式错误严格遵循标准公式:( v = w \cdot v + c1 \cdot \text{rand}() \cdot (\text{pbest}-x) + c2 \cdot \text{rand}() \cdot (\text{gbest}-x) )
粒子位置/速度越界位置更新后强制截断到搜索空间边界;速度限制在[-v_max, v_max]避免震荡
目标函数定义错误单独定义目标函数并测试其正确性(如Sphere函数最小值为0)
pbest/gbest初始化错误pbest初始化为粒子初始位置,gbest初始化为初始pbest中的最优值
迭代终止条件缺失设置最大迭代次数作为终止条件,避免死循环

二、自定义函数实现(优化后)

1. 目标函数(Sphere函数)
function f = objective_func(x)
% 目标函数:Sphere函数(球体函数),用于测试PSO优化性能
% 数学表达式:f(x) = sum_{i=1}^D x_i^2,其中D为输入向量x的维度
% 函数特性:连续、凸函数,全局最小值为0(位于x=[0,0,...,0]处)
% 参数:
%   x:输入位置向量(1xD维,D为问题维度)
% 返回值:
%   f:目标函数值(标量)
f = sum(x.^2);  % 计算x各维度分量的平方和(x1² + x2² + ... + xD²)
end
2. 速度更新函数
function v_new = update_velocity(v, x, pbest, gbest, w, c1, c2)
% 速度更新函数:根据PSO标准公式计算粒子新速度
% 速度公式:v_new = 惯性项 + 个体认知项 + 社会经验项
% 参数:
%   v:当前速度矩阵(NxD维,N为粒子数,D为维度)
%   x:当前位置矩阵(NxD维)
%   pbest:个体最优位置矩阵(NxD维,每行对应一个粒子的历史最优位置)
%   gbest:全局最优位置向量(1xD维,整个种群的历史最优位置)
%   w:惯性权重(标量,控制速度继承程度)
%   c1:个体认知系数(标量,控制向pbest靠近的权重)
%   c2:社会经验系数(标量,控制向gbest靠近的权重)
% 返回值:
%   v_new:更新后的速度矩阵(NxD维)

% 惯性项:w*v(保留部分当前速度,体现"惯性")
% 个体认知项:c1*rand()*(pbest-x)(随机权重×个体最优与当前位置的差距,体现"自我认知")
% 社会经验项:c2*rand()*(gbest-x)(随机权重×全局最优与当前位置的差距,体现"社会协作")
v_new = w * v + ...  % 惯性项:w越大,粒子保持原有运动趋势越强(全局探索能力强)
        c1 * rand(size(v)) .* (pbest - x) + ...  % 个体认知项:rand()生成[0,1)随机数,增加随机性
        c2 * rand(size(v)) .* (gbest - x);  % 社会经验项:gbest为1xD向量,Matlab自动广播适配NxD矩阵运算
end
3. 位置更新函数
function x_new = update_position(x, v)
% 位置更新函数:基于速度计算新位置(假设时间步长Δt=1)
% 物理意义:位置变化量 = 速度×时间(Δt=1时,新位置=当前位置+速度)
% 参数:
%   x:当前位置矩阵(NxD维)
%   v:当前速度矩阵(NxD维,与x同尺寸)
% 返回值:
%   x_new:更新后的位置矩阵(NxD维)
x_new = x + v;  % 位置更新公式:x_{t+1} = x_t + v_{t+1}(速度对位置的累积效应)
end
4. 边界处理函数(通用截断法)
function x_clamped = boundary_handle(x, lb, ub)
% 边界处理函数:采用截断法限制输入x在[lb, ub]范围内
% 截断法原理:若x元素 < lb则强制设为lb,> ub则强制设为lb,实现简单且稳定
% 适用场景:位置越界处理(避免目标函数定义域外计算)、速度越界处理(避免速度过大震荡)
% 参数:
%   x:待处理矩阵(NxD维,可为位置或速度矩阵)
%   lb:下界(标量,假设各维度边界相同;若需不同维度边界,可改为向量输入)
%   ub:上界(标量,同上)
% 返回值:
%   x_clamped:边界处理后的矩阵(NxD维,所有元素∈[lb, ub])
x_clamped = max(min(x, ub), lb);  % 元素级操作:先将x中>ub的元素设为ub,再将<lb的元素设为lb
end

三、主程序(PSO_main.m,优化后)

% 粒子群算法(PSO)主程序:求解Sphere函数最小值
clear;  % 清除工作区所有变量,避免历史变量干扰
clc;    % 清空命令窗口,便于查看输出信息
close all;  % 关闭所有图形窗口,避免残留图像

%% 1. 参数设置(PSO核心参数,直接影响算法性能)
N = 30;          % 粒子数量(种群规模):经验值20-100,30为经典取值(平衡收敛速度与计算量)
D = 2;           % 问题维度(优化变量个数):设为2便于二维空间可视化(可修改为任意正整数)
max_iter = 100;  % 最大迭代次数(终止条件):经验值100-1000,100次足以测试Sphere函数收敛性
w = 0.7;         % 惯性权重:控制速度继承程度,经验值0.4-0.9(0.7为经典取值,平衡全局探索与局部开发)
c1 = 1.5;        % 个体认知系数:粒子向自身历史最优(pbest)靠近的权重,经验值1-2
c2 = 1.5;        % 社会经验系数:粒子向群体最优(gbest)靠近的权重,经验值1-2(c1=c2=1.5为对称设置,协作与认知平衡)
lb = -10;        % 位置下界(搜索空间下限):Sphere函数常用测试范围[-10,10]
ub = 10;         % 位置上界(搜索空间上限)
v_max = 0.2 * (ub - lb);  % 速度上限:设为搜索空间宽度(ub-lb)的20%(0.2*20=4),避免速度过大导致粒子飞过最优区域

%% 2. 初始化粒子群(位置和速度随机生成,确保初始多样性)
% 初始化粒子位置:在[lb, ub]均匀随机分布(确保初始位置覆盖整个搜索空间)
x = lb + (ub - lb) .* rand(N, D);  % rand(N,D)生成N行D列[0,1)随机数,通过线性变换映射到[lb, ub]
% 示例:若lb=-10, ub=10,rand()=0 → x=-10;rand()=1 → x=10(实际rand()取不到1,故x∈[lb, ub),近似覆盖)

% 初始化粒子速度:在[-v_max, v_max]均匀随机分布(避免初始速度过大或过小)
v = -v_max + 2*v_max .* rand(N, D);  % rand(N,D)∈[0,1) → 2*v_max*rand()∈[0, 2v_max) → -v_max + ... ∈[-v_max, v_max)

%% 3. 初始化最优位置(pbest和gbest的初始状态)
% 个体最优位置(pbest):初始化为粒子初始位置(每个粒子最初的最优就是自己的起点)
pbest = x;  % pbest为NxD矩阵,每行对应一个粒子的历史最优位置

% 个体最优目标值(pbest_value):计算初始位置的目标函数值
pbest_value = zeros(N, 1);  % 初始化Nx1向量,存储每个粒子的个体最优目标值
for i = 1:N  % 循环计算每个粒子的初始目标值(因objective_func输入为1xD向量,需逐粒子计算)
    pbest_value(i) = objective_func(pbest(i,:));  % pbest(i,:)为第i个粒子的初始位置(1xD向量)
end

% 全局最优位置(gbest):初始化为pbest中目标值最小的位置(种群最初的最优是个体最优中的最好者)
[gbest_value, idx] = min(pbest_value);  % min返回最小值gbest_value和对应索引idx
gbest = pbest(idx,:);  % 提取第idx个粒子的pbest作为初始gbest(1xD向量)

%% 4. 迭代优化(PSO核心循环,实现种群进化)
history = zeros(max_iter, 1);  % 初始化收敛曲线记录数组(max_iter行1列),存储每次迭代的全局最优值
for iter = 1:max_iter  % 循环max_iter次(迭代终止条件)
    
    % Step 1: 更新速度(核心步骤,体现PSO的"群体智能"机制)
    v = update_velocity(v, x, pbest, gbest, w, c1, c2);  % 调用速度更新函数
    
    % Step 1.5: 速度边界处理(避免速度累积过大导致粒子"飞出"搜索空间)
    v = boundary_handle(v, -v_max, v_max);  % 将速度限制在[-v_max, v_max]范围内
    
    % Step 2: 更新位置(基于新速度计算新位置)
    x = update_position(x, v);  % 调用位置更新函数
    
    % Step 3: 位置边界处理(确保粒子始终在搜索空间内活动)
    x = boundary_handle(x, lb, ub);  % 将位置限制在[lb, ub]范围内
    
    % Step 4: 计算当前位置的目标函数值(评估粒子当前性能)
    current_value = arrayfun(@(i) objective_func(x(i,:)), 1:N);  % arrayfun等价于for循环,对每个粒子计算目标值
    % 注:arrayfun(@(i) func(x(i,:)), 1:N) → 将x的每行(第i个粒子)输入objective_func,返回Nx1向量
    
    % Step 5: 更新个体最优(pbest):若当前位置优于历史最优,则更新
    mask = current_value < pbest_value;  % 逻辑矩阵(Nx1):current_value(i) < pbest_value(i)时为true(1),否则为false(0)
    pbest(mask,:) = x(mask,:);          % 仅更新mask为true的粒子的pbest位置
    pbest_value(mask) = current_value(mask);  % 同步更新对应粒子的pbest_value
    
    % Step 6: 更新全局最优(gbest):若个体最优中出现更优值,则更新
    [current_gbest_value, current_idx] = min(pbest_value);  % 找到当前所有个体最优中的最小值及索引
    if current_gbest_value < gbest_value  % 仅当新的个体最优优于当前全局最优时更新
        gbest_value = current_gbest_value;  % 更新全局最优值
        gbest = pbest(current_idx,:);       % 更新全局最优位置
    end
    
    % Step 7: 记录当前迭代的全局最优值(用于绘制收敛曲线)
    history(iter) = gbest_value;
    
    % 打印迭代信息(每10次迭代显示一次,避免输出过多)
    if mod(iter, 10) == 0  % mod(iter,10)=0 → 迭代次数为10的倍数(10,20,...,100)
        fprintf('迭代次数: %d, 全局最优值: %.6f\n', iter, gbest_value);  % 显示当前迭代次数和全局最优值
    end
end

%% 5. 结果展示(输出优化结果并可视化收敛过程)
% 输出最终优化结果
fprintf('\n优化结束!\n');
fprintf('全局最优位置: [');
for d = 1:D  % 循环输出每个维度的最优位置(适应任意维度D)
    fprintf('%.4f', gbest(d));  % 每个维度保留4位小数
    if d < D  % 非最后一个维度时添加逗号分隔
        fprintf(', ');
    end
end
fprintf(']\n');  % 闭合中括号
fprintf('全局最优值: %.6f\n', gbest_value);  % 全局最优值保留6位小数(Sphere函数理论最小值为0,此处应接近0)

% 绘制收敛曲线(直观展示算法收敛过程)
figure;  % 创建新图形窗口
plot(1:max_iter, history, 'b-', 'LineWidth', 1.5);  % 蓝色实线绘制收敛曲线,线宽1.5
xlabel('迭代次数', 'FontSize', 10);  % x轴标签,字体大小10
ylabel('全局最优目标值', 'FontSize', 10);  % y轴标签
title('PSO收敛曲线(Sphere函数)', 'FontSize', 12);  % 图形标题
grid on;  % 显示网格线,便于观察数据点
set(gca, 'FontSize', 9);  % 设置坐标轴刻度字体大小为9

四、代码逐一讲解(重点参数与核心逻辑)

1. 自定义函数讲解
  • objective_func
    目标函数采用Sphere函数(( f(x) = \sum_{i=1}^D x_i^2 )),是优化算法的“测试基准”。其特性为:连续、凸函数、唯一全局最小值0(在( x=[0,0,…,0] )处),便于验证PSO是否能找到理论最优。

  • update_velocity
    实现PSO核心速度更新公式,包含三部分:

    • 惯性项(w*v):控制粒子保持当前运动趋势的能力。w越大(如0.9),全局探索能力越强(适合初期);w越小(如0.4),局部开发能力越强(适合后期)。当前取0.7为平衡值。
    • 个体认知项(c1rand()(pbest-x)):粒子“回忆”并向自己历史最优位置靠近的动力。c1越大,粒子越依赖自身经验(易陷入局部最优)。
    • 社会经验项(c2rand()(gbest-x)):粒子“学习”并向群体最优位置靠近的动力。c2越大,粒子越依赖群体信息(易快速收敛但可能早熟)。
  • boundary_handle
    采用“截断法”处理越界,是最常用的边界处理方式。优点:实现简单、计算高效;缺点:可能导致粒子在边界“卡住”(可通过其他方法如反弹法改进,但截断法稳定性最好,适合初学者)。

2. 主程序核心逻辑讲解
  • 参数设置

    • N(粒子数):30。太少(如<10)会导致种群多样性不足,易早熟;太多(如>100)会增加计算量,收敛速度反而下降。
    • D(维度):2。此处为可视化设置,实际问题中可设为任意维度(如10维、100维),代码兼容。
    • max_iter(迭代次数):100。Sphere函数简单,100次足以收敛;复杂问题(如高维、多峰函数)需增加至500-1000次。
    • w(惯性权重):0.7。经典取值,平衡探索与开发。动态w(如从0.9线性递减至0.4)可进一步优化,但固定w更简单稳定。
    • c1, c2(加速系数):均为1.5。对称设置使个体认知与社会经验同等重要,符合标准PSO设计。
    • v_max(速度上限):0.2*(ub-lb)=4。若不限制速度,粒子可能因速度累积“飞过”最优区域;若过小(如<0.1*(ub-lb)),粒子探索能力不足,收敛慢。
  • 初始化阶段

    • 位置x在[lb, ub]均匀分布,确保初始种群覆盖整个搜索空间,避免遗漏最优区域。
    • 速度v在[-v_max, v_max]均匀分布,避免初始速度过大导致粒子跳出搜索空间,或过小导致运动迟缓。
  • 迭代优化阶段
    核心循环按“速度更新→速度边界→位置更新→位置边界→目标值计算→pbest更新→gbest更新→记录历史”顺序执行,实现种群从“随机探索”到“向最优聚集”的进化过程。

    • pbest更新:通过逻辑矩阵mask实现向量化操作(仅更新更优粒子),比循环更高效。
    • gbest更新:每次迭代仅比较个体最优中的最小值,确保全局最优是“历史最佳”。
  • 结果展示
    收敛曲线直观展示全局最优值随迭代次数的下降趋势,理想情况下应逐渐趋于0(Sphere函数理论最优),验证PSO的有效性。

五、运行结果说明

运行主程序后,命令窗口会输出每10次迭代的全局最优值,最终显示:

优化结束!
全局最优位置: [0.00xx, 0.00xx]  % 接近[0,0]
全局最优值: 0.000xxx  % 接近0

同时弹出收敛曲线图,曲线从初始较大值(如几百)快速下降,最终趋于0,表明PSO成功找到了Sphere函数的全局最优。

总结

优化后的代码修正了原代码中“速度无边界限制”和“全局最优位置输出依赖D=2”的问题,增加了详细批注,并通过参数讲解明确了各设置的意义。代码结构清晰、逻辑严谨,可直接用于低维优化问题,或通过调整参数(如D、max_iter)扩展至高维场景。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐