版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/jiang425776024/article/details/84532018

效果图:

程序会动态的展示迭代过程,40以内城市大概迭代300次能收敛到最优;这里是用中国城市地理坐标直接做欧式距离计算,实际上可以根据问题作出调整。
Github:https://github.com/425776024/TSP-GA-py

测试数据:china.csv:

北京 ;116.46;39.92
天津 ;117.2;39.13
上海 ;121.48;31.22
重庆 ;106.54;29.59
拉萨 ;91.11;29.97
乌鲁木齐 ;87.68;43.77
银川 ;106.27;38.47
呼和浩特 ;111.65;40.82
南宁 ;108.33;22.84
哈尔滨 ;126.63;45.75
长春 ;125.35;43.88
沈阳 ;123.38;41.8
石家庄 ;114.48;38.03
太原 ;112.53;37.87
西宁 ;101.74;36.56
济南 ;117;36.65
郑州 ;113.6;34.76
南京;118.78;32.04
合肥;117.27;31.86
杭州;120.19;30.26
福州;119.3;26.08
南昌;115.89;28.68
长沙;113;28.21
武汉;114.31;30.52
广州;113.23;23.16
台北;121.5;25.05
海口;110.35;20.02
兰州;103.73;36.03
西安;108.95;34.27
成都;104.06;30.67
贵阳;106.71;26.57
昆明;102.73;25.04
香港;114.1;22.2
澳门;113.33;22.13

TSP-GA.py

