遗传算法框架Geatpy学习之——基于网格化处理的多种群进化优化及其在含等式约束的优化问题中的应用

Geatpy是由华南理工大学、华南农业大学、德州奥斯汀公立大学学生联合团队开发的一款Python上的遗传和进化算法高性能权威框架。其性能远高于matlab遗传算法工具箱及类似的诸如gatbx、GEATbx、gaot等第三方工具箱。尤其适合需要应用遗传或其他进化算法求解建模问题、与当前的其他项目结合、抑或是需要一个平台来从事进化算法研究与实验的用户。

在前面几篇文章中,我们已经介绍了高性能Python遗传和进化算法框架——Geatpy的使用及一些案例。

Geatpy更新方法:

pip install --user --upgrade geatpy

(注意:Geatpy已于2018.10.03更新至1.0.7版本,这是一个重要更新,新版本完善了对约束优化问题的求解,重构了多目标优化非支配排序以及帕累托前沿搜索算法的内核,并提供网格化的单目标优化求解、多种群竞争的单目标优化算法模板)。

https://blog.csdn.net/qq_33353186/article/details/82014986

https://blog.csdn.net/qq_33353186/article/details/82020507

https://blog.csdn.net/qq_33353186/article/details/82021750

https://blog.csdn.net/qq_33353186/article/details/82047692

详细的Geatpy官方教程文档在github可以查看:

https://github.com/geatpy-dev/geatpy/tree/master/geatpy/doc/tutorial

也可以到官网上查看:http://www.geatpy.com/tutorials

================分割线==================

下面就等式约束问题展开论述:

含等式约束的目标优化问题是常见的比较难用遗传算法求解的一类问题。经典的处理方法有以下三类:

一. 直接采取罚函数来处理等式约束:

这种方法相对简单,直接把遗传算法中不满足等式约束条件的个体赋予最低的适应度,使其在种群进化中逐渐被淘汰。

然而,罚函数在处理不等式约束较为成功,但面对等式约束这类可行解空间远比非可行解空间小的问题时,无论罚函数对处于非可行解的个体加以多么严厉的惩罚,种群进化过程中会很难跳出非可行解区域,这就极有可能导致遗传算法出现连可行解都找不到的结果。

二. 将等式约束化成一个新的目标,用多目标优化算法去处理等式约束问题:

例如一个等式约束为 x + y + z = 1,那么,可以设计一个新的目标函数:

该目标表示 x + y + z - 1的绝对值越小越好。该目标越接近0,说明越接近满足约束条件。当该目标的值为0时,对应的解就能满足约束条件了。

这种方法可以极大地拓宽所研究问题的可行解的区域,从而使得遗传算法更方便地进行最优解的搜索。

但是:这种方法也存在弊端。用这种方法对可行解的拓宽程度相对较大,并且,由于使用多目标优化算法求解,它得到的结果是一个帕累托最优解集。而问题最容易出在有时候会因为在搜索时解的分布性不好而导致的搜索得到的帕累托前沿种并不包含使得上述新增目标达到绝对最优(即abs(x+y+z-1)=0)的解,从而导致所有帕累托最优解均不满足该等式约束。

因此方法二也会导致算法的不稳定。

三. 采用数学方法降维消除等式约束:

该方法是利用数学推导,利用等式约束,将其中一个或多个变量用其余变量线性表出或非线性表出,从而使模型降维,同时也成功消除了等式约束,或是成功地将等式约束化为另一类不等式约束。

这种方法在效果上是最好的。但其局限性是:当对于复杂的等式约束、无法将其中一个或多个变量用其余变量线性表出或非线性表出时,该方法无法使用。

因此,应优先使用方法三,当不可行时再考虑方法一和二。

================分割线==================

采用Geatpy来求解这类含等式约束优化问题:

问题抽象成模型描述如下:

我们利用x3 = 1 - x1 - x2实现降维。此时成功将等式约束条件转化成了x1 + x2 <= 1这个不等式约束条件,此时由于x3 = 1 - x1 - x2 必定小于1,因此降维后模型是等价于原模型的。

Geatpy解决这类约束优化问题极为简单。首先创建目标函数,写在“aimfuc.py”文件中:

# -*- coding: utf-8 -*-
"""
aimfc.py - 目标函数demo
描述:
    Geatpy的目标函数遵循本案例的定义方法,
    若要改变目标函数的输入参数、输出参数的格式,则需要修改或自定义算法模板
"""

def aimfuc(Phen):
    x1 = Phen[:, [0]]
    x2 = Phen[:, [1]]
    x3 = 1 - x1 - x2 # 将x1 + x2 + x3 = 1的等式约束降维化处理
    f = 4 * x1 + 2 * x2 + x3
    return f

Geatpy v1.0.7版本之后,对罚函数作出了重要改进:罚函数不仅应该返回修改后的适应度矩阵,还应该返回不满足约束条件的个体所在的下标。因此,编写罚函数如下,写在"punishing.py"文件中:

