了却一个心愿

文章目录

目录

文章目录

前言

二、主要内容

三、使用步骤

1.将压缩包下载解压

2.读入数据

3.最终结果


前言

遗传算法(Genetic Algorithm,GA)最早是由美国的 John holland于20世纪70年代提出,该算法是根据大自然中生物体进化规律而设计提出的。是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。相信对于路径规划来说,这种方法其实也是一种目前较好的寻找最优解的方法。


一、遗传算法原理

原理都是一样的,有很多博客都写得很好,其理论的都是万变不离其宗。

二、主要内容

虽然理论摆在那里,有人能够看懂,有人看不懂,我也是只能看懂一点点,这就使得理论运用到代码当中就变得相当困难了,所以对于路径规划这样的题目,我想自己编出一个合适的遗传算法几乎就不可能了,还好在github里面发现了一个关于遗传算法TSP问题的代码,代码简单易懂(注释多),我自己试着运行了一下,发现效果也还不错,运行时间短,结果也不会总变来变去(几乎就是正确答案)。

GItHub链接

大哥的视频讲解

三、使用步骤

1.将压缩包下载解压

会发现有如下三个代码文件:

config.py:各参数配置
ga.py:遗传算法实现
main.py:程序入口,数据预处理,效果展示

 ga.py:就用了Python的一两个基础库,强我只能说。

from config import ConfigParser
import randomcity_dist_mat = None
Cf = ConfigParser(city_nums=101, gen_nums=10000)
config = Cf.get_config()
# 各项参数
gene_len = config.city_num
individual_num = config.individual_num
gen_num = config.gen_num
mutate_prob = config.mutate_probdef copy_list(old_arr: [int]):new_arr = []for element in old_arr:new_arr.append(element)return new_arr# 个体类
class Individual:def __init__(self, genes=None):# 随机生成序列if genes is None:genes = [i for i in range(gene_len)]random.shuffle(genes)self.genes = genesself.fitness = self.evaluate_fitness()def evaluate_fitness(self):# 计算个体适应度fitness = 0.0for i in range(gene_len - 1):# 起始城市和目标城市from_idx = self.genes[i]to_idx = self.genes[i + 1]fitness += city_dist_mat[from_idx, to_idx]# 连接首尾fitness += city_dist_mat[self.genes[-1], self.genes[0]]return fitnessclass Ga:def __init__(self, input_):global city_dist_matcity_dist_mat = input_self.best = None  # 每一代的最佳个体self.individual_list = []  # 每一代的个体列表self.result_list = []  # 每一代对应的解self.fitness_list = []  # 每一代对应的适应度def cross(self):new_gen = []random.shuffle(self.individual_list)for i in range(0, individual_num - 1, 2):# 父代基因genes1 = copy_list(self.individual_list[i].genes)genes2 = copy_list(self.individual_list[i + 1].genes)index1 = random.randint(0, gene_len - 2)index2 = random.randint(index1, gene_len - 1)pos1_recorder = {value: idx for idx, value in enumerate(genes1)}pos2_recorder = {value: idx for idx, value in enumerate(genes2)}# 交叉for j in range(index1, index2):value1, value2 = genes1[j], genes2[j]pos1, pos2 = pos1_recorder[value2], pos2_recorder[value1]genes1[j], genes1[pos1] = genes1[pos1], genes1[j]genes2[j], genes2[pos2] = genes2[pos2], genes2[j]pos1_recorder[value1], pos1_recorder[value2] = pos1, jpos2_recorder[value1], pos2_recorder[value2] = j, pos2new_gen.append(Individual(genes1))new_gen.append(Individual(genes2))return new_gendef mutate(self, new_gen):for individual in new_gen:if random.random() < mutate_prob:# 翻转切片old_genes = copy_list(individual.genes)index1 = random.randint(0, gene_len - 2)index2 = random.randint(index1, gene_len - 1)genes_mutate = old_genes[index1:index2]genes_mutate.reverse()individual.genes = old_genes[:index1] + genes_mutate + old_genes[index2:]# 两代合并self.individual_list += new_gendef select(self):# 锦标赛group_num = 10  # 小组数group_size = 10  # 每小组人数group_winner = individual_num // group_num  # 每小组获胜人数winners = []  # 锦标赛结果for i in range(group_num):group = []for j in range(group_size):# 随机组成小组player = random.choice(self.individual_list)player = Individual(player.genes)group.append(player)group = Ga.rank(group)# 取出获胜者winners += group[:group_winner]self.individual_list = winners@staticmethoddef rank(group):# 冒泡排序for i in range(1, len(group)):for j in range(0, len(group) - i):if group[j].fitness > group[j + 1].fitness:group[j], group[j + 1] = group[j + 1], group[j]return groupdef next_gen(self):# 交叉new_gen = self.cross()# 变异self.mutate(new_gen)# 选择self.select()# 获得这一代的结果for individual in self.individual_list:if individual.fitness < self.best.fitness:self.best = individualdef train(self, ifplot=False):# 初代种群self.individual_list = [Individual() for _ in range(individual_num)]self.best = self.individual_list[0]# 迭代for i in range(gen_num):self.next_gen()# 连接首尾result = copy_list(self.best.genes)result.append(result[0])self.result_list.append(result)self.fitness_list.append(self.best.fitness)return self.result_list, self.fitness_list

 config.py:我为了运行时调参,将其改为类帮助我不用每次都要到隔壁去修改参数

