因为毕业论文的缘故,自己和导师说了句我学学GA和PSO之类的算法去优化一下……
哈哈哈,然后我就开始了我学智能算法的道路,谁让我菜呢…
这里推荐《MATLAB智能算法30个案例分析》,我以下博文中的代码和说明也是这本书里的。
先挖个坑,以后应该会更新关于海洋声速反演的相关算法。
首先是遗传算法的常用函数(默认会使用MATLAB的工具箱)
1. 创建种群函数——crtbp
功能:创建任意离散随机种群
调用格式:
① [Chrom,Lind,BaseV] = crtbp(Nind,Lind) %创建一个大小为Nind*Lind的随机二进制矩阵,其中,Nind为种群个体数,Lind为个体长度。返回种群编码Chrom和染色体基因位的基本字符向量BaseV。
② [Chrom,Lind,BaseV] = crtbp(Nind,Base) %创建一个种群个体为Nind,个体的每位编码的进制数由Base决定(Base的列数即为个体长度)
③ [Chrom,Lind,BaseV] = crtbp(Nind,Lind,Base) %创建一个大小为Nind*Lind的随矩阵,个体的各位的进制数由Base决定,这时输入参数Lind可省略(Base的列数即为Lind),即格式②。
看到这里…作为初学者的我,一脸懵逼。
Nind和Lind能够理解,反正是自己设置的参数,甚至可以理解为这个矩阵的行列数,但是加上Base之后,啥叫进制数啊,经过查资料觉得自己是傻子,就是2进制,10进制的意思,这里要注意,个体长度是多少,那Base这个矩阵就要有几列。
那就很简单了,举个粒子:
[Chrom,Lind,BaseV] = crtbp(5,10)
[Chrom,Lind,BaseV] = crtbp(5,10,[2 2 2 2 2 2 2 2 2 2]) %有10个2
[Chrom,Lind,BaseV] = crtbp(5,[2 2 2 2 2 2 2 2 2 2]) %同样10个2
得到的结果都是:
Chrom =
[
0 1 0 0 1 0 0 0 1 0
1 0 1 1 1 0 0 0 0 1
0 0 0 1 0 0 1 1 0 1
1 0 0 1 1 0 1 0 0 1
1 1 0 0 0 0 0 0 0 0
]
不要问我为什么Chrom是这样的,因为随机。而且从上例可知,crtbp默认是2进制,如果不是,需要在Base项中标记,且独立限制。
2. 适应度计算函数——ranking
功能:基于排序的适应度分配。(我也不知为什么书里要讲得这么专业,学术壁垒太可怕了)
调用格式:
① FitnV = ranking(ObjV) % 按照个体的目标值ObjV(列向量)有小到大的顺序对个体进行排序,并返回个体适应度FitnV的列向量。
② FitnV = ranking(ObjV,RFun)
%有三种情况:
% (1) 若RFun是一个在[1,2]区间内的标量,则采用线性排序,这个标量指定选择的压差。
% (2) 若RFun是一个具有两个参数的向量,则
% RFun(2):指定排序方法,0为线性排序,1为 非线性排序
% RFun(1):对线性排序,标量指定的选择压差RFun(1)必须在[1,2]区间;对非线性排序,RFun(1)必须在[1,length(ObjV)-2]区间;如果为NAN,则RFun(1)假设为2。
③ FitnV = ranking(ObjV,RFun,SUBPOP)
% 若RFun是长度为length(ObjV)的向量,则它包含对每一行的适应度值计算。
%SUBPOP是一个任选参数,表明在ObjV中的子种群的数量。省略SUBPOP或SUBPOP为NAN,则SUBPOP=1。在ObjV指中的所有子种群大小必须相同。如果ranking被调用于多子种群,则ranking独立地对每个子种群执行。
我我我…又一次懵了
书上给出的例子是:
ObjV = [1;2;3;4;5;10;9;8;7;6]
(1) 使用线性排序和压差为2估算适应度
FitnV = ranking(ObjV)
FitnV = ranking(ObjV,[2,0])
FitnV = ranking(ObjV,[2,0],1)
得到的运行结果都是
FitnV = 2.0000
1.7778
1.5556
1.3333
1.1111
0
0.2222
0.4444
0.6667
0.8889
从例子里可以找出这几个规律:连续的数相对应的适应度的差值大概为0.2222;最小的数对应的适应度最大,同样,最大的数对应的适应度最小。
现在反推0.2222从哪来:大概率是0.2222222222,压差为2,2/9满足条件,那么也就是说,差值就是压差/(max-min)吗?
看第二个粒子…例子,调教过后的输入法已经把粒子放在第一位了吗hhh
(2) 使用RFun中的值估算适应度
RFun = [3;5;7;10;14;18;25;30;40;50];
FitnV = ranking(ObjV,RFun)
FitnV=
[
50
40
30
25
18
3
5
7
10
14
]
这个例子是第三种情况了,即RFun是长度为length(ObjV)的向量,但是没有SUBPOP。
但是这个例子推翻了上面的猜想……
第三个例子呢
FitnV = ranking (ObjV,[2,1],2)
得到
FitnV =
[
2.0000
1.2889
0.8307
0.5354
0.3450
0.3450
0.5354
0.8307
1.2889
2.0000
]
嗯???
这……又是为什么啊
要不…先放着,学到后面应该有解释…到时候来补充
3. 选择函数——select
功能:从种群中选择个体(高级函数)。
调用格式:
① SelCh = select(SEL_F,Chrom,FitnV) %SEL_F是一个字符串,包含一个低级函数选择名,如rws或sus。FitnV就是上面的个体适应度值,表明了每个个体被选择的预期概率
② SelCh = select(SEL_F,Chrom,FitnV,GGAP) %GGAP是可选参数,指出了代购部分种群被复制。如果GGAP省略或为NAN,则GGAP假设为1.0。
③ SelCh = select(SEL_F,Chrom,FitnV,GGAP,SUBPOP)
还行…迷迷糊糊的,先看例子。
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]
用随机遍历抽样方式(sus)选择8个个体:
SelCh = select('sus',Chrom,FitnV)
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里是8行,随机选取再放入SelCh变量里的意思。
第二个例子是:
假设Chrom由两个子种群组成,通过轮盘赌选择函数sus对每个子种群选择150%的个体。
FitnV = [1.50;1.16;0.83;0.50;1.50;1.16;0.83;0.5];
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
]
这个也很好理解,Chrom中的个体有8个,现在假设有两个种群,也就是SUBPOP=2;在两个种群中选择出来150%的个体,也就是12,即GGAP=1.5;得到新的SelCh。
4. 交叉算子函数——recombin
功能:重组个体(高级函数)。
调用格式:
① NewChrom = recombin(REC_F,Chrom) %REC_F是一个包含低级重组函数名的字符串,例如recdis或xovsp。
② NewChrom = recombin(REC_F,Chrom,RecOpt) %RecOpt是一个指明交叉概率的任选参数,如省略或为NAN,将设为缺省值。
③ NewChrom = recombin(REC_F,Chrom,RecOpt,SUBPOP)
这个函数很好理解的,就不放例子了,就是种群中的个体重新排列。
5. 变异算子函数——mut
功能:离散变异算子
调用格式:NewChrom = mut (OldChrom,Pm,BaseV)
OldChrom为当前种群,Pm为变异概率(省略时为0.7/Lind),BaseV指明染色体个体元素的变异的基本字符(省略时种群为二进制编码)。
和上面的重组不同,重组的话,用二进制举例,0和1的数量是不会变,变的是位置;而变异的话,0会变成1,1会变成0。
也不放例子了。这里的变异应该是有进制约束的,就是二进制只能变成0或1,10进制只能在0-9里变。
6. 重插入函数——reins
功能:重插入子代到种群。
调用格式:
① Chrom = reins(Chrom,SleCh)
② Chrom = reins(Chrom,SleCh,SUBPOP)
③ Chrom = reins(Chrom,SleCh,SUBPOP,InsOpt,objVCh)
%InsOpt是一个最多有两个参数的任选向量。
%InsOpt(1)是一个标量,指明用子代代替父代的方法。0为均匀选择,子代代替父代使用均匀随机选择。1为基于适应度的选择,子代代替父代中适应度最小的个体。如果省略InsOpt(1)或InsOpt(1)为NAN,则假设为0。
%InsOpt(2)是一个在[0,1]区间的标量,表示每个子种群中重插入的子代个体在整个子种群中个体的比率。如果InsOpt(2)省略或为NAN,则假设InsOpt(2) = 1.0。
④ [Chrom,ObjCVh] = reins(Chrom,SleCh,SUBPOP,InsOpt,objVCh,objVSel)
% ObjVCh是一个可选列向量,包括Chrom中个体的目标值。对基于适应度的重插入,ObjVCh是必需的。
% ObjVSel是一个可选参数,包含SelCh中个体的目标值。如果子代的数量大于重插入种群中的子代数量,则ObjVSel是必需的。这种情况子代将按它们的适应度大小选择插入。
reins完成插入子代到当前种群,用子代代替父代并返回结果种群。Chrom为父代种群,SelCh为子代,每一行对应一个个体。
我个人觉得它和上面的变异就是遗传算法的核心了。就像达尔文的优胜劣汰一样,用最优的个体创造出最精确的预测。
看一下例子:
Chrom = crtbp(5,10) %父代
Chrom =
[
0 1 1 1 1 0 0 1 1 0
1 1 0 0 0 0 1 1 1 1
1 1 0 0 1 0 0 0 0 0
1 1 0 0 1 0 1 0 0 0
0 1 0 0 1 1 1 0 0 0
]
SelCh = crtbp(2,10) %子代
SelCh=
[
1 0 0 1 0 0 0 0 0 0
1 1 1 1 1 0 1 0 0 1
]
Chrom = reins(Chrom,SelCh) %重插入
Chrom =
[
0 1 1 1 1 0 0 1 1 0
1 0 0 1 0 0 0 0 0 0
1 1 0 0 1 0 0 0 0 0
1 1 0 0 1 0 1 0 0 0
1 1 1 1 1 0 1 0 0 1
]
但是这里就有个疑问了,子代和父代都是随机生成,重插入所得的种群和父代是一样的,那么插入的规则是什么?上面例子中一个替换了第二行一个替换了第五行,暂时没有找到什么规律。
先欠着,以后再答。
7. 实用函数——bs2rv
功能:二进制到十进制的转换。
调用格式:Phen = bs2rv(Chrom,FieldD)
bs2rv根据译码矩阵FieldD将二进制串矩阵Chrom转换为实值向量,返回十进制的矩阵。
矩阵FieldD有如下结构:
FieldD =
[
len %包含在Chrom中的每个字串的长度,注意,sum(len) = size(Chrom,2)
lb %变量的下界
ub %变量的上界
code %表明子串如何编码,1为标准二进制编码,0为格雷代码
scale %表明每个子串所使用的刻度,0表示算术刻度,1表示对数刻度
lbin %lbin和ubin指明表示范围中是否包含边界。0表示不包含边界,1表示包含边界。
ubin
]
其他的算是能懂,就是有些疑问:1. 这里的组成部分可以省略吗 2. 变量上下界是一开始就自己设定吧 3. lbin和ubin是两个不同的参数,那么,到底代表什么边界呢。
看看例子:
Chrom = crtbp(4,8)
得
Chrom =
[
1 0 1 0 1 0 1 1
0 0 1 0 0 1 1 1
1 1 1 1 1 0 1 1
1 0 0 1 0 1 0 0
]
FieldD = [size(Chrom,2);-1;10;1;0;1;1]; %包含边界
Phen = bs2rv(Chrom,FieldD) %转换二进制到十进制
得
Phen =
[
7.8431
1.5020
6.4627
8.9647
]
这里表示的是下界-1,上界10的变量,注明标准的二进制编码,算术刻度,但…我还是不知道这个边界到底是什么。
同样欠着hhh
8. 实用函数——rep
功能:矩阵复制。
调用格式:MatOut = rep(MatIn,REPN)
函数rep完成矩阵MatIn的复制,REPN指明复制次数,返回复制后的矩阵MatOut。REPN包含每个方向复制的次数,REPN(1)表示纵向复制次数,REPN(2)表示水平方向复制次数。
这个挺简单的,但是REPN(1)和REPN(2)大概是猜测的,那直接看代码:
MatIn = [1 2 3 4;5 6 7 8]
得
MatIn =
[
1 2 3 4
5 6 7 8
]
MatOut = rep(MatIn,[1,2])
得
MatOut=
[
1 2 3 4 1 2 3 4
5 6 7 8 5 6 7 8
]
MatOut=rep(MatIn,[2,1])
得
MatOut=
[
1 2 3 4
5 6 7 8
1 2 3 4
5 6 7 8
]
MatOut = rep(MatIn,[2,3])
得
MatOut =
[
1 2 3 4 1 2 3 4 1 2 3 4
5 6 7 8 5 6 7 8 5 6 7 8
1 2 3 4 1 2 3 4 1 2 3 4
5 6 7 8 5 6 7 8 5 6 7 8
]
好了,以上就是遗传算法的常用函数了
欠了好多坑啊哈哈哈哈,会一一补上的。