- 1.编码
GA包括浮点编码以及二进制编码,这里介绍后者,因为既符合计算机二进制工作原理又能方便表示染色体变异、基因突变等概念。设某一参数取值范围为(L,U),使用长度为k的二进制编码该参数,有
2k
2^k种不同编码。有对应关系:
00000000000=0−→L
00000000000=0 \xrightarrow{}L
00000000001=1−→L+δ
00000000001=1 \xrightarrow{}L +\delta
00000000010=2−→L+2δ
00000000010=2 \xrightarrow{}L+2\delta
…
…
11111111111=2k−1−→U=L+(2k−1)∗δ
11111111111=2^k-1 \xrightarrow{}U=L+(2^k-1 )*\delta 因此,
δ=(U−L)/(2k−1)
\delta=(U-L)/(2^{k}-1)
- 2.解码
解码就是把二进制数化为10进制,转换公式为
x=L+(∑i=1kbi2i−1)∗(U−L)/(2k−1−1)
x=L+(\sum_{i=1}{k}b_{i}2{i-1})*(U-L)/(2^{k-1}-1)
- 3.个体适应度评估(即目标函数值)
先随机产生(L,U)范围内的二进制数串(需初始种群数量),再解码为对应的10进制数,代入y=(x1,x2,…),求出对应的多组适应度值,即y值,对所有y值求和并求出每个y所占比例(适应度所占概率)以及每一个一个下来的累积概率 - 4.复制与剔除(进化与自然选择)
根据6求得的适应度所占概率表格,先产生一组随机数(数量和初始化种群数一致),判定每个随机数在累积概率的哪个区间,例如:第一个随机数是0.1,累积概率序列为(对应染色体序列)0.02,0.05,0.2,1,则0.05<0.1<0.2,落在第2、3个区间中,3对应的染色体被选中。对所有产生的随机数如此操作。 - 5.新种群交配
对7筛选出来的新的染色体交配(交叉互换)产生新个体 - 6.基因突变
先定下突变概率。如概率为0.01,有10个个体,染色体对应的二进制数串有33位,则新一代(即8产生后代)有33*10*0.01=3.3个突变基因。由于,突变几率对于每个染色体概率均等,先产生330个0-1之间的随机数(对应330个基因序列),挑出<0.01的对应染色体,并找出对应的基因所在染色体序列位置以及基因的位数。 - 7.循环
然后,把突变后的新种群染色体(二进制数串)再转为10进制代入目标函数求得适应度。返回4,不断循环(可设置循环次数,即代数),最后如果都是同一个体(即均为同一个染色体二进制数串)或到达最大迭代代数时,跳出循环,得到对应染色体数串时的目标函数值为最优值。 - 伪代码
%Matlab & GA
%遗传算法伪代码(GA's pseudocode)
BEGINdd
t=0; %遗传代数
初始化P(t); %初始化种群或染色体
计算P(t)的适应值;
while(不满足停止法则)do
begin
t=t+1;
从P(t-1)中选择P(t); %选择
重组P(t); %交叉&变异
计算P(t)的适应值;
end
END
- Attention
建议:初始化种群数量为0-100;变异概率为0.0001-0.2;
交配概率为0.4-0.99;进化代数为100-500.
个人认为,简单看来,遗传算法的目的是:求解特定约束下,目标函数的最优值(max or min)。以下为例子代码,一切尽在代码中。
- 求解
maxf(x)=200e−0.05xsin(x),x∈[−2,2]
max f(x)=200e^{-0.05x}sin(x),x\in[-2,2]
(1)在求解之前,先用Matlab画出该函数在[-2,2]中的图像,代码如下:
%matlab画图
x=[-2:0.1:2];
y=200.*exp(-0.05.*x).*sin(x);
plot(x,y);
grid on;
xlabel('x');ylabel('f(x)');
title('函数图像');
下图为结果输出:
由上图估计,max f(x)大概在(1.543,185.1)的坐标位置。
(2)以下为matlab代码(待更)
由于代码过长,分为几个函数po出,需要慢慢看懂代码才是关键啊。。。打码时,把子函数存为M文件,主程序main.m为代码调用子函数。
以下为主程序:
%主程序main:用遗传算法求解y=200\*exp(-0.05\*x).\*sin(x)在[-2,2]区间上的最大值
clc;
clear all;
close all;
global BitLength
global BitLength2
global BitLength3
global boundsbegin
global boundsend
global bounds2begin
global bounds2end
global bounds3begin
global bounds3end
bounds=[-2 2];%一维自变量的取值范围
precision=0.0001; %运算精度
boundsbegin=bounds(:,1);
boundsend=bounds(:,2);
bounds2begin=bounds2(:,1);
bounds2end=bounds2(:,2);
bounds3begin=bounds3(:,1);
bounds3end=bounds3(:,2);
%计算如果满足求解精度至少需要多长的染色体
BitLength=ceil(log2((boundsend-boundsbegin)' ./ precision));
BitLength2=ceil(log2((bounds2end-bounds2begin)' ./ precision));
BitLength3=ceil(log2((bounds3end-bounds3begin)' ./ precision));
popsize=300; %初始种群大小
Generationnmax=500; %最大代数
pcrossover=0.90; %交配概率
pmutation=0.09; %变异概率
%产生初始种群
population=round(rand(popsize,BitLength+BitLength2+BitLength3));
%计算适应度,返回适应度Fitvalue和累积概率cumsump
[Fitvalue,cumsump]=fitnessfun(population);
Generation=1;
while Generation<Generationnmax+1
for j=1:2:popsize
%选择操作
seln=selection(population,cumsump);
%交叉操作
scro=crossover(population,seln,pcrossover);
scnew(j,:)=scro(1,:);
scnew(j+1,:)=scro(2,:);
%变异操作
smnew(j,:)=mutation(scnew(j,:),pmutation);
smnew(j+1,:)=mutation(scnew(j+1,:),pmutation);
end
population=smnew; %产生了新的种群
%计算新种群的适应度
[Fitvalue,cumsump]=fitnessfun(population);
%记录当前代最好的适应度和平均适应度
[fmax,nmax]=max(Fitvalue);
fmean=mean(Fitvalue);
ymax(Generation)=fmax;
ymean(Generation)=fmean;
%记录当前代的最佳染色体个体
x=transform2to10(population(nmax,:),BitLength);
x2=transform2to10\_2(population(nmax,:),BitLength,BitLength2);
x3=transform2to10\_3(population(nmax,:),BitLength,BitLength2,BitLength3);
%根据自变量取值范围,需要把经过遗传运算的最佳染色体整合到取值范围的区间
xx=boundsbegin+x\*(boundsend-boundsbegin)/(power(2,BitLength)-1);
xx2=bounds2begin+x2\*(bounds2end-bounds2begin)/(power(2,BitLength2)-1);
xx3=bounds3begin+x3\*(bounds3end-bounds3begin)/(power(2,BitLength3)-1);
%求解出变量的十进制结果
xmax(Generation,:)=[xx,xx2,xx3];
Generation=Generation+1
end
Generation=Generation-1;
Bestpopulation=[xx,xx2,xx3]
Besttargetfunvalue=targetfun(xx,xx2,xx3)
%绘制经过遗传运算后的适应度曲线。一般地,如果进化过程中种群的平均适应度与最大适
%应度在曲线上有相互趋同的形态,表示算法收敛进行得很顺利,没有出现震荡;在这种前
%提下,最大适应度个体连续若干代都没有发生进化表明种群已经成熟。
figure(1);
hand1=plot(1:Generation,ymax);
set(hand1,'linestyle','-','linewidth',1.8,'marker','\*','markersize',6)
hold on;
hand2=plot(1:Generation,ymean);
set(hand2,'color','r','linestyle','-','linewidth',1.8,...
'marker','h','markersize',6)
xlabel('进化代数');ylabel('最大/平均适应度');xlim([1 Generationnmax]);
legend('最大适应度','平均适应度');
box off;hold off;
以下为各个零散的子函数的子程序:
- crossover.m
%子程序:新种群交叉操作,函数名称存储为crossover.m
function scro=crossover(population,seln,pc);
BitLength=size(population,2);
pcc=IfCroIfMut(pc); %根据交叉概率决定是否进行交叉操作,1则是,0则否
if pcc==1
chb=round(rand*(BitLength-2))+1; %在[1,BitLength-1]范围内随机产生一个交叉位
scro(1,:)=[population(seln(1),1:chb) population(seln(2),chb+1:BitLength)];
scro(2,:)=[population(seln(2),1:chb) population(seln(1),chb+1:BitLength)];
else
scro(1,:)=population(seln(1),:);
scro(2,:)=population(seln(2),:);
end
- fitnessfun.m
%子程序:计算适应度函数, 函数名称存储为fitnessfun
function [Fitvalue,cumsump]=fitnessfun(population);
global BitLength
global BitLength2
global BitLength3
global boundsbegin
global boundsend
global bounds2begin
global bounds2end
global bounds3begin
global bounds3end
popsize=size(population,1); %有popsize个个体
for i=1:popsize
x=transform2to10(population(i,:),BitLength); %将二进制转换为十进制
x2=transform2to10_2(population(i,:),BitLength,BitLength2);
x3=transform2to10_3(population(i,:),BitLength,BitLength2,BitLength3);
%转化为[-2,2]区间的实数
xx=boundsbegin+x*(boundsend-boundsbegin)/(power(2,BitLength)-1);
xx2=bounds2begin+x2*(bounds2end-bounds2begin)/(power(2,BitLength2)-1);
xx3=bounds3begin+x3*(bounds3end-bounds3begin)/(power(2,BitLength3)-1);