Geatpy数据结构学习

本文摘自Geatpy库的官方文档---仅供学习参考

目录

目录

一 、基本数据结构

1.1 种群染色体

1.2 种群表现型

1.3 目标函数值

1.4 个体适应度

1.5 违反约束程度

1.6 译码矩阵

1.7 进化追踪器

二. 种群结构

2.1 Population 类

2.2 PsyPopulation 类

2.3 多种群


一 、基本数据结构

1.1 种群染色体

        Geatpy 中,种群染色体是一个 numpy 的 array 类型的二维矩阵,一般用 Chrom 命 名,每一行对应一个个体的一条染色体。

        若要采用多染色体,则可以创建多个相关联的 Chrom 即可。

        默认一个 Chrom 的一行对应的只有一条染色体。 我们一般把种群的规模 (即种群的个体数) 用 Nind 命名;把种群个体的染色体长度 用 Lind 命名,则 Chrom 的结构如下所示:

        

 1.2 种群表现型

        种群表现型的数据结构跟种群染色体基本一致,也是 numpy 的 array 类型。

        我们一 般用 Phen 来命名。

        它是种群染色体矩阵 Chrom 经过解码后得到的基因表现型矩阵,每 一行对应一个个体,每一列对应一个决策变量。

        若用 Nvar 表示变量的个数,则种群表现型矩阵 Phen 的结构如下图:

        Phen 的值与采用的解码方式有关。

        Geatpy 提供二进制/格雷码编码转十进制整数或 实数的解码方式。

        另外,在 Geatpy 也可以使用不需要解码的“实值编码”种群,这种种群的染色体的每一位就对应着决策变量的实际值,即这种编码方式下 Phen 等价 Chrom。

        这里需要注意的是:我们可以用不同的方式去解码一个种群染色体,得到的结果往往是不同的。

 1.3 目标函数值

        Geatpy 采用 numpy 的 array 类型矩阵来存储种群的目标函数值。

        一般命名为 ObjV ,  每一行对应每一个个体,因此它拥有与 Chrom 相同的行数;

        每一列对应一个目标函数, 因此对于单目标函数,ObjV 会只有 1 列;而对于多目标函数,ObjV 会有多列。

        例如 ObjV 是一个二元函数值矩阵:

 1.4 个体适应度

        Geatpy 采用列向量来存储种群个体适应度。一般命名为 FitnV ,它同样是 numpy 的 array 类型,每一行对应种群矩阵的每一个个体。因此它拥有与 Chrom 相同的行数。

 Geatpy 中的适应度遵循“最小适应度为 0”的约定。

1.5 违反约束程度

        Geatpy 采用 Numpy array 类型的矩阵 CV(Constraint Violation Value) 来存储种群个体违反各个约束条件的程度。

        一般命名为 CV ,它的每一行对应种群的每一个个体,因此它拥有与 Chrom 相同的行数;

        每一列对应一个约束条件,因此若有一个约束条件,那 么 CV 矩阵就会只有一列,如有多个约束条件,CV 矩阵就会有多列。

        如果设有 num 个 约束,则 CV 矩阵的结构如下图所示:

         CV 矩阵的某个元素若小于或等于 0,则表示该元素对应的个体满足对应的约束条件。

        若大于 0,则表示违反约束条件,在大于 0 的条件下值越大,该个体违反该约束的 程度就越高。

        Geatpy 提供两种处理约束条件的方法,一种是罚函数法,另一种是可行性法则。

        在使用可行性法则处理约束条件时,需要用到CV矩阵。具体用法可详见后面两章中关于使用可行性法则来处理约束条件的相关说明。

