智能算法之遗传算法

2022-06-16 14:04:14 浏览数 (1)

首先来解释一下几个名词:

1. 染色体,一条染色体对应的就是你需要求的一个解,例如你需要求一个三元四次的复杂方程的极小值,那么你的一个结当然包含三个数(因为是三元嘛,当然是三个未知数啦),假设是x,y,z。那么你的一条染色体就包含三个数,类似于一个向量[x y z]。类似的如果你的一个解只有一个数,那么一条染色体就只包含一个数。

2. 基因,咱们都是理科生,当然知道染色体是由基因组成的,上面说到了[x y z]对应的是一条染色体,那么自然组成x , y , z的就是基因喽,这里我们就要说到编码了,一般我们会将染色体进行编码,假设使用的是二进制编码,那么我们用二进制0和1将[x y z]横着写成一排,那么是不是就是遗传0和1。那么这些0和1就是基因了。

3. 交叉,交叉也是跟生物里面学的一样,就是两条染色体并排的时候相对应的那一段交叉接起来

4. 变异,变异就是基因中某个bit的0变成了1,或者1变成了0,几率很小。当然在算法中是我们让它变异的。

5. 压差,在下面的例子中,有个词语叫“压差”,之前网上都没找到明白的解释,其实说的那么高端,压差就是指你把本来0~255之间的数按照某种算法映射到1~10的话,那么压差就是指这个1~10了,其实就是归一化之后的范围。

6. 适应度,上面说到优胜劣汰,我们作为上帝需要指定一个规则,怎么样的算是优秀,什么样的算是劣质,说让谁淘汰就让谁淘汰,比如说我们求一个方程的极小值,那么我们当然是将每条染色体的值带入到方程中,求得的值越小就越优秀,越大就越劣质喽。那么我们就要淘汰那些使得方程值大的染色体,通过交叉编译来补充那些被淘汰染色体的位置。

7. 适应度函数,适应度函数顾名思义就是用来计算适应度的函数,这个函数的定义很重要,但是总得来说只要保证越符合我们要求的,得出来的值(适应度)越大理论上就可以接受,至于好不好另说。

8. 种群,就是若干个染色体组成种群。

示例:

求方程y = sin(10*pi*x)/x , x属于[1,2] 的极值

程序:

clc;

clear all;

close all;

figure(1);

hold on;

tic;

lb = 1; ub = 2; %这个值是自变量的范围,在这个范围内求解

ezplot('sin(10*pi*X)/X',[lb,ub]); %第一个参数表示的是方程,y的计算公式,画出图像

xlabel('自变量/X');

ylabel('函数值/Y');

NIND = 40; %初始化40个解,每一个解代表的是一条染色体,这条染色体就代表的是一个x的值

MAXGEN = 20; %最大遗传代数

PRECT = 20; %染色体精度,也就是一个个体的基因数(2进制数长度),也就是用多少个bit表示一个x的值

GGAP = 0.95; %代沟,表示每一代从种群中选择多少个体到下一代

px = 0.7; %染色体交叉几率,具体自己写的话不知道这个概率怎么用的,不过matlab中作为参数直接带入就好了

pm = 0.01; %染色体变异几率,具体自己写的话不知道这个概率怎么用的,不过matlab中作为参数直接带入就好了

trace = zeros(2,MAXGEN);%初始化为0

FieldD = [PRECT;lb;ub;1;0;1;1];

% PRECT:2进制位数 lb:范围下限 ub:表示范围上限

% 1:二进制编码 0:表示用算术刻度 1:表示包含左边界 1:表示包含右边界

Chrom = crtbp(NIND,PRECT); %随机产生初始解

gen = 0;%遗传代数

X = bs2rv(Chrom , FieldD);

%根据区域描述器,自动将2进制编码转化成指定范围内的实数值

%得出的X是一个长度为40的列向量

ObjV = sin(10*pi*X)./X ;

%“./”表示为阵列操作,非矩阵运算,得出的也是一个长度为40的列向量,适应度值

%经过上一步,X已经为列向量,所以ObjV也是列向量了

while gen<MAXGEN