# -*- encoding: utf-8 -*-
import numpy as np
import pandas as pd
from DW import * class TSP(object):
citys = np.array([]) #城市数组
citys_name = np.array([])
pop_size = 50 #种群大小
c_rate = 0.7 #交叉率
m_rate = 0.05 #突变率
pop = np.array([]) #种群数组
fitness = np.array([]) #适应度数组
city_size = -1 #标记城市数目
ga_num = 200 #最大迭代次数
best_dist = -1 #记录目前最优距离
best_gen = [] #记录目前最优旅行方案
dw = Draw() #绘图类 def __init__(self, c_rate, m_rate, pop_size, ga_num):
self.fitness = np.zeros(self.pop_size)
self.c_rate = c_rate
self.m_rate = m_rate
self.pop_size = pop_size
self.ga_num = ga_num def init(self):
tsp = self
# tsp.load_Citys() #加载城市数据
tsp.load_Citys2() #加载城市数据
tsp.pop = tsp.creat_pop(tsp.pop_size) #创建种群
tsp.fitness = tsp.get_fitness(tsp.pop) #计算初始种群适应度
tsp.dw.bound_x = [np.min(tsp.citys[:, 0]), np.max(tsp.citys[:, 0])] #计算绘图时的X界
tsp.dw.bound_y = [np.min(tsp.citys[:, 1]), np.max(tsp.citys[:, 1])] #计算绘图时的Y界
tsp.dw.set_xybound(tsp.dw.bound_x, tsp.dw.bound_y) #设置边界 def creat_pop(self, size):
pop = []
for i in range(size):
gene = np.arange(self.citys.shape[0]) #问题的解,基因,种群中的个体:[0,...,city_size]
np.random.shuffle(gene) #打乱数组[0,...,city_size]
pop.append(gene) #加入种群
return np.array(pop) def get_fitness(self, pop):
d = np.array([]) #适应度记录数组
for i in range(pop.shape[0]):
gen = pop[i] # 取其中一条基因(编码解,个体)
dis = self.gen_distance(gen) #计算此基因优劣(距离长短)
dis = self.best_dist / dis #当前最优距离除以当前pop[i](个体)距离;越近适应度越高,最优适应度为1
d = np.append(d, dis) # 保存适应度pop[i]
return d def get_local_fitness(self, gen, i):
'''
计算地i个城市的邻域
交换基因数组中任意两个值组成的解集:称为邻域。计算领域内所有可能的适应度
:param gen:城市路径
:param i:第i城市
:return:第i城市的局部适应度
'''
di = 0
fi = 0
if i == 0:
di = self.ct_distance(self.citys[gen[0]], self.citys[gen[-1]])
else:
di = self.ct_distance(self.citys[gen[i]], self.citys[gen[i - 1]])
od = []
for j in range(self.city_size):
if i != j:
od.append(self.ct_distance(self.citys[gen[i]], self.citys[gen[i - 1]]))
mind = np.min(od)
fi = di - mind
return fi def EO(self, gen):
#极值优化,传统遗传算法性能不好,这里混合EO
#其会在整个基因的领域内,寻找一个最佳变换以更新基因
local_fitness = []
for g in range(self.city_size):
f = self.get_local_fitness(gen, g)
local_fitness.append(f)
max_city_i = np.argmax(local_fitness)
maxgen = np.copy(gen)
if 1 < max_city_i < self.city_size - 1:
for j in range(max_city_i):
maxgen = np.copy(gen)
jj = max_city_i
while jj < self.city_size:
gen1 = self.exechange_gen(maxgen, j, jj)
d = self.gen_distance(maxgen)
d1 = self.gen_distance(gen1)
if d > d1:
maxgen = gen1[:]
jj += 1
gen = maxgen
return gen def select_pop(self, pop):
#选择种群,优胜劣汰,策略1:低于平均的要替换改变
best_f_index = np.argmax(self.fitness)
av = np.median(self.fitness, axis=0)
for i in range(self.pop_size):
if i != best_f_index and self.fitness[i] < av:
pi = self.cross(pop[best_f_index], pop[i])
pi = self.mutate(pi)
# d1 = self.distance(pi)
# d2 = self.distance(pop[i])
# if d1 < d2:
pop[i, :] = pi[:] return pop def select_pop2(self, pop):
#选择种群,优胜劣汰,策略2:轮盘赌,适应度低的替换的概率大
probility = self.fitness / self.fitness.sum()
idx = np.random.choice(np.arange(self.pop_size), size=self.pop_size, replace=True, p=probility)
n_pop = pop[idx, :]
return n_pop def cross(self, parent1, parent2):
"""交叉p1,p2的部分基因片段"""
if np.random.rand() > self.c_rate:
return parent1
index1 = np.random.randint(0, self.city_size - 1)
index2 = np.random.randint(index1, self.city_size - 1)
tempGene = parent2[index1:index2] # 交叉的基因片段
newGene = []
p1len = 0
for g in parent1:
if p1len == index1:
newGene.extend(tempGene) # 插入基因片段
if g not in tempGene:
newGene.append(g)
p1len += 1
newGene = np.array(newGene) if newGene.shape[0] != self.city_size:
print('c error')
return self.creat_pop(1)
# return parent1
return newGene def mutate(self, gene):
"""突变"""
if np.random.rand() > self.m_rate:
return gene
index1 = np.random.randint(0, self.city_size - 1)
index2 = np.random.randint(index1, self.city_size - 1)
newGene = self.reverse_gen(gene, index1, index2)
if newGene.shape[0] != self.city_size:
print('m error')
return self.creat_pop(1)
return newGene def reverse_gen(self, gen, i, j):
#函数:翻转基因中i到j之间的基因片段
if i >= j:
return gen
if j > self.city_size - 1:
return gen
parent1 = np.copy(gen)
tempGene = parent1[i:j]
newGene = []
p1len = 0
for g in parent1:
if p1len == i:
newGene.extend(tempGene[::-1]) # 插入基因片段
if g not in tempGene:
newGene.append(g)
p1len += 1
return np.array(newGene) def exechange_gen(self, gen, i, j):
#函数:交换基因中i,j值
c = gen[j]
gen[j] = gen[i]
gen[i] = c
return gen def evolution(self):
#主程序:迭代进化种群
tsp = self
for i in range(self.ga_num):
best_f_index = np.argmax(tsp.fitness)
worst_f_index = np.argmin(tsp.fitness)
local_best_gen = tsp.pop[best_f_index]
local_best_dist = tsp.gen_distance(local_best_gen)
if i == 0:
tsp.best_gen = local_best_gen
tsp.best_dist = tsp.gen_distance(local_best_gen) if local_best_dist < tsp.best_dist:
tsp.best_dist = local_best_dist #记录最优值
tsp.best_gen = local_best_gen #记录最个体基因
#绘图
tsp.dw.ax.cla()
tsp.re_draw()
tsp.dw.plt.pause(0.001)
else:
tsp.pop[worst_f_index] = self.best_gen
print('gen:%d evo,best dist :%s' % (i, self.best_dist)) tsp.pop = tsp.select_pop(tsp.pop) #选择淘汰种群
tsp.fitness = tsp.get_fitness(tsp.pop) #计算种群适应度
for j in range(self.pop_size):
r = np.random.randint(0, self.pop_size - 1)
if j != r:
tsp.pop[j] = tsp.cross(tsp.pop[j], tsp.pop[r]) #交叉种群中第j,r个体的基因
tsp.pop[j] = tsp.mutate(tsp.pop[j]) #突变种群中第j个体的基因
self.best_gen = self.EO(self.best_gen) #极值优化,防止收敛局部最优
tsp.best_dist = tsp.gen_distance(self.best_gen) #记录最优值 def load_Citys(self, file='china_main_citys.csv', delm=','):
# 中国34城市经纬度
data = pd.read_csv(file, delimiter=delm, header=None).values
#china_main_citys.csv数据太大,只计算部分如:湖南省关键字的
self.citys = data[data[:, 0] == '湖南省', 4:]
self.citys_name = data[data[:, 0] == '湖南省', 2]
self.city_size = self.citys.shape[0] def load_Citys2(self, file='china.csv', delm=';'):
# 中国34城市经纬度
data = pd.read_csv(file, delimiter=delm, header=None).values
self.citys = data[:, 1:]
self.citys_name = data[:, 0]
self.city_size = data.shape[0] def gen_distance(self, gen):
#计算基因所代表的总旅行距离
distance = 0.0
for i in range(-1, len(self.citys) - 1):
index1, index2 = gen[i], gen[i + 1]
city1, city2 = self.citys[index1], self.citys[index2]
distance += np.sqrt((city1[0] - city2[0]) ** 2 + (city1[1] - city2[1]) ** 2)
return distance def ct_distance(self, city1, city2):
#计算2城市之间的欧氏距离
d = np.sqrt((city1[0] - city2[0]) ** 2 + (city1[1] - city2[1]) ** 2)
return d def draw_citys_way(self, gen):
'''
根据一条基因gen绘制一条旅行路线
:param gen:
:return:
'''
tsp = self
dw = self.dw
m = gen.shape[0]
tsp.dw.set_xybound(tsp.dw.bound_x, tsp.dw.bound_y)
for i in range(m):
if i < m - 1:
best_i = tsp.best_gen[i]
next_best_i = tsp.best_gen[i + 1]
best_icity = tsp.citys[best_i]
next_best_icity = tsp.citys[next_best_i]
dw.draw_line(best_icity, next_best_icity)
start = tsp.citys[tsp.best_gen[0]]
end = tsp.citys[tsp.best_gen[-1]]
dw.draw_line(end, start) def draw_citys_name(self, gen, size=5):
'''
根据一条基因gen绘制对应城市名称
:param gen:
:param size: text size
:return:
'''
tsp = self
m = gen.shape[0]
tsp.dw.set_xybound(tsp.dw.bound_x, tsp.dw.bound_y)
for i in range(m):
c = gen[i]
best_icity = tsp.citys[c]
tsp.dw.draw_text(best_icity[0], best_icity[1], tsp.citys_name[c], 10) def re_draw(self):
#重绘图;每次迭代后绘制一次,动态展示。
tsp = self
tsp.dw.draw_points(tsp.citys[:, 0], tsp.citys[:, 1])
tsp.draw_citys_name(tsp.pop[0], 8)
tsp.draw_citys_way(self.best_gen) def main():
tsp = TSP(0.5, 0.1, 100, 500)
tsp.init()
tsp.evolution()
tsp.re_draw()
tsp.dw.plt.show() if __name__ == '__main__':
main()

