博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python遗传算法库和进化算法框架(三)自定义Geatpy编程模板解决约束优化问题...
阅读量:6504 次
发布时间:2019-06-24

本文共 6650 字,大约阅读时间需要 22 分钟。

上一篇讲了Geatpy的库函数和数据结构

熟悉了之后,我尝试编写一个编程模板解决一个约束优化问题:

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

在这个问题里,我们很容易知道目标函数的最小值为0,而这是个目标函数最大化问题,因此,我们可以对不符合约束条件的解的目标函数值设为0。而且不需要写罚函数了,直接把约束条件写在目标函数接口文件里即可。

编写目标函数接口文件:

""" aimfuc.py """import numpy as np# aim functiondef aimfuc(variables):    x1 = variables[:, 0] # get x1    x2 = variables[:, 1] # get x2    f  = 5 * x1 + 8 * x2    idx1 = np.where(x1 + x2 > 6)[0]    idx2 = np.where(5 * x1 + 9 * x2 > 45)[0]    f[idx1] = 0    f[idx2] = 0    return np.array([f]).T # 对结果进行转置,使目标函数值矩阵符合Geatpy数据结构
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

下面一步步来编写编程模板,以解决这个约束优化问题。

编写编程模板时一个要注意的地方是:调用目标函数时,传入的参数必须和目标函数的参数列表一致。

我们试一下一种改进的遗传算法,即不用遗传算法的经典流程,而是在进化过程中,先对父代进行交叉和变异产生子代,然后父代和子代直接合并成一个大的种群,再从这个大的种群中挑选50%的优秀个体存活下来。在下一次进化迭代中,这50%的个体继续沿用上面的流程进行交叉、变异、选择。

这种改进遗传算法的好处是具有很强的精英保留能力。可以使算法快速收敛,得到最优结果。

为了使模板函数能够用于更多的场景,能同时解决整数型和实数型控制变量的问题。于是编写编程模板如下:

