前言

自从上一篇博客详细讲解了Python遗传和进化算法工具箱及其在带约束的单目标函数值优化中的应用之后,我经过不断学习工具箱的官方文档以及对源码的研究,逐步更加地掌握如何利用遗传算法求解更多有趣的问题了。

首先简单回顾一下Python高性能实用型遗传和进化算法工具箱的用法。对于一个优化问题,需要做两个步骤便可进行求解:Step1:自定义问题类;Step2:编写执行脚本调用Geatpy进化算法模板对问题进行求解。在上一篇博客曾“详细”介绍过具体的用法:Python遗传算法工具箱的使用(一)求解带约束的单目标优化_Strong_wind的博客-CSDN博客_python遗传算法工具包,但完整的中文教程可以参考官方文档。

下面切入主题:

本文的“最短路径问题”专指图的最短路径问题,而且只研究单目标的最短路径问题。(实际上最短路径问题还可以是多目标的),参考用书推荐:《网络模型与多目标遗传算法》。这本书我已经上传到此处,可以直接下载到:

网络模型与多目标遗传算法参考资料.zip_网络模型与多目标遗传算法-机器学习文档类资源-CSDN下载

图的最短路径问题从广义上说其实有很多种类型,比如:

  • 确定起点和终点的有向图和无向图的最短路径问题。
  • 旅行商最短路径问题。
  • 车辆配送中的最短路径问题。
  • 物流中心选址的最短路径问题。

其中确定起点和终点的无向图的最短路径问题可以延伸为机器人路径规划问题。也就是说,机器人避开障碍物从起点走向终点的那种路径规划问题本质上是一种复杂一些的“确定起点和终点的无向图的最短路径问题”。

本文主要讲解如何利用遗传算法求解“确定起点和终点的有向图最短路径问题”。对于无向图的,另外再写博客以机器人路径规划作为案例来展开叙述。

正文

问题举例:

以《网络模型与多目标遗传算法》一书中的一个小案例为例,如图所示,当从结点1驶向结点10时,我们经常会考虑怎样选择路径使得花最短的距离达到目的地。此时不需要像旅行商问题(TSP)那样,此类问题不需要要求所有的地点都访问一遍,而只需要想办法用最短的距离从起点走到终点即可。

书中讲述了两种遗传算法编码方式对上述问题进行求解。

法一

利用二进制编码。假设 Xij 是有向图中所有边的一个集合,那么其中一种可行的路径对应的染色体可以是:

其中元素为1表示对应的边被“激活”,即最终路径上包含这条边。于是上面的染色体所代表的路径为:1 → 3 → 6 → 7 → 8 → 10。

这种编码方式最为直观,但有个很大的弊端:在进化过程中染色体往往无法表达一个合法的路径。于是这种情况下需要给遗传算法添加很多约束,此时便增加了遗传算法寻优的难度。

法二