# -*- coding: utf-8 -*-
import argparseclass ConfigParser:def __init__(self, city_nums=101, pos_dimensions=2, individual_nums=60, gen_nums=1000, mutate_probs=0.25):'''参数调整,默认值可修改:param city_num: 城市数量:param pos_dimension: 坐标维度:param individual_num: 个体数:param gen_num: 迭代轮数:param mutate_prob: 变异概率:return: 参数说明'''self.parser = argparse.ArgumentParser(description='Configuration file')self.arg_lists = []# Datadata_arg = self.add_argument_group('Data')data_arg.add_argument('--city_num', type=int, default=city_nums, help='city num')  # 城市数量data_arg.add_argument('--pos_dimension', type=int, default=pos_dimensions, help='city num')  # 坐标维度data_arg.add_argument('--individual_num', type=int, default=individual_nums, help='individual num')  # 个体数data_arg.add_argument('--gen_num', type=int, default=gen_nums, help='generation num')  # 迭代轮数data_arg.add_argument('--mutate_prob', type=float, default=mutate_probs, help='probability of mutate')  # 变异概率def add_argument_group(self, name):arg = self.parser.add_argument_group(name)self.arg_lists.append(arg)return argdef get_config(self):self.config, self.unparsed = self.parser.parse_known_args()return self.configdef print_config(self):print('\n')print('Data Config:')print('* city num:', self.config.city_num)print('* individual num:', self.config.individual_num)print('* generation num:', self.config.gen_num)print('* probability of mutate:', self.config.mutate_prob)if __name__ == '__main__':Cf = ConfigParser(city_nums=101, gen_nums=10000)config = Cf.get_config()print("路径个数:", config.city_num)print("迭代次数:", config.gen_num)

main.py:我将ga.py里的代码拷到这里来了,所以没有调用ga,py,方便调参 

