最近利用学习遗传算法的使用,对着MATLAB智能算法 30案例来的,首先是入门的遗传算法对简单一元函数优化:
最先上代码看不懂,得提前熟悉Sheffield工具箱里面的各种函数:
采用的是 gatbx 1.3版本
工具箱中主要函数列表:
创建种群
[Chrom Lind BaseV] = crtbp(Nind, Lind, Base)
Nind---种群个体数
Lind---个体长度
Base---进制数
Lind就是Base的列数
Chrom---种群编码
BaseV---染色体基因位的基本字符向量
[Chrom,Lind,BaseV]=crtbp(5,10)
Chrom =
1 0 0 0 1 1 1 1 0 0
1 0 1 0 0 1 0 1 0 0
0 1 1 1 1 0 0 0 1 1
1 1 0 1 1 1 0 1 1 1
1 1 1 1 1 0 0 0 0 1
Lind =
10
BaseV =
2 2 2 2 2 2 2 2 2 2
进制数可以任意
适应度函数
- FitnV = ranking(ObjV, RFun, SUBPOP)
- FitnV = ranking(ObjV)
- FitnV = ranking(ObjV, Rfun)
3---按照个体的目标值ObjV(列向量)有小到大的顺序对个体进行排序,返回个体适应度值FitnV(列向量)
2---Rfun a:若是在[1,2]中的一个标量(压差),采用线性排序
b:两个参数的向量: Rfun(1):对线性排序,标量指定的选择压差RFun(1)必须在【1,2】区间;
对非线性排序,RFun(1)必须在【1,length(ObjV)-2】区间;若为NAN,RFun(1)假设为2
Rfun(2):制定排序方法,0--线性排序,1--非线性
【a(压差) ,b(0 线性| 1非线性) 】
c:RFun长度为length(ObjV) 则它包含对每一行的适应度计算值
1---SUBPOP 指明ObjV中子种群的数量,省略或NAN则为1
ObjV=[1;2;3;4;5;10;9;8;7;6];
RFun=[3;53;71;101;14;18;25;30;40;50];
F=ranking(ObjV,RFun)
F =
50
40
30
25
18
3
53
71
101
14
选择函数
SelCh= select(Self_F,Chrom,FitnV)
SelCh= select(Self_F,Chrom,FitnV,GGAP)
SelCh= select(Self_F,Chrom,FitnV,GGAP,SUBPOP)
Sel_F 是一个字符串,包含一个低级选择函数名,入rws或sus
GGAP是可选参数,指出了代沟部分种群被复制。省略或者为NAN,则GGAP假设为1.0
SUBPOP决定Chrom中子种群的数量。省略或者为NAN,则SUBPOP假设为1.0
********************************************************************************
Chrom=[1 11 21;2 12 22;3 13 23;4 14 24;5 15 25;6 16 26;7 17 27;8 18 28];
FitnV=[1.50;1.35;1.21;1.07;0.92;0.78;0.64;0.5];
SelCh=select('sus',Chrom,FitnV)
%'sus' 轮盘赌选择函数
SelCh =
4 14 24
2 12 22
5 15 25
6 16 26
3 13 23
1 11 21
2 12 22
8 18 28
********************************************************************************
假设Chrom由两个子种群组成,通过轮盘赌选择函数 sus 对每个子种群选择 150% 的个体
Fitnv=[1.50;1.16;0.83;0.50;1.50;1.16;0.83;0.5];
SelCh=select('sus',Chrom,1.5,2)
错误使用 select (line 35)
Chromand FitnV disagree
SelCh=select('sus',Chrom,Fitnv,1.5,2)
SelCh =
4 14 24
1 11 21
2 12 22
3 13 23
2 12 22
1 11 21
7 17 27
6 16 26
5 15 25
8 18 28
5 15 25
6 16 26
交叉算子函数recombin
NewChrom = recombin(REC_F, OldChrom,RecOpt, SUBPOP)
完成种群Chrom中个体重组,在新种群NewChrom中返回重组后的个体,一行对应一个个体
REC_F是包含低级重组函数名的字符串,如 recdisxovsp
RecOpt是一个指明交叉概率的任选参数,如省略或为NAN,将设为缺省值
SUBPOP是一个决定Chrom中子群个数的可选参数,如果为NAN,则为1.
********************************************************************************
对5个个体的种群进行重组
Chrom=crtbp(5,10)
Chrom =
1 1 0 1 1 1 0 1 1 0
1 0 0 0 0 1 0 0 1 0
1 1 1 0 0 0 0 1 1 1
1 0 1 0 0 1 1 0 1 0
0 0 0 1 1 1 0 1 0 1
NewChrom=recombin('xovsp',Chrom)
NewChrom =
1 1 0 1 0 1 0 0 1 0
1 0 0 0 1 1 0 1 1 0
1 1 1 0 0 0 0 1 1 1
1 0 1 0 0 1 1 0 1 0
0 0 0 1 1 1 0 1 0 1
********************************************************************************
变异算子函数mut
NewChrom = mut(OldChrom,Pm,BaseV)
OldChrom---当前种群
Pm---为变异概率(省略时为 0.7/Lind)
BaseV指明染色体个体元素的变异的基本字符(省略是种群编码为二进制)
********************************************************************************
>>%种群为2进制编码
>>OldChrom=crtbp(5,10);
>>NewChrom=mut(OldChrom)
NewChrom =
0 1 1 1 0 0 1 0 1 0
1 1 0 1 0 1 1 1 0 0
0 1 1 1 0 0 1 0 1 0
0 0 0 0 0 1 0 1 0 1
1 1 0 1 0 0 0 1 1 0
>> OldChrom
OldChrom =
0 1 1 1 0 0 1 0 1 0
1 1 0 1 0 1 1 1 0 1
0 1 1 1 0 0 1 0 0 1
0 0 0 0 0 1 0 1 0 1
1 1 0 1 1 0 0 1 1 0
********************************************************************************
种群为非二进制编码,创建一个长度为8、有6个个体的随机种群
BaseV=[8 8 8 4 4 4 44];
[Chrom,Lind,BaseV]=crtbp(6,BaseV);
Chrom
Chrom =
0 5 4 2 2 1 3 2
2 1 0 1 2 1 0 0
3 0 2 2 0 3 1 2
4 2 6 0 1 0 1 1
2 2 0 1 2 3 2 3
4 3 7 3 2 3 0 2
注意到加粗的为8进制,但是发现了没,这个顺序是和BaseV不一样的!
NewChrom=mut(Chrom,0.7,BaseV)
NewChrom =
0 5 4 1 1 3 0 2
2 4 0 2 0 1 0 2
6 4 4 1 3 3 3 1
0 2 2 0 2 0 1 2
5 1 3 1 1 0 1 2
1 5 7 1 0 2 1 2
红色的变异的
重插入函数,重新插入子代到种群
[Chrom, ObjVCh] = reins(Chrom, SelCh, SUBPOP,InsOpt, ObjVCh, ObjVSel)
用子代代替附带并返回结果种群
SelCh---子代
InsOpt---
[1]:标量,指明替代方法,0位均匀选择,1为适应度选择,代替父类中适应度最小的,默认为0
[2]:[0,1]之间的标量,表示每个子种群中重插入的子代个体在整个子种群中个体的比率,默认为1
ObjVCh---可选的列向量,包括Chrom中个体的目标值。对于基于适应度的重插入,ObjVCh是必须的
ObjVSel--- 包含SelCh中个体的目标值。如果子代的数量大于重插入种群中的子代数量,则是必须的,
此时按照适应度大小插入
>>Chrom=crtbp(5,10)
Chrom =
0 1 0 1 1 0 0 1 1 1
0 0 1 0 1 0 1 0 0 0
0 0 0 1 0 0 0 0 1 0
0 1 1 0 1 0 1 0 1 1
0 0 1 1 0 0 1 1 1 1
>>SelCh=crtbp(2,10)
SelCh =
0 0 0 1 1 1 1 1 1 0
0 0 0 0 1 1 0 0 1 0
>>Chrom=reins(Chrom,SelCh)
Chrom =
0 0 0 1 1 1 1 1 1 0
0 0 1 0 1 0 1 0 0 0
0 0 0 1 0 0 0 0 1 0
0 0 0 0 1 1 0 0 1 0
0 0 1 1 0 0 1 1 1 1
实用函数
bs2rv
二进制到十进制的转换
Phen =bs2rv(Chrom,FieldD)
将二进制的Chrom转换为实值
Field---- len
lb
ub
code
scale
lbin
ubin
len 子串长度 sum(len)=size(Chrom,2)
lb ub 每个变量的上下界
code 指明子串怎样编码,1为标准的二进制编码,0为格雷编码
scale 指明每个子串所使用的刻度,0表示算术刻度,1表示对数刻度
lbin ubin表示指示范围是否包含边界,0不包含 1包含
FieldD=[size(Chrom,2);-1;10;1;0;1;1;]
FieldD=
8
-1
10
1
0
1
1
Phen=bs2rv(Chrom,FieldD)
Phen =
4.5216
1.5020
9.9569
0.7686
********************************************************************************
rep 复制矩阵
MatOut =rep(MatIn,REPN);
REPN指明复制次数 REPN:【1,2】表示 纵向复制1次,横向复制2次
熟悉完了函数,就可以利用这些函数来进行一些简单的求解:
附上代码:
%简单一元函数优化
% f(x)=(sin(10*pi*x)/x),x belongs to [1,2]
clc
clear
close all
%%画出函数图
figure(1);
hold on;
lb=1;ub=2; %函数自变量范围 [1,2],初始种群是随机的,但是将初始种群利用 bs2rv 映射到实数时,这两个值限制了实数的范围
ezplot('sin(10*pi*X)/X',[lb,ub]);
xlabel('自变量');
ylabel('函数值');
%%定义遗传算法参数
NIND=40; %种群大小
MAXGEN=20000; %最大遗传代数,书中用的是20,我用20000写的玩的
PRECI=20; %个体长度
GGAP=0.95; %代沟
px=0.7; %交叉概率
pm=0.01; %变异概率
trace=zeros(2,MAXGEN); %寻优结果初始值
FieldD=[PRECI;lb;ub;1;0;1;1]; %FieldD=[20 20;-2,-2;-2,-2; 1 1;0 0;1 1; 1 1],利用bs2rv计算出来的会有两列值
Chrom=crtbp(NIND,PRECI);
%%优化
gen=0; %代计数器
X=bs2rv(Chrom,FieldD); %初始种群二进制到十进制
ObjV=sin(10*pi*X)./X; %计算目标函数值,NIND个目标
while gen<MAXGEN
FitnV=ranking(ObjV); %分配适应度
SelCh=select('sus',Chrom,FitnV,GGAP); %根据适应度,代数,用sus选择子种群
SelCh=recombin('xovsp',SelCh,px); %重组,将样本截断,随机重组成新的值
SelCh=mut(SelCh,pm); %另重组后的种群进行变异,pm为概率
X=bs2rv(SelCh,FieldD); %变异后形成新的种群,转化为实值
ObjVSel=sin(10*pi*X)./X; %计算实值对应的目标函数值
[Chrom,ObjV]=reins(Chrom,SelCh,1,1,ObjV,ObjVSel); %将子种群,看做一个子种群,用适应度选择,ObjV是初始种群的目标值,ObjVSel是选择后的目标值
X=bs2rv(Chrom,FieldD);
gen=gen+1;
%获取每一代的最优解及其序号,Y为最优解,I为个体的序号
[Y,I]=min(ObjV); %Y是最小值,I是其索引
trace(1,gen)=X(I); %记录每代的最优值,目标函数的x值
trace(2,gen)=Y; %记录每代的最优值,目标函数的y值
end
plot(trace(1,:),trace(2,:),'b*');
grid on;
plot(X,ObjV,'b*');
hold off;
%%画进化图
figure(20);
plot(1:MAXGEN,trace(2,:));
grid on;
xlabel('遗传代数');
ylabel('解得变化');
title('进化过程');
bestY=trace(2,end); %end表示最后的索引
bestX=trace(1,end);
fprintf(['最优解:\nX=',num2str(bestX),'\nY=',num2str(bestY),'\n']);
最后的输出结果: