遗传算法,其本质上是一种进化算法,相比其他的算法应用范围比较广泛,特别是对于一些非线性、多模型、多目标的函数优化问题,用其他的优化方法较难求解,而遗传算法可以方便的得到较好的结果。不过正如我在PSO粒子群算法的文章中说道,每种算法的应用场景往往和所应用的问题相关,对于特定的问题,某一种优化算法可能展现出其他算法所达不到的效果。
想必遗传算法的原理大家都大概了解,这里就不过多赘述,总之也是一种在迭代中不断进化,探索,想最优情况靠近的一种迭代算法。遗传算法包括三个基本操作:选择、交叉和变异。不同改进的遗传算法,往往都是在这三个基本操作上进行改进。
本文给出的是基本的遗传算法程序,同样也是引自龚纯的这本《精通MATLAB最优计算》,用于求取优化函数的最大值,当然求最小值的情况只需更改目标函数的正负即可。要注意的是,本算法是遗传算法的最基本的格式,只能用于解决一维无约束的优化问题。由于略去了很多操作的原理比如编码操作、轮盘赌选择策略、交叉方法,变异方法等,我在代码上加了详细的备注,由于代码本身并不复杂,需要的读者自己阅读一下即可理解。下面给出基本遗传算法函数的调用格式:
function [xv,fv]=myGA(fitness,a,b,NP,NG,Pc,Pm,eps)
fitness是待优化函数,调用时可以自己编写后使用句柄调用,随后会举例展示调用的方法。除此之外的参数的意义分别是:
a:自变量下界;
b:自变量上界;
NP:种群大小;
Pc:杂交概率;
Pm:变异概率;
eps:自变量离散精度;
xm:目标函数取最大值时的自变量值;
fv:目标函数的最大值。
基本遗传算法的程序为:
function [xv,fv]=myGA(fitness,a,b,NP,NG,Pc,Pm,eps)
%待优化的目标函数:fitness
%自变量下界:a
%自变量上界:b
%种群个体数:NP
%最大进化代数:NG
%杂交概率:Pc
%变异概率:Pm
%自变量离散精度:eps
%目标函数取最小值时的自变量值:xm
%目标函数的最小值:fv
L = ceil(log2((b-a)/eps+1)); %根据离散精度,确定二进制编码需要的码长
x = zeros(NP,L); %NP行L列的全零矩阵
for i=1:NP
x(i,:) = Initial(L); %种群初始化
fx(i) = fitness(Dec(a,b,x(i,:),L)); %个体适应值
end
for k=1:NG
sumfx = sum(fx); %所有个体适应值之和
Px = fx/sumfx; %所有个体的选择概率
PPx = 0;
PPx(1) = Px(1);
for i=2:NP %从第二个开始
PPx(i) = PPx(i-1) + Px(i); %轮盘赌策略的概率累加
end
for i=1:NP
sita = rand(); %sita是0,1之间的随机数
for n=1:NP
if sita <= PPx(n)
SelFather = n; %根据轮盘赌策略确定的父亲
break;
end
end
Selmother = floor(rand()*(NP-1))+1;%随机选择母亲
posCut = floor(rand()*(L-2))+1; %随机群定交叉点
r1 = rand(); %r1为0,1之间随机数
if r1<=Pc %如果r1小于杂交概率,交叉
nx(i,1:posCut) = x(SelFather,1:posCut); %将切点前编码替换为父亲的
nx(i,(posCut+1):L) = x(Selmother,(posCut+1):L); %将切点后编码替换为母亲的
r2 = rand(); %r2为0,1之间随机数
if r2<=Pm %如果r2小于变异概率,变异
posMut = round(rand()*(L-1)+1);%随机确定变异位
nx(i,posMut) = ~nx(i,posMut); %变异位编码取非
end
else
nx(i,:) = x(SelFather,:); %若r1不小于杂交概率,则将该个体替换为父亲的编码
end
end
x = nx;
for i=1:NP
fx(i) = fitness(Dec(a,b,x(i,:),L)); %子代适应值
end
end
fv = -inf;
for i=1:NP
fitx = fitness(Dec(a,b,x(i,:),L));
if fitx > fv %取个体中的最好值作为最终结果
fv = fitx; %fv为最优解的函数值
xv = Dec(a,b,x(i,:),L); %xv为最优解的编码
end
end
function result = Initial(length) %初始化函数
for i=1:length
r = rand();
result(i) = round(r);
end
function y = Dec(a,b,x,L) %二进制编码转换为十进制编码
base = 2.^((L-1):-1:0);
y = dot(base,x);
y = a+y*(b-a)/(2^L-1);
再次提醒,本程序是最基本的遗传算法程序,只能解决一维无约束的优化问题,若对于多目标问题,其实上文的PSO算法可以完成,或者在本文的遗传算法上做一些更改,之后我也会更新多目标情况下的遗传算法程序。下面举例展示本程序的调用方法,首先将待优化的目标函数在MATLAB中写成函数的形式:
function F = fitness(x)
F = x^3-60*x^2+900*x+100;
现在用刚刚的遗传算法代码求该函数的最大值,设置自变量的范围是0-30,可以直接在命令行调用,其调用格式为:
[xv,fv] = myGA(@fitness,0,30,50,100,0.9,0.04,0.01)
运行结果为:
xv =
10.3223
fv =
4.0969e+03
遗传算法求得的结果的精度一方面与离散精度有关,另一方面与个体数目有关,离散精度决定了遗传算法能得到的最大精度,个体数目越大, 求得的结果精度越有可能达到离散精度。同样的迭代次数越大,也越有可能找到更优的解,不过也有可能陷入到局部最优中,所以需要适当的调整杂交概率与变异概率的大小。