""" templet.py """# -*- coding: utf-8 -*-import numpy as npimport geatpy as gaimport time"""输入参数:    AIM_M - 目标函数的地址,传入该函数前通常由AIM_M = __import__('目标函数名')语句得到        AIM_F : str - 目标函数名        PUN_M - 罚函数的地址,传入该函数前通常由PUN_M = __import__('罚函数名')语句得到        PUN_F : str - 罚函数名        FieldDR : array - 实际值种群区域描述器        [lb;		(float) 指明每个变量使用的下界         ub]		(float) 指明每个变量使用的上界         注:不需要考虑是否包含变量的边界值。在crtfld中已经将是否包含边界值进行了处理         本函数生成的矩阵的元素值在FieldDR的[下界, 上界)之间        problem : str - 表明是整数问题还是实数问题,'I'表示是整数问题,'R'表示是实数问题                         maxormin int - 最小最大化标记,1表示目标函数最小化;-1表示目标函数最大化        MAXGEN : int - 最大遗传代数        NIND : int - 种群规模,即种群中包含多少个个体        SUBPOP : int - 子种群数量,即对一个种群划分多少个子种群        GGAP : float - 代沟,本模板中该参数为无用参数,仅为了兼容同类的其他模板而设        selectStyle : str - 指代所采用的低级选择算子的名称,如'rws'(轮盘赌选择算子)        recombinStyle: str - 指代所采用的低级重组算子的名称,如'xovsp'(单点交叉)        recopt : float - 交叉概率        pm : float - 重组概率输出参数:    pop_trace : array - 种群进化记录器(进化追踪器),                        第0列记录着各代种群最优个体的目标函数值                        第1列记录着各代种群的适应度均值                        第2列记录着各代种群最优个体的适应度值        var_trace : array - 变量记录器,记录着各代种群最优个体的变量值,每一列对应一个控制变量        times     : float - 进化所用时间"""def templet(AIM_M, AIM_F, PUN_M, PUN_F, FieldDR, problem, maxormin, MAXGEN, NIND, SUBPOP, GGAP, selectStyle, recombinStyle, recopt, pm):    """==========================初始化配置==========================="""    GGAP = 0.5 # 因为父子合并后选择50%的个体留到下一代,因此要将代沟设为0.5以维持种群规模    # 获取目标函数和罚函数    aimfuc = getattr(AIM_M, AIM_F) # 获得目标函数    if PUN_F is not None:        punishing = getattr(PUN_M, PUN_F) # 获得罚函数    NVAR = FieldDR.shape[1] # 得到控制变量的个数    # 定义进化记录器,初始值为nan    pop_trace = (np.zeros((MAXGEN ,2)) * np.nan)    # 定义变量记录器,记录控制变量值,初始值为nan    var_trace = (np.zeros((MAXGEN ,NVAR)) * np.nan)     """=========================开始遗传算法进化======================="""    if problem == 'R':        Chrom = ga.crtrp(NIND, FieldDR) # 生成初始种群    elif problem == 'I':        Chrom = ga.crtip(NIND, FieldDR)    start_time = time.time() # 开始计时    # 开始进化!!    for gen in range(MAXGEN):        # 进行遗传算子,生成子代        SelCh=ga.recombin(recombinStyle, Chrom, recopt, SUBPOP) # 重组        if problem == 'R': # 若是实数型控制变量,则用mutbga进行变异            SelCh=ga.mutbga(SelCh,FieldDR, pm) # 变异        elif problem == 'I': # 若是整数型控制变量,则用mutint进行变异            SelCh=ga.mutint(SelCh, FieldDR, pm)        Chrom = np.vstack([Chrom, SelCh]) # 父子合并        ObjV = aimfuc(Chrom) # 求后代的目标函数值        pop_trace[gen,0] = np.sum(ObjV) / ObjV.shape[0] # 记录种群个体平均目标函数值        if maxormin == 1:            pop_trace[gen,1] = np.min(ObjV) # 记录当代目标函数的最优值            var_trace[gen,:] = Chrom[np.argmin(ObjV), :] # 记录当代最优的控制变量值        elif maxormin == -1:            pop_trace[gen,1] = np.max(ObjV)            var_trace[gen,:] = Chrom[np.argmax(ObjV), :] # 记录当代最优的控制变量值        # 最后对合并的种群进行适应度评价并选出一半个体留到下一代        FitnV = ga.ranking(maxormin * ObjV, None, SUBPOP)        if PUN_F is not None:            FitnV = punishing(Chrom, FitnV) # 调用罚函数        Chrom=ga.selecting(selectStyle, Chrom, FitnV, GGAP, SUBPOP) # 选择    end_time = time.time() # 结束计时    # 绘图    ga.trcplot(pop_trace, [['种群个体平均目标函数值', '种群最优个体目标函数值']])    if maxormin == 1:        best_gen = np.argmin(pop_trace[:, 1]) # 记录最优种群是在哪一代        print('最优的目标函数值为:'+ str(np.min(pop_trace[:, 1])))    elif maxormin == -1:        best_gen = np.argmax(pop_trace[:, 1]) # 记录最优种群是在哪一代        print('最优的目标函数值为:' + str(np.max(pop_trace[:, 1])))    print('最优的控制变量值为:')    for i in range(NVAR):        print(var_trace[best_gen, i])    print('最优的一代是第' + str(best_gen + 1) + '代')    times = end_time - start_time    print('时间已过'+ str(times) + '秒')    # 返回进化记录器、变量记录器以及执行时间    return [pop_trace, var_trace, times]
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

好了,现在该编程模板可以用于解决这类约束优化问题了。控制变量既可以是整数,也可以是实数。

下面编写执行脚本:

import numpy as npimport geatpy as gafrom aimfuc import aimfucfrom templet import templet # 导入自定义的编程模板# 获取函数接口地址AIM_M = __import__('aimfuc')# 变量设置x1 = [0, 100] # 自变量1的范围x2 = [0, 100] # 自变量2的范围b1 = [1, 1] # 自变量1是否包含下界b2 = [1, 1] # 自变量2是否包含上界ranges=np.vstack([x1, x2]).T # 生成自变量的范围矩阵borders = np.vstack([b1, b2]).T # 生成自变量的边界矩阵# 生成区域描述器FieldDR = ga.crtfld(ranges, borders)# 调用编程模板[pop_trace, var_trace, times] = templet(AIM_M, 'aimfuc', None, None, FieldDR, problem = 'I', maxormin = -1, MAXGEN = 2000, NIND = 100, SUBPOP = 1, GGAP = 0.9, selectStyle = 'tour', recombinStyle = 'xovdp', recopt = 0.7, pm = 0.1)
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

