差分进化(DE)算法实现带约束优化(Matlab源码)

单目标带约束优化——差分进化算法实现(算例+Matlab代码实现)

关于单目标无约束优化问题,常见的做法为对违反约束的个体惩罚,即对适应度加上惩罚项,此方法一定程度上可以解决简单约束问题。但面对复杂的约束问题,惩罚项系数的选择变得十分困难;现提供一种思路,基于多目标优化思想,Pareto无支配排序准则,同等重要的看待目标函数(cost)和约束(cons),以下结合一种实例对给出Matlab源码实现。

应用于简单的带约束的优化模型:
两个自变量的单目标多约束优化模型
优化模型出处:同时该博主给出了函数图像和自己代码的运行结果(表示感谢):
链接:优化模型出处.

代码实现:

1、给定函数的自变量的上下限,和约束的上下限:

function [lower,upper,cons_low,cons_up] = cons_detail()
    lower = [1,-1];
    upper = [2,0];
    cons_up = [6,5];
    cons_low= [-10000,-10000];  %由于原函数没有下限,需随意给一个:      
end

2、计算目标函数Z 约束 g1 g2

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

3、处理约束 和 目标函数

约束处理方法如下:
约束处理

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

4、主函数:

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;

5、差分进化算法(个人偏好:收敛效果很好,易于实现)

特别需要注意的是:在选择时使用贪婪策略(有点像精英保留,提高全局搜索能力和收敛速度)

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

6、差分进化里选择母本基向量

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

7、无支配排序(代码搬用参考某位大神)

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

8、运行结果

运行结果
时间上也非常快!用时:2.7 s 左右!

9 提升

当约束比较复杂时,上述方法可能很难兼顾(多)约束和目标搜寻到最优解(可行解)。
实际单(多)目标优化中常常遇到带约束的优化问题,如何解决这些问题,一种可行的思路是使用基于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).

有相关问题探讨请私信或留言,谢谢!
创作不易:如果有帮助请点赞!

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Duckbubi1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值