import numpy as np
import sys
sys.path.append(r'D:\86176\PycharmProjects\pythonProject\Interesting argrism\ga-tsp-main')
from config import ConfigParser
import matplotlib.pyplot as plt
# 解决中文显示问题
plt.rcParams['font.sans-serif'] = ['KaiTi']  # 指定默认字体
plt.rcParams['axes.unicode_minus'] = False  # 解决保存图像是负号'-'显示为方块的问题
from haversine import haversine
import time
import randomCf = ConfigParser(city_nums=101, gen_nums=10000)
config = Cf.get_config()
print("路径个数:", config.city_num)
print("迭代次数:", config.gen_num)
# 各项参数
gene_len = config.city_num
individual_num = config.individual_num
gen_num = config.gen_num
mutate_prob = config.mutate_probdef build_dist_mat(input_list):n = config.city_numdist_mat = np.zeros([n, n])for i in range(n):for j in range(i + 1, n):d = input_list[i, :] - input_list[j, :]# 计算点积dist_mat[i, j] = np.dot(d, d)dist_mat[j, i] = dist_mat[i, j]return dist_matdef dist_ance(sj):n = config.city_numdistance = np.zeros([n, n])for i in range(n):for j in range(i + 1, n):distance[i, j] = haversine(sj[i, :], sj[j, :])distance[j, i] = distance[i, j]return distance#######################################
# 遗传算法主要部分GA
def copy_list(old_arr: [int]):new_arr = []for element in old_arr:new_arr.append(element)return new_arr# 个体类
class Individual:def __init__(self, genes=None):# 随机生成序列if genes is None:genes = [i for i in range(gene_len)]random.shuffle(genes)self.genes = genesself.fitness = self.evaluate_fitness()def evaluate_fitness(self):# 计算个体适应度fitness = 0.0for i in range(gene_len - 1):# 起始城市和目标城市from_idx = self.genes[i]to_idx = self.genes[i + 1]fitness += city_dist_mat[from_idx, to_idx]# 连接首尾fitness += city_dist_mat[self.genes[-1], self.genes[0]]return fitnessclass Ga:def __init__(self, input_):global city_dist_matcity_dist_mat = input_self.best = None  # 每一代的最佳个体self.individual_list = []  # 每一代的个体列表self.result_list = []  # 每一代对应的解self.fitness_list = []  # 每一代对应的适应度def cross(self):new_gen = []random.shuffle(self.individual_list)for i in range(0, individual_num - 1, 2):# 父代基因genes1 = copy_list(self.individual_list[i].genes)genes2 = copy_list(self.individual_list[i + 1].genes)index1 = random.randint(0, gene_len - 2)index2 = random.randint(index1, gene_len - 1)pos1_recorder = {value: idx for idx, value in enumerate(genes1)}pos2_recorder = {value: idx for idx, value in enumerate(genes2)}# 交叉for j in range(index1, index2):value1, value2 = genes1[j], genes2[j]pos1, pos2 = pos1_recorder[value2], pos2_recorder[value1]genes1[j], genes1[pos1] = genes1[pos1], genes1[j]genes2[j], genes2[pos2] = genes2[pos2], genes2[j]pos1_recorder[value1], pos1_recorder[value2] = pos1, jpos2_recorder[value1], pos2_recorder[value2] = j, pos2new_gen.append(Individual(genes1))new_gen.append(Individual(genes2))return new_gendef mutate(self, new_gen):for individual in new_gen:if random.random() < mutate_prob:# 翻转切片old_genes = copy_list(individual.genes)index1 = random.randint(0, gene_len - 2)index2 = random.randint(index1, gene_len - 1)genes_mutate = old_genes[index1:index2]genes_mutate.reverse()individual.genes = old_genes[:index1] + genes_mutate + old_genes[index2:]# 两代合并self.individual_list += new_gendef select(self):# 锦标赛group_num = 10  # 小组数group_size = 10  # 每小组人数group_winner = individual_num // group_num  # 每小组获胜人数winners = []  # 锦标赛结果for i in range(group_num):group = []for j in range(group_size):# 随机组成小组player = random.choice(self.individual_list)player = Individual(player.genes)group.append(player)group = Ga.rank(group)# 取出获胜者winners += group[:group_winner]self.individual_list = winners@staticmethoddef rank(group):# 冒泡排序for i in range(1, len(group)):for j in range(0, len(group) - i):if group[j].fitness > group[j + 1].fitness:group[j], group[j + 1] = group[j + 1], group[j]return groupdef next_gen(self):# 交叉new_gen = self.cross()# 变异self.mutate(new_gen)# 选择self.select()# 获得这一代的结果for individual in self.individual_list:if individual.fitness < self.best.fitness:self.best = individualdef train(self):# 初代种群self.individual_list = [Individual() for _ in range(individual_num)]self.best = self.individual_list[0]# 迭代# plt.figure()# plt.ion()for i in range(gen_num):self.next_gen()# 连接首尾result = copy_list(self.best.genes)result.append(result[0])self.result_list.append(result)self.fitness_list.append(self.best.fitness)# plt.plot(self.fitness_list)# plt.pause(0.01)# plt.title(u"适应度曲线")# plt.legend()return self.result_list, self.fitness_listif __name__ == '__main__':Start = time.time()# 城市坐标# 读取数据city_pos_list = np.loadtxt(r'D:\86176\PycharmProjects\pythonProject\sj.txt', dtype=np.float32)city_pos_list = np.vstack([city_pos_list[:, [2 * i, 2 * i + 1]]for i in range(4)])d0 = np.array([70, 40])city_pos_list = np.vstack([d0, city_pos_list])# 城市距离矩阵city_dist_mat = dist_ance(city_pos_list)# print(city_pos_list)# print(city_dist_mat)# 遗传算法运行ga = Ga(city_dist_mat)result_list, fitness_list = ga.train()result = result_list[-1]idx = result.index(0)result = result[idx:-1]result.extend(result_list[-1][:idx])result.append(0)result_pos_list = city_pos_list[result, :]# fig = plt.figure()# plt.plot(result_pos_list[:, 0], result_pos_list[:, 1], 'o-r')# plt.title(u"路线")# plt.legend()# fig.show()# 画图# plt.figure()# plt.ion()# # plt.plot(fitness_list)# xx = [fitness_list[0]]# for i in range(1, len(fitness_list)):#     xx.append(fitness_list[i])#     plt.plot(xx)#     plt.pause(0.01)# plt.title(u"适应度曲线")# plt.legend()# plt.show()plt.figure()plt.ion()xs = [result_pos_list[0, 0]]ys = [result_pos_list[0, 1]]for i in range(1, len(result_pos_list)):xs.append(result_pos_list[i, 0])ys.append(result_pos_list[i, 1])plt.plot(xs, ys, '-o')plt.pause(0.1)End = time.time()print("用时", End - Start, '秒')print('运行路线为:')for i in result:print(i, end=' ')print("\n最短总距离为:", fitness_list[-1])

