差分进化算法介绍:
在自然界中,遗传,变异,选择的作用,使得生物体优胜略汰,不断由低级向高级进化,人们发现适者生存这一规律可以模式化,从而构成一些列优化算法。差分进化算法就是从这种模式中产生的一种智能优化算法。差分进化算法是基于群体只能理论的优化算法,与进化算法相比,保留了基于种群的全局搜索策略,采用实数编码,基于差分的简单变异操作操作和“一对一”的竞争生存策略。降低了操作的复杂性,差分进化算法特有的记忆能力使其可以动态的跟踪当前的搜索情况,以调整其搜索策略,具有较强的收敛能力和稳健性,且不需要借助问题的特侦信息。
算法流程:
1. 初始化:(与遗传算法类似)
种群中的个体可以表示为:(种群大小为NP)
其中: i=1,2,....NP
初始种群一般在给定的约束边界内随机生成
2. 变异
对于种群中每个个体,差分进化算法的变异向量按照下面的方式产生:
其中:在种群中随机选择且
,参数
,用于控制偏差的放大作用。
除此之外,偏差向量还可以由其他的方式产生:表示方法:DE/x/y/z, x当前被变异的向量是随机的还是最优的,y差向量的个数,z交叉程序的操作方法(bin)
DE/best/1/bin:
DE/rand-to-best/1/bin:
DE/best/2/bin:
DE/rand/2/bin:
3. 交叉
这里的交叉和遗传算法的交叉操作有所区别,这里的交叉操作是针对整个种群的某一维度,而遗传算法中的交叉是针对种群中的每一个个体。
4.选择:
差分进化算法按照贪婪准则,从实验种群u中选择个体作为下一代种群x中的个体,具体的选择方式是:
其中:fit(x)为x的适应度。
5. 边界条件处理:
对于这一类的算法,通常会对种群中的个体执行一些列的操作(如交叉,变异),这会导种群中个体的范围(即决策变量的范围)超出给定的范围,所以需要对上述操作后所得到种群进行边界条件检查和处理,对于边界之外的个体一般有两种处理方法:
1. 边界吸收:
假设x的范围是x_max, x_min, x'是经过变异或者交叉操作后所得的新的个体:则新个体的边界检查和处理规则为:
2. 重新随机生成新的个体:
基本差分进化算法的流程:
算法中的参数:
1. 种群大小NP
2. 变异算子F ,
一般取[0,2],决定偏差向量的放大比例。F过小,造成算法早熟,F过大,导致算法的收敛性变差
3.交叉算子CR
4. 进化代数G
5.终止条件
matlab代码实现:
测试函数为:
取n=10,决策变量的范围为[-20,20]
close all;
clear all;
clc;
NP=50;
D=10; % 染色体长度
G=200;
F0=0.4;
CR=0.1;
a=-20; % 寻优区间
b=20;
yz=10^-6;
x=zeros(NP,D); % 初始种群
v=zeros(NP,D); % 变异种群
u=zeros(NP,D); % 选择种群
% 种群怫初值
x=rand(NP,D)*(b-a)+a;
% 计算目标参数
for i=1:1:NP
ob(i)=sum(x(i,:).^2);
end
trace(1)=min(ob);
% 差分进化循环
for gen=1:G
% 变异操作
for m=1:NP
r1=randi([1,NP],1,1);
while(r1==m)
r1=randi([1,NP],1,1);
end
r2=randi([1,NP],1,1);
while(r2==r1)||(r2==m)
r2=randi([1,NP],1,1);
end
r3=randi([1,NP],1,1);
while(r3==m)||(r3==r2)||(r3==r1)
r3=randi([1,NP],1,1);
end
% 产生不同的r1,r2,r3
v(m,:)=x(r1,:)+F0*(x(r2,:)-x(r3,:));
end
% 交叉操作
r=randi([1,D],1,1); % 这个变异是针对整个种群的变异,不正对单个个体
for n=1:D
cr=rand;
if (cr<=CR)||(n==r)
u(:,n)=v(:,n);
else
u(:,n)=x(:,n);
end
end
% 边界条件处理
for m=1:NP
for n=1:D
if u(m,n)<a
u(m,n)=a;
end
if u(m,n)>b
u(m,n)=b;
end
end
end
% 自然选择
% 计算新的适应度
for m=1:NP
ob_1(m)=sum(u(m,:).^2);
end
for m=1:NP
if ob_1(m)<ob(m)
x(m,:)=u(m,:);
else
x(m,:)=x(m,:);
end
end
% 现在x为经过选择后的种群
for m=1:NP
ob(m)=sum(x(m,:).^2);
end
trace(gen+1)=min(ob);
tt=min(ob);
end
x(1,:);
figure(1);
title(['差分进化算法(DE)', '最小值: ', num2str(tt)]);
xlabel('迭代次数');
ylabel('目标函数值');
plot(trace);
寻优结果:
差分进化算法的该改进:
自适应差分进化算法:
差分进化算法的变异系数F的确定:在实际的应用中,若果F取为常数,F过大,则会导致算法的收敛速度变慢,求得的全局最优解精度降低,F过小,会导致种群的多样性降低,出现早熟,所以可以将参数F设置为一个随着迭代次数变化的值,在迭代初期的时候,F较大,可以保持种群的多样性,随着迭代次数的增加,F减小,能够保存优良的种群信息,避免破坏最优解。
自适应算子如下所示:
其中Gm表示最大迭代次数,G表示当前迭代次数
变异系数F表示为:
改进的差分进化算法:
clear all;
close all;
clc;
NP=40; % 种群大小
G=100; % 迭代次数
D=2; % 决策变量个数
F0=0.3; % 初始的变异系数
CR=0.5*(1+rand());
X_min=-100;
X_max=100;
% 偏差向量的生成方式
DE_vector = 4;
% DE_vector=1,2,3,4,0
% DE_vector=0 表示DE/best/1/bin
% DE_vector=1 表示DE/best/1/bin
% DE_vector=2 表示DE/rand-to-best/1/bin
% DE_vector=3 表示DE/best/2/bin
% DE_vector=4 表示DE/rand/2/bin
mode = 'Schaffer'; % 测试函数
% mode = 'self_define';
if strcmp(mode, 'Schaffer')
figure(1)
x = -4:0.1:4;
y = -4:0.1:4;
[X,Y] = meshgrid(x,y);
% Z = 3*cos(X.*Y)+X+Y.^2;
Z = 0.5-((sin(sqrt(X.^2+Y.^2)).^2)-0.5)./(1+0.001.*(X.^2+Y.^2)).^2;
surf(X,Y,Z);
title('Schaffer Function');
xlabel('X-轴');
ylabel('Y-轴');
zlabel('Z-轴');
figure(2);
contour(X, Y, Z, 8);
title('Schaffer函数等高线');
xlabel('X-轴');
ylabel('Y-轴');
end
if strcmp(mode, 'self_define')
figure(1);
x = -4:0.1:4;
y = -4:0.1:4;
[X,Y] = meshgrid(x,y);
% Z = 100.*(Y-X.^2).^2+(1-X).^2;
Z = (cos(X.^2+Y.^2)-0.1)./(1+0.3*(X.^2+Y.^2).^2)+3;
surf(X,Y,Z);
%title('Rosen Brock valley Function');
title('Self define Function');
xlabel('X-轴');
ylabel('Y-轴');
zlabel('Z-轴');
end
% 种群初始化
x=zeros(NP,D);
v=zeros(NP,D);
u=zeros(NP,D);
x=X_min + (X_max-X_min)*rand(NP,D);
for gen=1:1:G
for i=1:1:NP
ob(i) = func(x(i,:), mode);
end
[fitness_max, index] = max(ob);
lamb(gen) = exp(1-(G/(G+1-gen)));
F = F0*2^lamb(gen);
% 变异
if(DE_vector==0)
for m=1:NP
r1=randi([1,NP],1,1);
while (r1==m)
r1=randi([1,NP],1,1);
end
r2=randi([1,NP],1,1);
while(r2==r1)||(r2==m)
r2=randi([1,NP],1,1);
end
r3=randi([1,NP],1,1);
while (r3==m)||(r3==r2)||(r3==r1)
r3=randi([1,NP],1,1);
end
v(m,:)=x(r1,:)+F*(x(r2,:)-x(r3,:)); % DE/best/1bin
end
elseif(DE_vector==1)
for m=1:NP
r1=randi([1,NP],1,1);
while (r1==m)
r1=randi([1,NP],1,1);
end
r2=randi([1,NP],1,1);
while(r2==r1)||(r2==m)
r2=randi([1,NP],1,1);
end
v(m,:)=x(index,:)+x(r1,:)+F*(x(r1,:)-x(r2,:));
end
elseif(DE_vector==2)
lambda = 0.35;
for m=1:NP
r1=randi([1,NP],1,1);
while (r1==m)
r1=randi([1,NP],1,1);
end
r2=randi([1,NP],1,1);
while(r2==r1)||(r2==m)
r2=randi([1,NP],1,1);
end
v(m,:)=x(m,:)+lambda*(x(index,:)-x(m,:))+F*(x(r1,:)-x(r2,:));
end
elseif(DE_vector==3)
for m=1:NP
r1=randi([1,NP],1,1);
while (r1==m)
r1=randi([1,NP],1,1);
end
r2=randi([1,NP],1,1);
while(r2==r1)||(r2==m)
r2=randi([1,NP],1,1);
end
r3=randi([1,NP],1,1);
while (r3==m)||(r3==r2)||(r3==r1)
r3=randi([1,NP],1,1);
end
r4=randi([1,NP],1,1);
while (r4==m)||(r4==r3)||(r4==r2)||(r4==r1)
r4=randi([1,NP],1,1);
end
v(m,:)=x(index,:)+F*(x(r1,:)-x(r2,:)+x(r3,:)-x(r4,:));
end
else
for m=1:NP
r1=randi([1,NP],1,1);
while (r1==m)
r1=randi([1,NP],1,1);
end
r2=randi([1,NP],1,1);
while(r2==r1)||(r2==m)
r2=randi([1,NP],1,1);
end
r3=randi([1,NP],1,1);
while (r3==m)||(r3==r2)||(r3==r1)
r3=randi([1,NP],1,1);
end
r4=randi([1,NP],1,1);
while (r4==m)||(r4==r3)||(r4==r2)||(r4==r1)
r4=randi([1,NP],1,1);
end
r5=randi([1,NP],1,1);
while (r5==m)||(r5==4)||(r5==r3)||(r5==r2)||(r5==r1)
r5=randi([1,NP],1,1);
end
v(m,:)=x(r5,:)+F*(x(r1,:)-x(r2,:)+x(r3,:)-x(r4,:));
end
end
% 交叉操作
r=randi([1,D],1,1);
for i=1:D
cr=rand;
if (cr<=CR)||(i==r)
u(:,i)=v(:,i);
else
u(:,i)=x(:,i);
end
end
% 边界条件处理
for m=1:NP
for n=1:D
if u(m,n)<X_min
u(m,n)=X_min;
end
if u(m,n)>X_max
u(m,n)=X_max;
end
end
end
% 自然选择
for i=1:NP
ob_1(i)=func(u(i,:), mode);
end
for i=1:NP
if ob_1(i)>ob(i)
x(i,:)=u(i,:);
else
x(i,:)=x(i,:);
end
end
trace(gen+1)=fitness_max;
end
figure(3);
% plot(trace);
title('差分进化算法');
xlabel('迭代次数');
ylabel('目标函数值');
plot(trace);
function f=func(buf, md)
if strcmp(md, 'Schaffer')
f=0.5-((sin(sqrt(buf(1).^2+buf(2).^2)).^2)-0.5)./(1+0.001.*(buf(1).^2+buf(2).^2)).^2;
end
if strcmp(md,'self_define')
% f = 100*(buf(2)-buf(1).^2).^2+(1-buf(1)).^2;
f = (cos(buf(1).^2+buf(2).^2)-0.1)./(1+0.3*(buf(1).^2+buf(2).^2).^2)+3;
end
end
测试函数:
适应度进化曲线:
源代码中只是添加了典型的测试函数,参数只是粗略设置一下。对于其他的测试函数。可以在原代码中添加,并且修改源代码中的一些参数来得到算法最好的性能。