从Matlab实例学习遗传算法

news2025/4/6 9:34:38

文章目录

  • 前言
  • 问题背景
  • 遗传算法
  • Matlab实例代码
  • 附录
    • 君主方案
    • 遗传算法解决旅行商问题

前言

本文旨在使用智能优化算法及其MATLAB实例(第2版) 一书中的例子,来透彻理解遗传算法的本质。

问题背景

目标: 求解最大化函数 f ( x ) = x + 10 sin ⁡ ( 5 x ) + 7 cos ⁡ ( 4 x ) f(x)=x+10 \sin (5 x)+7 \cos (4 x) f(x)=x+10sin(5x)+7cos(4x) x x x, 其中 x ∈ [ 0 , 10 ] x\in[0,10] x[0,10]

这个问题可以直接通过导数为0求解,但我们选择以此作为遗传算法的简单示例。

遗传算法的本质是优化后的穷搜算法事实上几乎所有此类启发式算法,本质都是用不同方式尽可能规避无效搜索后的优化版穷搜算法

对于这个优化问题,变量 x x x为连续变量,可行解有无穷个, 这样甚至连穷搜都不可行。 因此,我们首先要将可行域离散化,使其可行解个数为有限个方能进行搜索。 很简单的一种办法就是遗传算法中所谓的染色体编码: 定义一个编码 X X X是一个 L × 1 L\times 1 L×1 0 − 1 0-1 01向量, 例如:
X = [ 0 , 1 , 1 , 0 , ⋯   , 1 ] X=[0, 1, 1, 0, \cdots, 1] X=[0,1,1,0,,1]
那么很显然, 共有 2 L 2^L 2L个不同的 X X X。 我们可以认为每个 X X X都代表一个原问题中的可行 x x x, 具体而言,我们可以定义函数:
g ( X ) = 0 + m × 10 2 L , m = ∑ i = 1 L 2 i − 1 X i g(X) = 0 + \frac{m\times 10} {2^L}, m = \sum_{i=1}^{L}2^{i-1}X_i g(X)=0+2Lm×10,m=i=1L2i1Xi
那么 g ( X ) g(X) g(X)就代表了 [ 0 , 10 ] [0, 10] [0,10]之间的一个可行的 x x x

通过均匀量化的方式,我们将无限的可行空间缩小成一个有限的可行空间。 当 L L L足够大时,解的精度几乎不会受损。 而这一简单的思想在遗传算法中就被称作听起来更高大上一些的染色体编码。

这样一来,使用穷搜算法的话,就是无脑遍历 2 L 2^L 2L个解,选择最好的那个。 接下来介绍遗传算法的搜索方式,以期在搜索数远少于 2 L 2^L 2L次的情况下,搜到很好的解。

