遗传算法求解带时间窗的VRP问题(python)

遗传算法求解带时间窗的VRP问题(python)

来来来,继续学习物流路径优化问题,这次是带时间窗的VRP问题。
城市生鲜食品冷链物流配送中心选址及路径优化问题研究为学习材料。以下遗传算法的数据均来源于该文献。

1.问题描述

一般的VRPTW问题(带时间窗的车辆优化调度问题)可描述为: 一个配送中心或车场(发车点),z个客户 (1, 2,⋯, z),第 i个客户的货运量为 g,使用载重量相同的货车( 车速为 v, 车载量为Q )完成货物需求点的配送任务。每个任务都有最早送达时间 ET,和最迟送达时间 LT 。每个需求点的需求量均小于配送货车的载重量( g < Q), 且要求只由一辆货车一 次运送完成,但允许一辆车一次运输可完成多个任务;配送中心和各客户点位置已知,各点之间的距离也已知; 所有配送车辆均从配送中心出发,完成运送任务后返回配送中心。现要求在满足所有任务时间窗约束和车辆载重量约束的情况下,如何安排车辆运输路线,使得总费用最小。

城市生鲜食品冷链物流配送中心选址及路径优化问题研究下层模型中总的运输成本=车辆的固定使用成本+车辆运输成本+时间窗的惩罚成本+货损成本。数学模型的目标函数是求总运输成本最小化,所以遗传算法的适应度函数就是总运输成本的倒数。

2.确定遗传算子的编码规则

2.1染色体的编码方式

采用整数编码,染色体的个数是配送需求点的数量。生成的初始种群中的每条染色体都应该是可行解,求解的问题中只有车辆数不能超过配送中心可支配的最大车辆数限制这一个硬性的约束条件,所以采用get_feasible_route函数保证随机生成的染色体形成的车辆路线在最大车辆数范围内。

def set_codeForm(Popsize):
    demand_node_num = Data_class.demand_node_num
    population = np.zeros((Popsize, demand_node_num), dtype=int)
    for i in range(Popsize):
        while 1:
            population[i, :] = random.sample(range(1, demand_node_num+1), demand_node_num)
            if get_feasible_route(population[i, :]):
                break
    return population
def get_feasible_route(chrom):
    individual = copy.deepcopy(chrom)
    split_flag_node = True
    total_path_list = []
    vehicle_capacity_max = Data_class.vehicle_capacity_max
    demand_quantity = Data_class.demand_quantity
    vehicle_num = Data_class.vehicle_num
    while split_flag_node:
        vehicle_load_list = demand_quantity[0, individual]
        cumsum_list = np.cumsum(vehicle_load_list)
        if len(np.where(cumsum_list > vehicle_capacity_max)[0]) != 0:
            split_flag_node = np.where(cumsum_list > vehicle_capacity_max)[0][0]
        else:
            split_flag_node = False
            path_list = [0] * (len(individual) + 2)
            path_list[1:-1] = copy.deepcopy(individual)
            total_path_list.append(path_list)
        if split_flag_node:
            path_list = [0] * (split_flag_node + 2)
            path_list[1:-1] = copy.deepcopy(individual[:split_flag_node])
            total_path_list.append(path_list)
            individual = individual[split_flag_node:]
    if len(total_path_list) > vehicle_num:
        # 生成的车辆路线数量超过了配送中心可以调配的实际车辆数
        return []
    else:
        return total_path_list

2.2选择算子

采用锦标赛选择

def select(population, fitness):
    # 进行选择操作
    Popsize = Data_class.Popsize
    # 二复本锦标赛选择方法
    new_population = np.zeros((Popsize, demand_node_num), dtype=int)
    new_fitness = []
    for i in range(Popsize):
        index = random.choices(list(range(Popsize)), k=2)
        if fitness[index[0]] < fitness[index[1]]:
            new_population[i, :] = population[index[1], :]
            new_fitness.append(fitness[index[1]])
        else:
            new_population[i, :] = population[index[0], :]
            new_fitness.append(fitness[index[0]])
    # 精英保留策略
    new_population[np.argmin(new_fitness), :] = population[np.argmax(fitness), :]
    return new_population

