NSGA-II自定义优化函数MATLAB实现
一、NSGA-II算法核心原理
1.1 算法特点
-
非支配排序:将种群分层,优先选择非支配解
-
拥挤度计算:保持种群多样性
-
精英保留:结合父代和子代选择最优解
-
多目标优化:同时优化多个相互冲突的目标
1.2 算法流程
graph TD
A[初始化种群] --> B[评估目标函数]
B --> C[非支配排序]
C --> D[计算拥挤度]
D --> E[选择操作]
E --> F[交叉操作]
F --> G[变异操作]
G --> H[合并种群]
H --> I[环境选择]
I -->|满足终止条件| J[输出Pareto前沿]
I -->|否则| B
二、NSGA-II自定义优化函数实现
2.1 主函数代码
function [pop, F, front, crowding] = nsga2_custom(fun, nVar, varMin, varMax, nPop, maxGen, params)
% NSGA-II多目标优化算法
% 输入:
% fun: 目标函数句柄 (返回行向量)
% nVar: 变量个数
% varMin: 变量最小值 (标量或向量)
% varMax: 变量最大值 (标量或向量)
% nPop: 种群大小
% maxGen: 最大迭代次数
% params: 算法参数字典
% 输出:
% pop: 最终种群 (nPop×nVar)
% F: 目标函数值 (nPop×nObj)
% front: 非支配前沿 (nPop×1)
% crowding: 拥挤度 (nPop×1)
% 默认参数设置
if nargin < 7
params = struct();
end
if ~isfield(params, 'pc'), params.pc = 0.9; end % 交叉概率
if ~isfield(params, 'pm'), params.pm = 1/nVar; end % 变异概率
if ~isfield(params, 'eta_c'), params.eta_c = 15; end % 交叉分布指数
if ~isfield(params, 'eta_m'), params.eta_m = 20; end % 变异分布指数
if ~isfield(params, 'show_progress'), params.show_progress = true; end
% 初始化种群
pop = initializePopulation(nPop, nVar, varMin, varMax);
% 主循环
for gen = 1:maxGen
% 评估目标函数
F = evaluatePopulation(fun, pop);
% 非支配排序
[front, rank] = nonDominationSort(F);
% 计算拥挤度
crowding = crowdingDistance(F, front);
% 选择父代
parents = tournamentSelection(pop, front, crowding, nPop);
% 交叉和变异
offspring = geneticOperators(parents, params, varMin, varMax);
% 评估子代
F_offspring = evaluatePopulation(fun, offspring);
% 合并种群
combined_pop = [pop; offspring];
combined_F = [F; F_offspring];
% 环境选择
[pop, F, front, crowding] = environmentalSelection(combined_pop, combined_F, nPop);
% 显示进度
if params.show_progress && mod(gen, 10) == 0
fprintf('NSGA-II: Generation %d/%d, Pareto Front Size: %d\n', ...
gen, maxGen, sum(front == 1));
end
end
% 最终结果排序
[front, rank] = nonDominationSort(F);
crowding = crowdingDistance(F, front);
end
2.2 种群初始化函数
function pop = initializePopulation(nPop, nVar, varMin, varMax)
% 初始化种群
% 输入:
% nPop: 种群大小
% nVar: 变量个数
% varMin: 变量最小值 (标量或向量)
% varMax: 变量最大值 (标量或向量)
% 输出:
% pop: 初始种群 (nPop×nVar)
% 统一处理标量边界
if isscalar(varMin), varMin = repmat(varMin, 1, nVar); end
if isscalar(varMax), varMax = repmat(varMax, 1, nVar); end
% 随机初始化
pop = rand(nPop, nVar) .* (varMax - varMin) + varMin;
end
2.3 目标函数评估函数
function F = evaluatePopulation(fun, pop)
% 评估种群中所有个体的目标函数值
% 输入:
% fun: 目标函数句柄
% pop: 种群 (nPop×nVar)
% 输出:
% F: 目标函数值 (nPop×nObj)
nPop = size(pop, 1);
F = zeros(nPop, 0);
for i = 1:nPop
% 计算目标函数值
f = fun(pop(i, :));
% 确保结果是行向量
if iscolumn(f)
f = f';
end
% 添加到结果矩阵
F(i, 1:length(f)) = f;
end
end
2.4 非支配排序函数
function [front, rank] = nonDominationSort(F)
% 非支配排序
% 输入:
% F: 目标函数值 (nPop×nObj)
% 输出:
% front: 非支配前沿 (nPop×1)
% rank: 每个个体的秩 (nPop×1)
nPop = size(F, 1);
nObj = size(F, 2);
% 初始化
dominatedCount = zeros(nPop, 1); % 被支配计数
dominatedSet = cell(nPop, 1); % 支配的个体集合
rank = zeros(nPop, 1); % 秩
front = zeros(nPop, 1); % 前沿
% 计算支配关系
for i = 1:nPop
for j = 1:nPop
if i == j, continue; end
% 检查i是否支配j
if all(F(i, :) <= F(j, :)) && any(F(i, :) < F(j, :))
dominatedSet{i} = [dominatedSet{i}, j];
% 检查j是否支配i
elseif all(F(j, :) <= F(i, :)) && any(F(j, :) < F(i, :))
dominatedCount(i) = dominatedCount(i) + 1;
end
end
% 如果i不被任何个体支配,则属于第一前沿
if dominatedCount(i) == 0
front(i) = 1;
rank(i) = 1;
end
end
% 构建其他前沿
currentFront = 1;
while any(front == currentFront)
nextFront = currentFront + 1;
for i = 1:nPop
if front(i) == currentFront
for j = dominatedSet{i}
dominatedCount(j) = dominatedCount(j) - 1;
if dominatedCount(j) == 0
front(j) = nextFront;
rank(j) = nextFront;
end
end
end
end
currentFront = nextFront;
end
end
2.5 拥挤度计算函数
function crowding = crowdingDistance(F, front)
% 计算拥挤度距离
% 输入:
% F: 目标函数值 (nPop×nObj)
% front: 非支配前沿 (nPop×1)
% 输出:
% crowding: 拥挤度距离 (nPop×1)
nPop = size(F, 1);
nObj = size(F, 2);
crowding = zeros(nPop, 1);
% 找到最大和最小目标值
fmin = min(F, [], 1);
fmax = max(F, [], 1);
% 对每个目标函数计算拥挤度
for m = 1:nObj
% 按当前目标函数排序
[sortedF, sortIdx] = sort(F(:, m));
sortedFront = front(sortIdx);
% 边界点设置为无穷大
crowding(sortIdx(1)) = Inf;
crowding(sortIdx(end)) = Inf;
% 计算中间点的拥挤度
for i = 2:(nPop-1)
if sortedFront(i) ~= sortedFront(i-1) || sortedFront(i) ~= sortedFront(i+1)
% 避免不同前沿的点相互影响
continue;
end
% 归一化距离
normDist = (sortedF(i+1) - sortedF(i-1)) / (fmax(m) - fmin(m) + eps);
crowding(sortIdx(i)) = crowding(sortIdx(i)) + normDist;
end
end
end
2.6 锦标赛选择函数
function parents = tournamentSelection(pop, front, crowding, nPop)
% 二元锦标赛选择
% 输入:
% pop: 种群 (nPop×nVar)
% front: 非支配前沿 (nPop×1)
% crowding: 拥挤度 (nPop×1)
% nPop: 要选择的个体数
% 输出:
% parents: 选择的父代 (nPop×nVar)
n = size(pop, 1);
parents = zeros(nPop, size(pop, 2));
for i = 1:nPop
% 随机选择两个个体
candidates = randperm(n, 2);
cand1 = candidates(1);
cand2 = candidates(2);
% 比较前沿等级
if front(cand1) < front(cand2)
winner = cand1;
elseif front(cand1) > front(cand2)
winner = cand2;
else
% 相同前沿,比较拥挤度
if crowding(cand1) > crowding(cand2)
winner = cand1;
else
winner = cand2;
end
end
parents(i, :) = pop(winner, :);
end
end
2.7 遗传操作函数
function offspring = geneticOperators(parents, params, varMin, varMax)
% 交叉和变异操作
% 输入:
% parents: 父代种群 (nPop×nVar)
% params: 算法参数
% varMin: 变量最小值
% varMax: 变量最大值
% 输出:
% offspring: 子代种群 (nPop×nVar)
nPop = size(parents, 1);
nVar = size(parents, 2);
% 统一处理标量边界
if isscalar(varMin), varMin = repmat(varMin, 1, nVar); end
if isscalar(varMax), varMax = repmat(varMax, 1, nVar); end
offspring = zeros(nPop, nVar);
for i = 1:2:nPop
% 选择两个父代
p1 = parents(i, :);
p2 = parents(i+1, :);
% 交叉
if rand < params.pc
[c1, c2] = sbxCrossover(p1, p2, params.eta_c, varMin, varMax);
else
c1 = p1;
c2 = p2;
end
% 变异
c1 = polynomialMutation(c1, params.pm, params.eta_m, varMin, varMax);
c2 = polynomialMutation(c2, params.pm, params.eta_m, varMin, varMax);
% 添加到子代
offspring(i, :) = c1;
if i+1 <= nPop
offspring(i+1, :) = c2;
end
end
end
2.8 SBX交叉函数
function [c1, c2] = sbxCrossover(p1, p2, eta_c, varMin, varMax)
% 模拟二进制交叉 (SBX)
% 输入:
% p1, p2: 父代个体
% eta_c: 交叉分布指数
% varMin, varMax: 变量边界
% 输出:
% c1, c2: 子代个体
nVar = length(p1);
c1 = p1;
c2 = p2;
for i = 1:nVar
if rand < 0.5
% 计算交叉参数
u = rand;
if u <= 0.5
beta = (2*u)^(1/(eta_c+1));
else
beta = (1/(2*(1-u)))^(1/(eta_c+1));
end
% 生成子代
c1(i) = 0.5*((1+beta)*p1(i) + (1-beta)*p2(i));
c2(i) = 0.5*((1-beta)*p1(i) + (1+beta)*p2(i));
% 边界处理
c1(i) = min(max(c1(i), varMin(i)), varMax(i));
c2(i) = min(max(c2(i), varMin(i)), varMax(i));
end
end
end
2.9 多项式变异函数
function c = polynomialMutation(p, pm, eta_m, varMin, varMax)
% 多项式变异
% 输入:
% p: 父代个体
% pm: 变异概率
% eta_m: 变异分布指数
% varMin, varMax: 变量边界
% 输出:
% c: 变异后个体
nVar = length(p);
c = p;
for i = 1:nVar
if rand < pm
% 计算变异参数
u = rand;
if u < 0.5
delta = (2*u)^(1/(eta_m+1)) - 1;
else
delta = 1 - (2*(1-u))^(1/(eta_m+1));
end
% 应用变异
c(i) = p(i) + delta*(varMax(i) - varMin(i));
% 边界处理
c(i) = min(max(c(i), varMin(i)), varMax(i));
end
end
end
2.10 环境选择函数
function [newPop, newF, newFront, newCrowding] = environmentalSelection(combined_pop, combined_F, nPop)
% 环境选择 (从合并种群中选择nPop个个体)
% 输入:
% combined_pop: 合并种群 (2nPop×nVar)
% combined_F: 合并种群目标值 (2nPop×nObj)
% nPop: 要选择的数量
% 输出:
% newPop: 新种群
% newF: 新种群目标值
% newFront: 新种群前沿
% newCrowding: 新种群拥挤度
nCombined = size(combined_pop, 1);
% 非支配排序
[front, rank] = nonDominationSort(combined_F);
% 计算拥挤度
crowding = crowdingDistance(combined_F, front);
% 按前沿和拥挤度排序
[~, sortIdx] = sortrows([rank, -crowding], [1, 2]);
% 选择前nPop个个体
selectedIdx = sortIdx(1:nPop);
newPop = combined_pop(selectedIdx, :);
newF = combined_F(selectedIdx, :);
newFront = front(selectedIdx);
newCrowding = crowding(selectedIdx);
end
三、自定义目标函数示例
3.1 ZDT1测试函数
function f = zdt1(x)
% ZDT1测试函数
% 输入: x - 决策变量向量
% 输出: f - 目标函数值 [f1, f2]
n = length(x);
f1 = x(1);
g = 1 + 9 * sum(x(2:end)) / (n-1);
f2 = g * (1 - sqrt(x(1)/g));
f = [f1, f2];
end
3.2 DTLZ2测试函数
function f = dtlz2(x, M)
% DTLZ2测试函数
% 输入:
% x - 决策变量向量
% M - 目标函数个数
% 输出: f - 目标函数值 (1×M)
n = length(x);
k = n - M + 1;
g = 0;
for i = M:n
g = g + (x(i) - 0.5)^2;
end
f = zeros(1, M);
for i = 1:M-1
f(i) = (1 + g) * cos(x(1)*pi/2) * cos(x(2)*pi/2) ...
* prod(cos(x(j)*pi/2) for j=3:i-1) * sin(x(i)*pi/2);
end
f(M) = (1 + g) * prod(cos(x(j)*pi/2) for j=1:M-1);
% 简化版本
if M == 3
f(1) = (1 + g) * cos(x(1)*pi/2) * cos(x(2)*pi/2);
f(2) = (1 + g) * cos(x(1)*pi/2) * sin(x(2)*pi/2);
f(3) = (1 + g) * sin(x(1)*pi/2);
end
end
3.3 自定义工程问题
function f = custom_engineering_problem(x)
% 自定义工程优化问题示例
% 输入: x - 设计变量 [x1, x2, x3]
% 输出: f - 目标函数值 [成本, 重量, 应力]
% 设计变量
x1 = x(1); % 梁高度 (m)
x2 = x(2); % 梁宽度 (m)
x3 = x(3); % 材料强度 (MPa)
% 约束处理 (惩罚函数法)
penalty = 0;
if x1 < 0.1 || x1 > 0.5
penalty = penalty + 1e6 * (min(abs(x1-0.1), abs(x1-0.5)))^2;
end
if x2 < 0.05 || x2 > 0.3
penalty = penalty + 1e6 * (min(abs(x2-0.05), abs(x2-0.3)))^2;
end
if x3 < 100 || x3 > 500
penalty = penalty + 1e6 * (min(abs(x3-100), abs(x3-500)))^2;
end
% 目标函数1: 成本 (与体积和材料相关)
volume = x1 * x2 * 1.0; % 假设长度1m
material_cost = 0.1 * x3; % 材料成本与强度相关
cost = 1000 * volume + 0.1 * material_cost;
% 目标函数2: 重量 (与体积和密度相关)
density = 7800; % 钢密度 (kg/m³)
weight = volume * density;
% 目标函数3: 最大应力 (越小越好)
load = 10000; % 载荷 (N)
stress = (6 * load * 1.0) / (x1 * x2^2); % 简支梁弯曲应力
f = [cost, weight, stress] + penalty;
end
四、NSGA-II应用示例
4.1 基本使用
% 参数设置
nVar = 3; % 变量个数
varMin = [0, 0, 0]; % 变量最小值
varMax = [1, 1, 1]; % 变量最大值
nPop = 100; % 种群大小
maxGen = 200; % 最大迭代次数
% 定义目标函数
fun = @(x) zdt1(x);
% 运行NSGA-II
[pop, F, front, crowding] = nsga2_custom(fun, nVar, varMin, varMax, nPop, maxGen);
% 结果可视化
plot(F(:,1), F(:,2), 'ro');
xlabel('目标1'); ylabel('目标2');
title('Pareto前沿');
4.2 自定义工程问题优化
% 参数设置
nVar = 3; % 变量个数: [高度, 宽度, 材料强度]
varMin = [0.1, 0.05, 100]; % 最小值
varMax = [0.5, 0.3, 500]; % 最大值
nPop = 50; % 种群大小
maxGen = 100; % 最大迭代次数
% 定义目标函数
fun = @custom_engineering_problem;
% 运行NSGA-II
[pop, F, front, crowding] = nsga2_custom(fun, nVar, varMin, varMax, nPop, maxGen);
% 提取Pareto前沿
paretoIdx = find(front == 1);
paretoPop = pop(paretoIdx, :);
paretoF = F(paretoIdx, :);
% 结果可视化
figure;
subplot(1,3,1);
plot(paretoF(:,1), paretoF(:,2), 'bo');
xlabel('成本'); ylabel('重量');
title('成本 vs 重量');
subplot(1,3,2);
plot(paretoF(:,1), paretoF(:,3), 'ro');
xlabel('成本'); ylabel('应力');
title('成本 vs 应力');
subplot(1,3,3);
plot(paretoF(:,2), paretoF(:,3), 'go');
xlabel('重量'); ylabel('应力');
title('重量 vs 应力');
% 显示最佳折衷解
[~, idx] = min(paretoF(:,1) + paretoF(:,2) + paretoF(:,3));
fprintf('最佳折衷解:\n');
fprintf(' 高度: %.3f m\n', paretoPop(idx,1));
fprintf(' 宽度: %.3f m\n', paretoPop(idx,2));
fprintf(' 材料强度: %.1f MPa\n', paretoPop(idx,3));
fprintf(' 成本: %.2f 元\n', paretoF(idx,1));
fprintf(' 重量: %.2f kg\n', paretoF(idx,2));
fprintf(' 应力: %.2f MPa\n', paretoF(idx,3));
参考代码 NSGA2自定义优化函数MATLAB代码 www.youwenfan.com/contentcnt/160564.html
五、算法性能评估
5.1 性能指标计算
function metrics = evaluatePerformance(F, front, truePareto, trueFront)
% 评估NSGA-II性能
% 输入:
% F: 算法得到的Pareto前沿目标值
% front: 算法得到的前沿等级
% truePareto: 真实Pareto前沿 (可选)
% trueFront: 真实前沿等级 (可选)
% 输出:
% metrics: 性能指标结构
metrics = struct();
% 1. 收敛性指标 (GD, IGD)
if exist('truePareto', 'var') && ~isempty(truePareto)
% 世代距离 (Generational Distance)
gd = 0;
for i = 1:size(F, 1)
if front(i) == 1 % 只考虑Pareto前沿
minDist = min(vecnorm(F(i,:) - truePareto, 2, 2));
gd = gd + minDist^2;
end
end
metrics.GD = sqrt(gd) / size(F(front==1,:), 1);
% 反向世代距离 (Inverted Generational Distance)
igd = 0;
for i = 1:size(truePareto, 1)
minDist = min(vecnorm(truePareto(i,:) - F, 2, 2));
igd = igd + minDist^2;
end
metrics.IGD = sqrt(igd) / size(truePareto, 1);
end
% 2. 多样性指标 (Spacing, Spread)
paretoF = F(front==1, :);
nPareto = size(paretoF, 1);
if nPareto > 1
% 间距指标 (Spacing)
distances = pdist2(paretoF, paretoF);
minDists = min(distances + eye(nPareto)*Inf, [], 2);
metrics.Spacing = std(minDists);
% 分布性指标 (Spread)
fmin = min(paretoF, [], 1);
fmax = max(paretoF, [], 1);
d1 = norm(paretoF(1,:) - fmin) / norm(fmax - fmin);
d2 = norm(paretoF(end,:) - fmin) / norm(fmax - fmin);
metrics.Spread = (d1 + d2 + sum(abs(minDists - mean(minDists))) / (nPareto-1)) / (d1 + d2 + nPareto-1);
end
% 3. 超体积指标 (Hypervolume)
refPoint = max(F, [], 1) * 1.1; % 参考点
metrics.HV = hypervolume(paretoF, refPoint);
% 4. Pareto前沿大小
metrics.ParetoSize = nPareto;
end
function hv = hypervolume(front, refPoint)
% 计算超体积
n = size(front, 1);
m = size(front, 2);
if n == 0
hv = 0;
return;
end
% 按第一个目标排序
[front, idx] = sortrows(front, 1);
hv = 0;
for i = 1:n
if m == 2
% 二维情况
hv = hv + (refPoint(1) - front(i,1)) * (refPoint(2) - front(i,2));
else
% 多维情况 (简化)
hv = hv + prod(refPoint(1:m-1) - front(i,1:m-1)) * (refPoint(m) - front(i,m));
end
end
end
5.2 性能测试函数
function runPerformanceTest()
% 运行NSGA-II性能测试
% 测试问题
testProblems = {
struct('name', 'ZDT1', 'fun', @zdt1, 'nVar', 10, 'nObj', 2, 'varMin', 0, 'varMax', 1)
struct('name', 'DTLZ2', 'fun', @(x)dtlz2(x,3), 'nVar', 7, 'nObj', 3, 'varMin', 0, 'varMax', 1)
};
% 算法参数
nPop = 100;
maxGen = 200;
results = cell(length(testProblems), 1);
for i = 1:length(testProblems)
prob = testProblems{i};
fprintf('运行测试: %s\n', prob.name);
% 运行NSGA-II
[pop, F, front, crowding] = nsga2_custom(...
prob.fun, prob.nVar, prob.varMin, prob.varMax, nPop, maxGen);
% 评估性能
metrics = evaluatePerformance(F, front);
% 存储结果
results{i} = struct('problem', prob, 'metrics', metrics, 'F', F, 'front', front);
% 显示结果
fprintf(' Pareto前沿大小: %d\n', metrics.ParetoSize);
fprintf(' 超体积: %.4f\n', metrics.HV);
fprintf(' 间距指标: %.4f\n', metrics.Spacing);
fprintf(' 分布性指标: %.4f\n', metrics.Spread);
end
% 可视化结果
visualizeResults(results);
end
六、高级功能扩展
6.1 约束处理
function [c, ceq] = constraintFunction(x)
% 约束函数示例
% 输入: x - 决策变量
% 输出:
% c - 不等式约束 (c <= 0)
% ceq - 等式约束 (ceq = 0)
% 示例约束:
c = [x(1) + x(2) - 1.5; % x1 + x2 <= 1.5
-x(1) - x(2) + 0.5; % -x1 - x2 <= -0.5
x(1)^2 - 0.25]; % x1^2 <= 0.25
ceq = []; % 无等式约束
end
% 在目标函数中添加约束惩罚
function f = constrainedObjective(x)
% 原始目标函数
f_raw = zdt1(x);
% 约束处理
[c, ceq] = constraintFunction(x);
% 惩罚函数法
penalty = 0;
if ~isempty(c)
penalty = penalty + 1e6 * sum(max(0, c).^2);
end
if ~isempty(ceq)
penalty = penalty + 1e6 * sum(ceq.^2);
end
f = f_raw + penalty;
end
6.2 并行计算支持
function F = evaluatePopulationParallel(fun, pop)
% 并行评估种群
nPop = size(pop, 1);
F = zeros(nPop, 0);
parfor i = 1:nPop
f = fun(pop(i, :));
if iscolumn(f)
f = f';
end
F(i, 1:length(f)) = f;
end
end
% 修改主函数以支持并行
function [pop, F, front, crowding] = nsga2_parallel(fun, nVar, varMin, varMax, nPop, maxGen, params)
% 使用并行评估的NSGA-II
% 初始化
pop = initializePopulation(nPop, nVar, varMin, varMax);
for gen = 1:maxGen
% 并行评估
F = evaluatePopulationParallel(fun, pop);
% 其余部分与原版相同...
end
end
6.3 自定义选择策略
function parents = customSelection(pop, front, crowding, nPop, strategy)
% 自定义选择策略
% 策略: 'tournament' (默认), 'roulette', 'random'
n = size(pop, 1);
parents = zeros(nPop, size(pop, 2));
switch lower(strategy)
case 'tournament'
% 二元锦标赛选择 (原版)
for i = 1:nPop
candidates = randperm(n, 2);
cand1 = candidates(1);
cand2 = candidates(2);
if front(cand1) < front(cand2)
winner = cand1;
elseif front(cand1) > front(cand2)
winner = cand2;
else
if crowding(cand1) > crowding(cand2)
winner = cand1;
else
winner = cand2;
end
end
parents(i, :) = pop(winner, :);
end
case 'roulette'
% 轮盘赌选择
% 计算选择概率 (基于秩和拥挤度)
ranks = front;
invRanks = 1 ./ (ranks + 1); % 避免除以0
probs = invRanks / sum(invRanks);
for i = 1:nPop
idx = randsample(n, 1, true, probs);
parents(i, :) = pop(idx, :);
end
case 'random'
% 随机选择
idx = randperm(n, nPop);
parents = pop(idx, :);
otherwise
error('未知的选择策略: %s', strategy);
end
end
七、使用注意事项
-
目标函数设计
-
确保目标函数返回行向量
-
处理无效解(返回大惩罚值)
-
考虑目标函数的尺度差异
-
-
参数调优
-
种群大小:通常50-200
-
最大代数:100-1000
-
交叉概率:0.7-0.95
-
变异概率:1/nVar - 1/2
-
分布指数:20-100
-
-
性能优化
-
使用并行计算加速评估
-
对于高维问题,考虑使用代理模型
-
使用JIT加速或C/MEX实现关键函数
-
-
结果分析
-
检查Pareto前沿的多样性和收敛性
-
使用多种性能指标综合评估
-
进行统计显著性检验
-
浙公网安备 33010602011771号