遗传算法

  1. 首先, 获取初始种群, 也就是先随机要搜索的 N P N_P NP个初始可行解 X X X
  2. 对初始种群进行评估: 计算这 N P N_P NP个解对应的目标函数大小。 就本例而言,基于 X X X换算为 x x x后再计算 f ( x ) f(x) f(x)的值,记录对应最大 f ( x ) f(x) f(x)和最小 f ( x ) f(x) f(x)值的个体, 也即 X X X
  3. 计算适应度: 越优秀的个体,要有越大的概率遗传到下一代。我们以适应度来量化刻画优秀: F = f ( x ) − f m i n f m a x − f m i n F=\frac{f(x)-f_{min}}{f_{max}-f_{min}} F=fmaxfminf(x)fmin
    此处 f m i n f_{min} fmin f m a x f_{max} fmax代表了第二步中计算得到的当代种群的最优和最差解。 经这一步操作,我们可以得到一个归一化的适应度结果 F F F。 显然, F ∈ [ 0 , 1 ] F\in[0,1] F[0,1], 且是 f ( x ) f(x) f(x)的单调递增函数, 也符合了我们优胜劣汰的遗传思想。
  4. 复制操作: 从这一步开始我们准备基于初始种群生成下一代的种群了。 首先,我们要基于适应度进行优胜劣汰: 更好的个体将有更大的概率进行复制,遗传到下一代种群。 我们采用本例中所使用的所谓轮盘赌的选择准则:
    p i = F i ∑ F i p_i=\frac{F_i}{\sum F_i} pi=FiFi
    这里 p i p_i pi F i F_i Fi分别代表第 i i i个个体被选中进行复制的概率和其对应的适应度。 显然, F i F_i Fi越大,被复制的概率越高。基于此,我们复制出下一代的 N p N_p Np个可行解 X X X
    (可以看到,表现最差的那个个体已不可能被复制,因为其 F i F_i Fi为0。)
  5. 交叉操作: 这个操作就是完全启发自遗传的思想了——父母结合产生新的下一代。 具体而言, 将我们刚刚复制出来的下一代的 N p N_p Np个个体中,随机选择一对,将它们随机 l l l位的编码互换, 从而更新这两个个体,创造出新的个体来。 在本例中, 对复制好的 N p N_p Np个个体,我们按序两两成对, 如1和2, 3和4,然后随机交换它们对应位的编码。每个位置交换与否的概率为 0.5 0.5 0.5。 另外, 对每一对选出的个体,都有20%的概率不进行交叉, 有80%的概率执行刚刚所述的交叉。 而80%则被称为交叉率。
  6. 变异操作: 除了通过交叉操作产生新个体,变异操作也是得到新个体的重要手段。 首先定义变异率 p m p_m pm, 那么我们将随机选取 p m × N p p_m\times N_p pm×Np个个体进行变异。 变异操作如下: 对一个个体, 随机挑选其 L × p m L\times p_m L×pm个基因(也即编码)进行变异,也即取反,从而得到一个新的个体。 这里如果 p m × L p_m\times L pm×L的结果非整则还需取整。
  7. 保留最优: 经过上述操作后,我们实际上已经生成了共有 N p N_p Np个个体的新一代种群。 此时,我们将第一个个体踢掉,用上一代种群中最好的那个个体代替之。 也即: 下一代种群永远保留上一代的最优解。
  8. 判断是否已迭代到指定的遗传代数。如果没有,则跳转到第二步进行迭代。 若已达到, 选择最优的个体作为最终解。 由于在每一代遗传时都保留了上一代的最优解,因此事实上我们的最终解就是所有搜索过的个体中的历史最优解。

以上就是遗传算法的具体流程。 虽然看到许多文章会说他各种优点,但笔者看来,本质上就是如果基于一些启发式的(来自于自然的)思想进行更高效的搜索,虽然欠缺扎实的理论分析,但看上去就是个行之有效的方案。 下面则是Matlab实例运行结果:

Matlab实例代码

在这里插入图片描述
作者给出的代码中用到了已被淘汰的randint API, 这里笔者进行了修改使得可以直接在新版matlab上运行了,代码如下:

