精华内容
下载资源
问答
  • 算法描述

    千次阅读 2019-09-22 17:40:02
    (2)描述算法工具:算法可用自然语言、框图或高级程序设计语言进行描述。自然语言简单但易产生二义性;框图直观但不擅长表达数据的组织结构;而高级程序设计语言则较为准确、严谨,但因需考虑细节问题而显得相对...

    1.算法、语言、程序的关系

    首先分析数据结构中算法、语言和程序的关系。

    (1)算法:描述数据对象之间的关系(包括数据逻辑关系、存储关系描述)。

    (2)描述算法的工具:算法可用自然语言、框图或高级程序设计语言进行描述。自然语言简单但易产生二义性;框图直观但不擅长表达数据的组织结构;而高级程序设计语言则较为准确、严谨,但因需考虑细节问题而显得相对繁琐。

    (3)程序是算法在计算机中的实现(与所用计算机及所用语言有关)。程序设计的实质是对实际问题选择一种好的数据结构,加之设计一个好的算法,而好的算法在很大程度上取决于描述实际问题的数据结构。

    2.设计实现算法过程的步骤

    (1)找出与求解有关的数据元素之间的关系(建立结构关系)

    (2)确定在某一数据对象上所施加的运算。

    (3)考虑数据元素的存储表示。

    (4)选择描述算法的语言。

    (5)设计实现求解的算法,并用程序语言加以描述。

    3.描述算法的语言选择

    高级语言描述算法具有严格、准确的优点,但用于描述算法,也有语言细节过多的弱点,为此可采用类语言形式。所谓类语言,是指接近于高级语言而又不是严格的高级语言,它具有高级语言的一般语句,撇掉语言中的细节,以便把注意力集中在算法处理步骤本身的描述上。

    传统的描述语言是采用Pascal语言,由于该语言语法规范严谨,非常适合于数据结构。在Windows环境下,又出现了一系列功能强大且面向对象的程序开发工具,如visual C++、Borland C++、Visual Basic等。近年来在计算机科学研究、系统开发、教学以及应用开发中,C语言的使用范围越来越广,C语言成为许多学校计算机专业与非计算机专业必修的高级程序设计语言。C语言类型丰富,执行效率高。

     

    展开全文
  • 用流程图描述算法

    万次阅读 多人点赞 2018-07-18 08:41:11
    【前面了解了程序和算法的关系,知道了算法是解决问题的具体方法和步骤,也学会了用文字去描述算法。哪还有没有其它描述算法的方式呢?毕竟文字看起来比较费劲。流程图就是一种描述算法的图形化描述,用流程图可以...

    课程导言

    【前面了解了程序和算法的关系,知道了算法是解决问题的具体方法和步骤,也学会了用文字去描述算法。哪还有没有其它描述算法的方式呢?毕竟文字看起来比较费劲。流程图就是一种描述算法的图形化描述,用流程图可以清晰地描述出算法的思路和过程。通过本篇的学习,你将了解到如何用流程图来描述算法。】

     

    流程图是算法的图形化描述。俗话说:一张图胜过千言万语,用流程图可以清晰地描述出算法的思路和过程。

    1、从生活中认识流程图

    说到流程图,同学们可能会感到比较陌生和不理解,其实在我们生活中,经常会看到流程图,也会读懂流程图,并能按照流程图的要求去执行流程图中的各个步骤。例如,我们去图书馆借书就要遵循图书馆制定的流程,当初次使用车站自动售票机购票时,就要仔细看自动购票流程图。看流程图的目的,就是让我们能够明确每一个步骤,而不会出现差错。

                                                 

    0033.png

    图1 借书与自动售票流程图

    现在家庭中一般都有电冰箱、洗衣机等家用电器,家用电器包装箱里面都会附带使用说明书,使用说明书包含了产品的使用方法、注意事项以及一般故障排除流程等内容,当家用电器发生故障时,可以先根据使用说明书的故障排除流程进行故障检查,多半故障原因是因使用不当造成的。下图是某一洗衣机不启动的故障原因排除流程图:

    000999.jpg

     

    图2 洗衣机不启动故障排除流程图

    流程图明确给出了排除因使用不当原因而造成洗衣机不启动故障的排查方法和流程,可以参照流程图给出的步骤,逐步排查洗衣机不能启动的原因。

    按照流程图给出的步骤进行排查:

    第一步需要检查电源是否接通,如果电源有问题,则解决电源问题后,故障排除。如果电源没有问题,则进入第二个步骤。

    第二步需要检查洗衣机门是否关严,如果洗衣机门没有关严,则关严洗衣机门,故障排除。如果洗衣机门已关严,则进入第三个步骤。

    第三步需要检查洗衣机进水部分,查看水龙头是否打开,没有水压,洗衣机也不能启动,如果水龙头没有打开,则打开水龙头,故障排除。如果水龙头已打开且有水压,则进入第四个步骤。

    第四步需要检查是否按下了启动键并有蜂鸣声,如果没有按下启动键,则按下启动键,故障排除。如果已按下启动键且有蜂鸣声,则需要给售后服务打电话报修。

    2、认识流程图的符号

    前面看了洗衣机故障排除流程图,同学们一定很奇怪,流程图的椭圆框、菱形框、平行四边形、长方形以及带线的箭头都表示什么意义?画流程图是不是可以用其它形状画呢?

    其实,流程图是可以允许用其它图形符号画的,只要自己能看明白,能记住流程就行。问题是,如果你希望其他人也能看懂你的流程图,可能就有点麻烦了,你需要给他们解释你流程图中采用的每个图形所表示的含义是什么,当需要给多个人解释时,这时你一定在想,如果这些图形表示的含义他们都知道该多好,就不用我一个个去讲,去沟通了。

    因此,规范的流程图可以帮助人们对流程的统一认识,便于沟通和讨论,有助于工作效率的提高。它使用一组预定义的符号来说明如何执行特定任务,这些预先定义的符号已经标准化,从而让全世界的开发人员都可以采用这些符号而不会引起混淆。表1-1对流程图中使用的符号进行了汇总。

    blob.png

    3、如何绘制流程图?

    先请同学们思考一个计算长方形面积的问题,并给出算法,用文字描述出来。

    问题的解决可分为下面几个步骤:

    (1)设置num1和num2两个变量,接收用户输入的长度和宽度,并存储到num1和num2两个变量;

    (2)判断num1和num2是否大于0,如果大于0,继续下一个步骤,否则提示用户长度和宽度输入错误,算法结束;

    (3)计算num1和num2的乘积,并将乘积结果存储到result变量;

    (4)显示result变量的值到屏幕。

    流程图可以采用多个工具软件进行绘制,下面所列是常用的绘制流程图的工具软件,建议使用Microsoft Visio软件绘制,本课程流程图采用Microsoft Visio 2013软件绘制,流程图见图2-3。

    (1)Microsoft Visio 2010或更高版本

    (2)在线流程图绘制工具processon.com

    (3)PPT、Word等软件

       blob.png                                          

    图3 计算长方形面积算法流程

    使用Microsoft Visio 2013绘制流程图步骤如下:

    (1)Visio 2013是一款比较强大的画图工具,不仅用于软件、办公室用图表,还可以绘制工程图表,启动Visio2013后,Visio会展现各种特色的图表,双击图表,就进入绘制页面了。如图4所示。

    blob.png

    图4  Visio2013可绘制的图表类型

    (2)选择类别,Visio进入类别页面,找到流程图类别,用鼠标单击流程图,进入流程图选择页面。如图5所示。

    blob.png

    图5 Visio2013类别选择页

    (3)在流程图新建页面,选择基本流程图,用鼠标单击基本流程图,在弹出的创建对话框中,单击创建按钮,进入绘图页面。如图6所示。

    blob.png

    图6 创建基本流程图

    (4)在绘图页面中,左侧的是图形符号窗口,可以在这里选择不同的图形符号拖拽到绘图区域,右侧用灰色线条框住的区域是绘图区域,如图7所示。

    blob.png

    图7 流程图绘图页面

    (5)绘制流程图,先从开始符号绘制,在左侧符号区域选择开始/结束图形符号,按下鼠标左键,用鼠标拖拽到绘图区域的适当位置,并输入“开始”文字,如图8所示。

    blob.png

    图8 绘制开始符号

    (6)算法的第一个步骤是接收用户输入的长度和宽度,并存储到num1和num2变量中,此时要用到输入/输出符号,在左侧符号区域选择输入/输出符号,按下鼠标左键,用鼠标拖拽到开始符号的下方适当位置,输入“接收num1和num2”内容。并在开始符号和输入/输出符号之间绘制流程线,流程线的箭头指向输入/输出符号。如图9所示。

    blob.png

    图9 绘制流程图输入/输出符号

    (7)算法的第二个步骤是判断输入的num1和num2是否大于零,根据判断情况执行不同的分支。此时要用到判断符号,在左侧符号区域选择判定符号,按下鼠标左键,用鼠标拖拽到输入/输出符号下方适当位置,并输入判定内容。如图10所示。

    blob.png

    图10 绘制流程图判断符号

    (8)如果num1或num2 小于零,提示用户输入错误。此时拖拽输入/输出符号到判定符号的左侧适当位置,输入“显示输入错误”内容,并用流程线连接判定符号和输入/输出符号,在流程线上标注“否”。如图211所示。

    blob.png

    图11 绘制判定流程否分支

    (9)算法的第三个步骤是,如果num1或num2 大于零,则执行两数相乘操作。此时应选用流程符号,拖拽流程符号到判定符号的下方适当位置,输入活动内容,并在判定符号和流程符号之间绘制流程线,流程线上标注“是”。如图12所示。

    blob.png

    图12 绘制判定流程“是”分支

    (10)算法的第四个步骤是将result变量输出到屏幕,此时应选用输入/输出符号,拖拽输入/输出符号到流程符号下方的适当位置,并绘制流程线,输入活动内容。如图213所示。

    blob.png

    图13 绘制输出/输出符号

    (11)算法流程图的绘制到此结束,拖拽开始/结束符号到绘图区域适当位置,并在结束符号和“显示输入错误”符号、“显示result”符号之间绘制流程线。在“显示输入错误”符号和结束符号之间绘制流程线,主要是算法规定当输入的num1和num2小于零时,提醒用户并退出程序。如图214所示。

    blob.png

    图14 绘制流程结束符号

     

    使用图形表示算法是非常好的思路,绘制流程图的过程就是整理思路的过程。通过绘制流程图,可以对算法进行一次完整的梳理,及时发现问题,调整思路。流程图一定要有开始和结束;菱形框表示判断,判断必须有两个分支,或者满足条件或者不满足条件;平行四边形框表示输入输出框,用于输入数据和输出数据的处理;矩形框表示处理过程,用于数值计算和业务处理;引线表示流程的方向。

     

    ■ 课程小结

    1. 流程图是算法的图形化描述。流程图用图形化的方式描述了算法从开始到结束的所有步骤,通过流程图可以直观的了解算法执行的过程,是人们之间交流算法很重要的图形化工具。

    2. 人们为了方便地使用流程图交流算法,而不至于因图形符号的问题引起对算法过程理解的混淆。人们规定了一组预定义的图形符号来表示算法的过程,并给出每个图形符号的说明。标准的流程图符号包括开始/结束符号、输入/输出符号、流程符号、子流程符号、判断符号、流程线6种图形符号,用这6种图形符号可以绘制任何类型的流程图。

    3. 绘制流程图的工具有很多,比较常用的有Visio、PPT等工具软件。绘制流程图时,必须要有开始和结束,并要遵循流程图各符号表示的含义。当需要输入数据或输出数据时,就要用输入/输出符号;当需要对条件进行判断时,就要用判断符号;当需要执行计算过程时,就要用流程符号。另外,流程线的箭头指向算法当前步骤的下一个步骤,表示算法执行过程的走向。

     

    ■ 思考与练习

    1. 思考一个求三个数最大值的算法,算法步骤通过流程图绘制出来。

    作业要求:接受用户输入的三个数值,求出最大值,将计算结果输出到显示器。

    2. 请给出第一篇思考与练习第4题算法的流程图描述。

    展开全文
  • 网上很多博客讲解遗传算法,但是大都只是“点到即止”,虽然给了一些代码实现,但也是“浅尝辄止”,没能很好地帮助大家进行扩展应用,抑或是进行深入的研究。 这是我的开篇之作~之前没有写博客的习惯,一般是将...

    加了个小目录~方便定位查看~

    前言

    正文

    一. 基础术语:

    二. 遗传算法基本算子:

    三.完整实现遗传算法:

    四.后记:


    前言

    网上有很多博客讲解遗传算法,但是大都只是“点到即止”,虽然给了一些代码实现,但也是“浅尝辄止”,没能很好地帮助大家进行扩展应用,抑或是进行深入的研究。

    这是我的开篇之作~之前没有写博客的习惯,一般是将笔记存本地,但久而久之发现回看不便,而且无法与大家交流和学习。现特此写下开篇之作,若有疏漏之处,敬请指正,谢谢!

    本文对遗传算法的原理进行梳理,相关代码是基于国内高校学生联合团队开源的高性能实用型进化算法工具箱geatpy来实现,部分教程引用了geatpy的官方文档:

    http://geatpy.com/index.php/details/

    geatpy官网:http://www.geatpy.com

    若有错误之处,恳请同志们指正和谅解,谢谢!

    因为是基于geatpy遗传和进化算法工具箱,所以下文的代码部分在执行前,需要安装geatpy:

    pip install geatpy

    安装时会自动根据系统版本匹配下载安装对应的版本。这里就有个小坑:如果最新版Geatpy没有与当前版本相匹配的包的话,会自动下载旧版的包。而旧版的包在Linux和Mac下均不可用。

    安装好后,在Python中输出版本检查是否是最新版(version 2.6.0):

    import geatpy as ea
    print(ea.__version__)
    

    下面切入主题:

    自然界生物在周而复始的繁衍中,基因的重组、变异等,使其不断具有新的性状,以适应复杂多变的环境,从而实现进化。遗传算法精简了这种复杂的遗传过程而抽象出一套数学模型,用较为简单的编码方式来表现复杂的现象,并通过简化的遗传过程来实现对复杂搜索空间的启发式搜索,最终能够在较大的概率下找到全局最优解,同时与生俱来地支持并行计算。

    下图展示了常规遗传算法(左侧) 和某种在并行计算下的遗传算法(右侧) 的流程。

    本文只研究经典的遗传算法,力求最后能够解决各种带约束单目标优化问题,并能够很轻松地进行扩展,让大家不仅学到算法理论,还能轻松地通过“复制粘贴”就能够将相关遗传算法代码结合到各类不同的现实问题的求解当中。

    从上面的遗传算法流程图可以直观地看出,遗传算法是有一套完整的“固定套路”的,我们可以把这个“套路”写成一个“算法模板”,即把:种群初始化、计算适应度、选择、重组、变异、生成新一代、记录并输出等等这些基本不需要怎么变的“套路”写在一个函数里面,而经常要变的部分:变量范围、遗传算法参数等写在这个函数外面,对于要求解的目标函数,由于在遗传进化的过程中需要进行调用目标函数进行计算,因此可以把目标函数、约束条件写在另一个函数里面。

    另外我们还可以发现,在遗传算法的“套路”里面,执行的“初始化种群”、“选择”、“重组”、“变异”等等,其实是一个一个的“算子”,在geatpy工具箱里,已经提供现行的多种多样的进化算子了,因此直接调用即可。

    Geatpy工具箱提供一个面向对象的进化算法框架,因此一个完整的遗传算法程序就可以写成这个样子:

    关于算法框架的详细介绍可参见:http://geatpy.com/index.php/geatpy%E6%95%99%E7%A8%8B/

    下面就来详细讲一下相关的理论和代码实现:

    正文

    一. 基础术语:

        先介绍一下遗传算法的几个基础的术语,分别是:”个体“、”种群“、”编码与解码“、”目标函数值“、”适应度值“。

    1.个体:“个体”其实是一个抽象的概念,与之有关的术语有:

    (1)个体染色体:即对决策变量编码后得到的行向量。

    比如:有两个决策变量x1=1,x2=2,各自用3位的二进制串去表示的话,写成染色体就是:

    (2)个体表现型:即对个体染色体进行解码后,得到的直接指代各个控制变量的值的行向量。

     比如对上面的染色体“0 0 1 0 1 0”进行解码,得到 “1 2”,它就是个体的表现型,可看出该个体存储着两个变量,值分别是1和2。

    注意:遗传算法中可以进行“实值编码”,即可以不用二进制编码,直接用变量的实际值来作为染色体。这个时候,个体的染色体数值上是等于个体的表现型的。

    (3)染色体区域描述器:用于规定染色体每一位元素范围,详细描述见下文。

    2. 种群:“种群”也是一个抽象的概念,与之有关的术语有:

    (1)种群染色体矩阵(Chrom):它每一行对应一个个体的染色体。此时会发出疑问:一个个体可以有多条染色体吗?答:可以有,但一般没有必要,一条染色体就可以存储很多决策变量的信息了,如果要用到多条染色体,可以用两个种群来表示。

    例如:

    它表示有3个个体(因为有3行),因此有3条染色体。此时需要注意:这些染色体代表决策变量的什么值,我们是不知道的,我们也不知道该种群的染色体采用的是什么编码。染色体具体代表了什么,取决于我们采用什么方式去解码。假如我们采用的是二进制的解码方式,并约定上述的种群染色体矩阵中前3列代表第一个决策变量,后3列代表第二个决策变量,那么,该种群染色体就可以解码成:

    (2)种群表现型矩阵(Phen):它每一行对应一个个体的表现型。比如上图就是根据Chrom种群染色体矩阵解码得到的种群表现型矩阵。同样地,当种群染色体采用的是“实值编码”时,种群染色体矩阵与表现型矩阵实际上是一样的。

    (3)种群个体违反约束程度矩阵(CV):它每一行对应一个个体,每一列对应一种约束条件(可以是等式约束或不等式约束)。CV矩阵中元素小于或等于0表示对应个体满足对应的约束条件,大于0则表示不满足,且越大表示违反约束条件的程度越高。比如有两个约束条件:

    如何计算CV矩阵?可以创建两个列向量CV1和CV2,然后把它们左右拼合而成一个CV矩阵。

    假设x1、x2、x3均为存储着种群所有个体的决策变量值的列向量(这里可以利用种群表现型矩阵Phen得到,比如x1=Phen[:, [0]];x2=Phen[:, [1]]);x3=Phen[:, [2]]),这样就可以得到种群所有个体对应的x1、x2和x3)。

    那么:

    比如在某一代中,种群表现型矩阵Phen为:

    则有:

    此时CV矩阵的值为:

    由此可见,第一个个体满足两个约束条件;第二个个体违反了2个约束条件;第三和第四个个体满足第一个约束条件但违反了第二个约束条件。

    下面看下如何用代码来生成一个种群染色体矩阵:

    代码1. 实整数值种群染色体矩阵的创建:

    import numpy as np
    from geatpy import crtpc
    help(crtpc) # 查看帮助
    # 定义种群规模(个体数目)
    Nind = 4
    Encoding = 'RI' # 表示采用“实整数编码”,即变量可以是连续的也可以是离散的
    # 创建“区域描述器”,表明有4个决策变量,范围分别是[-3.1, 4.2], [-2, 2],[0, 1],[3, 3],
    # FieldDR第三行[0,0,1,1]表示前两个决策变量是连续型的,后两个变量是离散型的
    FieldDR=np.array([[-3.1, -2, 0, 3],
                      [ 4.2,  2, 1, 5],
                      [ 0,    0, 1, 1]])
    # 调用crtri函数创建实数值种群
    Chrom=crtpc(Encoding, Nind, FieldDR)
    print(Chrom)
    

    代码1的运行结果:

    这里要插入讲一下“区域描述器”(见代码1中的FieldDR),它是用于描述种群染色体所表示的决策变量的一些信息,如变量范围、连续/离散性。另外还有一种区域描述器(FIeldD),用于描述二进制/格雷码的种群染色体。FieldDR和FieldD两个合称“Field”,又可以认为它们是“译码矩阵”。FieldDR具有以下的数据结构:

    代码1中的FieldDR矩阵的第三行即为这里的varTypes。它如果为0,表示对应的决策变量是连续型的变量;为1表示对应的是离散型变量。

    另一种则是用于二进制/格雷编码种群染色体解码的译码矩阵FieldD,它是具有以下结构的矩阵:

    其中,lens, lb, ub, codes, scales, lbin, ubin, varTypes均为长度等于决策变量个数的行向量。

    lens 包含染色体的每个子染色体的长度。sum(lens) 等于染色体长度。

    lb 和ub 分别代表每个决策变量的上界和下界。

    codes 指明染色体子串用的是二进制编码还是格雷编码。codes[i] = 0 表示第i 个变量使用的是标准二进制编码;codes[i] = 1 表示使用格雷编码。

    scales 指明每个子串用的是算术刻度还是对数刻度。scales[i] = 0 为算术刻度,scales[i] = 1 为对数刻度。对数刻度可以用于变量的范围较大而且不确定的情况,对于大范围的参数边界,对数刻度让搜索可用较少的位数,从而减少了遗传算法的计算量。(注意:当某个变量是对数刻度时,其取值范围中不能有0,即要么上下界都大于0,要么上下界都小于0。)

    从2.5.0版本开始,取消了对对数刻度的支持,该参数暂时保留,但不在起作用。

    lbin 和ubin 指明了变量是否包含其范围的边界。0 表示不包含边界;1 表示包含边界。

    varTypes 指明了决策变量的类型,元素为0 表示对应位置的决策变量是连续型变量;1 表示对应的是离散型变量。

    对于二进制编码,二进制种群的染色体具体代表决策变量的什么含义是不由染色体本身决定的,而是由解码方式决定的。因此在创建二进制种群染色体之初就要设定好译码矩阵(又称“区域描述器”)。

    因此,可以通过以下代码构建一个二进制种群染色体矩阵

    代码2. 二进制种群染色体矩阵的创建:

    import numpy as np
    from geatpy import crtpc
    help(crtpc) # 查看帮助
    # 定义种群规模(个体数目)
    Nind = 4
    Encoding = 'BG' # 表示采用“实整数编码”,即变量可以是连续的也可以是离散的
    # 创建“译码矩阵”
    FieldD = np.array([[3, 2], # 各决策变量编码后所占二进制位数,此时染色体长度为3+2=5
                       [0, 0], # 各决策变量的范围下界
                       [7, 3], # 各决策变量的范围上界
                       [0, 0], # 各决策变量采用什么编码方式(0为二进制编码,1为格雷编码)
                       [0, 0], # 各决策变量是否采用对数刻度(0为采用算术刻度)
                       [1, 1], # 各决策变量的范围是否包含下界(对bs2int实际无效,详见help(bs2int))
                       [1, 1], # 各决策变量的范围是否包含上界(对bs2int实际无效)
                       [0, 0]])# 表示两个决策变量都是连续型变量(0为连续1为离散)
    # 调用crtpc函数来根据编码方式和译码矩阵来创建种群染色体矩阵
    Chrom=crtpc(Encoding, Nind, FieldD)
    print(Chrom)
    

    代码2运行结果:

    3. 编码与解码

    对于实整数编码(即上面代码1所创建的实整数种群染色体),它是不需要解码,染色体直接就对应着它所代表的决策变量值。而对于代码2生成的二进制种群染色体矩阵,它需要根据译码矩阵FieldD来进行解码。在代码2后面添加以下语句即可解码:

    代码3(上接代码2):

    from geatpy import bs2ri
    help(bs2ri)
    Phen = bs2ri(Chrom, FieldD)
    print('表现型矩阵 = \n', Phen)

    运行效果如下:

    4.目标函数值

    种群的目标函数值存在一个矩阵里面(一般命名为ObjV),它每一行对应一个个体的目标函数值。对于单目标而言,这个目标函数值矩阵只有1列,而对于多目标而言,就有多列了,比如下面就是一个含两个目标的种群目标函数值矩阵:

    (这里Nind表示种群的规模,即种群含多少个个体;Nvar表示决策变量的个数)

    下面来跑一下代码,接着代码3,在对二进制染色体解码成整数值种群后,我们希望计算出f(x,y)=x+y这个目标函数值。同时设置一个等式约束:要求x + y = 3。于是完整代码如下:

    代码4:

    import numpy as np
    from geatpy import crtpc
    from geatpy import bs2ri
    
    def aim(Phen):
        x = Phen[:, [0]] # 取出种群表现型矩阵的第一列,得到所有个体的决策变量x
        y = Phen[:, [1]] # 取出种群表现型矩阵的第二列,得到所有个体的决策变量y
        CV = np.abs(x + y - 3) # 生成种群个体违反约束程度矩阵CV,以处理等式约束:x + y == 3
        f = x + y # 计算目标函数值
        return f, CV # 返回目标函数值矩阵
    
    # 定义种群规模(个体数目)
    Nind = 4
    Encoding = 'BG' # 表示采用“实整数编码”,即变量可以是连续的也可以是离散的
    # 创建“译码矩阵”
    FieldD = np.array([[3, 2], # 各决策变量编码后所占二进制位数,此时染色体长度为3+2=5
                       [0, 0], # 各决策变量的范围下界
                       [7, 3], # 各决策变量的范围上界
                       [0, 0], # 各决策变量采用什么编码方式(0为二进制编码,1为格雷编码)
                       [0, 0], # 各决策变量是否采用对数刻度(0为采用算术刻度)
                       [1, 1], # 各决策变量的范围是否包含下界(对bs2int实际无效,详见help(bs2int))
                       [1, 1], # 各决策变量的范围是否包含上界(对bs2int实际无效)
                       [0, 0]])# 表示两个决策变量都是连续型变量(0为连续1为离散)
    # 调用crtpc函数来根据编码方式和译码矩阵来创建种群染色体矩阵
    Chrom=crtpc(Encoding, Nind, FieldD)
    print('二进制染色体矩阵 = \n', Chrom)
    
    # 解码
    Phen = bs2ri(Chrom, FieldD)
    print('表现型矩阵 = \n', Phen)
    
    # 计算目标函数值矩阵
    ObjV, CV = aim(Phen)
    print('目标函数值矩阵 = \n', ObjV)
    print('CV矩阵 = \n', CV)
    

    运行结果如下:

    由上面对CV矩阵的描述可知,第三个个体的CV值为0,表示第三个个体满足x+y=3这个等式约束。其他都大于0,表示不满足该约束。

    疑问:CV矩阵有什么用呢?

    :CV矩阵既可用于标记非可行解,在含约束条件的优化问题中有用,又可用于度量种群个体违反各个约束条件的程度的高低。对于含约束条件的优化问题,我们可以采用罚函数或者是可行性法则来进行处理。罚函数法这里就不展开赘述了,最简单的罚函数可以是直接找到非可行解个体的索引,然后修改其对应的ObjV的目标函数值即可。

    对于可行性法则,它需要计算每个个体违反约束的程度,并把结果保存在种群类的CV矩阵中。CV矩阵的每一行对应一个个体、每一列对应一个约束条件(可以是等式约束也可以是不等式约束),CV矩阵中元素小于或等于0表示对应个体满足对应的约束条件,否则是违反对应的约束条件,大于0的值越大,表示违反约束的程度越高。生成CV标记之后,在后面调用适应度函数计算适应度时,只要把CV矩阵作为函数传入参数传进函数体,就会自动根据CV矩阵所描述的种群个体违反约束程度来计算出合适的种群个体适应度。

    5.适应度值

    适应度值通俗来说就是对种群个体的”生存能力的评价“。对于简单的单目标优化,我们可以简单地把目标函数值直接当作是适应度值(注意:当用geatpy遗传和进化算法工具箱时,则需要对目标函数值加个负号才能简单地把它当作适应度值,因为geatpy遵循的是”目标函数值越小,适应度值越大“的约定。)

    对于多目标优化,则需要根据“非支配排序”或是其他方法来确定种群个体的适应度值,本文不对其展开叙述。

    种群适应度(FitnV):它是一个列向量,每一行代表一个个体的适应度值:

    (这里Nind表示种群的规模,即种群含多少个个体)

    geatpy遗传和进化算法工具箱里面有几个函数可以计算种群个体的适应度 ,分别是:

    ranking、indexing、powing、scaling。具体的用法,可以用help命令查看,如help(ranking)。

    下面接着代码4,利用ranking(基于目标函数值排序的适应度分配)计算种群的适应度:

    代码5(接着代码4):

    from geatpy import ranking
    help(ranking)
    FitnV = ranking(ObjV, CV)
    print('种群适应度矩阵 = \n', FitnV)

    运行结果:

    分析这个结果我们发现,由于第1、2、4个体违反约束条件,而第三个个体满足约束条件,因此第3个个体的适应度最高。而在第1、2、4个体中,个体1的目标函数值最大,因此适应度最低。可见遵循“最小化目标”的约定,即目标函数值越小,适应度越大。

    好了,基本的术语和用法讲完后,下面讲一下遗传算法的基本算子:

     

    二. 遗传算法基本算子:

    我们不用破费时间去写底层的遗传算子,因为geatpy工具箱提供丰富的进化算子,以下所列算子不仅限于遗传算子:

     

     (如果是在iPython 控制台中调用可视化绘图函数(例如使用Spyder 开发工具),一般图像会默认显示在控制台或者是开发工具中。此时可以在iPython控制台下执行%matplotlib 来设置把图像显示在一个独立窗口中。)

    对于多目标优化,Geatpy中内置以下算子:

    可以用help(算子名)来查看对应的API文档,查看更详细的用法和例子。

    下面讲一下理论:

    1.选择:

    在进化算法中存在两个阶段的选择。第一次是参与进化操作的个体的选择。这个阶段的选择可以是基于个体适应度的、也可以是完全随机地选择交配个体。一旦个体被选中,那么它们就会参与交叉、变异等进化操作。未被选中的个体不会参与到进化操作中。

    第二次是常被称为“重插入”或“环境选择”的选择,它是指在个体经过交叉、变异等进化操作所形成的子代(或称“育种个体”)后用某种方法来保留到下一代从而形成新一代种群的过程。这个选择过程对应的是生物学中的” 自然选择”。它可以是显性地根据适应度(再次注意:适应度并不等价于目标函数值)来进行选择的,也可以是隐性地根据适应度(即不刻意去计算个体适应度)来选择。例如在多目标优化的NSGA-II 算法中,父代与子代合并后,处于帕累托分层中第一层级的个体以及处于临界层中的
    且拥挤距离最大的若干个个体被保留到下一代。这个过程就没有显性地去计算每个个体的适应度。

    经典的选择算子有:“轮盘赌选择”、“随机抽样选择”、“锦标赛选择”、“本地选择”、“截断选择”、“一对一生存者竞争选择”等等,这里不展开叙述了,可以参考:

    http://geatpy.com/index.php/2019/07/28/%E7%AC%AC%E5%9B%9B%E7%AB%A0%EF%BC%9A%E9%80%89%E6%8B%A9/

    这里要注意:遗传算法选择出的后代是可以有重复的。

    下面以低级选择函数:锦标赛选择算子(tour)为例,使用help(tour)查看其API,得到:

    实战演练如下:

    代码6:

    import numpy as np
    from geatpy import tour
    
    help(tour)
    FitnV = np.array([[1.2],[0.8],[2.1], [3.2],[0.6],[2.2],[1.7],[0.2]])
    chooseIdx = tour(FitnV, 6)
    print('个体的适应度为:\n', FitnV)
    print('选择出的个体的下标为:\n', chooseIdx)
    

    运行结果:

    光这样还不够,这里只是得出了选择个体的下标,如果我们需要得到被选中个体的染色体,同时尝试改用高级选择函数“selecting”来调用低级选择算子“tour”来进行选择,则可以如下操作:

    代码7:

    import numpy as np
    from geatpy import selecting
    
    help(selecting)
    Chrom=np.array([[1,11,21],
    [2,12,22],
    [3,13,23],
    [4,14,24],
    [5,15,25],
    [6,16,26],
    [7,17,27],
    [8,18,28]])
    
    FitnV = np.array([[1.2],[0.8],[2.1], [3.2],[0.6],[2.2],[1.7],[0.2]])
    SelCh = Chrom[selecting('tour', FitnV, 6), :] # 使用'tour'锦标赛选择算子,同时片取Chrom得到所选择个体的染色体
    print('个体的适应度为:\n', FitnV)
    print('选择后得到的种群染色矩阵为:\n', SelCh)
    

    代码7运行结果如下:

    将代码7中的'tour'换成工具箱中的其他选择算子的名称(如etour, rws, sus),就可以使用相应的选择算子进行选择。

    2.重组

    在很多的国内教材、博客文章、论文中,只提到“交叉”的概念。事实上,遗传算法的“交叉”是属于“重组”算子里面的。因为交叉算子经常使用,而对于“离散重组”、“中间重组”、“线性重组”等等,因为用的很少,所以我们常常只谈“交叉”算子了。交叉算子实际上是“值互换重组”(Values exchanged recombination)。这里就不展开叙述了,可以参考:

    http://geatpy.com/index.php/2019/07/28/%E7%AC%AC%E4%BA%94%E7%AB%A0%EF%BC%9A%E9%87%8D%E7%BB%84/

    与重组有关的遗传算法参数是“重组概率”(对于交叉而言就是“交叉概率”)(Pc),它是指两个个体的染色体之间发生重组的概率。

    下面以两点交叉(xovdp)为例,类似上面的“tour”那样我们使用help(xovdp)查看其API:

    代码实战演练如下:

    代码8:

    from geatpy import xovdp
    import numpy as np
    
    help(xovdp)
    OldChrom=np.array([[1,1,1,1,1],[1,1,1,1,1],[0,0,0,0,0],[0,0,0,0,0]]) #创建一个二进制种群染色体矩阵
    print('交叉前种群染色矩阵为:\n', OldChrom)
    NewChrom = xovdp(OldChrom, 1) # 设交叉概率为1
    print('交叉后种群染色矩阵为:\n', NewChrom)
    

    代码8运行结果如下:

    由此可见,xovdp是将前一半个体和后一半个体进行配对交叉的,有人认为应该随机选择交叉个体。事实上,在遗传算法进化过程中,各个位置的个体是什么,本身是随机的,不必要在交叉这里再增添一个随机(当然,可以在执行xovdp两点交叉之前,将种群染色体矩阵按行打乱顺序然后再交叉,从而满足自身需求)。

    3.变异

    下面以均匀突变(mutuni)为例,编写代码实现实数值编码的种群染色体的均匀突变,使用help(mutuni)查看API文档。

    代码9:

    from mutuni import mutuni
    import numpy as np
    # 自定义种群染色体矩阵,表示有3个个体,且染色体元素直接表示变量的值(即实值编码)
    OldChrom = np.array([[9,10],
                         [10,10],
                         [10,10]])
    # 创建区域描述器(又称译码矩阵)
    FieldDR = np.array([[7,8],
                        [10,10],
                        [1, 1]])
    # 此处设编码方式为实值编码中的“实整数编码”RI,表示染色体可代表实数和整数
    NewChrom = mutuni('RI', OldChrom, FieldDR, 1)
    print(NewChrom)
    

    代码9的运行结果如下:

    4.重插入

    经典遗传算法通过选择、重组和变异后,我们得到的是育种后代,此时育种后代的个体数有可能会跟父代种群的个体数不相同。这时,为了保持种群的规模,这些育种后代可以重新插入到父代中,替换父代种群的一部分个体,或者丢弃一部分育种个体,最终形成新一代种群。前面曾提到过“重插入”也是一种选择,但它是环境选择,是用于生成新一代种群的;而前面在交叉变异之前的选择是用于选择个体参与交叉变异,那个选择常被称作“抽样”。

    现考虑使用精英个体保留的遗传算法“EGA”,则重插入操作如下:

    代码10:

    from mutuni import mutuni
    import numpy as np
    # 自定义父代种群染色体(仅作为例子):
    Chrom = np.array([[1.1, 1.3],
                      [2.4, 1.2],
                      [3,   2.1],
                      [4,   3.1]])
    # 若父代个体的适应度为:
    FitnV = np.array([[1],
                     [2],
                     [3],
                     [4]])
    # 考虑采用“精英保留策略”的遗传算法,此时从父代选择出4-1=3个个体,经过交叉变异后假设子代的染色体为:
    offChrom = np.array([[2.1, 2.3],
                         [2.3, 2.2],
                         [3.4, 1.1]])
    # 假设直接把目标函数值当作适应度,且认为适应度越大越好。则通过以下代码重插入生成新一代种群:
    bestIdx = np.argmax(FitnV) # 得到父代精英个体的索引
    NewChrom = np.vstack([Chrom[bestIdx, :], offChrom]) # 得到新一代种群的染色体矩阵
    print('新一代种群的染色体矩阵为:\n', NewChrom)
    

    在“EGA”中,假设父代种群规模为N,则选择出(N-1)个个体进行交叉变异,然后找出父代的精英个体,用着个精英个体和交叉变异得到的子代个体进行“拼合”,得到新一代种群。

    除了这种重插入生成新一代种群的方法外,还有“父子两代个体合并选择”等更优秀的生成新一代种群的方法,这里就不一一赘述了。

    讲完上面的基本术语以及遗传算法基本算子后,我们就可以来利用遗传算法的“套路”编写一个遗传算法求解问题的程序了:

     

    三.完整实现遗传算法:

    上文提到遗传算法程序可以写成这个样子:

    其核心是算法模板类。在遗传算法模板里,我们根据遗传算法的“套路”,进行:初始化种群、目标函数值计算、适应度评价、选择、重组、变异、记录各代最优个体等操作。geatpy工具箱内置有开源的“套路模板”,源代码参见:

    https://github.com/geatpy-dev/geatpy/tree/master/geatpy/source-code/templets

    这些内置算法模板有详细的输入输出参数说明,以及遗传算法整个流程的完整注释,它们可以应对简单或复杂的、单目标优化的、多目标优化的、约束优化的、组合优化的等等的问题。

    但为了学习,我这里先不采用框架,直接利用工具箱提供的库函数来写一个带精英个体保留的遗传算法。这样代码量比较大,但有利于入门。

    编写代码 11、12,分别放在同一个文件夹下:

    代码11(目标函数aimfuc.py)(这里要回顾一下前面,Phen是种群表现型矩阵,存储的是种群所有个体的表现型,而不是单个个体。因而计算得到的目标函数值矩阵也是包含所有个体的目标函数值):

    # -*- coding: utf-8 -*-
    """
    aimfunc.py - 目标函数文件
    描述:
        目标:max f = 21.5 + x1 * np.sin(4 * np.pi * x1) + x2 * np.sin(20 * np.pi * x2)
        约束条件:
            x1 != 10
            x2 != 5
            x1 ∈ [-3, 12.1] # 变量范围是写在遗传算法的参数设置里面
            x2 ∈ [4.1, 5.8]
    """
    
    import numpy as np
    
    def aimfunc(Phen, CV):
        x1 = Phen[:, [0]] # 获取表现型矩阵的第一列,得到所有个体的x1的值
        x2 = Phen[:, [1]]
        f = 21.5 + x1 * np.sin(4 * np.pi * x1) + x2 * np.sin(20 * np.pi * x2)
        exIdx1 = np.where(x1 == 10)[0] # 因为约束条件之一是x1不能为10,这里把x1等于10的个体找到
        exIdx2 = np.where(x2 == 5)[0]
        CV[exIdx1] = 1
        CV[exIdx2] = 1
        return [f, CV]
    

    然后是编写算法:

    代码12:

    # -*- coding: utf-8 -*-
    """main.py"""
    import numpy as np
    import geatpy as ea # 导入geatpy库
    from aimfunc import aimfunc # 导入自定义的目标函数
    import time
    
    """============================变量设置============================"""
    x1 = [-3, 12.1] # 第一个决策变量范围
    x2 = [4.1, 5.8] # 第二个决策变量范围
    b1 = [1, 1] # 第一个决策变量边界,1表示包含范围的边界,0表示不包含
    b2 = [1, 1] # 第二个决策变量边界,1表示包含范围的边界,0表示不包含
    ranges=np.vstack([x1, x2]).T # 生成自变量的范围矩阵,使得第一行为所有决策变量的下界,第二行为上界
    borders=np.vstack([b1, b2]).T # 生成自变量的边界矩阵
    varTypes = np.array([0, 0]) # 决策变量的类型,0表示连续,1表示离散
    """==========================染色体编码设置========================="""
    Encoding = 'BG' # 'BG'表示采用二进制/格雷编码
    codes = [0, 0] # 决策变量的编码方式,设置两个0表示两个决策变量均使用二进制编码
    precisions =[4, 4] # 决策变量的编码精度,表示二进制编码串解码后能表示的决策变量的精度可达到小数点后6位
    scales = [0, 0] # 0表示采用算术刻度,1表示采用对数刻度
    FieldD = ea.crtfld(Encoding,varTypes,ranges,borders,precisions,codes,scales) # 调用函数创建译码矩阵
    """=========================遗传算法参数设置========================"""
    NIND      = 100; # 种群个体数目
    MAXGEN    = 200; # 最大遗传代数
    maxormins = [-1] # 列表元素为1则表示对应的目标函数是最小化,元素为-1则表示对应的目标函数是最大化
    selectStyle = 'rws' # 采用轮盘赌选择
    recStyle  = 'xovdp' # 采用两点交叉
    mutStyle  = 'mutbin' # 采用二进制染色体的变异算子
    pc        = 0.7 # 交叉概率
    pm        = 1 # 整条染色体的变异概率(每一位的变异概率=pm/染色体长度)
    Lind = int(np.sum(FieldD[0, :])) # 计算染色体长度
    obj_trace = np.zeros((MAXGEN, 2)) # 定义目标函数值记录器
    var_trace = np.zeros((MAXGEN, Lind)) # 染色体记录器,记录历代最优个体的染色体
    """=========================开始遗传算法进化========================"""
    start_time = time.time() # 开始计时
    Chrom = ea.crtpc(Encoding, NIND, FieldD) # 生成种群染色体矩阵
    variable = ea.bs2ri(Chrom, FieldD) # 对初始种群进行解码
    CV = np.zeros((NIND, 1)) # 初始化一个CV矩阵(此时因为未确定个体是否满足约束条件,因此初始化元素为0,暂认为所有个体是可行解个体)
    ObjV, CV = aimfunc(variable, CV) # 计算初始种群个体的目标函数值
    FitnV = ea.ranking(maxormins * ObjV, CV) # 根据目标函数大小分配适应度值
    best_ind = np.argmax(FitnV) # 计算当代最优个体的序号
    # 开始进化
    for gen in range(MAXGEN):
        SelCh = Chrom[ea.selecting(selectStyle,FitnV,NIND-1),:] # 选择
        SelCh = ea.recombin(recStyle, SelCh, pc) # 重组
        SelCh = ea.mutate(mutStyle, Encoding, SelCh, pm) # 变异
        # 把父代精英个体与子代的染色体进行合并,得到新一代种群
        Chrom = np.vstack([Chrom[best_ind, :].astype(int), SelCh])
        Phen = ea.bs2ri(Chrom, FieldD) # 对种群进行解码(二进制转十进制)
        ObjV, CV = aimfunc(Phen, CV) # 求种群个体的目标函数值
        FitnV = ea.ranking(maxormins * ObjV, CV) # 根据目标函数大小分配适应度值
        # 记录
        best_ind = np.argmax(FitnV) # 计算当代最优个体的序号
        obj_trace[gen,0]=np.sum(ObjV)/ObjV.shape[0] #记录当代种群的目标函数均值
        obj_trace[gen,1]=ObjV[best_ind] #记录当代种群最优个体目标函数值
        var_trace[gen,:]=Chrom[best_ind,:] #记录当代种群最优个体的染色体
    # 进化完成
    end_time = time.time() # 结束计时
    ea.trcplot(obj_trace, [['种群个体平均目标函数值', '种群最优个体目标函数值']]) # 绘制图像
    """============================输出结果============================"""
    best_gen = np.argmax(obj_trace[:, [1]])
    print('最优解的目标函数值:', obj_trace[best_gen, 1])
    variable = ea.bs2ri(var_trace[[best_gen], :], FieldD) # 解码得到表现型(即对应的决策变量值)
    print('最优解的决策变量值为:')
    for i in range(variable.shape[1]):
        print('x'+str(i)+'=',variable[0, i])
    print('用时:', end_time - start_time, '秒')

    执行代码12得到如下结果:

    终于,我们把遗传算法完整地实现了,但扩展性还不够高。下面学习下如何使用Geatpy提供的进化算法框架来求解上述问题:(关于使用框架来优化的介绍可详见http://geatpy.com/index.php/geatpy%E6%95%99%E7%A8%8B/

    在这里我们可以回顾以下在本文开头提到的采用遗传算法的“套路”来编程求解问题的基本流程:

    其中执行脚本和问题类是需要编写的,算法模板类我直接调用Geatpy内置的"soea_EGA_templet"(带精英个体保留的单目标遗传算法模板)。下面开始编写代码:

    代码13:问题类"MyProblem"的编写:

    # -*- coding: utf-8 -*-
    """
    MyProblem.py
    该案例展示了一个简单的连续型决策变量最大化目标的单目标优化问题。
    max f = x * np.sin(10 * np.pi * x) + 2.0
    s.t.
    -1 <= x <= 2
    """
    
    import numpy as np
    import geatpy as ea
    
    class MyProblem(ea.Problem): # 继承Problem父类
        def __init__(self):
            name = 'MyProblem' # 初始化name(函数名称,可以随意设置)
            M = 1 # 初始化M(目标维数)
            maxormins = [-1] # 初始化maxormins(目标最小最大化标记列表,1:最小化该目标;-1:最大化该目标)
            Dim = 2 # 初始化Dim(决策变量维数)
            varTypes = [0] * Dim # 初始化varTypes(决策变量的类型,元素为0表示对应的变量是连续的;1表示是离散的)
            lb = [-3, 4.1] # 决策变量下界
            ub = [12.1, 5.8] # 决策变量上界
            lbin = [1] * Dim # 决策变量下边界
            ubin = [1] * Dim # 决策变量上边界
            # 调用父类构造方法完成实例化
            ea.Problem.__init__(self, name, M, maxormins, Dim, varTypes, lb, ub, lbin, ubin)
        
        def aimFunc(self, pop): # 目标函数
            x1 = pop.Phen[:, [0]] # 获取表现型矩阵的第一列,得到所有个体的x1的值
            x2 = pop.Phen[:, [1]]
            f = 21.5 + x1 * np.sin(4 * np.pi * x1) + x2 * np.sin(20 * np.pi * x2)
            exIdx1 = np.where(x1 == 10)[0] # 因为约束条件之一是x1不能为10,这里把x1等于10的个体找到
            exIdx2 = np.where(x2 == 5)[0]
            pop.CV = np.zeros((pop.sizes, 2))
            pop.CV[exIdx1, 0] = 1
            pop.CV[exIdx2, 1] = 1
            pop.ObjV = f # 计算目标函数值,赋值给pop种群对象的ObjV属性
        

    第二步:编写执行脚本“main.py”

    # -*- coding: utf-8 -*-
    """main.py"""
    import geatpy as ea # import geatpy
    from MyProblem import MyProblem # 导入自定义问题接口
    """===============================实例化问题对象================================"""
    problem = MyProblem() # 生成问题对象
    """==================================种群设置=================================="""
    Encoding = 'BG'       # 编码方式
    NIND = 100            # 种群规模
    Field = ea.crtfld(Encoding, problem.varTypes, problem.ranges, problem.borders) # 创建区域描述器
    population = ea.Population(Encoding, Field, NIND) # 实例化种群对象(此时种群还没被初始化,仅仅是完成种群对象的实例化)
    """================================算法参数设置================================="""
    myAlgorithm = ea.soea_EGA_templet(problem, population) # 实例化一个算法模板对象
    myAlgorithm.MAXGEN = 200 # 最大进化代数
    myAlgorithm.logTras = 1  # 设置每隔多少代记录日志,若设置成0则表示不记录日志
    myAlgorithm.verbose = True  # 设置是否打印输出日志信息
    myAlgorithm.drawing = 1  # 设置绘图方式(0:不绘图;1:绘制结果图;2:绘制目标空间过程动画;3:绘制决策空间过程动画)
    """===========================调用算法模板进行种群进化==============--==========="""
    [BestIndi, population] = myAlgorithm.run()  # 执行算法模板,得到最优个体以及最后一代种群
    BestIndi.save()  # 把最优个体的信息保存到文件中
    """==================================输出结果=================================="""
    print('用时:%f 秒' % myAlgorithm.passTime)
    print('评价次数:%d 次' % myAlgorithm.evalsNum)
    if BestIndi.sizes != 0:
        print('最优的目标函数值为:%s' % BestIndi.ObjV[0][0])
        print('最优的控制变量值为:')
        for i in range(BestIndi.Phen.shape[1]):
            print(BestIndi.Phen[0, i])
    else:
        print('没找到可行解。')

    运行"main.py"执行脚本即可得到以下结果:

                                                                                                         ......

    代码解析:在“main.py”执行脚本中,一开始需要实例化一个问题对象。然后是种群对象的实例化。在实例化种群对象前,需要设定种群的编码方式Encoding、种群规模NIND,并且生成区域描述器Field(或称译码矩阵),因为种群类的构造方法中需要至少用到这三个参数(详见“Population.py”中种群类的构造方法)。

    在完成了问题类对象和种群对象的实例化后,将其传入算法模板类的构造方法来实例化一个算法模板对象。这里我实例化的是单目标优化的EGA算法(即带精英个体保留的遗传算法)的模板类对象,即代码中的"soea_EGA_templet"。里面的进化算法具体是如何操作的,可详见https://github.com/geatpy-dev/geatpy/blob/master/geatpy/templates/soeas/GA/EGA/soea_EGA_templet.py

    采用Geatpy提供的进化算法框架可以既能最大程度地描述清楚所要求解的问题,而且与进化算法是高度脱耦的,即上面在编写问题类的时候完全不需要管后面采用什么算法、采用什么样编码的种群,只需把问题描述清楚即可。

    而且,遗传算法有个好处是:目标函数可以写得相当复杂,可以解决各种复杂的问题,比如神经网络。以BP神经网络为例,可以把神经网络的参数作为决策变量,神经网络的训练误差作为目标函数值,只需把上面的例子修改一下就行了。

    而且,一般而言我们不需要像我刚刚最开始那样刻意去手写进化算法,可以直接调用geatpy内置的算法模板就可以解决问题了。geatpy工具箱提供这些内置的算法模板:

    应用Geatpy求解数学建模、工业设计、资源调度等实际优化问题的的朋友们可以直接使用这些算法模板快速解决各种灵活的优化问题。

    四.后记:

    最后十分感谢由Geatpy团队提供的高性能实用型遗传和进化算法工具箱,它提供开源的进化算法框架为遗传算法求解单目标/多目标优化、约束优化、组合优化等等给出了相当准确和快捷的解决方案。据称,geatpy的运行性能相当的高,远高于matlab的遗传算法工具箱、以及采用JAVA、matlab或者Python编写的一些进化优化平台或框架,比如jMetal、platemo、pymoo、deap等,后面有时间我将进行详细的性能对比实验分析,有相关经验的读者也可以自行对比性能。而且依我的体验来看,这是我网上到处找代码、找资料学习、碰了无数次壁后所看到的比较易学易用的工具箱了。

    最后值得注意的是Geatpy的顶层是面向对象的进化算法框架,底层是面向过程的进化算子。下面放一张geatpy的UML类图、算法调用的层次结构和库函数调用关系图,以此记录方便查看:

    下面附一张一位同行朋友使用犀牛软件(Rhinoceros)结合geatpy工具箱进行产品优化设计的截图:

    很多工程软件都提供Python接口,当需要用到进化优化时,就可以编写Python代码进行优化了。

    下一篇博客将介绍如何用遗传算法求解有向图的最短路径问题:

    https://blog.csdn.net/weixin_37790882/article/details/100622338

    后续我将继续学习和挖掘该工具箱的更多深入的用法。希望这篇文章在帮助自己记录学习点滴之余,也能帮助大家!

     

    展开全文
  •  为了方便测试,最好一个显示出树的当前状态的工具,这里的程序即是《数据结构:C#语言描述》(陈广)中所讲的二叉绘制算法的实现。  经过测试,基本肯定了我的红黑树算法实现的正确性,经过多次修改,算法的...

       红黑树的操作非常复杂,即使实现了也可能存在bug,因此我们需要反复进行测试。

      为了方便测试,最好有一个显示出树的当前状态的工具,这里的程序即是《数据结构:C#语言描述》(陈广)中所讲的二叉绘制算法的实现。

      经过测试,基本肯定了我的红黑树算法实现的正确性,经过多次修改,算法的代码已经比较简洁,等整理好后做一个完整的总结,这里先放一个效果图。

    展开全文
  • 自从上一篇博客详细讲解了Python遗传和进化算法工具箱及其在带约束的单目标函数值优化中的应用之后,我经过不断学习工具箱的官方文档以及对源码的研究,逐步更加地掌握如何利用遗传算法求解更多有趣的问题了。...
  • PHP中的遗传算法工具描述 该工具包专注于构建遗传算法应用程序,您可以使用自己的模式对其进行定制,例如: 染色体 初始人口 适应度函数 突变 * 用于选择和交叉,因为它只是染色体和适应度函数的简单行为,就...
  • 遗传算法工具箱使用1

    千次阅读 2016-02-28 22:37:00
    使用谢菲尔德大学的MATLAB遗传算法工具箱 1.简单一元函数优化:计算函数最小值 f(x) = sin(10*pi*x)/x , x范围[1,2] clc clear all close all %%画出函数图 figure(1); hold on; lb = 1;ub = 2; %函数自变量范围 ...
  • MATLAB遗传算法工具箱的使用及实例(线性规划)

    万次阅读 多人点赞 2020-07-11 15:00:57
    遗传算法一般用于求解优化问题。遗传算法最早是由美国的 John holland于20世纪70年代提出,该算法是根据大自然中生物体进化规律而设计提出的。是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型...
  • 可从下面的链接中获得以下算法的更详细描述: 致谢 Hartwig Medical Foundation使用YourKit Java Profiler进行性能调整。 YourKit支持具有创新和智能工具的开源项目,用于监视和分析Java和.NET应用程序。 YourKit是...
  • 根据Hacker News上提供的消息,用于编写加密算法工具Cryptol DSL目前已经开源了,向广大开发者开放项目源代码。 Cryptol是什么呢? Cryptol是一个用于指定加密算法的特定域语言。Cryptol实现算法类似...
  • 在过去的几年中,得益于Node.js和SpiderMonkey...这些工具包括经典的数据结构,如链表、栈、队列、图等,也包括经典的排序和查找算法。本书即讨论了在使用JavaScript进行服务器端编程时,如何实现这些经典的数据结构和
  • 更多数据挖掘算法:https://github.com/linyiqun/DataMiningAlgorithm ...在链接分析中2个经典的算法,1个是PageRank算法,还有1个是HITS算法,说白了,都是做链接分析的。具体是怎么做呢,继续往下看。 PageRank
  • MP算法和OMP算法及其思想

    万次阅读 多人点赞 2012-04-17 03:09:18
    主要介绍MP(Matching Pursuits)算法和OMP(Orthogonal Matching Pursuit)算法[1],这两个算法虽然在90年代初就提出来了,但作为经典的算法,国内文献(可能我没有搜索到)都仅描述算法步骤和简单的应用,并未对其...
  •   公元七世纪,在车迟国国家气象局组织的一次求雨活动中,虎力、鹿力、羊力三位大仙...本世纪,算法工程师们的境遇也差不多:早些年,信奉糙快猛主义的大佬们觉得他们饱食终日、无所用心,没工作只好在学校混博士...
  • 《数据结构与算法Python语言描述》裘宗燕 笔记系列 该系列笔记结合PPT的内容整理的,方便以后复习,需要的朋友可以看一下。 源码重新整理了 地址:https://github.com/StarsAaron/DS/tree/master   理解三个...
  • 分为两个部分,笔者看到的知识图谱在商业领域的应用,外加看到的一些算法框架与研究机构。 一、知识图谱商业应用 01 唯品金融大数据 使用的是OrientDB,Orientdb提供了大量的接口, 其中最常用的...
  • 国密算法(SM2,SM3,SM4)完善与算法辅助工具开发

    万次阅读 热门讨论 2013-03-14 16:46:55
    首先是国密SM2证书的升级,国内CA服务商要完成SM2算法证书支持,之后是国密算法在金融领域进行推广,新近编订的PBOC标准的增强安全部分,增加了SM2,SM3,SM4算法应用,但并没有像CA那样强行实施,也可能是考虑到...
  • 同时给出了多个问题示例,对每个问题分别采用不同复杂度的算法,可以直观地了解到在解决实际问题时,不仅仅需要能够得出结果的算法,更应该给出算法复杂度更低的算法的意义数学工具:“大O”表示法,用于估计一个...
  • 人工智能算法:遗传算法

    千次阅读 多人点赞 2021-01-21 19:33:15
    遗传算法是一种特殊的演化算法,但是在描述遗传算法的文献中,其定义各不相同。本书将遗传算法定义为一种可以用交叉和突变算子优化固定长度向量的演化算法。计分函数可以区分优劣方案,以优化该固定长度的向量。这个...
  • 用于词义消岐的Lesk算法

    千次阅读 2014-02-15 22:16:18
    算法由Michael E. Lesk于1986年提出,是一个基于词典的词义消岐方法。 该算法认为:一个词在词典中的词义解释与该词所在句子具有相似性。这种相似性可以由相同单词的个数来表示,比如“cone”和"pine"的意思分别...
  • 本文原题是《Timed Automata Semantics, Algorithms and Tools》,...时间自动机:语义,算法工具 Johan Bengtsson和Wang Yi   Uppsala大学 Email:{johanb,yi}@it.uu.se (译者:祝威http://bitzhuwei.cn...
  • 单种运输工具带时间窗2.1 带时间窗车辆路径问题的描述2.2 遗传算法的求解2.2.1 编码方案的设计2.2.2 种群初始化2.2.3 约束处理与适应度函数2.2.4 选择算子2.2.5 交叉算子2.2.6 变异算子2.2.7 其他部分2.3 粒子群...
  • 理解Raft算法

    千次阅读 2019-05-17 09:44:36
    之前已经Paxos算法用于解决分布式系统最终一致性问题,而且已经了zookeeper这个成熟的开源实现。那么这个Raft算法有啥用呢?按照Raft官网的说法,这个算法的错误容忍和性能和Paxos算法类似,但是拥有更加简单...
  • QGIS算法

    千次阅读 2015-12-16 11:52:04
    TablesProcessing providers and algorithms处理供应商和算法GDAL algorithm provider GDAL算法提供者GDAL是一个读写空间数据(这里的空间数据包括栅格数据和矢量数据)的...,此外还提供了一些非常常用的算法工具...
  • 全排列算法的全面解析

    万次阅读 多人点赞 2016-03-27 00:10:50
    对数组进行全排列是一个比较常见问题,如果是一个比较喜欢考算法的公司(貌似一些大公司都比较喜欢考算法),那么估计就会考察应聘者这个全排列的问题了(就算不让你编写完整代码,也会让你描述大致的思路)。...
  • 数据同步算法研究

    万次阅读 热门讨论 2010-08-06 16:52:00
    基于Rsync和RDC算法思想并借助重复数据删除(De-duplication)技术,对数据同步算法进行...与RDC算法,然后详细描述算法设计与相应的数据结构,并重点分析文件分块、差异编码、文件同步算法,最后简介推拉两种应用模式。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 165,559
精华内容 66,223
关键字:

常用于描述算法的工具有