Navigator
Demo 1: GA
求下列函数的极大值
f ( x ) = sin x x × sin y y , − 10 ≤ x , y ≤ 10 f(x)=\frac{\sin x}{x}\times \frac{\sin y}{y}, -10\leq x, y\leq 10 f(x)=xsinx×ysiny,−10≤x,y≤10
Code
function [max_x, max_fval] = MLYGA2(func, LB, UB, popsize, iter_max, px, pm, esp)
%func: 待优化的目标函数
% LB: 自变量的下界
% UB: 自变量的上界
% popsize: 种群大小
% iter_max: 最大迭代次数
% px: 交叉概率
% pm: 变异概率
% epsl: 自变量离散精度
if isempty(pm)
pm=0.1;
end
if isempty(px)
px=0.90;
end
if isempty(iter_max)
iter_max=8000;
end
if isempty(popsize)
popsize=50;
end
if isempty(LB) && isempty(UB)
nvar = input('请输入变量的数目nvar=');
else
nvar = size(LB, 1);
end
CodeLen = nvar*max(ceil(log2((UB-LB)/esp+1))); % 根据自变量的离散精度,确定二进制编码串的长度
x = zeros(popsize, CodeLen); % 种群编码的初始值
for i=1:popsize
x(i, :)=init(CodeLen); % 调用子程序初始化种群
FitValue(i) = func(Decl(LB, UB, x(i, :), CodeLen)); % 计算个体适应值
end
for j=1:iter_max
SumFitValue = sum(FitValue); % 所有个体的适应值之和
Ave_x = FitValue/SumFitValue;
Prob_Ave_x=0;
Prob_Ave_x(1)=Ave_x(1);
for i=2:popsize
Prob_Ave_x(i)=Prob_Ave_x(i-1)+Ave_x(i);
end
% operators
% FaSelection = 1; % 设置默认值
for k=1:popsize
rd = rand;
for n=1:popsize
if rd<=Prob_Ave_x(n)
FaSelection = n; % 由轮盘赌策略选择父代
break;
end
end
MoSelection=floor(rand() * (popsize-1))+1; % 随机确定母代
PosCrossover = floor(rand() * (CodeLen-2))+1; % 随机确定交叉点的位置
r1 = rand;
% 发生交叉操作
if r1<=px
nx(k, 1:PosCrossover) = x(FaSelection, 1:PosCrossover);
nx(k, (PosCrossover+1):CodeLen) = x(MoSelection, (PosCrossover+1):CodeLen);
r2 = rand;
% 进行变异操作
if r2<=pm
PosMutation = round(rand()*(CodeLen-1)+1); % 变异元素的位置
nx(k, PosMutation) = ~nx(k, PosMutation);
end
% 否则直接继承父代
else
nx(k, :)=x(FaSelection, :);
end
end
x = nx;
for m=1:popsize
% 计算适应度函数值
FitValue(m)=func(Decl(LB, UB, x(m, :), CodeLen));
end
[~, index]=max(FitValue); % 目标函数为求取极大值
best = x(index, :);
x(popsize, :)=best;
end
max_x = Decl(LB, UB, best, CodeLen);
max_fval = func(max_x);
end
% 初始化函数, 进行二进制编码
function y = init(L)
for i=1:L
y(i) = round(rand());
end
end
% 二进制编码转回十进制编码
function y=Decl(LB, UB, x, CodeLen)
nvar = size(LB, 1);
sublen = CodeLen/nvar;
bit_w = 2.^(0:sublen); % 计算位权
maxintval = 2^sublen-1;
range = UB'-LB';
start = 1;
fin = sublen;
for j = 1:nvar
tvars(1:sublen)=x(start:fin);
start = start+sublen;
fin = fin+sublen;
t_sum = 0;
for k=1:sublen
t_sum = t_sum+bit_w(k)*tvars(sublen-k+1);
end
y(j)=(range(j)*(t_sum/maxintval))+LB(j);
end
end
Demo2: GA
使用二进制编码,编写GA算法求解
function [max_x, max_fval] = MLYGA2(func, LB, UB, popsize, iter_max, px, pm, esp)
%func: 待优化的目标函数
% LB: 自变量的下界
% UB: 自变量的上界
% popsize: 种群大小
% iter_max: 最大迭代次数
% px: 交叉概率
% pm: 变异概率
% epsl: 自变量离散精度
if isempty(pm)
pm=0.1;
end
if isempty(px)
px=0.90;
end
if isempty(iter_max)
iter_max=8000;
end
if isempty(popsize)
popsize=50;
end
if isempty(LB) && isempty(UB)
nvar = input('请输入变量的数目nvar=');
else
nvar = size(LB, 1);
end
global fitall
fitall = zeros(1, iter_max);
CodeLen = nvar*max(ceil(log2((UB-LB)/esp+1))); % 根据自变量的离散精度,确定二进制编码串的长度
x = zeros(popsize, CodeLen); % 种群编码的初始值
for i=1:popsize
x(i, :)=init(CodeLen); % 调用子程序初始化种群
FitValue(i) = func(Decl(LB, UB, x(i, :), CodeLen)); % 计算个体适应值
end
for j=1:iter_max
SumFitValue = sum(FitValue); % 所有个体的适应值之和
Ave_x = FitValue/SumFitValue;
Prob_Ave_x=0;
Prob_Ave_x(1)=Ave_x(1);
for i=2:popsize
Prob_Ave_x(i)=Prob_Ave_x(i-1)+Ave_x(i);
end
% operators
% FaSelection = 1; % 设置默认值
for k=1:popsize
rd = rand;
for n=1:popsize
if rd<=Prob_Ave_x(n)
FaSelection = n; % 由轮盘赌策略选择父代
break;
end
end
MoSelection=floor(rand() * (popsize-1))+1; % 随机确定母代
PosCrossover = floor(rand() * (CodeLen-2))+1; % 随机确定交叉点的位置
r1 = rand;
% 发生交叉操作
if r1<=px
nx(k, 1:PosCrossover) = x(FaSelection, 1:PosCrossover);
nx(k, (PosCrossover+1):CodeLen) = x(MoSelection, (PosCrossover+1):CodeLen);
r2 = rand;
% 进行变异操作
if r2<=pm
PosMutation = round(rand()*(CodeLen-1)+1); % 变异元素的位置
nx(k, PosMutation) = ~nx(k, PosMutation);
end
% 否则直接继承父代
else
nx(k, :)=x(FaSelection, :);
end
end
x = nx;
for m=1:popsize
% 计算适应度函数值
FitValue(m)=func(Decl(LB, UB, x(m, :), CodeLen));
end
[bestV, index]=max(FitValue); % 目标函数为求取极大值
best = x(index, :);
x(popsize, :)=best;
fitall(j)=bestV;
end
max_x = Decl(LB, UB, best, CodeLen);
max_fval = func(max_x);
end
% 初始化函数, 进行二进制编码
function y = init(L)
for i=1:L
y(i) = round(rand());
end
end
% 二进制编码转回十进制编码
function y=Decl(LB, UB, x, CodeLen)
nvar = size(LB, 1);
sublen = CodeLen/nvar;
bit_w = 2.^(0:sublen); % 计算位权
maxintval = 2^sublen-1;
range = UB'-LB';
start = 1;
fin = sublen;
for j = 1:nvar
tvars(1:sublen)=x(start:fin);
start = start+sublen;
fin = fin+sublen;
t_sum = 0;
for k=1:sublen
t_sum = t_sum+bit_w(k)*tvars(sublen-k+1);
end
y(j)=(range(j)*(t_sum/maxintval))+LB(j);
end
end
使用MATLAB
自带的GA工具箱求解
% 使用自带的GA工具箱求解
global fitall_ga;
fitall_ga = zeros(1, Ngen);
% ops = optimoptions('ga', 'Generations', Ngen, 'PlotFcn', @gaplotbestf);
ops = optimoptions('ga', 'Generations', Ngen, 'OutputFcn', @myout, 'CrossoverFraction', 0.2);
[max_x_ga, maxfval_ga, ~, output, population, scores] = ga(@obj_func_3x, 2, [], [], [], [], LB, UB, [], ops);
plot(1:output.generations, -fitall_ga(:, 1:output.generations));
grid on;
Demo3: GA
求解下列函数的最小值
f ( x ) = − x 2 + 2 x + 0.5 , − 10 ≤ x , y ≤ 10 f(x)=-x^2+2x+0.5, -10\leq x, y\leq 10 f(x)=−x2+2x+0.5,−10≤x,y≤10
主函数
%%
[MinValue, MinFunc]=MLYGA3(@obj_func_3r, -10, 10, 0.001);
% GA工具箱求解
[x_ga, MinFunc_ga, ~, output, population, scores] = ga(@obj_func_3r, 1, [], [], [], [], -10, 10);
实数编码GA求解
function [MinValue, MinFunc] = MLYGA3(func, LB, UB, eps)
%eps为精度
n = ceil(log2((UB-LB)/eps+1));
individual = {};
for i=1:n
individual = [individual; [0 1]];
end
individualCode = exhaus(individual); % 枚举所有可能排列
% 染色体编码对应的10进制数
individualCodeValue = zeros(1, 2^n);
for i=1:2^n
for j=1:n
individualCodeValue(i)=individualCodeValue(i)+individualCode(i, j)*2^(n-j);
end
end
% 染色体编码对应给定定义域的实数(real-code)
CodeValue=zeros(1, 2^n);
for k=1:2^n
CodeValue(k)=CodeValue(k)+LB+individualCodeValue(k)*(UB-LB)/(2^n-1);
end
% 始终令第一个值为最小值
MinFunc=func(CodeValue(1));
MinIndividual = individualCode(1);
MinValue = CodeValue(1);
for i=2:2^n
FuncValue(i)=func(CodeValue(i));
if FuncValue(i)<MinFunc
MinFunc=FuncValue(i);
MinIndividual = individualCode(i);
MinValue = CodeValue(i);
end
end
end
Demo4: EP
使用进化计算求解
f i ( x ) = ∑ i = 1 n [ x i 2 − 10 cos ( 2 π x i ) + 10 ] , ∣ x i ∣ ≤ 5.12 f_i(x)=\sum_{i=1}^n[x_i^2-10\cos(2\pi x_i)+10], |x_i|\leq 5.12 fi(x)=i=1∑n[xi2−10cos(2πxi)+10],∣xi∣≤5.12
与遗传算法的出发点不同, 进化规划是从整体的角度出发来模拟生物的进化过程,在进化规划中不使用交叉等个体重组的算子,所以在进化规划中,个体的变异操作是唯一的个体最优搜索方法. 高斯变异算子是在变异过程中,通过计算每个个体适应度函数值的线性变换的平方根来获得该个体变异的标准差 σ i \sigma_i σi,并将每个分量上加上一个服从正态分布的随机数
X ( t + 1 ) = X ( t ) + N ( 0 , σ ) σ ( t + 1 ) = β F ( X ( t ) ) + γ x i ( t + 1 ) = x i ( t ) + N ( 0 , σ ( t + 1 ) ) \begin{aligned} &X(t+1)=X(t)+N(0, \sigma)\\ &\sigma(t+1)=\sqrt{\beta F(X(t))+\gamma}\\ &x_i(t+1)=x_i(t)+N(0, \sigma(t+1)) \end{aligned} X(t+1)=X(t)+N(0,σ)σ(t+1)=βF(X(t))+γxi(t+1)=xi(t)+N(0,σ(t+1))
EP
进化规划中,选择操作是按照一种随机竞争的方式,根据适应度函数值从父代和子代的 2 N 2N 2N个个体中选择 N N N个较好的个体组成下一代种群。选择方法有按照概率选择,锦标赛选择和精英选择三种,常用的是锦标赛选择:
- 将 N N N个父代个体组成的种群和经过一次变异运算后得到的 N N N个子代个体合并,组成一个共含有 2 N 2N 2N个个体的集合 I I I.
- 对每个个体 x i ∈ I x_i\in I xi∈I,从 I I I中随机选择 q q q个个体,并将 q q q个个体的适应度函数值与 x i x_i xi的适应度函数做比较,计算这 q ( q ≥ 1 ) q(q\geq 1) q(q≥1)个个体中适应度函数值比 x i x_i xi的适应度差的个体数量 w i w_i wi,并将 w i w_i wi作为 x i x_i xi的得分.
- 在所有 2 N 2N 2N个体都经过比较后,按每个个体的得分 w i w_i wi进行排序,选择 N N N个具有最高得分的个体作为下一代种群.
可以发现, q q q值是选择算子的关键,当 q q q值较大时,算子偏向确定性选择;当 q = 2 N q=2N q=2N时,算子确定从 2 N 2N 2N个个体中选择 N N N个适应度较高的个体,容易出现早熟等弊端. 而当 q q q值取值较小时,算子偏向于随机性选择,使得适应度的控制能力下降,导致大量低适应度值的个体被选出,造成种群退化.
CEP
自适应的标准进化规划算法
- 随机产生由 μ \mu μ个个体组成的种群,并设 k = 1 k=1 k=1,每个个体用一个实数对 ( x i , η i ) , ∀ i ∈ { 1 , 2 , … , μ } (x_i, \eta_i), \forall i\in\{1,2,\dots, \mu\} (xi,ηi),∀i∈{ 1,2,…,μ}表示,其中 x i x_i xi是目标变量, η i \eta_i ηi是正态分布标准差.
- 计算种群中每个个体关于目标函数的适应度函数值,在求解函数最小问题中,适应度函数值即为目标函数值 f ( x i ) f(x_i) f(xi).
- 对于每个个体 ( x i , η i ) (x_i, \eta_i) (xi,ηi),通过以下方法产生唯一的后代 ( x i ′ , η i ′ ) (x_i',\eta_i') (xi′,ηi′).
x i ′ ( j ) = x i ( j ) + η i ( j ) N j ( 0 , 1 ) η i ′ = η i ( j ) exp ( τ ′ N ( 0 , 1 ) + τ N j ( 0 , 1 ) ) \begin{aligned} &x_i'(j)=x_i(j)+\eta_i(j)N_j(0, 1)\\ &\eta'_i=\eta_i(j)\exp(\tau'N(0, 1)+\tau N_j(0, 1)) \end{aligned} xi′(j)=xi(j)+ηi(j)Nj(0,1)ηi′=ηi(j)exp(τ′N(0,1)+τNj(0,1))
SPMEP
单点变异算法是在CEP算法的基础上对个体的变异方法进行改进,在每次迭代中,仅对每个父代个体中的一个分量执行变异操作,提高了计算效率. 在SPMEP算法中后代产生的方法为
x i ′ ( j i ) = x i ( j i ) + η i N i ( 0 , 1 ) η i ′ ( j ) = η i ( j ) exp ( − α ) \begin{aligned} &x'_i(j_i)=x_i(j_i)+\eta_iN_i(0, 1)\\ &\eta'_i(j)=\eta_i(j)\exp(-\alpha) \end{aligned} xi′(ji)=xi(ji)+ηiNi(0,1)ηi′(j)=ηi(j)exp(−α)
其中 α = 1.01 \alpha=1.01 α=1.01,SPMEP算法求解高维多模函数问题具有明显的优越性,该算法也具有良好的稳定性.
对比进化算法和GA的求解
function [minx, minf]=MLYEP(func, popsize, iter_max, LB, UB, type)
global fitall
nvar = size(LB, 1); % 得到变量的个数
tau1=sqrt(2*nvar)^(-1); % CEP中的进化参数t1
tau2=sqrt(2*sqrt(nvar))^(-1); % CEP中的进化参数t2
q = round(0.9*popsize); % q值的设定,每次考虑90%的种群个体
chome=zeros(popsize, nvar);
for i=1:popsize
for j=1:nvar
chome(:, j)=unifrnd(LB(j), UB(j), popsize, 1); % 初始化
chomeLambda(j)=(UB(j)-LB(j))/2;
chomeVar(j)=var(chome(:, j));
end
chomeV(i, 1)=func(chome(i, :)); % 计算适应度
chomeSigma(i, 1)=sqrt(chomeV(i, 1));
end
[a, b]=sort(chomeV);
chome=chome(b, :);
chomeV=chomeV(b);
chomeSigma=chomeSigma(b);
minx=chome(1, :);
minf=chomeV(1);
for i=1:iter_max
if type==1 % 标准
for j=1:popsize
for k=1:nvar
newchome(j, k)=chome(j, k)+normrnd(0, chomeSigma(k), 1, 1);
newchome(j, k)=boundtest(newchome(j, k), LB(k), UB(k)); % 进行边界检测
end
end
elseif type==2 % 自适应, 使用一对实数对表示个体
for j=1:popsize
a = randn;
for k=1:nvar
newchome(j, k)=chome(j, k)+randn*chomeVar(k);
newchome(j, k)=boundtest(newchome(j, k), LB(k), UB(k));
chomeVar(k)=chomeVar(k)*exp(tau1*a+tau2*randn);
end
end
elseif type==3 % 单点变异
for j=1:popsize
b1 = ceil(nvar*rand);
if chomeLambda(b1)<1e-4
chomeLambda(b1)=(UB(b1)-LB(b1))/2;
end
newchome(j, b1)=chome(j, b1)+chomeLambda(b1)*randn;
newchome(j, b1)=boundtest(newchome(j, b1), LB(b1), UB(b1));
chomeLambda(b1)=chomeLambda(b1)*exp(-1.01);
end
end
for j=1:popsize
newchomeV(j, 1)=func(newchome(j, :));
end
chome=EPSelect(chome, newchome, chomeV, newchomeV, q); % 选择子代
for j=1:popsize
chomeV(j, 1)=func(chome(j, :));
chomeSigma(j, 1)=sqrt(chomeV(j, 1));
end
[~, b]=sort(chomeV); % 根据适应度值进行排序
chome=chome(b, :);
chomeV = chomeV(b);
chomeSigma = chomeSigma(b);
if minf>chomeV(1)
minx=chome(1, :);
minf=chomeV(1);
end
fitall(i)=minf;
end
end
% 选择算子
function chome=EPSelect(old, new, oldF, newF, q)
num=size(old, 1);
total_chome=[old; new]; % 合并父代和子代
total_F = [oldF; newF]; % 合并父代和子代的适应度函数
competitor = randperm(2*num);
for i=1:2*num
score = 0;
for j=1:q
if total_F(i)<total_F(competitor(j))
score = score+1;
end
end
templ(i)=score;
end
[~, b]=sort(templ, 'descend');
total_chome=total_chome(b, :);
chome=total_chome(1:num, :);
end
function y=boundtest(x, LB, UB)
if x>=UB
y=LB+(x-UB);
elseif x<=LB
y=UB-(LB-x);
else
y=x;
end
end
SPMEP适应度曲线(EP和CEP陷入到了局部最优之中)
GA工具箱求解
%% GA求解
global fitall_ga;
fitall_ga = zeros(1, iter_max);
ops = optimoptions('ga', 'Generations', iter_max, 'OutputFcn', @myout);
[minx_ga, minf_ga, ~, output, population, scores]=ga(@obj_func_7x, 10, [], [], [], [], LB, UB,[],ops);
plot(1:output.generations, fitall_ga(:, 1:output.generations));
grid on;
Reference
最优化方法及其Matlab实现