%%%%%%%%%%%%%%%%%%%%标准遗传算法求函数极值%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%初始化参数%%%%%%%%%%%%%%%%%%%%%%%%%%
clear all;              %清除所有变量
close all;              %清图
clc;                    %清屏
NP=50;                  %种群数量
L=20;                   %二进制数串长度
Pc=0.8;                 %交叉率
Pm=0.1;                 %变异率
G=100;                  %最大遗传代数
Xs=10;                  %上限
Xx=0;                   %下限
f=randi(2, NP,L) - 1;        %随机获得初始种群
%%%%%%%%%%%%%%%%%%%%%%%%%遗传算法循环%%%%%%%%%%%%%%%%%%%%%%%%
for k=1:G
    %%%%%%%%%%%%将二进制解码为定义域范围内十进制%%%%%%%%%%%%%%
    for i=1:NP
        U=f(i,:);
        m=0;
        for j=1:L
            m=U(j)*2^(j-1)+m;
        end
        x(i)=Xx+m*(Xs-Xx)/(2^L-1);
        Fit(i)= func1(x(i));
    end
    maxFit=max(Fit);           %最大值
    minFit=min(Fit);           %最小值
    rr=find(Fit==maxFit);
    fBest=f(rr(1,1),:);        %历代最优个体   
    xBest=x(rr(1,1));
    Fit=(Fit-minFit)/(maxFit-minFit);  %归一化适应度值
    %%%%%%%%%%%%%%%%%%基于轮盘赌的复制操作%%%%%%%%%%%%%%%%%%%
    sum_Fit=sum(Fit);
    fitvalue=Fit./sum_Fit;
    fitvalue=cumsum(fitvalue);
    ms=sort(rand(NP,1));
    fiti=1;
    newi=1;
    while newi<=NP
        if (ms(newi))<fitvalue(fiti)
            nf(newi,:)=f(fiti,:);
            newi=newi+1;
        else
            fiti=fiti+1;
        end
    end   
    %%%%%%%%%%%%%%%%%%%%%%基于概率的交叉操作%%%%%%%%%%%%%%%%%%
    for i=1:2:NP
        p=rand;
        if p<Pc
            q=randi(2, 1,L) - 1;
            for j=1:L
                if q(j)==1
                    temp=nf(i+1,j);
                    nf(i+1,j)=nf(i,j);
                    nf(i,j)=temp;
                end
            end
        end
    end
    %%%%%%%%%%%%%%%%%%%基于概率的变异操作%%%%%%%%%%%%%%%%%%%%%%%
    i=1;
    while i<=round(NP*Pm)
        h=randi(NP);      %随机选取一个需要变异的染色体
        for j=1:round(L*Pm)         
            g=randi(L);   %随机需要变异的基因数
            nf(h,g)=~nf(h,g);
        end
        i=i+1;
    end
    f=nf;
    f(1,:)=fBest;                   %保留最优个体在新种群中
    trace(k)=maxFit;                %历代最优适应度
end
xBest;                              %最优个体
figure
plot(trace)
xlabel('迭代次数')
ylabel('目标函数值')
title('适应度进化曲线')


附录

君主方案

不同于轮盘赌方案,君主方案的交叉、变异、选择操作如下:

  1. 降序排列种群的个体适应度,选出适应度最高的个体作为“君主”。
  2. 将君主与其他偶数位的个体进行交叉, 交叉的基因位个数决定于交叉率, 例如交叉率为80%,基因位数10, 则有8个基因将进行交叉置换。
  3. 基于变异率对所有个体进行变异,这一步操作与前例一致。 至此得到 N p N_p Np个新个体。
  4. 将这 N p N_p Np个新个体与上一代的 N p N_p Np个老个体一并进行适应度评价, 留下前 N p N_p Np个高适应度个体作为这一代的种群。、

遗传算法解决旅行商问题

假设有 N N N个城市, 旅行商问题就是解决到这 N N N个城市的顺序问题, 也即可行解 X X X [ 1 , 2 , ⋯   , N ] [1,2,\cdots, N] [1,2,,N]的任意乱序排列。 因此,我们可以将一个个体定义为一种乱序排列 (也即基因位数仍是 32 32 32, 但取值不再是 0 , 1 0,1 0,1, 而是 1 , ⋯   , N 1,\cdots, N 1,,N), 也即任意个体就是一个可行解。

为此,我们需要重新定义交叉、变异操作, 以使得创造出的新个体是可行解。

非常启发式的, 交叉操作可以定义为:随机交换两个个体成对的城市索引。 变异操作可定义为: 随机交换一个个体的一对城市索引。

由此我们也可以看出, 用遗传算法解决问题的核心,就在于如何定义交叉、变异操作,使得新个体仍是可行解,即实现有效搜索。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/5506.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023最新SSM计算机毕业设计选题大全(附源码+LW)之java星光之夜香水网站的设计与开发bfmcr

大学计算机专业毕业的&#xff0c;实际上到了毕业的时候&#xff0c;基本属于会与不会之间。说会&#xff0c;是因为学了整套的理论和方法&#xff0c;就是所谓的科班出身。说不会&#xff0c;是因为实践能力极差。 不会的问题&#xff0c;集中体现在毕设的时候&#xff0c;系…