1.6 译码矩阵

        Geatpy 使用译码矩阵 (俗称区域描述器) 来描述种群染色体的特征, 如

        染色体中的每一位元素所表达的决策变量的范围、是否包含范围的边界、采用二进制还是格雷码、 是否使用对数刻度、染色体解码后所代表的决策变量的是连续型变量还是离散型变量等。

        在只使用工具箱的库函数而不使用 Geatpy 提供的面向对象的进化算法框架时,译码矩阵可以单独使用。

        若采用 Geatpy 提供的面向对象的进化算法框架时,译码矩阵可以与一个存储着种群染色体编码方式的字符串 Encoding 来配合使用。

        目前 Geatpy 中有 三种 Encoding,分别为:

        • ’BG’ (二进制/格雷码)

        • ’RI’ (实整数编码,即实数和整数的混合编码)

        • ’P’ (排列编码,即染色体每一位的元素都是互异的)
        这里有个小小的归类值得注意:’RI’ 和’P’ 编码的染色体都不需要解码,染色体上 的每一位本身就代表着决策变量的真实值,因此“实整数编码”和“排列编码”可统称 为“实值编码”。

        1) 对于 Encoding =′ BG′ 的种群,使用 8 行 n 列的矩阵 FieldD 来作为译码矩阵,n 是染色体所表达的决策变量个数。FieldD 的结构如下:

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

        其中,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 表示对应的是离散型变量。

        例如:

         它表示待解码的种群染色体矩阵 Chrom 解码后可以表示成 3 个决策变量,每个决策变量的取值范围分别是 [1,10], [2,9], [3,15]。其中第一第二个变量采用的是二进制编码,第三个变量采用的是格雷编码,且第一、第三个决策变量为连续型变量;第二个为离散型遍历。

        若 Chrom 为:

则可以执行以下语句进行解码:

        

import geatpy as ea
Phen = ea.bs2ri(Chrom, FieldD)

 解码后得到的种群表现型矩阵为:

 2) 对于实值编码 (即前面所说的不需要解码的编码方式) 的种群,使用 3 行 n 列的 矩阵 FieldDR 来作为译码矩阵,n 是染色体所表达的控制变量个数。

        FieldDR 的结构如下:

        这种结构的译码矩阵适用于 Encoding为’RI’(实整数编码) 和’P’(排列编码) 的种群染色体的解码。

        其中’P’(排列编码) 的译码矩阵会稍微有一点特殊之处它要求 FieldDR 的第一行所有元素都相等,第二行所有元素也都相等,且第三行元素均为 1(这是因为排 列编码本身变量是离散的)。

        此时若记 FieldDR 有 Lind 列 (即染色体长度为 Lind),则要 求上界 - 下界 + 1 ≥ Lind。例如:

         它若是作为排列编码种群的译码矩阵,则表示种群染色体是由集合2, 3, 4, 5, 6, 7, 8, 9, 10 中任意抽取 7 个数出来的全排列,比如 Chrom为:

         上面的 FieldD 和 FieldDR 都是 numpy 的 array 类型,可统称为“Field”。可以直接用代码创建,例如:

import numpy as np
FieldDR=np.array([[-3, -4, 0, 2],
[ 2, 3, 2, 2],
[ 0, 0, 0, 0]])

        也可以用 Geatpy 内置的 crtfld 函数来方便地快速生成区域描述器,其详细用法可执行 help(crtfld) 或查看 API 文档。

1.7 进化追踪器

        在使用 Geatpy 进行进化算法编程时,常常建立一个进化追踪器 (如 pop_trace) 来记录种群在进化的过程中各代的最优个体,尤其是采用无精英保留机制时,进化追踪器帮助我们记录种群在进化的“历史长河”中产生过的最优个体。

        待进化完成后,再从进化 追踪器中挑选出“历史最优”的个体。

        这种进化记录器有多种,其中一种是 numpy 的 array 类型的,结构如下:

         其中 MAXGEN 是种群进化的代数。trace 的每一列代表不同的指标,比如第一列记录各代种群的最佳目标函数值,第二列记录各代种群的平均目标函数值……

        trace 的每一行对应每一代,如第一行代表第一代,第二行代表第二代……

        另外一种进化记录器是一个列表,列表中的每一个元素都是一个拥有相同数据类型的数据。比如在 Geatpy 的面向对象进化算法框架中的 pop_trace,它是一个列表,列表中的每一个元素都是历代的种群对象。

二. 种群结构