因为这道题的控制变量x1和x2的区间都是单侧的,因此我们设个大一点的区间以便搜索最优解。我们采用锦标赛选择算子,并设置最大进化代数为100,种群规模为100,使用两点交叉,交叉和变异概率分别是0.9和0.1。

运行结果如下:

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

最优的目标函数值为:39.0

最优的控制变量值为:
3.0
3.0
最优的一代是第40代
时间已过0.11623454093933105秒

至此,我们知道了如何自定义编程模板实现遗传算法了。在Geatpy中,内置了好几种进化算法编程模板。详细源码可以参见

使用Geatpy内置模板会使上面的例子变得更加简单,只需编写目标函数接口和执行脚本就可以了。比如上面的例子,使用Geatpy框架,真正只需几行代码便可以解决

""" main.py """import numpy as npimport geatpy as ga# define aim functiondef aimfuc(variables):    x1 = variables[:, 0] # get x1    x2 = variables[:, 1] # get x2    f  = 5 * x1 + 8 * x2    idx1 = np.where(x1 + x2 > 6)[0]    idx2 = np.where(5 * x1 + 9 * x2 > 45)[0]    f[idx1] = 0; f[idx2] = 0    return np.array([f]).T           # 对结果进行转置,使目标函数值矩阵符合Geatpy数据结构# 获取目标函数地址AIM_M = __import__('main')# 变量设置x1 = [0, 100]                        # 自变量1的范围x2 = [0, 100]                        # 自变量2的范围b1 = [1, 1]                          # 自变量1是否包含下界b2 = [1, 1]                          # 自变量2是否包含上界ranges = np.vstack([x1, x2]).T       # 生成自变量的范围矩阵borders = np.vstack([b1, b2]).T      # 生成自变量的边界矩阵FieldDR = ga.crtfld(ranges, borders) # 生成区域描述器# 调用Geatpy内置编程模板[pop_trace, var_trace, times] = ga.sga_new_real_templet(AIM_M, 'aimfuc', None, None, FieldDR, problem = 'I', maxormin = -1, MAXGEN = 100, NIND = 100, SUBPOP = 1, GGAP = 0.9, selectStyle = 'tour', recombinStyle = 'xovdp', recopt = 0.7, pm = 0.1)
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

在后面的版本中,Geatpy将不断丰富和改进编程模板,以Geatpy的算法性能。比如添加MOEA/D多目标优化编程模板等。有相关想法的也可以email:jazzbin@geatpy.com。

更多教程可以参见官网 (repairing),以及参见Geatpy的源码和demo示例: 你将有更多的收获。

在下一篇,我们将讲述如何使用Geatpy解决一些实际的有趣问题。

 欢迎继续跟进,谢谢大家!

你可能感兴趣的文章
linux不能访问80端口,lunux开放80端口(本地访问不了linux文件可能是这个原因)...
查看>>
android单位转换小程序,微信小程序中rpx与rem单位转换
查看>>
ps切图教程 android,PS前端切图完整教程
查看>>
html显示服务器状态,显示服务器时间并一直显示(html代码)
查看>>
在线html代码优化,网站seo优化html代码方法
查看>>
HTML如何把输入框变成必填值,required输入框为必填项
查看>>
html定位有几种,POSITION定位有哪几种?各有什么特点?
查看>>
背锅侠逆袭之路
查看>>
演示:使用协议分析器取证IPv6的报文结构
查看>>
oracle 11gr2 rac中的4种IP解说
查看>>
为什么你找不到工作?
查看>>
20 个免费的 jQuery 的工具提示插件:
查看>>
汇编语言的应用
查看>>
device platform 相应的表
查看>>
php des 加密解密实例
查看>>
【Mac】Mac键盘实现Home, End, Page UP, Page DOWN
查看>>
实战使用Axure设计App,使用WebStorm开发(1) – 用Axure描述需求
查看>>
安德鲁斯----多媒体编程
查看>>
swift版的元组
查看>>
[zz]在linux中出现there are stopped jobs 的解决方法
查看>>