2025全国大学生数学建模C题思路模型代码(9.4开赛第一时间更新)备战国赛,算法解析——粒子群优化算法
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,...,N,NNN为粒子总数) | 每个粒子的位置对应优化问题的一个潜在解 |
| 速度(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)+认知项c1⋅r1⋅(pid−xid(t))+社会项c2⋅r2⋅(pgd−xid(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(pid−xid(t)):pid−xid(t)p_{id} - x_{id}(t)pid−xid(t)是当前位置到个体最优的“距离差”,c1c_1c1是“个体学习强度”,r1r_1r1是[0,1]随机数(增加随机性)。 |
| 社会项 | 鸟根据群体中“最好位置”调整方向(“大家都说B点食物最多,我也往B点飞一点”)。 | c2r2(pgd−xid(t))c_2 r_2 (p_{gd} - x_{id}(t))c2r2(pgd−xid(t)):pgd−xid(t)p_{gd} - x_{id}(t)pgd−xid(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)=ωmax−Tmaxωmax−ωmin⋅t(从0.9减到0.4,先全局后局部)。 |
| 学习因子c1,c2c_1,c_2c1,c2 | c1c_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,d−xmin,d)(kkk取0.1~0.2,xmax,xminx_{\text{max}},x_{\text{min}}xmax,xmin是位置边界),超出时截断为vminv_{\text{min}}vmin或vmaxv_{\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=3但vmax=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=6但xmax=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}ϵ=10−6,即“食物足够多了”)。
- 否则,返回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. 核心流程讲解
- 初始化:
initialize_particles生成随机位置(覆盖搜索空间)和速度(控制初始移动),并将初始位置设为个体最优(pbest)。 - 速度更新:
update_velocities通过惯性项(保留当前趋势)、认知项(向pbest移动)、社会项(向gbest移动)计算新速度,裁剪边界防止越界。 - 位置更新:
update_positions根据速度更新位置,裁剪边界确保粒子在有效空间内。 - pbest/gbest更新:每次迭代计算当前位置适应度,若优于历史pbest则更新pbest;再从pbest中选最优更新gbest。
- 收敛监控:记录每代gbest值,迭代结束后输出最优解并绘制收敛曲线(应随迭代下降至0附近)。
4. 运行结果预期
- 全局最优位置:接近
[0, 0, 0, 0, 0](Sphere函数最小值点)。 - 全局最优值:接近0(如
0.00012345,受随机初始化影响略有波动)。 - 收敛曲线:从初始较高值(如100-500,因初始位置平方和)快速下降,100代后趋于平缓(收敛到最小值)。
通过以上参数设置和流程设计,PSO算法能高效找到Sphere函数的最优解,代码可直接用于其他优化问题(只需替换sphere_function为目标函数,并调整dim、pos_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更新:每次迭代仅比较个体最优中的最小值,确保全局最优是“历史最佳”。
- pbest更新:通过逻辑矩阵
-
结果展示:
收敛曲线直观展示全局最优值随迭代次数的下降趋势,理想情况下应逐渐趋于0(Sphere函数理论最优),验证PSO的有效性。
五、运行结果说明
运行主程序后,命令窗口会输出每10次迭代的全局最优值,最终显示:
优化结束!
全局最优位置: [0.00xx, 0.00xx] % 接近[0,0]
全局最优值: 0.000xxx % 接近0
同时弹出收敛曲线图,曲线从初始较大值(如几百)快速下降,最终趋于0,表明PSO成功找到了Sphere函数的全局最优。
总结
优化后的代码修正了原代码中“速度无边界限制”和“全局最优位置输出依赖D=2”的问题,增加了详细批注,并通过参数讲解明确了各设置的意义。代码结构清晰、逻辑严谨,可直接用于低维优化问题,或通过调整参数(如D、max_iter)扩展至高维场景。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)