DW.py

#DW.py

import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
import matplotlib.animation as animation class Draw(object):
bound_x = []
bound_y = [] def __init__(self):
self.fig, self.ax = plt.subplots()
self.plt = plt
self.set_font() def draw_line(self, p_from, p_to):
line1 = [(p_from[0], p_from[1]), (p_to[0], p_to[1])]
(line1_xs, line1_ys) = zip(*line1)
self.ax.add_line(Line2D(line1_xs, line1_ys, linewidth=1, color='blue')) # def draw_arrow(self, p_from, p_to):
# if p_from.shape[0] != 2 and p_to.shape[0] != 2:
# print('error,', p_from, p_to)
# return
# p_from = list(p_from)
# p_to = list(p_to)
# self.ax.arrow(p_from[0], p_from[1], p_to[0] - p_from[0], p_to[1] - p_from[1],
# length_includes_head=True,
# head_width=(self.bound_x[1] - self.bound_x[0]) / 100,
# head_length=(self.bound_x[1] - self.bound_x[0]) / 50,
# fc='blue', ec='black') def draw_points(self, pointx, pointy):
self.ax.plot(pointx, pointy, 'ro') def set_xybound(self, x_bd, y_bd):
self.ax.axis([x_bd[0], x_bd[1], y_bd[0], y_bd[1]]) def draw_text(self, x, y, text, size=8):
self.ax.text(x, y, text, fontsize=size) def set_font(self, ft_style='SimHei'):
plt.rcParams['font.sans-serif'] = [ft_style] # 用来正常显示中文标签

