关于单目标无约束优化问题,常见的做法为对违反约束的个体惩罚,即对适应度加上惩罚项,此方法一定程度上可以解决简单约束问题。但面对复杂的约束问题,惩罚项系数的选择变得十分困难;现提供一种思路,基于多目标优化思想,Pareto无支配排序准则,同等重要的看待目标函数(cost)和约束(cons),以下结合一种实例对给出Matlab源码实现。
应用于简单的带约束的优化模型:
优化模型出处:同时该博主给出了函数图像和自己代码的运行结果(表示感谢):
链接:优化模型出处.
代码实现:
function [lower,upper,cons_low,cons_up] = cons_detail()
lower = [1,-1];
upper = [2,0];
cons_up = [6,5];
cons_low= [-10000,-10000]; %由于原函数没有下限,需随意给一个:
end
function [Z,g1,g2] = return_f_c(one_pop)
a = 10;
x = one_pop(1);
y = one_pop(2);
Z = 2*a + x^2 - a*cos(2*pi*x) + y^2 - a*cos(2*pi*y);
g1 = x+y;
g2 = 3*x-2*y;
end
function pop = add_f_consFactor(x_pop)
% -------------------- 传入的是 x-y ----------------------%
[~,~,cons_low,cons_up] = cons_detail();
[m,n] = size(x_pop);
pop = ones(m,n+2);
pop(:,1:n) = x_pop;
for i =1:m
[Z,g1,g2]= return_f_c(x_pop(i,:));
pop(i,n+1) = Z; %目标函数
%% 计算违反度
% c1 g1范围
if g1 > cons_up(1)
c1 = (g1 -cons_up(1))/cons_up(1);
end
if g1 < cons_low(1)
c1 = abs((g1 - cons_low(1))/cons_low(1));
end
if g1 <= cons_up(1) && g1 >= cons_low(1)
c1 = 0;
end
% c2 g2 范围
if g2 > cons_up(2)
c2 = (g2 - cons_up(2)) / cons_up(2);
end
if g2 < cons_low(2)
c2 = abs( (g2 - cons_low(2))/cons_low(2));
end
if g2 <= cons_up(2) && g2 >= cons_low(2)
c2 = 0;
end
pop(i,n+2) = c1+c2; %违反程度的简单相加
end
end
clc;clear;close;
%% initialize
tic;
pop_num = 50;
iter_max = 100;
%% 种群初始化
[lower,upper,~,~] =cons_detail();
for i = 1:pop_num
x_pop(i,:) = rand(1,2).*(upper(1:2)-lower(1:2)) + lower(1:2);
end
disp('-------------种群初始化完成---------------');
x_pop = add_f_consFactor(x_pop(:,1:2));
%% iter
iter =1;
while iter <= iter_max
disp(['第',num2str(iter),'次迭代']);
x_pop = DE_for_cons(x_pop(:,1:2));
best_fitness(iter,1:4) = x_pop(1,1:4);
iter = iter+1; %%此处可考虑迭代停止条件
end
toc;
%% Plot
figure(1);
hold on;
title(["min Z = 20+x^2-10cos(2pi*x) + y^2 -10cos(2pi*y):",['Z best= ',num2str(best_fitness(end,3))]]);
xlabel(['best [X,Y] = ',num2str(best_fitness(end,1:2))]);
ylabel("fitness");
plot(best_fitness(:,3));
hold off;
特别需要注意的是:在选择时使用贪婪策略(有点像精英保留,提高全局搜索能力和收敛速度)
function pop = DE_for_cons(x_pop)
%------------ 传入的种群是变量(x1 --- x2)--------------------%
F = 0.5; % 缩放因子
CR = 0.5; % 交叉概率
x_temp = x_pop; %复制一份
[m,n]= size(x_pop);
[x_min,x_max,~,~] = cons_detail();
%% 1)变异
% 随机选取种群中两个不同的个体,将向量缩放后与待变异的个体进行向量合成 ,得到变异中间体
parent =zeros(m,3); %存放母本1,母本2,母本3的序号;
for i = 1:m
parent(i,:) = choose_parent(x_temp,i);
x_pop(i,:) = x_temp(i,:) + F*(x_temp(parent(i,2),:) - x_temp(parent(i,3),:));
for j = 1:n %%边界处理
if x_pop(i,j)>x_max(j) || x_pop(i,j)<x_min(j)
x_pop(i,j) = rand*(x_max(j) - x_min(j)) + x_min(j);
end
end
end
%% 2) 交叉
% 使用g代种群和其变异中间体进行交叉
for i = 1:m
for j = 1:n
prob = rand;
j_rand = floor(rand*n+0.5);
if prob > CR && j_rand ~= j
x_pop(i,j) = x_temp(i,j);
end
end
end
%% 3) 选择
% 采用贪婪算法来选择下一代种群个体: 合并种群,根据要求选择最优选择 前pop_num个。
x_temp = [x_temp;x_pop];
x_temp = add_f_consFactor(x_temp(:,1:2));
[F,~] = non_domination_sort(m*2,x_temp,2,2 ); %%选取F1 - FL层
len = 0;
i_count = 0;
while(len < m)
i_count = i_count+1;
temp = len; %%记录len的上一个状态
len = len +length(F(i_count).ss);
end
need_add_num = m-temp; %第l层需要加入的个体数;
index1 = [];
for i = 1:i_count-1
index1 =[index1,F(i).ss];
end
for j = 1:need_add_num
index1 = [index1,F(i_count).ss(j)];
end
pop = x_temp(index1,:) ;
end
function parent = choose_parent(x_pop,i) %差分进化算法需要的母本选择(选择基向量)
parent1 = i;
flag = 1;
[m, ~]= size(x_pop);
while flag
parent2 = floor(rand*m);
parent3 = floor(rand*m);
if(parent2 ~= 0 && parent3 ~= 0)
if(parent1 ~= parent2 && parent1 ~= parent3)
if(parent2~= parent3)
flag = 0;
end
end
end
end
parent = [parent1,parent2,parent3];
end
function [F,x_pop] = non_domination_sort( pop,x_pop,f_num,x_num )
%non_domination_sort 初始种群的非支配排序和计算拥挤度
%初始化pareto等级为1
pareto_rank=1;
F(pareto_rank).ss=[];%pareto等级为pareto_rank的集合
p=[];%每个个体p的集合
for i=1:pop
%%%计算出种群中每个个体p的被支配个数n和该个体支配的解的集合s
p(i).n=0;%被支配个体数目n
p(i).s=[];%支配解的集合s
for j=1:pop
less=0;%y'的目标函数值小于个体的目标函数值数目
equal=0;%y'的目标函数值等于个体的目标函数值数目
greater=0;%y'的目标函数值大于个体的目标函数值数目
for k=1:f_num
if(x_pop(i,x_num+k)<x_pop(j,x_num+k))
less=less+1;
elseif(x_pop(i,x_num+k)==x_pop(j,x_num+k))
equal=equal+1;
else
greater=greater+1;
end
end
if(less==0 && equal~=f_num)%if(less==0 && greater~=0)
p(i).n=p(i).n +1;%被支配个体数目n+1
elseif(greater==0 && equal~=f_num)%elseif(greater==0 && less~=0)
p(i).s=[p(i).s j];
end
end
%%%将种群中参数为n “被支配个体数目为0” 的个体放入集合F(1)中
if(p(i).n == 0)
x_pop(i,f_num+x_num+1)=1;%储存个体的等级信息
F(pareto_rank).ss=[F(pareto_rank).ss i]; %%记录下该个体的位置i
end
end
%% 求pareto等级为pareto_rank+1的个体
while ~isempty(F(pareto_rank).ss)
temp=[];
for i=1:length(F(pareto_rank).ss)
if ~isempty(p(F(pareto_rank).ss(i)).s) %等级为pareto_rank的第i个个体的“支配解记录表” 为非空
for j=1:length(p(F(pareto_rank).ss(i)).s)
p(p(F(pareto_rank).ss(i)).s(j)).n = p(p(F(pareto_rank).ss(i)).s(j)).n - 1;%nl=nl-1
if p(p(F(pareto_rank).ss(i)).s(j)).n == 0
x_pop(p(F(pareto_rank).ss(i)).s(j),f_num+x_num+1)=pareto_rank+1;%储存个体的等级信息
temp=[temp p(F(pareto_rank).ss(i)).s(j)];
end
end
end
end
pareto_rank=pareto_rank+1;
F(pareto_rank).ss=temp;
end
end
时间上也非常快!用时:2.7 s 左右!
当约束比较复杂时,上述方法可能很难兼顾(多)约束和目标搜寻到最优解(可行解)。
实际单(多)目标优化中常常遇到带约束的优化问题,如何解决这些问题,一种可行的思路是使用基于Pareto的无支配排序,对约束进行违反程度评价后排序,然后使用双策略进行优化:可行解过多时使用单目标无约束优化;可行解过少时使用约束满足优化【1】!
参考文献:
[1] Surry P D , Radcliffe N J . The COMOGA method: Constrained optimisation by multi-objective genetic algorithms[J]. Control & Cybernetics, 1997, 26(3).
有相关问题探讨请私信或留言,谢谢!
创作不易:如果有帮助请点赞!