不知道自己对锦标赛选择的理解是不是对的,上面代码的实现过程是随机选择两个染色体,通过比较它们的适应度函数值的大小,保留较大值作为下一代种群的染色体,重复该选择操作Popsize次,Popsize为种群的规模也就是染色体的总数。同时采取精英保留策略,保存上一代种群中适应度函数值最大的染色体,替换掉已经选中的种群中的最差的染色体。

2.3交叉算子

交叉算子参考简书上面的文章:遗传算法实践(九) VRP问题
在这里插入图片描述
本文交叉操作思想和上图的交叉操作不同的是:不是选择生成的子路径中代价最小的,而是通过get_feasible_route函数实现自动生成路径,直接添加到已经从父代1选中的子路径后面。

def crossover(population):
    # 是否进行交叉操作由交叉概论决定
    Popsize = Data_class.Popsize
    Pc = Data_class.Pc
    for i in range(Popsize):
        r = random.random()
        if r > Pc:
            continue
        while 1:
            # 随机选择两条染色体,进行交叉操作
            index = random.choices(range(Popsize), k=2)
            chrom1 = population[index[0], :]
            chrom2 = population[index[1], :]
            routes1 = get_feasible_route(chrom1)
            # 随机选择父代1的一条路径
            ind1 = routes1[random.choice(range(len(routes1)))]
            ind1_index = []
            ind2 = copy.deepcopy(chrom2)
            for j in ind1[1:-1]:
                ind1_index.append(ind2.tolist().index(j))
            nodes = chrom2[list(set(range(len(chrom2))) - set(ind1_index))]
            route_list = get_feasible_route(nodes)
            if len(route_list) != 0 and (len(route_list) <= Data_class.vehicle_num-1):
                break
        new_route = ind1[1:-1]
        for route in route_list:
            new_route += route[1:-1]
        population[index[0], :] = new_route
        population[index[1], :] = new_route
    return population

2.4变异算子

变异算子参考城市生鲜食品冷链物流配送中心选址及路径优化问题研究中的变异算子
在这里插入图片描述

def mutate(population):
    # 采用逆转变异
    Popsize = Data_class.Popsize
    Pm = Data_class.Pm
    for i in range(Popsize):
        r = random.random()
        # 变异概率决定该轮循环是否进行变异操作
        if r > Pm:
            continue
        chrom = population[i, :]
        while 1:
            index = random.choices(range(demand_node_num), k=2)
            ind = chrom[index[0]:index[1]]
            chrom[index[0]:index[1]] = ind[::-1]
            if get_feasible_route(chrom):
                break
        population[i, :] = chrom
    return population

3.结果展示

遗传算法的相关参数设置:种群规模100,交叉概率0.85,变异概率0.15,最大迭代次数300。
运行python3程序,运行环境为win64,pycharm2019.3.2,在某一次运行中得到的算例结果如下(手算检验该结果也是正确的):
最优解结构:[ 9 11 10 3 12 13 1 2 5 15 8 7 4 6 14]
最优车辆运行路线为:[[0, 9, 11, 10, 3, 0], [0, 12, 13, 1, 2, 0], [0, 5, 15, 8, 7, 0], [0, 4, 6, 14, 0]]
车辆的使用成本:1200
车辆的运输路线成本: 6538.0
时间窗的惩罚成本: 678.0
货损成本: 2370.305
总运输成本: 10786.305
在这里插入图片描述

4.小结

感觉选择操作、交叉操作和变异操作的方法还不是很好,三种算子的处理还需要改进。

参考文献:
1.matlab智能优化算法30个案例.pdf
(关注公众号,获得百度网盘的提取码就能看了,本人就是这么得到的^ * ^)
2.遗传算法实践(十) VRPTW问题求解https://www.jianshu.com/p/ca9a7cde6532

3.将python文件加入到python的环境变量中https://www.cnblogs.com/beginner-boy/p/9052483.html
4.全局变量的最佳实践https://zhuanlan.zhihu.com/p/43808665
5.python 获取当前目录,上级目录,上上级目录
https://blog.csdn.net/We_are_family678/article/details/82593944?utm_source=distribute.pc_relevant.none-task
6.python遗传算法工具箱:https://www.zhihu.com/question/60545629?sort=created
7.【算法】超详细的遗传算法(Genetic Algorithm)解析https://www.jianshu.com/p/ae5157c26af9
8.常用的选择策略https://www.cnblogs.com/legend1130/archive/2016/03/29/5333087.html

评论 55
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Logintern09

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值