遗传算法应用
[1]、[2]、[3]在文章的最后用图像进行说明。
一、问题概述
求 y=10sin(5x)+7*|x-5|+10 最大值。函数图像如图:
二、问题解决
1.产生初始种群
用随机数生成器分别产生8、16、32[1]个随机数作为初始种群。
由于给出的函数定义域是全体实数,且rand()函数只能生成[0,1]的随机数,我们取一个范围(如 [0,10])作为倍率,以产生大于1的数
代码如下:
%% 设置变量
N=32;%初始群体大小,即产生N个在(a,b)范围内的随机数
a=0;%自变量取值下界
b=10;%自变量取值上界
%% 1.产生初始群体
initalGroup10=a+(b-a).*rand([N 1]);%初始群体,十进制编码
2.编码与解码
采用二进制编码,matlab默认编码位数。matlab中十进制转二进制函数dec2bin()
默认会取最合适的编码位数。如果指定了编码位数,则多余部分会补零。
需要注意的是,matlab中的dec2bin()只能转换整数部分,小数部分会被自动省去。下面链接介绍了一种能将十进制小数转换为二进制的方法。这里我们先用dec2bin()。
matlab实现十进制小数转换为二进制
3.确定适应度
将初始种群带入目标函数,目标函数的值定为适应度。
%% 2.求初始群体的适应度
%适应度函数,即为目标函数
adaptLevel = objectFun(initalGroup10);
%将初始种群和适应度组合
initalGroup = [initalGroup10 adaptLevel];
其中,objectFun()
代码如下:
function y = objectFun(x)
y = 10.*sin(5.*x)+7.*abs(x-5)+10;
end
4.复制
采用轮盘赌的方法确定复制个体。
%% 3.确定复制个体
%确定需要复制的个体的序号
copyIndex=trochalDisk(initalGroup,N);
%copyIndex返回的序号是对initalGroup排序后的序号,因此对适应度值升序排序
sortrows(initalGroup,-2);
%复制后的种群
copyGroup10=[];
for i=1:size(copyIndex)
copyGroup10=[copyGroup10 initalGroup(copyIndex(i),1)];
end
其中,trochalDisk()
是轮盘赌实现函数,代码如下:
function index =trochalDisk(pk,N)
%pk 轮盘每一份的值
%N 轮盘的份数
%排序
sortrows(pk,-2);
pk=pk(:,2);
%确定轮盘法则的区间trochal
trochal=cumsum(pk(:));
%随机产生N个数,并确定在轮盘的哪个区间
tc=trochal(1)+(trochal(end)-trochal(1)).*rand([N 1]);
index=[];
for i=1:size(tc)
t=find(trochal>=tc(i));
index=[index;t(1)];
end
end
5.交叉和变异
需要依次确定交叉和变异中的几个随机。
1)交叉中有三个随机:个体随机、概率可调、编码位置随机。
- 用随机数生成器确定发生交叉的个体序号。
- 交叉概率为50%~80%[2],可以上下浮动。采用人为输入。
- 用随机数生成器确定发生交叉的编码位置(产生一个或多个,这里以多个为例)。
2)变异中有三个随机:个体随机、哪位变异随机、变异几位随机。
- 用随机数生成器确定发生变异的个体序号。
- 变异概率为0.1%~1%[3],可以上下浮动。采用人为输入。
- 用随机数生成器确定发生变异的编码位置(产生一个或多个,用随机数决定)。
代码如下:
crossProbility=0.07;%交叉概率50%~80%,可以上下浮动
variationProbility=0.001;%变异概率0.1%~1%,可以上下浮动
crossGroup = cross(crossProbility,copyGroup10);
variationGroup = variation(variationProbility,crossGroup);
其中,cross()
是交叉实现函数,variation()
是变异实现函数。
function crossGroup = cross(probility,group)
%crossGroup 交叉后的种群
%probility 交叉概率
%group 复制后的种群
%确定几个个体发生交叉,让每两个相邻个体发生交叉,因此定为偶数个
crossNumber=floor(probility*size(group,2));
if rem(crossNumber,2)~=0
crossNumber = crossNumber+1;
end
%随机产生个体交叉的序号
crossIndex=floor(1+(size(group,2)-1).*rand([crossNumber 1]));
%随机产生个体交叉的位置,范围:1-二进制长度
group2=dec2bin(group);
crossPos=floor(1+(size(group2,2)-1).*rand([crossNumber/2 1]));
%交叉
for i=1:2:crossNumber
%下面这段代码和C语言中最基本的swamp()函数效果一样
temp=group2(crossIndex(i),crossPos:end);
group2(crossIndex(i),crossPos:end)=group2(crossIndex(i+1),crossPos:end);
group2(crossIndex(i+1),crossPos:end)=temp;
end
%将2进制变为10进制
crossGroup=bin2dec(group2);
end
function variationGroup = variation(probility,group)
%variationGroup 变异后的种群
%probility 变异概率
%group 变异后的种群
%确定几个个体发生变异
variationNumber=floor(probility*size(group,2));
%随机产生个体变异的序号
variationIndex=floor(1+(size(group,2)-1).*rand([variationNumber 1]));
group2=dec2bin(group);
%确定发生变异的位置的个数
variationPosNum=floor(1+(size(group2,2)-1));
%随机产生个体变异的位置,1-二进制长度
variationPos=floor(1+(size(group2,2)-1).*rand([variationPosNum 1]));
%变异
for i=1:variationNumber
for j=1:variationPosNum
if group2(variationIndex(i),variationPos(j))==0
group2(variationIndex(i),variationPos(j))='1';
else
group2(variationIndex(i),variationPos(j))='0';
end
end
end
variationGroup=bin2dec(group2);
end
6.适应度验算
以本次迭代和上一次迭代适应度值改变量是否小于给定精度,决定是否终止循环。
下面给出主函数
clear,clc
%% 设置变量
N=32;%初始群体大小,即产生N个在(a,b)范围内的随机数
a=0;%自变量取值下界
b=10;%自变量取值上界
esp=0.0001;%精度
crossProbility=0.7;%交叉概率50%~80%,可以上下浮动
variationProbility=0.005;%变异概率0.1%~1%,可以上下浮动
maxX=[];
maxAdapt=[];
count=0;%记录迭代次数
%% 1.编码,产生初始群体
initalGroup10=a+(b-a).*rand([N 1]);%初始群体,十进制编码
while true
count=count+1;
%% 2.求初始群体的适应度
%适应度函数,即为目标函数
adaptLevel=objectFun(initalGroup10);
initalGroup=[initalGroup10 adaptLevel];
%% 5.适应度验算
%对initalGroup适应度值升序排序
sortrows(initalGroup,-2);
%画图用
index=find(initalGroup(:,2)==max(initalGroup(:,2)));
maxX=[maxX initalGroup(index(1),1)];
%最大适应度,如果求的是目标函数的最小值,就保留最小值
maxAdapt=[maxAdapt initalGroup(index(1),2)];
if size(maxX,2)~=1
if abs(maxX(end)-maxX(end-1))<esp
break;
end
end
%% 3.确定复制个体
copyIndex=trochalDisk(initalGroup,N);
copyGroup10=[];
for i=1:size(copyIndex)
copyGroup10=[copyGroup10 initalGroup(copyIndex(i),1)];
end
%% 4.交叉与变异
%交叉中的随机:个体随机、交叉位置随机、概率可调
%变异中的随机:个体随机、哪位变异随机、变异几位随机
crossGroup = cross(crossProbility,copyGroup10,a,b,esp);
variationGroup = variation(variationProbility,crossGroup',a,b,esp);
%% 为下次循环准备
%交叉和变异过程中难免会出大于给定范围的值
%将所有超出范围的值设成最大值
%因为下面还会给每个数加上小数部分,所以最大值取范围上界-1
variationGroup(find(variationGroup>=(b-1)))=b-1;
%前面说到dec2bin只会编码整数部分,所以我们在这里加一个小数部分。
%可以尝试一下去掉会是什么样子
initalGroup10=variationGroup+rand([N 1]);
end
下面是一些实验结果图和分析过程
各个图参数如下:
N=32;%初始群体大小,即产生N个在(a,b)范围内的随机数
a=0;%自变量取值下界
b=10;%自变量取值上界
esp=0.0001;%精度
crossProbility=0.7;%交叉概率50%~80%,可以上下浮动
variationProbility=0.005;%变异概率0.1%~1%,可以上下浮动
[4]:在图1所用参数的基础上,采用十进制小数转换为二进制的编码方式。一定要提高变异概率
采用含小数的二进制后,二进制编码位数会加长,需要提高变异概率。
如 9.9283,dec2bin() 编码只考虑整数部分,编码结果是 ‘1001’ ,每次变异产生差为1的概率是1/16 = 6.25%;而考虑到小数后编码结果为 ‘10011110110110100’(整数部分占4位,小数部分占13位),每次变异产生差为1的概率是24/217 = 0.012%。
综上,采用含小数的二进制后,变异概率为编码方式为dec2bin()的变异概率的100倍左右,才会产生比较好的结果。
左图是变异概率为0.1%时的结果,右图是变异概率为10%时的结果。
到这里这道题就结束啦!
如果哪里有错误还请大家批评指正呀~~~
或者有哪位发现了交叉概率和变异概率取值的意义,烦请评论区留言呀,不胜感激!