遗传算法(matlab实现)

遗传算法(matlab实现)

计算智能理论与方法课程作业

遗传算法求解如下问题:  MIN  f ( x ) = ( x − 3 ) 2 x ∈ { 0 , 1 , 2 , 3 , 4 , 5 , … , 15 } \text { MIN } f(x)=(\mathrm{x}-3)^{2} \quad \mathrm{x} \in\{0,1,2,3,4,5, \ldots, 15\}  MIN f(x)=(x3)2x{0,1,2,3,4,5,,15}


迭代个体数目为4,采用格雷码和二进制编码,变异概率取编码长度倒数,筛选方式为轮盘赌和锦标赛算法。

一、执行效果

其中蓝色曲线为原函数,红色圆点为父代,蓝色圆点为筛选后的子代,最后红色三角点为迭代筛选结果。
在这里插入图片描述

二、算法流程图与实现

1. 算法流程图

开始
初始化参数
随机产生四个个体
开始迭代
迭代次数i
编码
交叉
变异
合并子代与父代
解码
计算子代表现形
是否绘图
绘制当前点
继续
选择
是否轮盘赌
轮盘赌选择
锦标赛选择
更新父代
是否完成所有迭代
选择最优解
输出结果
结束

2. 算法实现

  • 编码与解码

  • 二进制与十进制的相互转化

    1. 十进制转二进制
    % 十进制转二进制
    function [bin] = my_dec2bin(dec,nums)
    % bin:输出的二进制数据,dec:输入的十进制数据,nums:编码位数
        cols = size(dec, 2);
        bin = zeros(nums, cols); % 初始化二进制矩阵
        
        for i = 1:cols
            % 计算二进制表示
            num = dec(1, i);
            for j = nums:-1:1
                bin(i, j) = mod(num, 2); % 计算余数并填充到矩阵
                num = floor(num / 2);   % 整数除以2
            end
        end
    end
    

    1. 二进制转十进制
    % 二进制转十进制
    function [x] = my_bin2dec(mat)
    % x:十进制输出,mat:二进制输入
        rows = size(mat, 1);
        cols = size(mat, 2);
        x = zeros(rows,1);
        for ir = 1:rows
            for ic = 1:cols
                if mat(ir,ic)
                    x(ir,1) = x(ir,1) + 2^(cols-ic);
                end
            end  
        end
    
    end
    
  • 编码与解码

    基于前面的二进制十进制转换函数实现对十进制与二进制码/格雷码的编码与解码,其中参数WayOfCoding用于设置编码方式。

    1. 编码
    % 编码
    function [x_DNA] = encode(x,WayOfCoding)
    x_bin = my_dec2bin(x,4);
    if WayOfCoding == 1 % 二进制编码
        x_DNA = x_bin;
    elseif WayOfCoding == 0 % 格雷码编码
        x_r1 = my_dec2bin(bitshift(x, -1),4); % 右移一位在编码为二进制
        % 计算格雷码 
        x_DNA = xor(x_bin,x_r1);
    end
    end
    

    1. 解码
    % 解码
    function [x] = decode(x_DNA,WayOfCoding)
    rows = size(x_DNA,1);
    cols = size(x_DNA,2);
    if WayOfCoding==1 % 二进制解码
        x = my_bin2dec(x_DNA);
    elseif WayOfCoding==0 % 格雷码解码
        % 转化为二进制码
        x_bin = zeros(rows, cols);
        for i = 1:rows
           x_bin(i,1) = x_DNA(i,1); % 最高位
            % 逐位进行异或运算
            for j = 2:cols
                x_bin(i,j) = xor(x_bin(i,j-1), x_DNA(i,j));
            end 
        end
        x = my_bin2dec(x_bin);
    
    end
    end
    
  • 交叉与变异

    将4个父代的基因通过一个4x4的矩阵描述,通过对矩阵的行元素进行操作实现基于的交叉与变异。

    基于如下公式进行交叉操作:

    { y ( i 1 ) ( 1 : r − 1 ) = x ( i 1 ) ( 1 : r − 1 ) y ( i 2 ) ( 1 : r − 1 ) = x ( i 2 ) ( 1 : r − 1 ) + { y ( i 1 ) ( r : D ) = x ( i 2 ) ( r : D ) y ( i 2 ) ( r : D ) = x ( i 1 ) ( r : D ) \left\{\begin{array}{l}\boldsymbol{y}^{\left(i_{1}\right)}(1: r-1)=\boldsymbol{x}^{\left(i_{1}\right)}(1: r-1) \\\boldsymbol{y}^{\left(i_{2}\right)}(1: r-1)=\boldsymbol{x}^{\left(i_{2}\right)}(1: r-1)\end{array}+\left\{\begin{array}{l}\boldsymbol{y}^{\left(i_{1}\right)}(r: D)=\boldsymbol{x}^{\left(i_{2}\right)}(r: D) \\\boldsymbol{y}^{\left(i_{2}\right)}(r: D)=\boldsymbol{x}^{\left(i_{1}\right)}(r: D)\end{array}\right.\right. {y(i1)(1:r1)=x(i1)(1:r1)y(i2)(1:r1)=x(i2)(1:r1)+{y(i1)(r:D)=x(i2)(r:D)y(i2)(r:D)=x(i1)(r:D)

    % 交叉
    % --确定交叉端
    r_index=[2,3,4];
    r1 = r_index(randi(3)); 
    r2 = r_index(randi(3));
    
    % --交叉后的子代echild_mat
    child_mat = father_mat; 
    
    % --交换片段1
    ex_part = child_mat(1, r1:4);
    child_mat(1, r1:4) = child_mat(2, r1:4);
    child_mat(2, r1:4) = ex_part;
    
    % --交换片段2
    ex_part = child_mat(3, r2:4);
    child_mat(3, r2:4) = child_mat(4, r2:4);
    child_mat(4, r2:4) = ex_part;
    
    

    变异操作采用随机选择一个基因位点进行取反操作。

    % 变异
    for i_muta = 1:4
        if rand()<Pm
            % ---变异位置
            timesofmuta = timesofmuta + 1;
            r_m_index=[1,2,3,4];
            r_m = r_m_index(randi(4));
            child_mat(i_muta, r_m) = ~child_mat(i_muta, r_m);
        end
    end
    
  • 选择

    筛选前需要将子代与父代进行合并,再计算其表现型

    % (4) 合并子代与父代 
    all_mat = [father_mat;child_mat]; % 垂直拼接
    
    % (5) 解码
    x_childs = decode(all_mat,WayOfcoding);
    
    % (6) 子代表现形
    y_childs = f(x_childs);
    

    基于表现型进行筛选,采用轮盘赌和锦标赛算法模拟自然选择。

    1. 轮盘赌算法

    依据个体的表现形算出被选择的概率,通过轮盘赌算法选出新的子代。代码实现如下:

    % 归一化
    P_d = 1./(y_childs+0.0001);
    P_Sum = sum(P_d, 'all');
    P_Child = P_d/P_Sum;
    
    % 计算累计密度
    Pf_Child = zeros(1,8);
    for pi = 1:8
        for pc = 1:pi
            Pf_Child(pi) = Pf_Child(pi) + P_Child(pc);
        end
    end
    
    % 轮盘赌,选择下一批迭代个体
    for in = 1:4
        Pr = rand();
        for pif = 1:8
            if Pf_Child(pif) >= Pr
                x_father(in) = x_childs(pif);
                break;
            end
        end
    end
    

    1. 锦标赛算法

    父代子代二选一,算法数学描述为:

    S = { s ( 1 ) , s ( 2 ) , … , s ( 2 M ) } = { x ( 1 ) , x ( 2 ) , … , x ( M ) , y ( 1 ) , y ( 2 ) , … , y ( M ) } , x ( i ) = { s ( i )  if  s ( i )  is better than  s ( i + M ) S ( i + M )  else  \begin{array}{l}\boldsymbol{S}=\left\{\boldsymbol{s}^{(1)}, \boldsymbol{s}^{(2)}, \ldots, \boldsymbol{s}^{(2 M)}\right\}=\left\{\boldsymbol{x}^{(1)}, \boldsymbol{x}^{(2)}, \ldots, \boldsymbol{x}^{(M)}, \boldsymbol{y}^{(1)}, \boldsymbol{y}^{(2)}, \ldots, \boldsymbol{y}^{(M)}\right\}, \\\boldsymbol{x}^{(i)}=\left\{\begin{array}{lc}\boldsymbol{s}^{(i)} & \text { if } \boldsymbol{s}^{(i)} \text { is better than } \boldsymbol{s}^{(i+M)} \\\boldsymbol{S}^{(i+M)} & \text { else }\end{array}\right.\end{array} S={s(1),s(2),,s(2M)}={x(1),x(2),,x(M),y(1),y(2),,y(M)},x(i)={s(i)S(i+M) if s(i) is better than s(i+M) else 

    代码实现:

    % 子代,父代二选一
    for ij = 1:Nums
        if y_childs(ij) > y_childs(ij+Nums)
            x_father(ij) = x_childs(ij+Nums);
        else
            x_father(ij) = x_childs(ij);
        end
    end
    

    最后选择出新的子代,重复上述过进行迭代直到满足结束条件(达到迭代次数/多代不变)。

结果分析

循环运行500次,计算平均运行时间、最优解率、平均最优解、标准差、相对标准差;


  • 测试结果(1)

    编码方式:二进制编码
    选择方式:轮盘赌

    迭代次数    平均运行时间(s)    最优解率(%)    平均最优解     标准差     相对标准差(%)
    _______    _____________    __________    _________    _______    ___________
    
      10        8.5748e-05         63.8         3.294      0.76729       23.294
    

    在这里插入图片描述


  • 测试结果(2)

    编码方式:格雷码编码
    选择方式:轮盘赌

    迭代次数    平均运行时间(s)    最优解率(%)    平均最优解     标准差     相对标准差(%)
    _______    _____________    __________    _________    _______    ___________
    
      10        0.00012561         87.4         3.044      0.77412       25.431
    

    在这里插入图片描述


  • 测试结果(3)

    编码方式:格雷码编码
    选择方式:锦标赛

    迭代次数    平均运行时间(s)    最优解率(%)    平均最优解     标准差     相对标准差(%)
    _______    _____________    __________    _________    _______    ___________
    
      10        0.00011234         74.2         3.07       0.90262       29.401
    

    在这里插入图片描述


  • 测试结果(4)

    编码方式:二进制编码
    选择方式:锦标赛

    迭代次数    平均运行时间(s)    最优解率(%)    平均最优解     标准差     相对标准差(%)
    _______    _____________    __________    _________    _______    ___________
    
      10        8.5653e-05          60          3.178      0.71227       22.413
    

    在这里插入图片描述


  • 测试结果(5)

    编码方式:格雷码编码
    选择方式:轮盘赌

    迭代次数    平均运行时间(s)    最优解率(%)    平均最优解     标准差     相对标准差(%)
    _______    _____________    __________    _________    _______    ___________
    
      35         0.0004159         99.6         3.006      0.09992       3.324
    

    在这里插入图片描述


结论

在实验中, 通过上述有限的测试数据,在迭代次数有限的情况下,格雷码编码方式优于二进制编码,轮盘赌略优于锦标赛。在迭代次数35次,采用格雷码编码方式结合轮盘赌选择算法时最优解率可实现99.5%以上,相对标准差达到3%以下,平均运行时间4ms。

源码:https://github.com/Esasoon/Algorithms/tree/main/Genetic_Algorithm

简单的遗传算法,计算函数最值. function ga_main() % 遗传算法程序 % n-- 种群规模% ger-- 迭代次数% pc--- 交叉概率% pm-- 变异概率 % v-- 初始种群(规模为n)% f-- 目标函数值% fit-- 适应度向量 % vx-- 最优适应度值向量% vmfit-- 平均适应度值向量 clear all; close all; clc;%清屏 tic;%计时器开始计时 n=20;ger=100;pc=0.65;pm=0.05;%初始化参数 %以上为经验值,可以更改。 % 生成初始种群 v=init_population(n,22); %得到初始种群,22串长,生成20*22的0-1矩阵 [N,L]=size(v); %得到初始规模行,列 disp(sprintf('Number of generations:%d',ger)); disp(sprintf('Population size:%d',N)); disp(sprintf('Crossover probability:%.3f',pc)); disp(sprintf('Mutation probability:%.3f',pm)); %sprintf可以控制输出格式 % 待优化问题 xmin=0;xmax=9; %变量X范围 f='x+10*sin(x.*5)+7*cos(x.*4)'; % 计算适应度,并画出初始种群图形 x=decode(v(:,1:22),xmin,xmax);"位二进制换成十进制,%冒号表示对所有行进行操作。 fit=eval(f);%eval转化成数值型的 %计算适应度 figure(1);%打开第一个窗口 fplot(f,[xmin,xmax]);%隐函数画图 grid on;hold on; plot(x,fit,'k*');%作图,画初始种群的适应度图像 title('(a)染色体的初始位置');%标题 xlabel('x');ylabel('f(x)');%标记轴 % 迭代前的初始化 vmfit=[];%平均适应度 vx=[]; %最优适应度 it=1; % 迭代计数器 % 开始进化 while it<=ger %迭代次数 0代 %Reproduction(Bi-classist Selection) vtemp=roulette(v,fit);%复制算子 %Crossover v=crossover(vtemp,pc);%交叉算子 %Mutation变异算子 M=rand(N,L)<=pm;%这里的作用找到比0.05小的分量 %M(1,:)=zeros(1,L); v=v-2.*(v.*M)+M;%两个0-1矩阵相乘后M是1的地方V就不变,再乘以2. NICE!!确实好!!!把M中为1的位置上的地方的值变反 %这里是点乘 %变异 %Results x=decode(v(:,1:22),xmin,xmax);%解码,求目标函数值 fit=eval(f); %计算数值 [sol,indb]=max(fit);% 每次迭代中最优目标函数值,包括位置 v(1,:)=v(indb,:); %用最大值代替 fit_mean=mean(fit); % 每次迭代中目标函数值的平均值。mean求均值 vx=[vx sol]; %最优适应度值 vmfit=[vmfit fit_mean];%适应度均值 it=it+1; %迭代次数计数器增加 end
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值