Python动态展示遗传算法求解TSP旅行商问题(转载)的更多相关文章

  1. 利用遗传算法求解TSP问题

    转载地址 https://blog.csdn.net/greedystar/article/details/80343841 目录 一.问题描述 二.算法描述 三.求解说明 四.参考资料 五.源代码 ...

  2. 基于遗传算法求解TSP问题(Java界面)

    近期为做展示,改写了一个遗传算法求TSP的Java界面版,思路代码和 http://blog.csdn.net/wangqiuyun/article/details/12838903 这篇文章思路是一 ...

  3. 基于GA遗传算法的TSP旅行商问题求解

    import random import math import matplotlib.pyplot as plt import city class no: #该类表示每个点的坐标 def __in ...

  4. 遗传算法求解TSP问题

    package com.louis.tsp; /** * Project Name:GeneticAlgorithm * File Name:Individual.java * Package Nam ...

  5. 遗传算法求解旅行商(TSP)问题 -- python

    参考资料: 遗传算法解决TSP旅行商问题(附:Python实现) 遗传算法详解(GA)(个人觉得很形象,很适合初学者) from itertools import permutations impor ...

  6. 遗传算法的C语言实现(二)-----以求解TSP问题为例

    上一次我们使用遗传算法求解了一个较为复杂的多元非线性函数的极值问题,也基本了解了遗传算法的实现基本步骤.这一次,我再以经典的TSP问题为例,更加深入地说明遗传算法中选择.交叉.变异等核心步骤的实现.而 ...

  7. 【优化算法】变邻域搜索算法(VNS)求解TSP(附C++详细代码及注释)

    00 前言 上次变邻域搜索的推文发出来以后,看过的小伙伴纷纷叫好.小编大受鼓舞,连夜赶工,总算是完成了手头上的一份关于变邻域搜索算法解TSP问题的代码.今天,就在此给大家双手奉上啦,希望大家能ENJO ...

  8. 模拟退火算法SA原理及python、java、php、c++语言代码实现TSP旅行商问题,智能优化算法,随机寻优算法,全局最短路径

    模拟退火算法SA原理及python.java.php.c++语言代码实现TSP旅行商问题,智能优化算法,随机寻优算法,全局最短路径 模拟退火算法(Simulated Annealing,SA)最早的思 ...

  9. ACS蚁群算法求解对称TSP旅行商问题的JavaScript实现

    本来以为在了解蚁群算法的基础上实现这道奇怪的算法题并不难,结果实际上大相径庭啊.做了近三天时间,才改成现在这能勉强拿的出手的模样.由于公式都是图片,暂且以截图代替那部分内容吧,mark一记. 1 蚁群 ...

随机推荐

  1. string+DP leetcode-4.最长回文子串

    5. Longest Palindromic Substring 题面 Given a string s, find the longest palindromic substring in s. Y ...

  2. 深度学习_1_Tensorflow_2_数据_文件读取

    tensorflow 数据读取 队列和线程 文件读取, 图片处理 问题:大文件读取,读取速度, 在tensorflow中真正的多线程 子线程读取数据 向队列放数据(如每次100个),主线程学习,不用全 ...

  3. Sliverlight/WPF 样式使用方法

    1,UserControl 页面级样式: UserControl.Resources style setter Property value. TargetType为应用的类型 <UserCon ...

  4. 关于Http协议与TCP协议的一些简单理解

    TCP协议对应于传输层,而HTTP协议对应于应用层,从本质上来说,二者没有可比性.Http协议是建立在TCP协议基础之上的,当浏览器需要从服务器获取网页数据的时候,会发出一次Http请求.Http会通 ...

  5. [Mac][Python][Jupyter Notebook]安装配置和使用

    Jupyter 项目(以前称为 IPython 项目),提供了一套使用功能强大的交互式 shell 进行科学计算的工具,实现了将代码执行与创建实时计算文档相结合. 这些 Notebook 文件可以包含 ...

  6. 接口自动化平台搭建(四),自动化项目Jenkins持续集成

    一.Jenkins的优点 1.传统网站部署流程   一般网站部署的流程 这边是完整流程而不是简化的流程 需求分析—原型设计—开发代码—内网部署-提交测试—确认上线—备份数据—外网更新-最终测试 ,如果 ...

  7. 小白学Python | 最简单的Django 简明教程

    作者:浅雨凉 来源:http://www.cnblogs.com/qianyuliang/p/6814376.html 一.Django简介 1. web框架介绍 具体介绍Django之前,必须先介绍 ...

  8. java应用本地缓存

            在java应用中,对于访问频率比较高,又不怎么变化的数据,常用的解决方案是把这些数据加入缓存.相比DB,缓存的读取效率快好不少.java应用缓存一般分两种,一是进程内缓存,就是使用ja ...

  9. api文档设计工具:RAML、Swagger

    api文档设计工具是用来描述和辅助API开发的. 一.RAML https://raml.org/ https://wenku.baidu.com/view/9523238d5ef7ba0d4b733 ...

  10. Pycharm----显示tab制表符

    设置前: 设置后: 操作方法: