文章目录
过程:①编码–>初始化种群–>(计算适应度值–>②选择–>③交叉–>④变异–>新种群–>判断是否满足条件)–>解码
1. 编码
1.1 二进制编码
1.1.1 编码长度
每个自变量编码长度之和。其中自变量的编码长度为:
(a,b)代表自变量的取值范围,eps是要求的精度
%% 1.计算二进制编码的长度
for i=1:varnum
L(i) = ceil(log2(ub(i)-lb(i)/eps + 1)); %求解每个变量的长度
end
LS = sum(L); %二进制编码的总长度
%% 2.初始化种群
pop = randi([0 1],n,LS); % 种群
spoint = cumsum([0 L]); % 保存各变量对应二进制编码的位置
1.1.2 解码
将二进制数据转换为十进制
其中X为二进制转化为十进制的整数值
function real = decode(pop,lb,ub)
[row col] = size(pop);
% 1.计算X
for i=col:-1:1
temp(i) = 2^(i-1)*pop(i);
end
X = sum(temp);
% 2.二进制-->十进制转换公式
real = lb + X*(ub-lb)/(2^col-1);
end
1.2 适应度函数计算与转换
fval = Objfun(x); % 直接计算适应度值
Cmin/Cmax转换(最简单 但效果不佳)
其中Cmin.Cmax可以是特定的输入值,也可以是目标函数的最大最小值
①最大值问题
function fitvalue = fitnessfun(x)
Cmin = 0.01; % 0 or 0.1
row = size(x,1);
for i=1:row
fval = Objfun(x(i,:)); % 种群中第i个个体的函数值
if fval+Cmin > 0
fitvalue(i) = fval+Cmin;
else
fitvalue(i) = 0;
end
end
end
②最小值问题
function fitvalue = fitnessfun(x)
% 1.计算Cmax
row = size(x,1);
temp = zeros(1,row);
for i=1:row
temp(i) = Objfun(x(i,:));
end
Cmax = max(temp);
% 2.适应度转换
for i=1:row
fval = Objfun(x(i,:)); % 种群中第i个个体的函数值
if fval < Cmax
fitvalue(i) = Cmax-fval;
else
fitvalue(i) = 0;
end
end
end
线性变换1(分max min)
函数表达式:F(x) = af(x)+b
max问题: F(x) = f(x)-fmin+σ
min问题:F(x) = fmax-f(x)+σ
其中σ是一个较小的数,可使种群中最差的个体也有繁殖的机会(具体取值可以由数值量级决定)
①max问题
case '线性变化1'
kesai =0.1; //数值根据数量级决定
fmin = min(fval);
fitvalue = fval-fmin+kesai;
②min问题
case '线性变化1'
kesai = 0.1;
fmax = max(fval);
fitvalue = fmax-fval+kesai
线性变换2
函数表达式:F(x) = af(x)+b
case '线性变换2'
C =1.5; // C取值为1.2~2
fmin = min(fval);
fmax = max(fval);
favg = sum(fval)/size(x,1);
if fmin >(C*favg-fmax)/(C-1)
a =(C-1)*favg/(fmax-favg);
b = (fmax-C*favg)*favg/(fmax-favg);
else
a = favg/(favg-fmin);
b = favg*fmin/(favg-fmin);
end
fitvalue =a*fval+b;
动态线性变换(推荐)
目的:M是一个较小的数,可使种群中最差的个体仍然有繁殖的机会。M随着迭代次数的增加,使附加值M逐渐减小,实现动态调节的目的
①max问题
case '动态线性变换'
c = unifrnd(0.9,0.999);
M = M*c; % 动态变换
fmin = min(fval);
fitvalue = fval-fmin+M; % fval越大,fitvalue越大
②min问题
case '动态线性变换'
c = unifrnd(0.9,0.999);
M = M*c;
fmax = max(fval);
fitvalue =fmax-fval+M; % fval越小,fitvalue越大
指数变换
(1)保证了适应度函数的非负性,因此原适应度函数可以直接取目标函数
(2)原适应度越大,则变换后的适应度越小。原适应度越小,变换后的适应度越大。因此根据适应度值选择操作的遗传算法的指数变换适合求解问题的最小值。若问题本身是最大值问题,则需转化为求最小值问题,如将原函数乘-1.
(3)α取值越小,变化前较大适应度个体的新适应度值与变化前较小适应度个体的新适应度值差距减小。反之,若α取值越大,两者的差距加大。
case '指数变换'
alfa = -0.5; % max问题,alfa可取负值 min问题,alfa取正值
fitvalue = exp(-alfa*fval);
2. 选择
搭配:精英保存+确定式采样
从种群中选择父代和母代,用于遗传变异。
2.1 轮盘赌选择法(随机误差较大)
(1)步骤
①计算各个体的适应度f_i
②每个个体被选中的概率p_i=f_i / Σf_i以及累积概率P_i
③随机产生[0 1]之间的随机数r
④比较P_1,P_2,…与r的值,选中第一个大于r的值
function [dad,mom] = selection(pop,fitvalue)
% 1.计算累加概率
p = fitvalue ./ sum(fitvalue);
PP = cumsum(p);
% 2.选择父代和母代
% 父代根据轮盘赌进行选择
row = size(pop,1);
for i=1:row
%选中第一个大于r的值
r = rand(1)
for j=1:row
if r < PP(j)
dad(i,:) = pop(j,:);
break
end
end
% 母代在原有种群中随机选择
mom(i,:) = pop(randi([1 row]),:);
end
end
特点:由于随即操作的原因,这种选择方法的随机误差比较大,有时甚至连适应度较高的个体也选择不上。
2.2 排序选择(忽略实际差别)
特点:抹杀个体适应度的实际差别,未能充分运用遗传信息(基于轮盘赌)
function [dad,mom] = selection(pop,fitvalue,q)
% 1. 按适应度大小排序,并计算个体与累加概率
row = size(pop,1);
[sortf,Sindex] = sort(fitvalue,'descend');
pop =pop(Sindex,:); % 排序后得到的种群个体排布
% 2. 计算个体概率与累加概率
P = q*(1-q).^((1:row)-1)/(1-(1-q)^row);
PP = cumsum(P);
% 3. 轮盘赌选择row个种群个体
for i=1:row
r =rand(1);
for j=1:row
if r <= PP(j)
dad(i,:) = pop(j,:); % 父代选择
break;
end
end
mom(i,:) =pop(randi([1 row]),:); % 母代选择
end
2.3 精英保存(配合其他选择算法)
由于选择、交叉、变异等遗传操作的随机性,当前群体中适应度最好的个体可能被破坏掉,从而降低了群体的平均适应度,影响遗传算法的运行效率和收敛速度。
将当前群体中适应度最高的个体不参与交叉运算和变异运算,用它来替换掉本代群体中经过交叉、变异等遗传操作后所产生的适应度最低的个体。
(注意:精英保存是一种用历史最优替换经过交叉、变异操作后最差个体的方法,因此可以将其理解为一种优化而非新的选择方法,此方法需要与其他选择方法配合使用)
function newpop = eselection(pop,bestfitvalue,bestx)
global n varnum lb ub L
% 1.计算各个体的适应度
spoint = cumsum([0 L]); % 各变量在编码中的位置
for i=1:n
for j=1:varnum % spoint长varnum+1
startpoint = spoint(j)+1;
endpoint = spoint(j+1);
real(i,j) = decode(pop(i,startpoint:endpoint),lb(j),ub(j))
end
end
fitvalue = fitnessfun(real);
% 2.找到最优与最差个体的值与对应的行(个体序号)
[Gbestfitvalue,Gbestindex] = max(fitvalue);
[Gbadfitvalue,Gbadindex] = min(fitvalue);
% 3.更新全局最优值
if Gbestfitvalue > bestfitvalue
bestfitvalue = Gbestfitvalue;
bestx = pop(Gbestindex(1),:);
end
% 4.历史最优值替换当前最差个体值
pop(Gbadindex(1),:) = bestx;
newpop = pop;
end
语法知识:[Y,U] = max(A)
其中,Y记录A中每列的最大值,U记录每列最大值Y对应的行号
特点:精英保存为选择操作的一部分,可保证迄今为止所得到的最有个体不会被交叉、变异等遗传运算所破坏,它是遗传算法收敛性的一个重要保证条件。但是,容易使某个局部最优个体不易被淘汰反而快速扩散,从而使算法全局搜索能力不强。该算法一般要与其他选择操作方法配合起来使用,方可有良好的效果。
2.4 锦标赛选择法(较优个体保留)
每次从种群中取出一定数量的个体,然后选择其中最好的一个进入子代种群。重复该步骤,直到新的种群达到原来的种群规模。
注意:sn越大,每次选出的优胜者具有较高的适应度(但同时可能选择多个相同个体)。sn越小,优胜者的适应度或高或低,随机性很强
function [dad,mom] = selection(pop,fitvalue)
global sn
row = size(pop,1);
for i=1:row
% 1.从种群中等概率选取sn个个体
r = randi([1 row],sn,1);
% 2.跟局适应度值,选择适应度最优个体
[bestval,bestindex] = max(fitvalue(r));
% note:最大值max 最小值min
dad(i,:) = pop(bestindex,:);
mom(i,:) = pop(randi([1 row]),:);
end
end
2.5 确定式采样选择(简单的较优个体保留)
人为地控制对个体的选择操作,其基本思想是按照一种确定的方式来进行选择。
注意:可保证适应度较大的一些个体一定能够被保存在下一代群体中,并且操作简单。
语法知识:[r,c,v] = find(A)
r,c,v分别返回A中非零元素的行、列号与对应元素值
function [dad,mom] = selection(pop,fitvalue)
row = size(pop,1);
% 1.计算每个个体在下一代中生存期望数目
N = row*fitvalue / sum(fitvalue);
Int = floor(N); % 数值取整
[r,~,v] = find(Int); % 找到非零值与对应行列
Newindex = cumsum([0;v]); % 个体数目和累加
% 2.由期望数目个个体组成的下一代种群
for i=1:length(r)
for j=Newindex(i)+1:Newindex(i+1)
dad(j,:) = pop(r(i),:);
end
end
% 3.按小数部分降序排列,将剩余数量个体按照顺序加入种群
Float = mod(N,1);
[~,index] = sort(Float,'descend');
Left = row - sum(v); % 加入期望个体数量后剩余的个数
if Left >0
dad(row:-1:row-Left+1,:) = pop(index(1:Left),:);
end
mom(1:row,:) = pop(randi([1 row],row,1),:);
end
3. 交叉
3.1 单点交叉
eg:
dad:1000 0001 mom:0101 1111
单点交叉结果: 1000 1111 (父代前+母代后)
function newpop = crossover(dad,mom,pc)
[row size] = size(dad);
newpop = dad;
% 当大于交叉概率时,执行交叉,否则保持父代不变
for i=1:row
if rand(1) < pc
cpoint = randi([1 col-1]);
newpop(i,:) = [dad(i,1:cpoint) mom(i,cpoint+1:end)];
end
end
end
4. 变异
4.1 基本位变异
对某个个体的某一个位置发生变异
function newpop = mutation(pop,pm)
[row col] = size(pop);
newpop = pop;
for i=1:row
if rand(1) < pm % 满足变异概率
mpoint = randi([1 col]);
newpop(i,mpoint) = ~newpop(i,mpoint);
end
end
end
4.2 大变异遗传算法(跳出局部最优)
简单遗传算法存在一个早熟问题,也就是算法过早收敛于一个非全局最优解。出现这种问题的主要原因是当算法进行到某一代时,若种群中某个个体的适应度值远大于其他任何个体的适应度,该个体被选中的概率很大,会造成子代中多个个体来自同一祖先,从而彼此近似。
大变异算法:当某代所有个体集中在一起时,以一个远大于通常变异概率的概率执行一次变异操作,具有大变异概率的变异操作能随机、独立地产生许多新个体,从而使整个种群脱离“早熟”
GeneticAlgorithm.m
%% 参数设置
% 大变异概率 Lpm 10*pm
% 密集因子 alfa 0.5
% 大变异代数阈值 T 500 <maxgen
%% 变异
% 1.计算适应度,判断是否执行大变异
% 1.1 适应度值计算
for i=1:n
for j=1:varnum
startpoint =spoint(j)+1;
endpoint = spoint(j+1);
real(i,j) = decode(pop(i,startpoint:endpoint),lb(j),ub(j));
end
end
% 1.2 适应度转换
fitvalue =fitnessfun(real);
[Fmax,Bestindex] = max(fitvalue);
Favg = sum(fitvalue)/n;
% 1.3 判断是否执行大变异
if alfa*Fmax <Favg && iter <T
newpop = Lmutation(newpop,Lpm,Bestindex);
else
newpop = mutation(newpop,pm,Bestindex);
end
pop =newpop;
Lmutation.m
function newpop = Lmutation(pop,Lpm,Bestindex)
[row col] =size(pop);
newpop = pop;
for i=1:row
r = rand(1);
mpoint = randi([1 col]);
if r<Lpm && i~=Bestindex
newpop(i,mpoint) =~pop(i,mpoint);
end
end
end
5. 自适应交叉变异 (推荐)
遗传控制参数中的交叉概率Pc和变异概率Pm的选择是影响行为和性能的关键,直接影响算法的收敛性。
Pc越大,旧个体的模式被破坏的可能型越大,新个体产生的速度就越快。但Pc过高可能使优良的个体模式遭到破坏,Pc过小又会延缓新个体的产生,导致算法早熟。
Pm太小,不易形成新的个体,Pm过大,随机性增强。
引入自适应调整函数,使交叉和变异概率随个体适应度大小和群体的分散程度自动调整。
%% 参数设置:
% 交叉概率常数 pc1 0.5
% 交叉概率常数 pc2 0.9
% 变异概率常数 pm1 0.01
% 变异概率常数 pm2 0.05
crossover.m
function newpop = crossover(dad,mom,pc1,pc2)
global varnum L lb ub n
% 1. 计算适应度值
[row col] = size(dad);
spoint = cumsum([0 L]);
for i = 1:n
for j = 1:varnum
startpoint = spoint(j) + 1;
endpoint = spoint(j+1);
real(i,j) = decode(dad(i,startpoint:endpoint),lb(j),ub(j));
end
end
fitvalue = fitnessfun(real);
Maxfitvalue = max(fitvalue);
Meanfitvalue = sum(fitvalue)/n;
% 2. pc自适应变化
for i=1:n
% 2.1 母代自适应值求解
for j = 1:varnum
startpoint = spoint(j) + 1;
endpoint = spoint(j+1);
Mreal = decode(mom(i,startpoint:endpoint),lb(j),ub(j));
end
Mfit = fitnessfun(Mreal);
% 2.2 选择较大值f'并于平均数进行比较判断
if max(Mfit,fitvalue(i)) >= Meanfitvalue
pc =pc1*(Maxfitvalue-max(Mfit,fitvalue(i)))/(Maxfitvalue - Meanfitvalue);
else
pc = pc2; % 远离最优值,认为个体性能不佳,加快更新速度
end
if rand(1) <pc
cpoint = randi([1 col-1]);
newpop(i,:) = [dad(i,1:cpoint) mom(i,cpoint+1:end)];
else
newpop(i,:) = dad(i,:);
end
end
end
mutation.m
function newpop =mutation(pop,pm1,pm2)
global varnum L lb ub n
% 1. 计算适应度值
[row,col] = size(pop);
real = zeros(row,varnum);
spoint = cumsum([0 L]);
for i = 1:n
for j = 1:varnum
startpoint = spoint(j) + 1;
endpoint = spoint(j+1);
real(i,j) = decode(pop(i,startpoint:endpoint),lb(j),ub(j));
end
end
fitvalue = fitnessfun(real);
Maxfitvalue = max(fitvalue);
Meanfitvalue = sum(fitvalue) / n;
% 2. pm自适应变化
newpop = pop;
for i=1:row
f =fitvalue(i);
if f >=Meanfitvalue % 接近最大适应度值
pm = pm1*(Maxfitvalue-f)/(Maxfitvalue-Meanfitvalue);
else
pm = pm2; % 远离最有适应度值 加快更新速度
end
end
% 3. 变异
mpoint = randi([1 col]);
if rand(1) <pm
newpop(i,mpoint) = ~pop(i,mpoint);
end
end
Reference
Matlab2016数值计算与智能算法:
https://www.51zxw.net/List.aspx?cid=641