遗传算法解决经典运输问题

简介: 欢迎关注我的微信公众号:Python学习杂记

遗传算法是优化求解常用的一种启发式算法,其原理是模拟进化的过程,包括交叉遗传、突变、选择等方式繁衍后代,计算机通过模拟这些算子,优中选优,通过一次次迭代、繁衍,这些过程的目的就是搜索最优解。运输问题里最经典的tsp问题,是个np-难题(多一个节点,其解的可能性按指数级别上升),很难通过枚举法寻找最优解。比如有20个节点,其运输的可能性就是:20!,其结果为19位数。一般的计算机难以短时间运算出其最优解。根据主流学者的研究,遗传算法解决此类问题效果较好。(完整代码已放在本文最后。)

本文用Python编写遗传算法解决经典tsp问题的基本编程。

1.导入数据

需要建立一个两两节点的距离矩阵,距离矩阵可通过该点的位置至百度API爬取实际路程距离。

2.构建一个种群(编码并设置参数)

用不重复的1-20自然数对种群进行编码,再在起始加上0,一组数据即为一个DNA。各种参数都可以调整,后面搜索最优解的时候可以看效果调整参数。

2.构建适应度函数

适应度函数用距离的倒数来衡量,即距离越短,适应度越高,后代繁衍选址该父本的基因概率就越高。

3.轮盘筛选(算子1,优秀的父本被选择的概率高)

轮盘选择我用的是np.random.choice函数,该函数可以按照后面的概率(我用适应度来做选址的概率)来选址比较优势的父本进行繁衍。np.random.choice函数举例:

4.变异(算子2)

发生变异,一般会设置一定变异概率,概率一般设置成0.1-0.2, 变异。比如说4个节点的情况(20个节点原理一样),本次是变异如【0,1,2,3,4,0】,两个点位置交换【0,1,2,4,3,0】

5.交叉(算子3)

发生交叉,一般会设置一个交叉概率,交叉概率一般设置成0.2至0.8(tsp问题尽量不要设置的太高)。比如【0,1,2,3,4,0】交叉时1,3不变,24,按照母体【0,1,2,4,3,0】排列,则新的样本为【0,1,3,2,4,0】(20个节点原理一样)

6.进化至下一代

每一代都按照以上的方式进行循环迭代。

7.绘图

每一代结果都存储在一个数组中,后面画图看看每一代迭代效果。

8.完整代码

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
data1=pd.read_excel('datatsp.xlsx',sheet_name=0)
distance_matrix0=data1.iloc[0:,1].values #出发点到各个点的距离
distance_matrixnew=data1.iloc[1:,2:].values#经过的20个点的距离矩阵
#计算总距离的时候由0到第一个点的距离+城市总距离+最后一个城市到0的距离
best_everygeneration=[]#后面存储每一代的最优路径
lx=[]#后面存储x坐标,即迭代次数
ly=[]#存储每一代的最优值
N_CITIES = 20  # DNA size 起点不放进去,20个城市
CROSS_RATE = 0.2 #交叉系数
MUTATE_RATE = 0.01 #变异系数
POP_SIZE = 2000 #种群数
N_GENERATIONS =2000#迭代次数
class GA(object):
    def __init__(self, DNA_size, cross_rate, mutation_rate, pop_size, ):
        self.DNA_size = DNA_size
        self.cross_rate = cross_rate
        self.mutate_rate = mutation_rate
        self.pop_size = pop_size
        self.pop = np.vstack([np.random.permutation(DNA_size)+1 for _ in range(pop_size)])
    def get_fitness(self, qq):
        total_distance = np.empty((len(qq)), dtype=np.float64)
        for i,t in enumerate(qq):
            m=0
            for p in range(len(t)-1):
                m+=distance_matrixnew[t[p]-1][t[p+1]-1]
            m+=distance_matrix0[t[0]]+distance_matrix0[t[-1]]
            total_distance[i]=m
        fitness = 1/total_distance #距离的倒数做适应度,距离越小适应度越高,适应度适当放大。
        return fitness, total_distance
    def select(self, fitness):    #轮盘筛选选出较优的父母,可重复
        idx = np.random.choice(np.arange(self.pop_size), size=self.pop_size, replace=True, p=fitness / fitness.sum())
        return self.pop[idx]
    def crossover(self, parent, pop):
        if np.random.rand() < self.cross_rate:
            i_ = np.random.randint(0, self.pop_size, size=1) #随机选择一个pop的编号,后面该母体选址一部分基因
            cross_points = np.random.randint(0, 2, self.DNA_size).astype(bool)  #随机选择要发生交叉变化的点 
            keep_city = parent[~cross_points]  # find the city number
            swap_city = pop[i_, np.isin(pop[i_].ravel(), keep_city, invert=True)]#筛选出另一个母体剩下的基因(城市)
            parent[:] = np.concatenate((keep_city, swap_city))#合并交叉选择的母体
        return parent    #生成一个单一父本, 比如【0,1,2,3,4】交叉时1,3不变,024,按照母体【1,2,4,0,3】排列,则新的样本为【1,3,2,4,0】
    def mutate(self, child):
        for point in range(self.DNA_size):
            if np.random.rand() < self.mutate_rate:
                swap_point = np.random.randint(0, self.DNA_size) #随机生成变异点
                swapA, swapB = child[point], child[swap_point]  #对应两个点选出来
                child[point], child[swap_point] = swapB, swapA #交换两个点
        return child#与上一步类似,但是本次是变异如【0,1,2,3,4】,两个点位置交换【0,1,2,4,3】
    def evolve(self, fitness):    #进化至下一代
        pop0=self.pop.copy()
        pop = self.select(fitness)
        pop_copy = pop.copy()
        #print(pop0)  #看是否需要打印全部路线
        print('本次迭代最优路线',np.concatenate(([0],pop0[best_idx],[0])))
        best_everygeneration.append(np.concatenate(([0],pop0[best_idx],[0])))
        for parent in pop:  # for every parent对pop里面的每一个dna都按概率进行交叉、变异,最后生成一个新的pop
            child = self.crossover(parent, pop_copy) #交叉生成新的后代
            child = self.mutate(child) #后代中少量发生变异
            parent[:] = child #生成新的一代做为新的父母繁衍后代
        self.pop = pop