2.读入数据

用的是一个飞机要经过的100个城市坐标(经纬度),所以在做的过程中要考虑经纬度之间距离的直接转化。飞机的起始坐标是(70,40),要经过下面的所有地点并回到起点。

经纬度坐标
经度 纬度 经度 纬度 经度 纬度 经度 纬度
53.7121 15.3046 51.1758 0.0322 46.3253 28.2753 30.3313 6.9348
56.5432 21.4188 10.8198 16.2529 22.7891 23.1045 10.1584 12.4819
20.105 15.4562 1.9451 0.2057 26.4951 22.1221 31.4847 8.964
26.2418 18.176 44.0356 13.5401 28.9836 25.9879 38.4722 20.1731
28.2694 29.0011 32.191 5.8699 36.4863 29.7284 0.9718 28.1477
8.9586 24.6635 16.5618 23.6143 10.5597 15.1178 50.2111 10.2944
8.1519 9.5325 22.1075 18.5569 0.1215 18.8726 48.2077 16.8889
31.9499 17.6309 0.7732 0.4656 47.4134 23.7783 41.8671 3.5667
43.5474 3.9061 53.3524 26.7256 30.8165 13.4595 27.7133 5.0706
23.9222 7.6306 51.9612 22.8511 12.7938 15.7307 4.9568 8.3669
21.5051 24.0909 15.2548 27.2111 6.207 5.1442 49.243 16.7044
17.1168 20.0354 34.1688 22.7571 9.4402 3.92 11.5812 14.5677
52.1181 0.4088 9.5559 11.4219 24.4509 6.5634 26.7213 28.5667
37.5848 16.8474 35.6619 9.9333 24.4654 3.1644 0.7775 6.9576
14.4703 13.6368 19.866 15.1224 3.1616 4.2428 18.5245 14.3598
58.6849 27.1485 39.5168 16.9371 56.5089 13.709 52.5211 15.7957
38.43 8.4648 51.8181 23.0159 8.9983 23.644 50.1156 23.7816
13.7909 1.951 34.0574 23.396 23.0624 8.4319 19.9857 5.7902
40.8801 14.2978 58.8289 14.5229 18.6635 6.7436 52.8423 27.288
39.9494 29.5114 47.5099 24.0664 10.1121 27.2662 28.7812 27.6659
8.0831 27.6705 9.1556 14.1304 53.7989 0.2199 33.649 0.398
1.3496 16.8359 49.9816 6.0828 19.3635 17.6622 36.9545 23.0265
15.732 19.5697 11.5118 17.3884 44.0398 16.2635 39.7139 28.4203
6.9909 23.1804 38.3392 19.995 24.6543 19.6057 36.998 24.3992
4.1591 3.1853 40.14 20.303 23.9876 9.403 41.1084 27.7149

求最短路径。

3.最终结果

只需修改运行main.py中的文件就行了

将结果坐标放入直角坐标中展示

迭代结果:

实时迭代结果的展示可能会使得算法在计算时速度会减慢,如果电脑好那就另说了,不建议实时结果展示。

运行路线为:
0 44 66 1 91 81 47 71 13 26 9 83 17 39 78 76 30 96 84 64 63 10 93 69 18 62 61 25 28 33 65 89 85 7 38 77 46 56 27 87 60 48 67 6 24 22 57 80 21 70 36 31 23 12 72 11 52 88 5 95 54 55 20 98 99 43 37 53 4 74 32 3 40 90 15 68 75 59 8 14 49 79 97 50 41 19 29 73 82 86 58 100 51 45 92 42 35 94 34 2 16 0 
最短总距离为: 40546.764132575256


总结

这是我在之前国赛训练训练时的一个题目,虽然很简单,但是当时是真的觉得很难,记录一下,希望对有需要的同学有帮助,其实我现在是对这个算法理解的也还算深了,因为和它对抗了很久,总是想找一个合适的Python算法没找到,自己写的也不尽人意,这也算是我对自己这一模块结束的标志了吧。

Python 遗传算法路径规划相关推荐

  1. 【python+ROS+路径规划】一、前置准备

    大学四年从来没有接触过ros,保研跨专业保到了电院,毕设需要在ros中用mpc进行路径规划与跟踪(从SCI上下了一篇论文,毕设准备复现算法),跟着B站学了3个月的ros,本以为毕设分分钟就能搞定,没想 ...

  2. 【python+ROS+路径规划】二、理解并处理地图数据

    目前打算使用python写出一个Astar的全局路径算法,总体分为三个部分:接收地图数据,设计路径(当然是顺过来的),发布路径. 文章目录 一.建立功能包 二.接受地图数据(处理上游) 查看地图发布的 ...

  3. python无人机路径规划算法_RRT算法在Python中的实现,快速,拓展,随机,树

    """ <基于智能优化与RRT算法的无人机任务规划方法研究>博士论文 <基于改进人工势场法的路径规划算法研究>硕士论文 ""& ...

  4. python无人机路径规划算法_快速拓展随机树(RRT)路径规划,python

    1 """2 version1.1,2018-05-09 3 <基于智能优化与RRT算法的无人机任务规划方法研究>博士论文4 <基于改进人工势场法的路径 ...

  5. 【python+ROS+路径规划】四、发布路径

    当上游和算法接上去之后,下面考虑如何将算法发布出去,并且现实在rviz中 文章目录 发布路径 算法给出的格式 查看rviz接收路径的数据类型 如何发布 在rviz中显示 发布路径 算法给出的格式 整理 ...

  6. python无人机路径规划算法_无人机集群——航迹规划你不知道的各种算法优缺点...

    我们都知道无人机(UAV )因具有可探测性低.造价低廉.不惧伤亡.起降简单.操作灵活.系统配置多样化.自动控制智能化等特点,因而在未来一体化联合作战中扮演越来越重要的角色.然而早期的无人机都是按照地面 ...

  7. 算法学习之模拟退火算法路径规划(python代码实现)

    模拟退火算法路径规划(python代码实现) 一.引言 二.算法介绍以及伪代码 1.算法通俗介绍 2.路径规划算法伪代码 三.算法流程及代码实现 1.地图创建 2.初始化路径 小结 3.计算适应度值 ...

  8. 基于遗传算法求解TSP问题(旅游路径规划,Python实现,超详细,可视化,结果分析)

    ps:作者是很用心写的,如果觉得不错,请给作者一点鼓励噢!(点赞收藏评论噢) 基于遗传算法求解TSP问题 摘要 巡回旅行商问题(TSP)是组合优化中的经典问题.常见的TSP问题求解算法例如穷举法.贪心 ...

  9. python 遗传算法 agv_基于改进遗传算法的AGV路径规划

    基于改进遗传算法的 AGV 路径规划 苑光明,翟云飞,丁承君,张 鹏 [摘 要] [摘 要] 针对 AGV 在自动化生产线中原有路径规划算法存在路径拐 弯次数多,不利于 AGV 自动控制的问题,提出了 ...

  10. 物流路径规划用遗传算法解决实例

    网上有很多关于遗传算法的教程,但基本千篇一律.这次物流课做了一个跟路径规划相关的案例,拿出来与大家分享. 先贴案例.案例摘自<企业物流管理>. < R&T批发公司> R ...

最新文章

  1. jenkins邮件配置
  2. postman断言测试脚本一
  3. 移动端 Web 开发踩坑之旅
  4. 并发编程之进程池,线程池 和 异步回调,协程
  5. 删除下拉框只找23火星软件_下拉推广选择23火星软件
  6. javascript系列:NaN类型
  7. shell linux中用shell写一个占用CPU的脚本
  8. CS224N笔记——词向量表示
  9. 如何让图片按照1 2 3排列不带括号
  10. 利用梳状函数求解周期函数傅里叶变换
  11. 新华全媒+|探秘北迁象群的“家”和“家人们”
  12. 大一php,大一总结 - 我的大一 - php中文网博客
  13. AtCoder题解 —— AtCoder Regular Contest 108 —— A - Sum and Product
  14. 朋友圈发圈助手文案,头像,壁纸组合微信小程序源码下载
  15. 程序设计-求解数独(C)
  16. linux去除文件中重复行,Linux Shell教程 - 如何删除重复的文本行
  17. Spring - Spring容器概念及其初始化过程
  18. Mac触控板设置以及使用
  19. 行业洞察 | Web3、AI4Science、机器人,热门赛道全解析...AI商业化受阻,拐点在何方?...
  20. linux ls和cd命令详解,Linux基础cd、pwd和ls命令

热门文章

  1. c语言代码99乘法表,c语言九九乘法表代码如何写
  2. Linux实战教学笔记
  3. Unity3D 汉化
  4. javaWeb新闻管理系统
  5. USBVIEW(带已分配带宽显示功能)-电脑圈圈
  6. OpenGL超级宝典(第7版)之第七章顶点处理与绘图命令
  7. Delphi7 在Windows 7上无法打开帮助文档
  8. 单片机c语言 课程设计报告,单片机课程设计心得体会精选
  9. 微信小程序大全:767个小程序
  10. 人工智能写诗全程测试输出的诗句