# -*- coding: utf-8 -*-
"""
punishing.py - 罚函数demo
描述:
    Geatpy的罚函数遵循本案例的定义方法,
    若要改变罚函数的输入参数、输出参数的格式,则需要修改或自定义算法模板
"""

import numpy as np

def punishing(Phen, FitnV):
    x1 = Phen[:, [0]]
    x2 = Phen[:, [1]]
    x3 = 1 - x1 - x2
    # 约束条件
    idx1 = np.where(2 * x1 + x2 > 1)[0]
    idx2 = np.where(x1 + 2 * x3 > 2)[0]
    idx3 = np.where(x1 + x2 > 1)[0]
    # 惩罚
    FitnV[idx1] = 0
    FitnV[idx2] = 0
    FitnV[idx3] = 0
    exIdx = np.unique(np.hstack([idx1, idx2, idx3])) # 得到非可行解在种群中的下标
    return [FitnV, exIdx]

最后编写执行脚本"main.py":

# -*- coding: utf-8 -*-
"""
执行脚本main.py
描述:
    该demo是展示如何计算带等式约束的单目标优化问题:
        max 4 * x1 + 2 * x2 + x3
        s.t.
            2 * x1 + x2 <= 1
            x1 + 2 * x3 > 2
            x1 + x2 + x3 = 1
            0 <= x1 <= 1
            0 <= x2 <= 1
            0 <= x3 <= 2
    其中目标函数写在aimfuc.py文件中,约束条件写在罚函数文件punishing.py中
    本案例通过降维的方法,将等式约束化成了不等式约束,大大拓宽了可行解的空间,方便遗传算法求解
    此外,本案例展示了利用多种群竞争的进化算法模板sga_mpc_real_templet了解决该问题。
"""

import numpy as np
import geatpy as ga

# 获取函数接口地址
AIM_M = __import__('aimfuc')
PUN_M = __import__('punishing')
# 变量设置
x1 = [0, 1] # 自变量1的范围
x2 = [0, 1] # 自变量2的范围
b1 = [1, 1] # 自变量1是否包含下界
b2 = [1, 1] # 自变量2是否包含上界
ranges=np.vstack([x1, x2]).T # 生成自变量的范围矩阵
borders = np.vstack([b1, b2]).T # 生成自变量的边界矩阵
precisions = [2] * 2 # 自变量的编码精度,由于控制变量是连续型的,并且算法模板中使用实值编码,因此这里设置成大于0的任意值即可
newRanges = ga.meshrng(ranges, gridnum = 2) # 对控制变量范围进行网格化,网格边长为2
# 生成网格化后的区域描述器集合
FieldDRs = []
for i in range(len(newRanges)):
    FieldDRs.append(ga.crtfld(newRanges[i], borders, precisions))
# 调用编程模板
[pop_trace, var_trace, times] = ga.sga_mpc_real_templet(AIM_M, 'aimfuc', PUN_M,\
 'punishing', FieldDRs, problem = 'R', maxormin = -1, MAXGEN = 50, NIND = 100,\
 SUBPOP = 1, GGAP = 0.9, selectStyle = 'tour', recombinStyle = 'xovdprs',\
 recopt = 0.9, pm = 0.3)

执行"main.py",得到结果如下:

最优的目标函数值为: 2.5
最优的控制变量值为:
0.5
0.0
最优的一代是第 5 代
时间已过 0.5979366302490234 秒

分析:sga_mpc_real_templet是Geatpy v1.0.7版本新增的一个内置算法模板,其源代码见:

https://github.com/geatpy-dev/geatpy/blob/master/geatpy/source-code/templets/sga_mpc_real_templet.py

该模板实现了基于多种群竞争进化的单目标优化算法。由于多种群是在相互竞争中进化的,因此收敛速度极快。并且,每个种群的最大进化代数也不需要设置太大,本例中设置50代就够了。

Geatpy v1.0.7另外还提供了多种群独立进化的单目标优化算法模板:sga_mps_real_templet。与上面的不同的是该算法模板中种群是互相独立进化,最后再挑选最优个体的,而不是在竞争中进化。

在调用多种群进化算法模板sga_mpc_real_templet和sga_mps_real_templet前,常根据各控制变量的范围先对其进行网格化,使其网格化成若干个小的范围,然后不同范围用不同的种群去进化搜索。变量范围网格化的库函数为:meshrng,用法详见:https://github.com/geatpy-dev/geatpy/blob/master/geatpy/doc/API/meshrng/meshrng.pdf

更多的demo详见:

https://github.com/geatpy-dev/geatpy/tree/master/geatpy/demo

欢迎继续跟进,感谢!

猜你喜欢

转载自blog.csdn.net/qq_33353186/article/details/82917477
今日推荐