2.1 Population 类

        在 Geatpy 提供的面向对象进化算法框架中,种群类 (Population) 是一个存储着与种 群个体相关信息的类。它有以下基本属性:

        sizes : int - 种群规模,即种群的个体数目。

        ChromNum : int - 染色体的数目,即每个个体有多少条染色体。

        Encoding : str - 染色体编码方式。

        Field : array - 译码矩阵,可以是 FieldD 或 FieldDR。

        Chrom : array - 种群染色体矩阵,每一行对应一个个体的一条染色体。

        Lind : int - 种群染色体长度。

        ObjV : array - 种群目标函数值矩阵。

        FitnV : array - 种群个体适应度列向量。

        CV : array - 种群个体违反约束条件程度的矩阵。

        Phen : array - 种群表现型矩阵。

        可以直接对种群对象进行提取个体、个体合并等操作,比如 pop1 和 pop2 是两个种群对象,则通过语句“pop3 = pop1 + pop2”,即可把两个种群的个体合并,得到一个新的种群。在合并的过程中,实际上是把种群的各个属性进行合并,然后用合并的数据来 生成一个新的种群 (详见Population.py)。又比如执行语句“pop3 = pop1[[0]]”,可以把种 群的第 0 号个体抽取出来,得到一个新的只有一个个体的种群对象 pop3。值得注意的 是,种群的这种个体抽取操作要求下标必须为列表或是 Numpy array 类型的行向量,不能是标量 (详见 Population.py)。

        易错注意:在 Geatpy 中,必要地对种群对象的这些成员属性进行合法性检查是必要的,但过多的检查会在一定程度上降低框架的性能。其中最容易使得种群对象成员属性出现异常的地方在于目标函数值矩阵 ObjV 以及 CV 矩阵的生成。在 Geatpy 中,ObjV 和 CV 是在 Problem 问题类的目标函数接口 aimFunc() 中计算生成的,无论中间过程它 们具体是如何计算的,计算得到的结果必须满足:ObjV 和 CV 都是 Numpy array 类型矩阵且行数等于种群的个体数目ObjV 的每一行对应一个个体,每一列对应一个优化目标。CV 矩阵的每一行也是对应一个个体,而每一列对应一个约束条件。

        根据 Geatpy 数据结构可知,种群对象中的 Chrom、ObjV、FitnV、CV 和 Phen 都是 Numpy array 类 型的行数等于种群规模 sizes 的矩阵,即这些成员属性的每一行都跟种群的每一个个体是一一对应的。Geatpy 框架在运行过程中所抛出大多数异常都是由于这些变量不合法所致。此时可以使用“shape”来输出变量的维度信息,比如:

# 其中 pop 为一个种群对象。
print(pop.sizes)
print(pop.Chrom.shape)
print(pop.ObjV.shape)
print(pop.CV.shape)

        特殊用法:在多种群进化优化中,往往需要将所有种群的所有个体进行统一的适应度评价,此时由于各个种群的编码方式 Encoding、译码矩阵 Field 以及染色体的长度 Lind 可能会不尽相同,不能直接把所有种群对象合并成一个种群对象。此时,可以构造一个 Encoding 为 None 的种群,这种类型的种群不携带有效的 Field、Chrom 的信息 (这些值都被自动设置为了 None)。这种特殊用法允许直接将所有种群合并成一个“联合种群”,从而方便进行个体适应度评价、进化记录、多目标优化非支配解的记录等操作。

2.2 PsyPopulation 类

        PsyPopulation 类是 Population 的子类,它提供 Population 类所不支持的多染色体混合编码。它有以下基本属性:

        sizes : int - 种群规模,即种群的个体数目。

        ChromNum : int - 染色体的数目,即每个个体有多少条染色体。

        Encodings : list - 存储各染色体编码方式的列表。

        Fields : list - 存储各染色体对应的译码矩阵的列表。

        Chroms : list - 存储种群各染色体矩阵的列表。

        Linds : list - 存储种群各染色体长度的列表。

        ObjV : array - 种群目标函数值矩阵。

        FitnV : array - 种群个体适应度列向量。

        CV : array - 种群个体违反约束条件程度的矩阵。

        Phen : array - 种群表现型矩阵。

        可见 PsyPopulation 类基本与 Population 类一样,不同之处是采用 Linds、Encodings、 Fields 和 Chroms 分别存储多个 Lind、Encoding、Field 和 Chrom。 PsyPopulation 类的对象往往与带“psy”字样的进化算法模板配合使用,以实现多染色体混合编码的进化优化。