利用“基于优先级编码”。这种编码方式是Gen & Lin 在2005年提出的有利于很好地求解图的路径规划问题的编码方法。参考文献:(Lin L, Gen M. Priority-Based Genetic Algorithm for Shortest Path Routing Problem in OSPF[M]// Intelligent and Evolutionary Systems. 2009.)这篇文献可能比较难下载到,我将其上传到这里了,可以直接下载查看:

Priority-BasedGeneticAlgorithmforShortestPathRoutingProbleminOSPF_ipospfpriority-机器学习文档类资源-CSDN下载

下面来详细讲解这种编码方式:

“基于优先级编码”是一种间接编码方式,这意味着染色体并不能直接表示路径,此时需要利用额外的数据来进行解码,解码后才表示一个路径。这种编码方式有个特点是染色体的每一位上的元素是互不相等的,这意味着这种编码方式具备“排列编码”的特征。(排列编码即比如从1到10的10个数中随机挑选若干个数组成的一个排列。)

以一条染色体为例,看看“基于优先级编码”的染色体是如何表示有向图中的一条路径的:

上面这条染色体是遗传算法中随机生成的(并非最优),结点优先级并不是指结点的访问先后顺序,而是结点的优先级,是给后面解码用的。为什么染色体长度是10?因为此时染色体每一位存储的是图的每个结点的优先级,因此染色体的长度需要和图的结点数一致。当然地,由于上面题目规定了是从结点1开始走,故设染色体长度为9也行。这里为了能和下标更直观地对应,就设染色体长度与图的结点数目一致。

解码需要一个集合nodes,用于存储以各结点为起点的有向边的终点,即各个结点下一步可达的结点。本题的集合nodes为:nodes = [[], [2,3], [3,4,5], [5,6], [7,8], [4,6], [7,9], [8,9], [9,10], [10]]。因为python中列表的下标是从0数起的,而本题的结点是从1数起的,为了能直接对应,故上面的nodes的第0号元素设置为[],表示无意义。解析一下nodes的组成:第1号元素是[2,3],表示题目的有向图中1号结点下一步可达的结点是2和3。nodes的第2号元素是[3,4,5],表示2号结点下一步可达的结点是3,4,5。以此类推。

于是上面的染色体[7, 3, 4, 6, 2, 5, 8, 10, 1, 9]的详细解码过程如下

从1号结点出发,在nodes中下标为1的元素是[2,3],表示1号结点下一步可以去2号结点或3号结点。此时从染色体中找到这两个结点对应的优先级分别为3和4,如图所示:

从中选出具有更高优先级的结点3作为结点1下一步需要访问的结点。

紧接着,在nodes中下标为3的元素是[5,6],表示3号结点下一步可以去5号或6号结点。此时从染色体中找到这两个结点对应的优先级分别为2和5,如图所示:

从中选出具有更高优先级的结点6作为结点1下一步需要访问的结点。

以此类推,最终得到完整的访问路径为:

1 → 3 → 6 → 7 → 8 → 10。

有了解码得到路径,如何求个体的适应度?

想要求个体的适应度,首先要定一个优化目标。本题是要让路径最短,于是我们便要根据访问结点求出路径长度,把这个作为优化目标。有了优化目标,便可利用基于目标函数值排序的适应度分配(ranking)求出适应度值。当然,这类单目标优化问题也可以直接让个体的适应度等于优化目标函数值(即路径长度)。而路径长度即为访问路径上各条有向边的权值之和。

代码实现

首先编写问题类,把待优化模型写在问题类中。然后编写执行脚本,调用“soea_SEGA_templet“(增强精英保留的遗传算法模板)进行进化优化。该算法模板的源码及算法流程详见

geatpy/soea_SEGA_templet.py at master · geatpy-dev/geatpy · GitHubEvolutionary algorithm toolbox and framework with high performance for Python - geatpy/soea_SEGA_templet.py at master · geatpy-dev/geatpyhttps://github.com/geatpy-dev/geatpy/blob/master/geatpy/algorithms/soeas/GA/soea_SEGA_templet.py

由于本题比较简单,故用4个个体、10代的进化即可得到很好的结果。完整的实验代码如下:

# -*- coding: utf-8 -*-
import numpy as np
import geatpy as eaclass MyProblem(ea.Problem): # 继承Problem父类def __init__(self):name = 'Shortest_Path' # 初始化name(函数名称,可以随意设置)M = 1 # 初始化M(目标维数)maxormins = [1] # 初始化maxormins(目标最小最大化标记列表,1:最小化该目标;-1:最大化该目标)Dim = 10 # 初始化Dim(决策变量维数)varTypes = [1] * Dim # 初始化varTypes(决策变量的类型,元素为0表示对应的变量是连续的;1表示是离散的)lb = [0] * Dim # 决策变量下界ub = [9] * Dim # 决策变量上界lbin = [1] * Dim # 决策变量下边界ubin = [1] * Dim # 决策变量上边界# 调用父类构造方法完成实例化ea.Problem.__init__(self, name, M, maxormins, Dim, varTypes, lb, ub, lbin, ubin)# 设置每一个结点下一步可达的结点(结点从1开始数,因此列表nodes的第0号元素设为空列表表示无意义)self.nodes = [[], [2,3], [3,4,5], [5,6], [7,8], [4,6], [7,9], [8,9], [9,10], [10]]# 设置有向图中各条边的权重self.weights = {'(1, 2)':36, '(1, 3)':27, '(2, 4)':18, '(2, 5)':20, '(2, 3)':13, '(3, 5)':12, '(3, 6)':23,'(4, 7)':11, '(4, 8)':32, '(5, 4)':16, '(5, 6)':30, '(6, 7)':12, '(6, 9)':38, '(7, 8)':20,'(7, 9)':32, '(8, 9)':15, '(8, 10)':24, '(9, 10)':13}def decode(self, priority): # 将优先级编码的染色体解码得到一条从节点1到节点10的可行路径edges = [] # 存储边path = [1] # 结点1是路径起点while not path[-1] == 10: # 开始从起点走到终点currentNode = path[-1] # 得到当前所在的结点编号nextNodes = self.nodes[currentNode] # 获取下一步可达的结点组成的列表chooseNode = nextNodes[np.argmax(priority[np.array(nextNodes) - 1])] # 从NextNodes中选择优先级更高的结点作为下一步要访问的结点,因为结点从1数起,而下标从0数起,因此要减去1path.append(chooseNode)edges.append((currentNode, chooseNode))return path, edgesdef aimFunc(self, pop): # 目标函数pop.ObjV = np.zeros((pop.sizes, 1)) # 初始化ObjVfor i in range(pop.sizes): # 遍历种群的每个个体,分别计算各个个体的目标函数值priority = pop.Phen[i, :]path, edges = self.decode(priority) # 将优先级编码的染色体解码得到访问路径及经过的边pathLen = 0for edge in edges:key = str(edge) # 根据路径得到键值,以便根据键值找到路径对应的长度if not key in self.weights:raise RuntimeError("Error in aimFunc: The path is invalid. (当前路径是无效的。)", path)pathLen += self.weights[key] # 将该段路径长度加入pop.ObjV[i] = pathLen # 计算目标函数值,赋值给pop种群对象的ObjV属性## 执行脚本
if __name__ == "__main__":# 实例化问题对象problem = MyProblem()# 构建算法algorithm = ea.soea_EGA_templet(problem,ea.Population(Encoding='RI', NIND=4),MAXGEN=10,  # 最大进化代数logTras=1)  # 表示每隔多少代记录一次日志信息# 求解res = ea.optimize(algorithm, verbose=True, drawing=1, outputMsg=False, drawLog=False, saveFlag=True, dirName='result')print('最短路程为:%s'%(res['ObjV'][0][0]))print('最佳路线为:')best_journey, edges = problem.decode(res['Vars'][0])for i in range(len(best_journey)):print(int(best_journey[i]), end = ' ')print()

运行结果如下:

在有向图中表现为:

后记

值得注意的是:上面题目中的有向图并不存在回路,实际上,复杂的有向图往往会存在许多回路,此时需要进行一定的处理来避免陷入回路当中,即避免一直在回路上“打转”。处理方式有很多,例如在解码过程中对已经访问过的结点的有限度进行惩罚等等。这里暂时就不深入探讨了,待之后讲述无向图最短路径及机器人寻路问题时再展开叙述。

最后回顾一下上一篇博客提到的”遗传算法套路“:

该套路实现了具体问题、使用的算法以及所调用的相关算子之间的脱耦。而Geatpy工具箱已经内置了众多进化算法模板类以及相关的算子,直接调用即可。对于实际问题的求解,只需关心如何把问题写在自定义问题类中就好了。

更多详细的教程可以详见:Geatpy教程 – Geatpy

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

Python遗传算法工具箱的使用(二)求解最短路径问题相关推荐

  1. Python遗传算法工具箱的使用(一)求解带约束的单目标优化

    加了个小目录~方便定位查看~ 前言 正文 一. 基础术语: 二. 遗传算法基本算子: 三.完整实现遗传算法: 四.后记: 前言 网上有很多博客讲解遗传算法,但是大都只是"点到即止" ...

  2. python遗传算法工具箱的使用_遗传算法的python实现,非常值得看的一篇文章

    遗传算法是一种智能优化算法,通常用于求解复杂的数学问题.相比于传统方法,遗传算法摒弃了盲目的穷举或完全随机的求解策略,借鉴了自然界优胜劣汰.自然进化的思想,快速逼近最优解.上文对遗传算法的基本内容进行 ...

  3. MATLAB遗传算法工具箱的使用及实例(线性规划)

    一.引言 在使用遗传算法(Genetic Algorithm,GA)之前,你得了解遗传算法是干什么的.遗传算法一般用于求解优化问题.遗传算法最早是由美国的 John holland于20世纪70年代提 ...

  4. MATLAB遗传算法工具箱的使用及实例(非线性规划)

    本文将介绍MATLAB遗传算法工具箱求解非线性规划问题.在阅读本文之前,建议读者阅读上一期"MATLAB遗传算法工具箱求解线性规划问题".文章传送门:https://blog.cs ...

  5. Python遗传算法求一元函数最大值

    Python遗传算法求一元函数最大值 前言 代码 后记 参考文献 前言 最近接触遗传算法,参考了众多例子,有些又不尽然对,所以自己边理解边修改,然后写出了下面这堆传说中的屎山... PS1:遗传算法原 ...

  6. python concat函数 多张表_最全Python数据工具箱:标准库、第三方库和外部工具都在这里了 - Mr_YJY...

    导读:Python数据工具箱涵盖从数据源到数据可视化的完整流程中涉及到的常用库.函数和外部工具.其中既有Python内置函数和标准库,又有第三方库和工具.这些库可用于文件读写.网络抓取和解析.数据连接 ...

  7. 《MATLAB智能算法30个案例》:第1章 谢菲尔德大学的MATLAB遗传算法工具箱

    <MATLAB智能算法30个案例>:第1章 谢菲尔德大学的MATLAB遗传算法工具箱 1. 前言 2. MATLAB 仿真示例一 3. MATLAB 仿真示例二 4. 小结 1. 前言 & ...

  8. 2021-05-11 Matlab遗传算法工具箱的使用及实例(非线性规划)

    Matlab遗传算法工具箱的使用及实例(非线性规划) 本文将介绍MATLAB遗传算法工具箱求解非线性规划问题.在阅读本文之前,建议读者阅读上一期"MATLAB遗传算法工具箱求解线性规划问题& ...

  9. matlab 遗传算法 等式约束,关于MATLAB遗传算法工具箱不等式约束

    过去很久了,之前写论文的经验分享一下. 写毕业论文的时候需要用到遗传算法,网上查了很多资料,由于没时间认真去学算法的内部结构,最后还是选择了MATLAB自带的遗传算法工具箱(MATLAB2017-GA ...

  10. python画抛物线_在python中利用最小二乘拟合二次抛物线函数的方法

    1.最小二乘也可以拟合二次函数 我们都知道用最小二乘拟合线性函数没有问题,那么能不能拟合二次函数甚至更高次的函数呢?答案当然是可以的.下面我们就来试试用最小二乘来拟合抛物线形状的的图像. 对于二次函数 ...

最新文章

  1. 你想要的生物信息知识全在这——生信宝典文章目录
  2. 买不到“震楼神器”的外国小哥,用Arduino编了一个
  3. python上海培训哪里比较好-python培训班上海哪里比较好?
  4. c语言以冒号分割字符串,C语言里面的冒号
  5. CentOS6中安装、配置、启动GitLab以及遇到的那些坑
  6. leetcode 141. Linked List Cycle
  7. mysql memory=off_MySQL内存调优
  8. python 路径的操作
  9. 网易易盾最新一代Java2c加固究竟有什么厉害之处?
  10. arcgis api for ios
  11. Mac好用的图片压缩软件——JPG Compress 2 for Mac
  12. mac 提示缺失Myriad字体
  13. html 正则表达式 正整数,javascript如何判断数字是否为正整数?
  14. stm32毕业设计 单片机指纹识别考勤系统
  15. 完美解决Pyqt5 调用软键盘适用于触摸屏
  16. 10部令人泣不成声的经典电影
  17. 微信小程序获取数据接口动态渲染Echarts折线图
  18. 【许晓笛】EOS 什么是智能合约(3)
  19. 解决方案:爬虫被反爬,检测出是selenium,报400,无法进入网站
  20. Httpservletrequest获取上传文件

热门文章

  1. 第一章 FPGA数字信号处理_数字混频(NCO与DDS)
  2. python 爬虫抓取网页数据导出excel_如何用excel实现网页爬虫
  3. java虚拟机之内存模型
  4. ASP.NET 文件后缀名详解
  5. gif透明背景动画_PS教程:把静态照片做成GIF放大动画效果
  6. 去除暴风影音2009广告的方法!
  7. MFC笔记2.双击改变listctrl中的值
  8. 生词生词生词生词[1]
  9. 《涂抹Oracle—三思笔记之一步一步学Oracle》看书笔记(序言)
  10. HTML5汽车赛道飙车游戏免费源码下载