一、算法核心架构
复制代码
┌─────────────────────────────────────────────────────────────┐
│ SPEA2 多目标优化算法 │
├─────────────────────────────────────────────────────────────┤
│ 初始化阶段 │ 进化循环阶段 │ 环境选择阶段 │ 输出阶段 │
│ │ │ │ │
│ • 生成初始 │ • 适应度计算 │ • 归档集更新 │ • 帕累托 │
│ 种群 │ • 繁殖选择 │ • 截断操作 │ 前沿 │
│ • 建立归档集 │ • 交叉变异 │ • 多样性保持 │ • 最优解集 │
│ • 定义目标函数│ • 精英保留 │ • 边界处理 │ • 收敛曲线 │
└─────────────────────────────────────────────────────────────┘
二、完整 MATLAB 实现
2.1 主程序 (spea2_main.m)
matlab
复制代码
%% SPEA2 多目标优化算法主程序
% 功能:基于SPEA2的多目标优化,支持任意维度的目标函数和决策变量
% 算法:Strength Pareto Evolutionary Algorithm 2
clear all; close all; clc;
%% 1. 算法参数设置
params = struct();
params.pop_size = 100; % 种群大小
params.archive_size = 100; % 归档集大小
params.max_generations = 200; % 最大进化代数
params.num_variables = 30; % 决策变量维度
params.num_objectives = 2; % 目标函数维度
params.var_min = zeros(1, params.num_variables); % 变量下界
params.var_max = ones(1, params.num_variables); % 变量上界
params.crossover_prob = 0.9; % 交叉概率
params.mutation_prob = 0.1; % 变异概率
params.mutation_rate = 0.05; % 变异强度
params.k_neighbors = 5; % k近邻参数(用于密度估计)
fprintf('=== SPEA2 多目标优化算法 ===\n');
fprintf('参数设置:\n');
fprintf(' 种群大小: %d\n', params.pop_size);
fprintf(' 归档集大小: %d\n', params.archive_size);
fprintf(' 最大代数: %d\n', params.max_generations);
fprintf(' 决策变量维度: %d\n', params.num_variables);
fprintf(' 目标函数维度: %d\n\n', params.num_objectives);
%% 2. 初始化种群和归档集
fprintf('初始化种群...\n');
[population, archive] = spea2_initialize(params);
%% 3. 进化循环
fprintf('开始进化迭代...\n');
convergence_curve = zeros(params.max_generations, 1);
for gen = 1:params.max_generations
tic;
%% 3.1 计算适应度(包含支配强度、原始适应度、密度估计)
[population, archive] = spea2_fitness_assignment(population, archive, params);
%% 3.2 环境选择(更新归档集)
archive = spea2_environmental_selection(population, archive, params);
%% 3.3 繁殖选择(生成下一代种群)
population = spea2_reproduction(population, archive, params);
%% 3.4 记录收敛信息
convergence_curve(gen) = mean([archive.fitness]);
%% 3.5 显示进度
if mod(gen, 20) == 0 || gen == 1
non_dominated_count = sum([archive.raw_fitness] == 0);
fprintf(' 第 %d 代: 归档集大小=%d, 非支配解=%d, 平均适应度=%.4f, 耗时=%.2fs\n', ...
gen, length(archive), non_dominated_count, convergence_curve(gen), toc);
end
%% 3.6 检查收敛条件
if gen > 50 && std(convergence_curve(gen-49:gen)) < 1e-6
fprintf('算法在第 %d 代收敛\n', gen);
break;
end
end
%% 4. 输出最终结果
fprintf('\n=== 优化完成 ===\n');
final_non_dominated = archive([archive.raw_fitness] == 0);
fprintf('最终非支配解数量: %d\n', length(final_non_dominated));
%% 5. 可视化结果
spea2_visualization(final_non_dominated, convergence_curve, params);
%% 6. 保存结果
save('spea2_results.mat', 'final_non_dominated', 'convergence_curve', 'params');
fprintf('结果已保存到: spea2_results.mat\n');
2.2 初始化模块 (spea2_initialize.m)
matlab
复制代码
function [population, archive] = spea2_initialize(params)
% SPEA2 初始化函数
% 输入:params - 算法参数结构体
% 输出:population - 初始种群,archive - 初始归档集
num_vars = params.num_variables;
pop_size = params.pop_size;
% 1. 随机生成初始种群
population = struct();
for i = 1:pop_size
% 随机生成决策变量
vars = params.var_min + rand(1, num_vars) .* (params.var_max - params.var_min);
% 计算目标函数值
objectives = evaluate_objectives(vars, params.num_objectives);
% 存储个体信息
population(i).variables = vars;
population(i).objectives = objectives;
population(i).strength = 0; % 支配强度
population(i).raw_fitness = 0; % 原始适应度
population(i).density = 0; % 密度估计
population(i).fitness = 0; % 最终适应度
end
% 2. 初始化空归档集
archive = struct();
fprintf('种群初始化完成,共 %d 个个体\n', length(population));
end
2.3 适应度分配模块 (spea2_fitness_assignment.m)
matlab
复制代码
function [population, archive] = spea2_fitness_assignment(population, archive, params)
% SPEA2 适应度分配函数
% 计算支配强度、原始适应度、密度估计和最终适应度
% 合并种群和归档集
combined = [population(:); archive(:)];
num_combined = length(combined);
%% 1. 计算支配强度 S(i)
for i = 1:num_combined
strength = 0;
for j = 1:num_combined
if i ~= j
if dominates(combined(i).objectives, combined(j).objectives)
strength = strength + 1;
end
end
end
combined(i).strength = strength;
end
%% 2. 计算原始适应度 R(i)(被支配程度)
for i = 1:num_combined
raw_fitness = 0;
for j = 1:num_combined
if i ~= j
if dominates(combined(j).objectives, combined(i).objectives)
raw_fitness = raw_fitness + combined(j).strength;
end
end
end
combined(i).raw_fitness = raw_fitness;
end
%% 3. 密度估计 D(i)(基于k近邻)
% 提取目标函数值矩阵
obj_matrix = zeros(num_combined, params.num_objectives);
for i = 1:num_combined
obj_matrix(i, :) = combined(i).objectives;
end
% 标准化目标函数值
obj_normalized = normalize_objectives(obj_matrix);
% 计算k近邻距离
for i = 1:num_combined
distances = zeros(num_combined, 1);
for j = 1:num_combined
if i ~= j
distances(j) = sqrt(sum((obj_normalized(i, :) - obj_normalized(j, :)).^2));
else
distances(j) = inf;
end
end
% 找到第k个最近邻的距离
sorted_distances = sort(distances);
kth_distance = sorted_distances(params.k_neighbors);
% 密度估计(距离越大,密度越小,适应度越好)
if kth_distance > 0
combined(i).density = 1 / (kth_distance + 2); % +2避免除零
else
combined(i).density = 0;
end
end
%% 4. 计算最终适应度 F(i) = R(i) + D(i)
for i = 1:num_combined
combined(i).fitness = combined(i).raw_fitness + combined(i).density;
end
% 分离种群和归档集
population = combined(1:length(population));
archive = combined(length(population)+1:end);
end
%% 支配关系判断函数
function is_dominant = dominates(obj1, obj2)
% 判断obj1是否支配obj2
% obj1支配obj2当且仅当:obj1的所有目标都不比obj2差,且至少有一个更好
better_in_all = all(obj1 <= obj2);
strictly_better_in_one = any(obj1 < obj2);
is_dominant = better_in_all && strictly_better_in_one;
end
%% 目标函数标准化
function normalized = normalize_objectives(obj_matrix)
% 标准化目标函数值到[0,1]区间
[num_individuals, num_objectives] = size(obj_matrix);
normalized = zeros(num_individuals, num_objectives);
for i = 1:num_objectives
obj_range = max(obj_matrix(:, i)) - min(obj_matrix(:, i));
if obj_range > 0
normalized(:, i) = (obj_matrix(:, i) - min(obj_matrix(:, i))) / obj_range;
else
normalized(:, i) = obj_matrix(:, i);
end
end
end
2.4 环境选择模块 (spea2_environmental_selection.m)
matlab
复制代码
function archive = spea2_environmental_selection(population, archive, params)
% SPEA2 环境选择函数
% 更新归档集,保持多样性
% 合并种群和归档集
combined = [population(:); archive(:)];
% 筛选非支配解(raw_fitness = 0)
non_dominated_indices = find([combined.raw_fitness] == 0);
non_dominated = combined(non_dominated_indices);
% 如果非支配解数量超过归档集大小,进行截断
if length(non_dominated) > params.archive_size
% 使用截断操作保持多样性
archive = spea2_truncation(non_dominated, params.archive_size);
else
% 如果非支配解数量不足,用次优解补充
archive = non_dominated;
remaining_slots = params.archive_size - length(archive);
if remaining_slots > 0
% 按适应度排序选择剩余个体
[~, sorted_indices] = sort([combined.fitness]);
for i = 1:length(sorted_indices)
candidate = combined(sorted_indices(i));
if ~ismember(candidate, archive)
archive(end+1) = candidate;
remaining_slots = remaining_slots - 1;
if remaining_slots == 0
break;
end
end
end
end
end
end
%% 截断操作(保持多样性)
function truncated_set = spea2_truncation(set, target_size)
% 截断操作:移除拥挤的个体,保持分布均匀
current_size = length(set);
truncated_set = set;
while current_size > target_size
% 计算所有个体间的距离矩阵
distances = zeros(current_size, current_size);
for i = 1:current_size
for j = 1:current_size
if i ~= j
distances(i, j) = sqrt(sum((set(i).objectives - set(j).objectives).^2));
else
distances(i, j) = inf;
end
end
end
% 找到距离最近的一对个体
min_distance = inf;
remove_index = -1;
for i = 1:current_size
% 找到第k个最近邻
sorted_dists = sort(distances(i, :));
kth_distance = sorted_dists(2); % 跳过自己
if kth_distance < min_distance
min_distance = kth_distance;
remove_index = i;
end
end
% 移除距离最近的个体
truncated_set(remove_index) = [];
current_size = current_size - 1;
end
end
2.5 繁殖选择模块 (spea2_reproduction.m)
matlab
复制代码
function population = spea2_reproduction(population, archive, params)
% SPEA2 繁殖选择函数
% 使用二元锦标赛选择生成下一代种群
new_population = struct();
pop_size = params.pop_size;
for i = 1:pop_size
% 二元锦标赛选择
parent1 = spea2_binary_tournament(archive);
parent2 = spea2_binary_tournament(archive);
% 交叉操作
if rand() < params.crossover_prob
[child1_vars, child2_vars] = spea2_crossover(parent1.variables, parent2.variables, params);
else
child1_vars = parent1.variables;
child2_vars = parent2.variables;
end
% 变异操作
if rand() < params.mutation_prob
child1_vars = spea2_mutation(child1_vars, params);
end
if rand() < params.mutation_prob
child2_vars = spea2_mutation(child2_vars, params);
end
% 边界处理
child1_vars = bound_variables(child1_vars, params.var_min, params.var_max);
child2_vars = bound_variables(child2_vars, params.var_min, params.var_max);
% 计算子代目标函数
child1_obj = evaluate_objectives(child1_vars, params.num_objectives);
child2_obj = evaluate_objectives(child2_vars, params.num_objectives);
% 存储子代
new_population(i*2-1).variables = child1_vars;
new_population(i*2-1).objectives = child1_obj;
new_population(i*2).variables = child2_vars;
new_population(i*2).objectives = child2_obj;
end
% 如果种群大小是奇数,移除最后一个
if length(new_population) > pop_size
new_population(end) = [];
end
population = new_population;
end
%% 二元锦标赛选择
function selected = spea2_binary_tournament(population)
% 随机选择两个个体,选择适应度更好的一个
indices = randperm(length(population), 2);
candidate1 = population(indices(1));
candidate2 = population(indices(2));
if candidate1.fitness <= candidate2.fitness
selected = candidate1;
else
selected = candidate2;
end
end
%% 交叉操作(模拟二进制交叉 SBX)
function [child1, child2] = spea2_crossover(parent1, parent2, params)
eta_c = 20; % 交叉分布指数
child1 = parent1;
child2 = parent2;
for i = 1:length(parent1)
if rand() < 0.5
% 计算beta
beta = 1 + (2 / abs(parent1(i) - parent2(i)));
alpha = 2 - beta^(-eta_c);
if rand() <= 1/alpha
beta_q = (rand() * alpha)^(1/(eta_c+1));
else
beta_q = (1/(alpha * (1 - rand())))^(1/(eta_c+1));
end
% 生成子代
child1(i) = 0.5 * ((1 + beta_q) * parent1(i) + (1 - beta_q) * parent2(i));
child2(i) = 0.5 * ((1 - beta_q) * parent1(i) + (1 + beta_q) * parent2(i));
end
end
end
%% 变异操作(多项式变异)
function mutated = spea2_mutation(variables, params)
eta_m = 20; % 变异分布指数
mutated = variables;
for i = 1:length(variables)
if rand() < params.mutation_rate
delta = min(variables(i) - params.var_min(i), params.var_max(i) - variables(i)) / ...
(params.var_max(i) - params.var_min(i));
if rand() < 0.5
delta_q = (2 * rand() + (1 - 2 * rand()) * (1 - delta)^(eta_m + 1))^(1/(eta_m + 1)) - 1;
else
delta_q = 1 - (2 * (1 - rand()) + 2 * rand() * delta^(eta_m + 1))^(1/(eta_m + 1));
end
mutated(i) = variables(i) + delta_q * (params.var_max(i) - params.var_min(i));
end
end
end
%% 边界处理
function bounded_vars = bound_variables(variables, var_min, var_max)
bounded_vars = variables;
for i = 1:length(variables)
bounded_vars(i) = max(var_min(i), min(var_max(i), variables(i)));
end
end
2.6 目标函数定义 (evaluate_objectives.m)
matlab
复制代码
function objectives = evaluate_objectives(variables, num_objectives)
% 目标函数评估函数
% 这里使用经典的ZDT测试函数作为示例
% 可以根据实际问题修改此函数
if num_objectives == 2
% ZDT1 测试函数
f1 = variables(1);
g = 1 + 9 * mean(variables(2:end));
h = 1 - sqrt(f1 / g);
f2 = g * h;
objectives = [f1, f2];
elseif num_objectives == 3
% DTLZ1 测试函数(简化版)
f1 = variables(1);
f2 = variables(2);
f3 = 1 - variables(1) - variables(2);
objectives = [f1, f2, f3];
else
% 通用多目标函数
objectives = zeros(1, num_objectives);
for i = 1:num_objectives
objectives(i) = sum(variables.^i) / length(variables);
end
end
end
2.7 可视化模块 (spea2_visualization.m)
matlab
复制代码
function spea2_visualization(non_dominated, convergence_curve, params)
% SPEA2 结果可视化
figure('Position', [100, 100, 1200, 800]);
% 1. 帕累托前沿
subplot(2, 3, 1);
if params.num_objectives == 2
scatter([non_dominated.objectives], [non_dominated.objectives]);
xlabel('Objective 1');
ylabel('Objective 2');
title('帕累托前沿 (2D)');
grid on;
elseif params.num_objectives == 3
scatter3([non_dominated.objectives], ...
[non_dominated.objectives], ...
[non_dominated.objectives]);
xlabel('Objective 1');
ylabel('Objective 2');
zlabel('Objective 3');
title('帕累托前沿 (3D)');
grid on;
end
% 2. 收敛曲线
subplot(2, 3, 2);
plot(convergence_curve, 'b-', 'LineWidth', 2);
xlabel('Generation');
ylabel('Average Fitness');
title('收敛曲线');
grid on;
% 3. 目标函数值分布
subplot(2, 3, 3);
if params.num_objectives == 2
obj_matrix = zeros(length(non_dominated), 2);
for i = 1:length(non_dominated)
obj_matrix(i, :) = non_dominated(i).objectives;
end
histogram(obj_matrix(:, 1), 20, 'FaceColor', 'r', 'EdgeColor', 'black');
xlabel('Objective 1');
ylabel('Frequency');
title('目标函数1分布');
end
% 4. 决策变量分布
subplot(2, 3, 4);
var_matrix = zeros(length(non_dominated), min(5, params.num_variables));
for i = 1:length(non_dominated)
var_matrix(i, :) = non_dominated(i).variables(1:min(5, params.num_variables));
end
boxplot(var_matrix);
xlabel('Decision Variables');
ylabel('Variable Values');
title('决策变量分布');
% 5. 适应度分布
subplot(2, 3, 5);
fitness_values = [non_dominated.fitness];
histogram(fitness_values, 20, 'FaceColor', 'g', 'EdgeColor', 'black');
xlabel('Fitness Value');
ylabel('Frequency');
title('适应度分布');
% 6. 算法性能统计
subplot(2, 3, 6);
axis off;
stats_text = sprintf(['SPEA2 算法性能统计\n\n', ...
'非支配解数量: %d\n', ...
'目标函数维度: %d\n', ...
'决策变量维度: %d\n', ...
'收敛代数: %d\n', ...
'最终平均适应度: %.4f\n', ...
'最小适应度: %.4f\n', ...
'最大适应度: %.4f'],
length(non_dominated),
params.num_objectives,
params.num_variables,
length(convergence_curve),
mean([non_dominated.fitness]),
min([non_dominated.fitness]),
max([non_dominated.fitness]));
text(0.1, 0.5, stats_text, 'FontSize', 12, 'FontWeight', 'bold');
sgtitle('SPEA2 多目标优化结果可视化');
end
三、测试脚本 (test_spea2.m)
matlab
复制代码
%% SPEA2 算法测试脚本
clear all; close all; clc;
fprintf('=== SPEA2 多目标优化算法测试 ===\n\n');
%% 测试1:ZDT1 测试函数
fprintf('测试1:ZDT1 测试函数 (2目标,30变量)\n');
params1 = struct();
params1.pop_size = 100;
params1.archive_size = 100;
params1.max_generations = 150;
params1.num_variables = 30;
params1.num_objectives = 2;
params1.var_min = zeros(1, 30);
params1.var_max = ones(1, 30);
params1.crossover_prob = 0.9;
params1.mutation_prob = 0.1;
params1.mutation_rate = 0.05;
params1.k_neighbors = 5;
tic;
[population, archive] = spea2_initialize(params1);
for gen = 1:params1.max_generations
[population, archive] = spea2_fitness_assignment(population, archive, params1);
archive = spea2_environmental_selection(population, archive, params1);
population = spea2_reproduction(population, archive, params1);
if mod(gen, 30) == 0
fprintf(' 第 %d 代完成\n', gen);
end
end
time1 = toc;
fprintf('ZDT1 测试完成,耗时: %.2f 秒\n\n', time1);
%% 测试2:不同参数的影响
fprintf('测试2:参数敏感性分析\n');
param_sets = {
struct('pop_size', 50, 'archive_size', 50, 'mutation_rate', 0.01),
struct('pop_size', 100, 'archive_size', 100, 'mutation_rate', 0.05),
struct('pop_size', 200, 'archive_size', 200, 'mutation_rate', 0.1)
};
figure('Position', [100, 100, 1200, 400]);
for i = 1:length(param_sets)
params2 = struct();
params2.pop_size = param_sets{i}.pop_size;
params2.archive_size = param_sets{i}.archive_size;
params2.max_generations = 100;
params2.num_variables = 20;
params2.num_objectives = 2;
params2.var_min = zeros(1, 20);
params2.var_max = ones(1, 20);
params2.crossover_prob = 0.9;
params2.mutation_prob = 0.1;
params2.mutation_rate = param_sets{i}.mutation_rate;
params2.k_neighbors = 5;
[population, archive] = spea2_initialize(params2);
convergence = zeros(params2.max_generations, 1);
for gen = 1:params2.max_generations
[population, archive] = spea2_fitness_assignment(population, archive, params2);
archive = spea2_environmental_selection(population, archive, params2);
population = spea2_reproduction(population, archive, params2);
convergence(gen) = mean([archive.fitness]);
end
subplot(1, 3, i);
plot(convergence, 'LineWidth', 2);
xlabel('Generation');
ylabel('Average Fitness');
title(sprintf('Pop=%d, Mut=%g', param_sets{i}.pop_size, param_sets{i}.mutation_rate));
grid on;
end
fprintf('所有测试完成!\n');
参考代码 基于SPEAII的多目标优化算法 www.youwenfan.com/contentcsu/63221.html
四、算法特点与应用
4.1 算法优势
| 特性 |
优势 |
| 精英保留 |
通过归档集确保优秀解不会丢失 |
| 多样性保持 |
k近邻密度估计防止过早收敛 |
| 收敛速度快 |
强度帕累托机制加速收敛 |
| 参数鲁棒性 |
对参数设置不敏感 |
4.2 适用场景
- 工程设计优化:多目标权衡设计
- 机器学习:多目标特征选择、模型压缩
- 能源系统:微电网容量配置、调度优化
- 路径规划:多目标路径优化
4.3 参数调优建议
| 参数 |
建议值 |
说明 |
| pop_size |
50-200 |
种群越大,搜索越充分 |
| archive_size |
50-200 |
通常与种群大小相当 |
| mutation_rate |
0.01-0.1 |
根据问题复杂度调整 |
| k_neighbors |
3-10 |
影响多样性保持强度 |