ga = GA(DNA_size=N_CITIES, cross_rate=CROSS_RATE, mutation_rate=MUTATE_RATE, pop_size=POP_SIZE)
for generation in range(1,N_GENERATIONS+1):
    fitness, total_distance = ga.get_fitness(ga.pop)
    best_idx = np.argmax(fitness)
    ga.evolve(fitness)#打印出路线
    lx.append(generation)
    ly.append(total_distance[best_idx])
    print('Gen:', generation, '| best fit: %.5f' % fitness[best_idx])
    print(total_distance[best_idx])

种群选择500个,迭代1000次,

看迭代的效果图,明显还有提高的空间。

增加种群至2000,迭代次数增加至1000,再运行一次程序。搜索最优解结果如下:其最优结果搜索到距离为690km。遗传算法需要多修改几次参数,多运行几次。因为遗传算法有可能在搜索解的过程中陷入局部最优。一般可以增加种群和迭代次数多尝试几次,也可以修改变异系数和交叉系数。


目录
相关文章
【VRP问题】基于遗传算法求解带容量的车辆路径规划问题(优化目标:运输成本)附Matlab代码
【VRP问题】基于遗传算法求解带容量的车辆路径规划问题(优化目标:运输成本)附Matlab代码
m基于PSO粒子群优化的第四方物流的作业整合算法matlab仿真,对比有代理人和无代理人两种模式下最低运输费用、代理人转换费用、运输方式转化费用和时间惩罚费用
m基于PSO粒子群优化的第四方物流的作业整合算法matlab仿真,对比有代理人和无代理人两种模式下最低运输费用、代理人转换费用、运输方式转化费用和时间惩罚费用
157 1
m基于PSO粒子群优化的第四方物流的作业整合算法matlab仿真,对比有代理人和无代理人两种模式下最低运输费用、代理人转换费用、运输方式转化费用和时间惩罚费用
m基于遗传优化算法的车辆货物运输问题matlab仿真,包括行驶距离,等待卸货时间及货损等问题
m基于遗传优化算法的车辆货物运输问题matlab仿真,包括行驶距离,等待卸货时间及货损等问题
160 0
m基于遗传优化算法的车辆货物运输问题matlab仿真,包括行驶距离,等待卸货时间及货损等问题
基于免疫算法的最优物流仓储点选址方案MATLAB仿真
本程序基于免疫算法实现物流仓储点选址优化,并通过MATLAB 2022A仿真展示结果。核心代码包括收敛曲线绘制、最优派送路线规划及可视化。算法模拟生物免疫系统,通过多样性生成、亲和力评价、选择、克隆、变异和抑制机制,高效搜索最优解。解决了物流仓储点选址这一复杂多目标优化问题,显著提升物流效率与服务质量。附完整无水印运行结果图示。
基于免疫算法的最优物流仓储点选址方案MATLAB仿真
基于GA遗传优化TCN时间卷积神经网络时间序列预测算法matlab仿真
本内容介绍了一种基于遗传算法优化的时间卷积神经网络(TCN)用于时间序列预测的方法。算法运行于 Matlab2022a,完整程序无水印,附带核心代码、中文注释及操作视频。TCN通过因果卷积层与残差连接学习时间序列复杂特征,但其性能依赖超参数设置。遗传算法通过对种群迭代优化,确定最佳超参数组合,提升预测精度。此方法适用于金融、气象等领域,实现更准确可靠的未来趋势预测。
基于LSB最低有效位的音频水印嵌入提取算法FPGA实现,包含testbench和MATLAB对比
本项目展示了一种基于FPGA的音频水印算法,采用LSB(最低有效位)技术实现版权保护与数据追踪功能。使用Vivado2019.2和Matlab2022a开发,完整代码含中文注释及操作视频。算法通过修改音频采样点的最低有效位嵌入水印,人耳难以察觉变化。然而,面对滤波或压缩等攻击时,水印提取可能受影响。该项目运行效果无水印干扰,适合实时应用场景,核心逻辑简单高效,时间复杂度低。

热门文章

最新文章