遗传算法应用(实现十进制小数转换为二进制)

遗传算法应用

[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%,可以上下浮动
   [1]:在图1所用参数的基础上,选择不同种群大小,发现种群越大,迭代次数越少,越容易能达到全局最优
   [2]:在图1所用参数的基础上,选择不同交叉概率。做了30多次实验。。。才疏学浅,实在发现不了任何关系。。。
   [3]:在图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%时的结果。

到这里这道题就结束啦!
如果哪里有错误还请大家批评指正呀~~~
或者有哪位发现了交叉概率和变异概率取值的意义,烦请评论区留言呀,不胜感激!

原创文章 35 获赞 17 访问量 7852

猜你喜欢

转载自blog.csdn.net/dear_jing/article/details/104247611