CTFSHOW菜狗杯 web

文章目录web签到web2 c0me_t0_s1gn我的眼里只有$抽老婆一言既出驷马难追TapTapTapWebshell化零为整无一幸免传说之下&#xff08;雾&#xff09;算力超群算力升级2遍地飘零茶歇区小舔田&#xff1f;LSB探姬Is_Not_Obfuscate龙珠NFTweb签到 eval($_REQUEST[$_GET[$_POST[$_COOK…

Ubuntu22.04虚拟机配置双网

文章目录Ubuntu22.04虚拟机配置双网一、 虚拟机网络1、 简介1.1 概述1.2 四种网络2、 配置双网2.1 NAT2.2 主机模式3、 添加到虚拟机二、 ubuntu设置Ubuntu22.04虚拟机配置双网 一、 虚拟机网络 1、 简介 1.1 概述 近期在使用VirtualBox的时候遇到这样的场景&#xff0c;我…

Docker(五)—— 镜像原理、容器快照commit

一、如何得到镜像 1&#xff09;从远程仓库下载 2&#xff09;朋友/同事拷贝给你 3&#xff09;自己制作DockerFile 二、联合文件系统 Docker的镜像是由一层层的文件系统组成&#xff0c;这种层级的文件系统叫做联合文件系统UnionFS。 三、Docker镜像加载原理 1. bootfs:…

第十四届蓝桥杯校内模拟赛第一期——Python

第十四届蓝桥杯校内模拟赛第一期——Python 文章目录第十四届蓝桥杯校内模拟赛第一期——Python1.二进制位数问题描述参考答案扩展2. 晨跑问题描述参考答案扩展3. 调和级数问题描述参考答案4. 山谷问题描述参考答案5. 最小矩阵问题描述参考答案6. 核酸日期问题描述输入格式输出…

redux与react-redux的学习笔记之react-redux

redux与react-redux前言一、redux和react-redux是啥&#xff1f;二、redux使用步骤1.引入库2.原理图原理图释义actions1&#xff09;含义2&#xff09;demostore.js1&#xff09;含义2&#xff09;demoreducer.js1&#xff09;含义2&#xff09;demoCount.jsx1&#xff09;含义…

2022年,我们为什么要学习C++?

“C已死” 大学时代&#xff0c;我就听过这样的说法——差不多十多年前的事儿了。那时候至少在美国&#xff0c;Java已经成了各公司的主流语言。程序员也许都很熟悉Joel Spolsky在2005年12月对JavaSchools发起的批驳。此外&#xff0c;作为微软应对Java的手段&#xff0c;2000…

Ubuntu环境配置(instant-ngp)

综合环境配置 这篇文章的综合配置我是在恒源云上配的&#xff0c;自己穷买不起机子&#xff0c;就只能租咯&#xff0c;这家价格还行&#xff0c;而且可以装VNC&#xff0c;非推广&#xff0c;只是感觉方便&#xff0c;请大家结合自身实际情况 数据上传 这里有几种方法&…

【免费】多种方法手把手教你如何将自己做的网页做成网络链接(直接访问)

目录 前言 ​一、github&#xff08;最常用的&#xff09; 二、七牛云&#xff08;推荐小白使用&#xff0c;简单粗暴&#xff09; 三、NATAPP 四、codepen&#xff08;建议学网页的人群使用&#xff09; 彩蛋 前言 http://t.csdn.cn/VaiP1我之前发的爱心代码&#xff0c;…

电脑突然开机无反应,怎么办

电脑常见故障之三开机无响应&#xff08;上&#xff09; 经常使用电脑的朋友应该会碰到这种情况&#xff0c;开机时按下电源按钮后&#xff0c;电脑无响应&#xff0c;显示器黑屏不亮。 除去那些傻瓜式的故障原因&#xff0c;如显示器、主机电源没插好&#xff1b;显示器与主…