%ranking : 根据适应度值,使用ranking()得出各自的入选率(适应度)

%第一个参数:注意ObjV必须是列向量(这是ranking函数要求的),表示需要计算适应度的种群,

%第二个参数:一个有两个标量的向量,第一个标量可以认为总为2,同时代表压差的上限

% 第二个标量有两重意义,如果为0表示线性排序,如果为1表示非线性排序,

% 同时它代表压差的下限。返回得到的FitnV会是一个长度跟ObjV相同的列向量

% 他们之间的值是一一对应的,FitnV中较大的表示适应度的值对应ObjV中较

% 较小的值。但是FitnV中的顺序并非是有序的,顺序跟ObjV中的每个值得顺序

% 是一样的。

%第三个参数:表示种群中子种群的数量

FitnV = ranking(ObjV,[2,0],1);

%select : 通过计算得到的适应度值,从原始种群Chrom中筛选一些不符合要求的个体得到

% 新的种群返回个SelCh

%第一个参数:表示选择筛选的策略,sus表示随机平均选择 ,还可以是rws表示轮盘赌选择

%第二个参数:表示原始的需要被筛选的种群

%第三个参数:表示这个种群对应的适应度

%第四个参数:表示代沟,也就是说从Chrom中选择多少百分比的个体到下一代,这里为0.95

% 也就是说从Chrom中选择Chrom*0.95个个体进入下一代,有0.05的染色体被淘汰

SelCh = select('sus',Chrom,FitnV,GGAP); %这就是优胜劣汰的过程

SelCh = recombin('xovsp',SelCh,px);

%交叉基因函数 ,xovsp或者recdis表示交叉策略 , px表示染色体交叉几率

SelCh = mut(SelCh,pm);

%变异函数 ,pm表示编译几率

X = bs2rv(SelCh , FieldD);

ObjVSel = sin(10*pi*X)./X;

%reins : 将子代个体插入到父代种群中,代替那些不合适的父代个体

%第一个参数:表示父代种群

%第二个参数:子代种群

%第三个参数:指明Chrom,SelCh中子种群个数,每个子种群必须有相同的大小

%第四个参数:其实是一个有两个元素的向量,在这里相当于[1,1] ,第一个标量表示用什么策略将子代

% 将子代插入父代种群,如果为0表示用随机均匀选择,如果为1表示根据适应度进行选择;

% 第二个标量表示子代种群插入父代,占百分比,可以是[0,1]之间的标量,如果缺省表示

% 默认值为1

%第五个参数:基于适应度重插入(也就是第四个参数为1)的时候这个参数是必须的,Objv包含Chrom中

% 个体的目标值(也就是根据公式计算得到的值比如上面的sin(10*pi*X)./X得到的值)。

% 这是因为基于适应度的方法,得到适应度必须是根据目标值来确定适应度,所以这里必须

% 要带入目标值。

%第六个参数:如果子代的个体数量大于将要插入父代的个体数量,那么这个参数是必须的,因为待插入

% 的个数多余需要插入的个数,那么必然存在有一部分不能插入,那么淘汰那一部分个体,是

% 根据子代种群的个体适应度来决定的,淘汰掉适应度底的个体,那么得到个体的适应度就需

% 要子种群的各个个体的目标值来计算。

[Chrom,ObjV] = reins(Chrom , SelCh , 1 , 1 , ObjV , ObjVSel)

X = bs2rv(Chrom , FieldD);

gen = gen 1;

%min : 返回向量ObjV的最小值,Y记录ObjV中每一列的最小值,I记录每一列的最小值的行号

[Y,I] = min(ObjV)

trace(1,gen) = X(I);

trace(2,gen) = Y;

end

plot(trace(1,:),trace(2,:),'bo');

grid on;

plot(X,ObjV,'b*');

hold off;

figure(2);

plot(1:MAXGEN,trace(2,:));

grid on;

xlabel('遗传代数');

ylabel('解的变化');

title('进化过程');

bestY = trace(2,end);

bestX = trace(1,end);

fprintf(['最优解:nX = ', num2str(bestX), 'nY = ' , num2str(bestY) , 'n']);

toc;

结果显示:

0 人点赞