一、MOPSO核心原理
1.1 多目标优化问题形式
对于一个多目标优化问题,我们有:
minF(x)=[f1(x),f2(x),...,fm(x)]\min \mathbf{F}(\mathbf{x}) = [f_1(\mathbf{x}), f_2(\mathbf{x}), ..., f_m(\mathbf{x})]minF(x)=[f1(x),f2(x),...,fm(x)]
其中,m 是目标函数的数量(本文中 m=2)
1.2 Pareto最优概念
| 概念 | 定义 | 在多目标PSO中的意义 |
|---|---|---|
| 支配关系 | 解A支配解B ⇔ ∀i: f_i(A) ≤ f_i(B) 且 ∃j: f_j(A) < f_j(B) | 粒子比较的依据 |
| Pareto最优 | 不被任何其他解支配的解 | 优化目标:找到Pareto最优解集 |
| Pareto前沿 | 所有Pareto最优解在目标空间的映射 | 算法输出:近似Pareto前沿 |
二、双目标MOPSO完整MATLAB实现
2.1 主程序(mopso_main.m)
matlab
%% 双目标粒子群优化算法(MOPSO)
clc; clear; close all;
addpath(genpath('.'));
%% 1. 算法参数设置
params.nVar = 10; % 决策变量维度
params.var_min = -5; % 变量下界
params.var_max = 5; % 变量上界
params.nPop = 100; % 种群大小
params.nRep = 50; % 存档(精英)集大小
params.maxIt = 100; % 最大迭代次数
params.w = 0.7; % 惯性权重
params.wdamp = 0.99; % 惯性权重衰减系数
params.c1 = 2.0; % 个体学习系数
params.c2 = 2.0; % 群体学习系数
params.nGrid = 7; % 网格数(用于档案维护)
params.alpha = 0.1; % 网格膨胀系数
params.beta = 2; % 选择压力系数
params.gamma = 2; % 删除压力系数
params.mu = 0.1; % 变异概率
%% 2. 测试问题(ZDT系列)
problem = 'ZDT1'; % 可选: ZDT1, ZDT2, ZDT3, ZDT4, ZDT6
switch problem
case 'ZDT1'
params.obj_func = @(x) zdt1(x);
case 'ZDT2'
params.obj_func = @(x) zdt2(x);
case 'ZDT3'
params.obj_func = @(x) zdt3(x);
case 'ZDT4'
params.obj_func = @(x) zdt4(x);
case 'ZDT6'
params.obj_func = @(x) zdt6(x);
end
%% 3. 初始化
fprintf('MOPSO 开始执行...\n');
fprintf('问题: %s, 维度: %d, 种群: %d, 迭代: %d\n', ...
problem, params.nVar, params.nPop, params.maxIt);
% 初始化粒子群
empty_particle.position = [];
empty_particle.velocity = [];
empty_particle.cost = [];
empty_particle.best.position = [];
empty_particle.best.cost = [];
empty_particle.isDominated = [];
empty_particle.gridIndex = [];
empty_particle.gridSubIndex = [];
particle = repmat(empty_particle, params.nPop, 1);
% 初始化全局存档
rep = repmat(empty_particle, 0, 1);
% 初始化网格
grid = CreateGrid(rep, params.nGrid, params.alpha);
%% 4. 主循环
best_costs = zeros(params.maxIt, 2);
convergence = zeros(params.maxIt, 1);
for it = 1:params.maxIt
% 4.1 评估粒子
for i = 1:params.nPop
% 初始化粒子
if isempty(particle(i).position)
particle(i).position = unifrnd(params.var_min, params.var_max, 1, params.nVar);
particle(i).velocity = zeros(1, params.nVar);
end
% 计算适应度
particle(i).cost = params.obj_func(particle(i).position);
% 初始化个体最优
if isempty(particle(i).best.position) || ...
dominates(particle(i).cost, particle(i).best.cost)
particle(i).best.position = particle(i).position;
particle(i).best.cost = particle(i).cost;
end
end
% 4.2 更新存档
rep = DetermineDomination(particle);
rep = [rep; particle([particle.isDominated] == false)];
rep = DetermineDomination(rep);
rep = rep([rep.isDominated] == false);
% 4.3 网格维护
if ~isempty(rep)
grid = CreateGrid(rep, params.nGrid, params.alpha);
% 网格拥挤度
grid = UpdateGrid(grid, rep, params.nGrid, params.alpha);
% 截断存档(保持多样性)
if length(rep) > params.nRep
rep = TruncateRep(rep, grid, params.nRep, params.gamma);
end
end
% 4.4 为每个粒子选择领导者
for i = 1:params.nPop
% 从存档中选择领导者
leader = SelectLeader(rep, params.beta);
% 4.5 更新速度和位置
% 速度更新
particle(i).velocity = params.w * particle(i).velocity + ...
params.c1 * rand(1, params.nVar) .* (particle(i).best.position - particle(i).position) + ...
params.c2 * rand(1, params.nVar) .* (leader.position - particle(i).position);
% 位置更新
particle(i).position = particle(i).position + particle(i).velocity;
% 边界处理
particle(i).position = max(particle(i).position, params.var_min);
particle(i).position = min(particle(i).position, params.var_max);
% 4.6 变异操作(防止早熟)
if rand < params.mu
particle(i).position = particle(i).position + 0.1*randn(1, params.nVar);
particle(i).position = max(particle(i).position, params.var_min);
particle(i).position = min(particle(i).position, params.var_max);
end
end
% 4.7 记录性能
if ~isempty(rep)
best_costs(it, :) = mean([rep.cost], 2)';
convergence(it) = Hypervolume(rep, [2, 2]); % 参考点设为[2,2]
end
% 4.8 更新惯性权重
params.w = params.w * params.wdamp;
% 4.9 显示进度
if mod(it, 10) == 0 || it == 1 || it == params.maxIt
fprintf('迭代 %d/%d: 存档大小=%d, 超体积=%.4f\n', ...
it, params.maxIt, length(rep), convergence(it));
end
end
%% 5. 结果可视化
PlotResults(rep, convergence, best_costs, problem, params);
2.2 双目标测试函数(zdt_functions.m)
matlab
function cost = zdt1(x)
% ZDT1测试函数
% 决策变量维度: n >= 2
% 帕累托前沿: f2 = 1 - sqrt(f1)
% 第一个目标
f1 = x(1);
% 计算g(x)
g = 1 + 9/(size(x,2)-1) * sum(x(2:end));
% 第二个目标
f2 = g * (1 - sqrt(f1/g));
cost = [f1, f2];
end
function cost = zdt2(x)
% ZDT2测试函数
% 帕累托前沿: f2 = 1 - f1^2
f1 = x(1);
g = 1 + 9/(size(x,2)-1) * sum(x(2:end));
f2 = g * (1 - (f1/g)^2);
cost = [f1, f2];
end
function cost = zdt3(x)
% ZDT3测试函数
% 帕累托前沿: 不连续的凸曲线
f1 = x(1);
g = 1 + 9/(size(x,2)-1) * sum(x(2:end));
f2 = g * (1 - sqrt(f1/g) - (f1/g)*sin(10*pi*f1));
cost = [f1, f2];
end
function cost = zdt4(x)
% ZDT4测试函数
% 包含多个局部帕累托前沿
f1 = x(1);
g = 1 + 10*(size(x,2)-1) + sum(x(2:end).^2 - 10*cos(4*pi*x(2:end)));
f2 = g * (1 - sqrt(f1/g));
cost = [f1, f2];
end
function cost = zdt6(x)
% ZDT6测试函数
% 非均匀帕累托前沿
f1 = 1 - exp(-4*x(1)) * sin(6*pi*x(1))^6;
g = 1 + 9 * (sum(x(2:end))/(size(x,2)-1))^0.25;
f2 = g * (1 - (f1/g)^2);
cost = [f1, f2];
end
2.3 支配关系判断(dominance.m)
matlab
function pop = DetermineDomination(pop)
% 判断粒子间的支配关系
% 输入: pop - 粒子群数组
% 输出: pop - 更新了isDominated属性的粒子群
nPop = length(pop);
for i = 1:nPop
pop(i).isDominated = false;
end
for i = 1:nPop
for j = i+1:nPop
if dominates(pop(i).cost, pop(j).cost)
pop(j).isDominated = true;
elseif dominates(pop(j).cost, pop(i).cost)
pop(i).isDominated = true;
end
end
end
end
function d = dominates(x, y)
% 判断x是否支配y
% 支配关系: x支配y ⇔ ∀i: x_i ≤ y_i 且 ∃j: x_j < y_j
d = all(x <= y) && any(x < y);
end
2.4 自适应网格系统(grid.m)
matlab
function grid = CreateGrid(pop, nGrid, alpha)
% 创建自适应网格
% 输入: pop - 粒子群
% nGrid - 网格数
% alpha - 膨胀系数
% 输出: grid - 网格结构体
% 提取目标值
costs = [pop.cost]';
nObj = size(costs, 2);
% 初始化网格边界
grid.min = min(costs, [], 1);
grid.max = max(costs, [], 1);
% 网格膨胀
delta = alpha * (grid.max - grid.min);
grid.min = grid.min - delta;
grid.max = grid.max + delta;
% 计算网格步长
grid.width = (grid.max - grid.min) / nGrid;
% 初始化网格索引
for i = 1:length(pop)
grid_index = floor((pop(i).cost - grid.min) ./ grid.width) + 1;
grid_index = min(grid_index, nGrid);
grid_index = max(grid_index, 1);
pop(i).gridIndex = grid_index;
pop(i).gridSubIndex = sub2ind([nGrid, nGrid], grid_index(1), grid_index(2));
end
grid.pop = pop;
grid.nGrid = nGrid;
end
function grid = UpdateGrid(grid, pop, nGrid, alpha)
% 更新网格
% 输入: grid - 当前网格
% pop - 粒子群
% nGrid - 网格数
% alpha - 膨胀系数
% 输出: grid - 更新后的网格
% 重新计算网格边界
costs = [pop.cost]';
% 更新最小最大值
grid.min = min([grid.min; costs], [], 1);
grid.max = max([grid.max; costs], [], 1);
% 网格膨胀
delta = alpha * (grid.max - grid.min);
grid.min = grid.min - delta;
grid.max = grid.max + delta;
% 更新网格步长
grid.width = (grid.max - grid.min) / nGrid;
% 更新网格索引
for i = 1:length(pop)
grid_index = floor((pop(i).cost - grid.min) ./ grid.width) + 1;
grid_index = min(grid_index, nGrid);
grid_index = max(grid_index, 1);
pop(i).gridIndex = grid_index;
pop(i).gridSubIndex = sub2ind([nGrid, nGrid], grid_index(1), grid_index(2));
end
grid.pop = pop;
end
2.5 领导者选择和存档截断(selection.m)
matlab
function leader = SelectLeader(rep, beta)
% 从存档中选择领导者
% 使用轮盘赌选择,基于网格拥挤度
% 计算每个网格的粒子数
grid_indices = [rep.gridSubIndex];
unique_indices = unique(grid_indices);
n_grids = length(unique_indices);
% 计算每个网格的拥挤度
grid_counts = zeros(1, n_grids);
for i = 1:n_grids
grid_counts(i) = sum(grid_indices == unique_indices(i));
end
% 计算选择概率(拥挤网格概率低)
p = 1 ./ (grid_counts .^ beta);
p = p / sum(p);
% 轮盘赌选择网格
selected_grid = unique_indices(RouletteWheelSelection(p));
% 从选中网格中随机选择一个粒子
candidates = find(grid_indices == selected_grid);
selected_index = candidates(randi(length(candidates)));
leader = rep(selected_index);
end
function rep = TruncateRep(rep, grid, nRep, gamma)
% 截断存档,保持多样性
% 输入: rep - 当前存档
% grid - 网格结构
% nRep - 目标存档大小
% gamma - 删除压力系数
% 输出: rep - 截断后的存档
while length(rep) > nRep
% 计算每个网格的粒子数
grid_indices = [rep.gridSubIndex];
unique_indices = unique(grid_indices);
grid_counts = zeros(1, length(unique_indices));
for i = 1:length(unique_indices)
grid_counts(i) = sum(grid_indices == unique_indices(i));
end
% 找到最拥挤的网格
[~, max_idx] = max(grid_counts);
target_grid = unique_indices(max_idx);
% 在该网格中找到要删除的粒子
candidates = find(grid_indices == target_grid);
if length(candidates) > 1
% 计算拥挤距离
costs = [rep(candidates).cost]';
distances = pdist2(costs, costs, 'euclidean');
% 找到与其他粒子平均距离最小的粒子
avg_distances = mean(distances, 2);
[~, min_idx] = min(avg_distances);
% 删除该粒子
delete_idx = candidates(min_idx);
else
delete_idx = candidates(1);
end
rep(delete_idx) = [];
end
end
function i = RouletteWheelSelection(p)
% 轮盘赌选择
r = rand;
c = cumsum(p);
i = find(r <= c, 1, 'first');
end
2.6 性能指标计算(metrics.m)
matlab
function hv = Hypervolume(pop, ref_point)
% 计算超体积指标
% 输入: pop - 粒子群
% ref_point - 参考点
% 输出: hv - 超体积值
% 提取非支配解
non_dominated = pop([pop.isDominated] == false);
if isempty(non_dominated)
hv = 0;
return;
end
costs = [non_dominated.cost]';
% 对目标值排序
costs = sortrows(costs, 1);
% 计算超体积
hv = 0;
for i = 1:size(costs, 1)
if i == 1
width = ref_point(1) - costs(i, 1);
else
width = costs(i, 1) - costs(i-1, 1);
end
height = ref_point(2) - costs(i, 2);
hv = hv + width * height;
end
end
function gd = GenerationalDistance(pop, true_front)
% 计算代距
% 输入: pop - 粒子群
% true_front - 真实帕累托前沿
% 输出: gd - 代距值
non_dominated = pop([pop.isDominated] == false);
if isempty(non_dominated)
gd = inf;
return;
end
costs = [non_dominated.cost]';
% 计算每个解到真实前沿的最小距离
n = size(costs, 1);
min_distances = zeros(n, 1);
for i = 1:n
distances = pdist2(costs(i, :), true_front, 'euclidean');
min_distances(i) = min(distances);
end
gd = sqrt(sum(min_distances.^2)) / n;
end
2.7 结果可视化(visualization.m)
matlab
function PlotResults(rep, convergence, best_costs, problem, params)
% 可视化结果
% 输入: rep - 最终存档
% convergence - 收敛曲线
% best_costs - 历史最优目标值
% problem - 问题名称
% params - 参数结构体
% 提取非支配解
non_dominated = rep([rep.isDominated] == false);
if isempty(non_dominated)
fprintf('没有找到非支配解!\n');
return;
end
costs = [non_dominated.cost]';
positions = {non_dominated.position};
% 创建图形窗口
figure('Position', [100, 100, 1400, 500]);
% 子图1: 帕累托前沿
subplot(1,3,1);
hold on; grid on; box on;
% 绘制帕累托前沿
scatter(costs(:,1), costs(:,2), 50, 'b', 'filled', 'DisplayName', 'MOPSO解');
xlabel('目标1: f_1(x)');
ylabel('目标2: f_2(x)');
title(sprintf('%s 帕累托前沿 (存档大小: %d)', problem, size(costs,1)));
% 绘制真实前沿(如果可用)
switch problem
case 'ZDT1'
f1 = linspace(0, 1, 100)';
f2 = 1 - sqrt(f1);
plot(f1, f2, 'r--', 'LineWidth', 2, 'DisplayName', '真实前沿');
case 'ZDT2'
f1 = linspace(0, 1, 100)';
f2 = 1 - f1.^2;
plot(f1, f2, 'r--', 'LineWidth', 2, 'DisplayName', '真实前沿');
case 'ZDT3'
f1 = linspace(0, 1, 100)';
f2 = 1 - sqrt(f1) - f1.*sin(10*pi*f1);
plot(f1, f2, 'r--', 'LineWidth', 2, 'DisplayName', '真实前沿');
case 'ZDT4'
f1 = linspace(0, 1, 100)';
f2 = 1 - sqrt(f1);
plot(f1, f2, 'r--', 'LineWidth', 2, 'DisplayName', '真实前沿');
case 'ZDT6'
f1 = linspace(0, 1, 100)';
f2 = 1 - f1.^2;
plot(f1, f2, 'r--', 'LineWidth', 2, 'DisplayName', '真实前沿');
end
legend('Location', 'best');
% 子图2: 收敛曲线
subplot(1,3,2);
hold on; grid on; box on;
plot(convergence, 'b-', 'LineWidth', 2);
xlabel('迭代次数');
ylabel('超体积(HV)');
title('算法收敛曲线');
% 绘制平均目标值
subplot(1,3,3);
hold on; grid on; box on;
plot(best_costs(:,1), 'b-', 'LineWidth', 2, 'DisplayName', '目标1');
plot(best_costs(:,2), 'r-', 'LineWidth', 2, 'DisplayName', '目标2');
xlabel('迭代次数');
ylabel('目标函数值');
title('平均目标值变化');
legend('Location', 'best');
% 显示统计信息
fprintf('\n=== 最终结果 ===\n');
fprintf('非支配解数量: %d\n', size(costs,1));
fprintf('目标1范围: [%.4f, %.4f]\n', min(costs(:,1)), max(costs(:,1)));
fprintf('目标2范围: [%.4f, %.4f]\n', min(costs(:,2)), max(costs(:,2)));
fprintf('最终超体积: %.4f\n', convergence(end));
% 显示部分解
fprintf('\n=== 帕累托最优解示例 ===\n');
fprintf('%-6s %-12s %-12s\n', '序号', '目标1', '目标2');
fprintf('%s\n', repmat('-', 30, 1));
for i = 1:min(5, size(costs,1))
fprintf('%-6d %-12.4f %-12.4f\n', i, costs(i,1), costs(i,2));
end
end
三、实际工程应用示例
3.1 机械设计优化(减速器设计)
matlab
function cost = reducer_design(x)
% 减速器设计双目标优化
% 目标1: 最小化重量
% 目标2: 最小化成本
% 决策变量: [齿宽, 模数, 齿数, 轴径, 材料强度]
% 约束条件
g1 = x(1) - 20; % 齿宽最小
g2 = 5 - x(2); % 模数限制
g3 = x(3) - 100; % 齿数限制
g4 = 10 - x(4); % 轴径限制
% 惩罚函数
penalty = 0;
if g1 > 0, penalty = penalty + 100*abs(g1); end
if g2 > 0, penalty = penalty + 100*abs(g2); end
if g3 > 0, penalty = penalty + 100*abs(g3); end
if g4 > 0, penalty = penalty + 100*abs(g4); end
% 目标1: 重量 (kg)
weight = 0.5*x(1)*x(2)*x(3) + 0.1*x(4)^2;
% 目标2: 成本 (元)
cost_material = 50*x(5) + 20; % 材料成本
cost_manufacturing = 10*x(1) + 5*x(2)*x(3) + 2*x(4);
total_cost = cost_material + cost_manufacturing;
% 加惩罚项
weight = weight + penalty;
total_cost = total_cost + penalty;
cost = [weight, total_cost];
end
3.2 电力系统调度优化
matlab
function cost = power_system_scheduling(x)
% 电力系统经济-环境调度
% 目标1: 最小化发电成本
% 目标2: 最小化污染物排放
% 决策变量: 各机组出力
n_units = 6; % 6台发电机组
if length(x) ~= n_units
error('决策变量维度必须为6');
end
% 发电成本系数 (a, b, c)
cost_coeff = [
0.15240, 38.53973, 756.79886;
0.10587, 46.15916, 451.32513;
0.02803, 40.39655, 1049.9977;
0.03546, 38.30553, 1243.5311;
0.02111, 36.32782, 1658.5596;
0.01799, 38.27041, 1356.6592
];
% 排放系数 (α, β, γ, η, δ)
emission_coeff = [
0.00419, 0.32767, 13.85932, 0.000203, 2.0;
0.00419, 0.32767, 13.85932, 0.000203, 2.0;
0.00683, -0.54551, 40.26690, 0.000338, 2.0;
0.00683, -0.54551, 40.26690, 0.000338, 2.0;
0.00461, -0.51116, 42.89553, 0.000307, 2.0;
0.00461, -0.51116, 42.89553, 0.000307, 2.0
];
% 计算总发电成本
total_cost = 0;
for i = 1:n_units
a = cost_coeff(i,1);
b = cost_coeff(i,2);
c = cost_coeff(i,3);
total_cost = total_cost + a*x(i)^2 + b*x(i) + c;
end
% 计算总排放量
total_emission = 0;
for i = 1:n_units
alpha = emission_coeff(i,1);
beta = emission_coeff(i,2);
gamma = emission_coeff(i,3);
eta = emission_coeff(i,4);
delta = emission_coeff(i,5);
total_emission = total_emission + alpha*x(i)^2 + beta*x(i) + gamma + ...
eta*exp(delta*x(i));
end
% 功率平衡约束
total_demand = 2.834; % 总需求 (MW)
power_balance = abs(sum(x) - total_demand);
% 惩罚项
penalty = 1000 * power_balance^2;
cost = [total_cost + penalty, total_emission + penalty/1000];
end
参考代码 两个适应度函数的多目标粒子群优化算法 www.youwenfan.com/contentcsu/53496.html
四、算法比较与分析
4.1 MOPSO vs NSGA-II
| 指标 | MOPSO | NSGA-II |
|---|---|---|
| 计算复杂度 | O(n^2) | O(mn^2) |
| 多样性保持 | 网格机制 | 拥挤距离 |
| 收敛速度 | 快 | 中等 |
| 参数敏感度 | 较高 | 较低 |
| 实现难度 | 中等 | 中等 |
4.2 参数调优指南
| 参数 | 推荐范围 | 影响 | 调优建议 |
|---|---|---|---|
| 种群大小 nPop | 50-200 | 探索能力 | 问题复杂则增大 |
| 惯性权重 w | 0.4-0.9 | 全局搜索 | 初始大,逐渐减小 |
| 学习因子 c1, c2 | 1.5-2.5 | 收敛速度 | 相等值为佳 |
| 存档大小 nRep | 50-100 | 解集质量 | 越大越精确,但计算量大 |
| 网格数 nGrid | 5-10 | 多样性 | 问题维度高则增大 |
| 变异概率 mu | 0.01-0.1 | 跳出局部最优 | 问题多模态则增大 |
五、高级改进算法
5.1 自适应MOPSO
matlab
function [w, c1, c2] = adaptive_parameters(it, maxIt, fitness_diversity)
% 自适应参数调整
% 输入: it - 当前迭代次数
% maxIt - 最大迭代次数
% fitness_diversity - 适应度多样性
% 输出: w, c1, c2 - 自适应参数
% 惯性权重自适应
w_max = 0.9; w_min = 0.4;
w = w_max - (w_max - w_min) * (it/maxIt);
% 学习因子自适应
if fitness_diversity > 0.5
% 种群分散,加强探索
c1 = 2.5;
c2 = 1.5;
else
% 种群集中,加强开发
c1 = 1.5;
c2 = 2.5;
end
end
5.2 约束处理机制
matlab
function pop = handle_constraints(pop, var_min, var_max)
% 约束处理机制
% 输入: pop - 粒子群
% var_min, var_max - 变量边界
% 输出: pop - 处理后的粒子群
for i = 1:length(pop)
% 边界约束
pop(i).position = min(max(pop(i).position, var_min), var_max);
% 速度约束
v_max = 0.1 * (var_max - var_min);
pop(i).velocity = min(max(pop(i).velocity, -v_max), v_max);
% 修复不可行解
if ~is_feasible(pop(i).position)
pop(i).position = generate_feasible_solution(var_min, var_max);
end
end
end
六、总结
这套MOPSO实现具有以下特点:
完整算法 :包含支配判断、自适应网格、存档维护等核心模块
双目标优化 :适用于任何两个相互冲突的目标优化问题
性能评估 :超体积、代距等多种性能指标
可视化 :帕累托前沿、收敛曲线直观展示
工程友好:提供实际工程应用示例
应用场景:
- 工程多目标优化设计
- 经济-环境综合调度
- 资源分配与调度
- 投资组合优化
- 机器学习超参数调优
改进方向:
- 引入三目标优化扩展
- 结合深度学习预测领导者
- 并行计算加速
- 动态环境自适应
- 混合整数多目标优化