手写小程序摇树优化工具(一)——依赖分析介绍

道可道&#xff0c;非常道&#xff1b;名可名&#xff0c;非常名&#xff1b;玄之又玄&#xff0c;众妙之门。 现在国内好像没有什么针对小程序代码的摇树优化方案&#xff0c;出现了很多超包的问题无法解决&#xff0c;本教程就手把手教大家如何编写一个完整的微信小程序摇树优…

深度学习零基础学习之路——第四章 UNet-Family中Unet、Unet++和Unet3+的简介

Python深度学习入门 第一章 Python深度学习入门之环境软件配置 第二章 Python深度学习入门之数据处理Dataset的使用 第三章 数据可视化TensorBoard和TochVision的使用 第四章 UNet-Family中Unet、Unet和Unet3的简介 Unet-Family的学习Python深度学习入门前言一、FCN全卷积网络…

【JavaSE】面向对象三大特性之多态

文章目录多态的概念向上转型重写之动态绑定与重载之静态绑定重写与重载的区别重写的注意事项总结不安全的向下转型多态的优点和注意事项优点缺点和注意事项多态的概念 多态可以理解为一个对象在某些时刻可以代表不同的对象&#xff0c;指的是对象的多种形态。所以在某些时刻&a…

CSDN第九次竞赛题解与总结

CSDN第九次竞赛题解与总结前言T1小艺读书题意分析T2鬼画符门之宗门大比题意分析代码别的方法T3硬币划分题意分析状态转移方程初始值代码T4饿龙咆哮-逃离城堡题意分析坑点代码写在最后前言 2022/11/12 我有幸参加了csdn第九次竞赛&#xff0c;终于拿了次满分&#xff0c;进了次…

Vuex④(多组件共享数据、Vuex模块化+namespace)

文章目录多组件共享数据代码实现Vuex模块化总结多组件共享数据 我们现在想实现这种情况&#xff1a; Person组件的总人数就是Person中列表的长度 br上的是Count组件&#xff0c;br下的是Person组件。 我们通过vuex中的state实现一些数据的多组件共享&#xff1a; 代码实现 …

第二章STP应用配置

目录 一 生成树 二 生成树算法 三 STP是什么 四 BPDU是什么 五 BPDU的概念 六 生成树基本配置 一 生成树 生成树算法的网桥协议STP(Spanning Tree Protocol) 它通过生成生成树保证一个已知的网桥在网络拓扑中沿一个环动态工作。网桥与其他网桥交换BPDU消息来监测环路&#xf…

使用 hugo oss 搭建个人博客网站

系列文章目录 文章目录系列文章目录前言一、下载hugo二、oss三、域名四、创建博客上传五、发布&#xff0c;上传文章前言 本文主要详解如何用最低的成本搭建个人博客网站 原本我是直接用的github搭建的博客网站&#xff0c;因为免费&#xff0c;但由于github访问很不稳定&…

Python——正则表达式的应用

文章目录前言正则表达式方法re.search方法group方法re.match方法re.findall方法re.finditer方法re.split方法re.sub方法正则表达式的应用前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 正则表达式是字符串处理的有力工具和技术。 使用正在表达式的目的…

多态(polymorphic)

目录 1. 多态的基本介绍 2. 多态实现条件 3. 重写 重写的介绍&#xff1a; 【重写和重载的区别】 动、静态绑定机制 5 向上转型和向下转型 向上转型 向上转型的特点&#xff08;总结&#xff09;&#xff1a; 向下转型 多态的优缺点 多态是Java三大基本特征中最抽象…

【数据结构初阶】数组栈和链式队列的实现

努力真的要贯穿人的一生吗&#xff1f; 你能活成你想要的样子吗&#xff1f; 真的不知道&#xff01; 文章目录一、栈的概念及结构二、栈的实现&#xff08;动态数组栈&#xff09;2.1 挑选实现栈的结构2.2 栈结构的定义2.3 初始化栈销毁栈2.4 入栈出栈2.5 判空取栈顶元素栈元…