2.3 多种群

        多种群的数据结构是一个 list 列表,即用一个列表来存储所有种群(每个种群都是 Population 类的对象),采用多种群协同进化的例子详见“多种群进化优化”章节。

三、Geatpy架构说明

Geatpy2整体上看由工具箱内核函数(内核层)和面向对象进化算法框架(框架层)两部分组成。其中面向对象进化算法框架主要有四个大类:Problem问题类、Algorithm算法模板类、Population种群类和PsyPopulation多染色体种群类。UML图如下所示:

Problem类定义了与问题相关的一些信息,

如问题名称name、优化目标的维数M、决策变量的个数Dim、决策变量的范围ranges、决策变量的边界borders等。

maxormins是一个记录着各个目标函数是最小化抑或是最大化的Numpy array行向量,其中元素为1表示对应的目标是最小化目标;为-1表示对应的是最大化目标。

例如M=3,maxormins=array([1,-1,1]),此时表示有三个优化目标,其中第一、第三个是最小化目标,第二个是最大化目标。

varTypes是一个记录着决策变量类型的行向量,其中的元素为0表示对应的决策变量是连续型变量;为1表示对应的是离散型变量。

待求解的目标函数定义在aimFunc()的函数中。

calReferObjV()函数则用于计算或读取目标函数参考值(一般用理论上的目标函数的最优值作为参考值),该参考值可以用于后续的指标分析。

在实际使用时,不是直接在Problem类的文件中修改相关代码来使用的,而是通过定义一个继承Problem的子类来完成对问题的定义的。这些在后面的章节中会详细讲述。

getReferObjV()是Problem父类中已经实现了的一个函数,它先尝试读取特定文件夹中的目标函数值参考数据,如果读取不到,则调用calReferObjV()进行计算。对于Problem类中各属性的详细含义可查看Problem.py源码。


Population 类是一个表示种群的类。

一个种群包含很多个个体,而每个个体都有一条染色体(若要用多染色体,则使用多个种群、并把每个种群对应个体关联起来即可)。

除了染色体外,每个个体都有一个译码矩阵Field(或俗称区域描述器) 来标识染色体应该如何解码得到表现型,同时也有其对应的目标函数值以及适应度。

种群类就是一个把所有个体的这些数据统一存储起来的一个类。

比如里面的Chrom 是一个存储种群所有个体染色体的矩阵,它的每一行对应一个个体的染色体;ObjV 是一个目标函数值矩阵,每一行对应一个个体的所有目标函数值,每一列对应一个目标。对于Population 类中各属性的详细含义可查看Population.py 源码以及“Geatpy 数据结构”


PsyPopulation类是继承了Population的支持多染色体混合编码的种群类。

一个种群包含很多个个体,而每个个体都有多条染色体。

用Chroms列表存储所有的染色体矩阵(Chrom);

Encodings列表存储各染色体对应的编码方式(Encoding);

Fields列表存储各染色体对应的译码矩阵(Field)。EncoIdxs是一个list,其元素表示每条染色体对应编码哪一个变量。比如EncoIdxs = [[0], [1,2,3,4]],表示一共有5个变量,其中第一个变量编码成第一条子染色体;后4个变量编码成第二条子染色体。


Algorithm 类是进化算法的核心类。它既存储着跟进化算法相关的一些参数,同时也在其继承类中实现具体的进化算法。

比如Geatpy 中的moea_NSGA3_templet.py 是实现了多目标优化NSGA-III 算法的进化算法模板类,它是继承了Algorithm 类的具体算法的模板类。关于Algorithm 类中各属性的含义可以查看Algorithm.py 源码。这些算法模板通过调用Geatpy 工具箱提供的进化算法库函数实现对种群的进化操作,同时记录进化过程中的相关信息,其基本层次结构如下图:

 

其中“算子类”是Geatpy2.2.2版本之后增加的特性,通过实例化算子类来调用低级操作函数,可以利用面向对象编程的优势使得对传入低级操作函数的一些参数的修改变得更加方便。目前内置的“算子类”有“重组算子类”和“变异算子类”。用户可以绕开对底层的低级操作函数的修改而直接通过新增“算子类”来实现新的算子例如自适应的重组、变异算子等。

例如:mutpolyn是多项式变异的低级变异算子。其对应的高级变异算子为:Mutpolyn。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值