学术资讯 » 论文写作

  • 首 页
  • 期刊选题
  • 期刊点评
  • 期刊大全
  • 学人博客
  • 编辑征稿
  • 投稿选刊
  • 万维群组
  • 学术会议
  • 万维读书
  • SCI/E期刊
  • SSCI期刊
  • AHCI期刊
  • Python | 聚焦MDVRPTW系列求解算法

    阅读: 2022/5/17 11:21:55

    摘要

    七大优化算法源码投递【蚁群算法、自适应大邻域算法、差分进化算法、粒子群算法、遗传算法、模拟退火算法、禁忌搜索算法】

    致力于打造交通领域优质代码分享平台

    祝大家五一快乐,外出遵守防疫政策,做好个人防护。

    今天为大家分享MDVRPTW系列求解算法源码。欢迎:点赞+收藏+关注。后续将推送更多优质内容,为避免错过一个亿,建议星标。

    前两期应用元启发式算法求解CVRP和MDCVRP时采用了简单的路径分割规则,其优点是简单易实现,但求解质量一般。若在此基础上进一步考虑时间窗约束,将进一步降低寻优效果。为了能够在时间窗约束下寻求更好的求解效果,今天在CVRP和MDCVRP代码基础上复现文献中的算法对Split函数进行改进,使其能够处理多(单)车场条件下带有时间窗约束的车辆路径规划问题。

    01

    注意事项

    · 求解MDVRPTW或VRPTW

    · 车辆类型单一

    · 车辆容量不小于需求节点最大需求

    · (多)车辆基地

    · 各车场车辆总数满足实际需求

    · 节点时间窗至少满足车辆路径只包含一个需求节点的情况

    · 车场车辆总数满足实际需求

    · 服务必须在要求时间窗内开始和结束

    02

    实现思路

    Christian Prins[2]给出的CVRP的Split方法过程如下:

    在此基础上Lin Chengs[3]给出了Split在VRPTW问题上的改进:

    我们将在以上算法流程上略加改进,使其具备处理MDVRPTW和VRPTW的能力。

    03

    数据结构

    继续以类的形式对算法参数、编码、解码、目标函数等进行封装。相比MDCVRP系列内容,有以下调整:

    · Node数据结构类中增加‘start_time’属性表示开始服务时间,‘end_time’属性表示结束服务时间,‘service_time’表示服务时长;

    · Sol数据结构中增加‘timetable_list’属性记录车辆到达每个节点的时刻,‘cost_of_distance’属性表示路径的距离成本,‘cost_of_time’表示路径的时间成本

    · Model数据结构类中增加‘time_matrix’属性记录网络弧旅行时间

    · splitRoutes函数参考经典方法实现

    基本数据结构定义如下:

    · Sol()类,表示一个可行解

    属性 描述

    obj 优化目标值

    node_id_list 需求节点id有序排列集合

    cost_of_distance 距离成本

    cost_of_time 时间成本

    route_list 车辆路径集合,对应MDVRPTW的解

    timetable_list 车辆节点访问时间集合,对应MDVRPTW的解

    · Node()类,表示一个网络节点

    属性 描述

    id 物理节点id,需唯一

    x_coord 物理节点x坐标

    y_coord 物理节点y坐标

    demand 物理节点需求

    depot_capacity

    车辆基地车队规模

    start_time 最早开始服务(被服务)时间

    end_time 最晚结束服务(被服务)时间

    service_time 需求节点服务时间

    蚁群算法(ACO)存储算法参数部分的数据结构定义如下:

    属性 描述

    best_sol 全局最优解,值类型为Sol()

    sol_list 蚁群集合,值类型为Sol()

    demand_dict 需求节点集合(字典),值类型为Node()

    depot_dict 车场节点集合(字典),值类型为Node()

    depot_id_list 车场节点id集合

    demand_id_list 需求节点id集合

    opt_type 优化目标类型,0:最小旅行距离,1:最小时间成本

    vehicle_cap 车辆容量

    vehicle_speed 车辆行驶速度,用于计算旅行时间

    distance_matrix 网络弧距离

    time_matrix 节点旅行时间矩阵

    popsize 蚁群规模

    alpha 信息启发式因子

    beta 期望启发式因子

    Q 信息素总量

    rho 信息素挥发系数

    tau 网络弧信息素

    tau0 路径初始信息素

    自适应大邻域搜索算法(ALNS)存储算法参数部分的数据结构定义如下(仅显示特有的数据结构定义部分):

    属性 描述

    rand_d_max

    随机破坏程度上限

    rand_d_min

    随机破坏程度下限

    worst_d_max

    最坏破坏程度上限

    worst_d_min

    最坏破坏程度下限

    regret_n

    次优位置个数

    r1

    算子奖励1

    r2

    算子奖励2

    r3

    算子奖励3

    rho

    算子权重衰减系数

    d_weight

    破坏算子权重

    d_select

    破坏算子被选中次数/每轮

    d_score

    破坏算子被奖励得分/每轮

    d_history_select

    破坏算子历史共计被选中次数

    d_history_score

    破坏算子历史共计被奖励得分

    r_weight

    修复算子权重

    r_select

    修复算子被选中次数/每轮

    r_score

    修复算子被奖励得分/每轮

    r_history_select

    修复算子历史共计被选中次数

    r_history_score

    修复算子历史共计被奖励得分

    差分进化算法(DE)存储算法参数部分的数据结构定义如下(仅显示特有的数据结构定义部分):

    属性 描述

    Cr

    交叉概率

    F

    缩放因子

    popsize

    种群规模

    离散粒子群算法(DPSO)存储算法参数部分的数据结构定义如下(仅显示特有的数据结构定义部分):

    属性 描述

    pl

    可行解历史最优位置

    pg

    全局最优解历史最优位置

    v

    可行解更新速度

    Vmax

    最大速度

    w

    惯性权重

    c1

    学习因子

    c2

    学习因子

    遗传算法(GA)存储算法参数部分的数据结构定义如下(仅显示特有的数据结构定义部分):

    属性 描述

    pc

    交叉概率

    pm

    突变概率

    n_select

    优良个体选择数量

    popsize

    种群规模

    模拟退火算法(SA)存储算法参数部分的数据结构定义均在前文出现过,不再赘述。

    禁忌搜索算法(TS)存储算法参数部分的数据结构定义如下(仅显示特有的数据结构定义部分):

    属性 描述

    tabu_list

    禁忌表

    TL

    算子禁忌长度

    04

    主程序

    蚁群算法(ACO)主程序如下:

    def run(demand_file,depot_file,Q,tau0,alpha,beta,rho,epochs,v_cap,opt_type,popsize):

    """

    :param demand_file: demand file path

    :param depot_file: depot file path

    :param Q:信息素总量

    :param tau0: 路径信息素初始值

    :param alpha:信息启发式因子

    :param beta:期望启发式因子

    :param rho:信息挥发因子

    :param epochs:迭代次数

    :param v_cap:车辆容量

    :param opt_type:优化类型:0:最小化车辆数,1:最小化行驶距离

    :param popsize:蚁群规模

    :return:

    """

    model=Model()

    model.vehicle_cap=v_cap

    model.opt_type=opt_type

    model.alpha=alpha

    model.beta=beta

    model.Q=Q

    model.tau0=tau0

    model.rho=rho

    model.popsize=popsize

    sol=Sol()

    sol.obj=float('inf')

    model.best_sol=sol

    history_best_obj = []

    readCSVFile(demand_file,depot_file,model)

    calDistanceTimeMatrix(model)

    for ep in range(epochs):

    movePosition(model)

    upateTau(model)

    history_best_obj.append(model.best_sol.obj)

    print("%s/%s, best obj: %s" % (ep,epochs, model.best_sol.obj))

    plotObj(history_best_obj)

    plotRoutes(model)

    outPut(model)

    if __name__=='__main__':

    demand_file = r'D:\code\py_projects\2021-05-24-algorithms-demos\datasets\MDVRPTW\demand.csv'

    depot_file = r'D:\code\py_projects\2021-05-24-algorithms-demos\datasets\MDVRPTW\depot.csv'

    run(demand_file,depot_file,Q=10,tau0=10,alpha=1,beta=5,rho=0.1,epochs=100,v_cap=80,opt_type=0,popsize=100)

    自适应大邻域算法(ALNS)主程序如下:

    def run(demand_file,depot_file,rand_d_max,rand_d_min,worst_d_min,worst_d_max,regret_n,r1,r2,r3,rho,phi,epochs,pu,v_cap,

    v_speed,opt_type):

    """

    :param demand_file: demand file path

    :param depot_file: depot file path

    :param rand_d_max: max degree of random destruction

    :param rand_d_min: min degree of random destruction

    :param worst_d_max: max degree of worst destruction

    :param worst_d_min: min degree of worst destruction

    :param regret_n: n next cheapest insertions

    :param r1: score if the new solution is the best one found so far.

    :param r2: score if the new solution improves the current solution.

    :param r3: score if the new solution does not improve the current solution, but is accepted.

    :param rho: reaction factor of action weight

    :param phi: the reduction factor of threshold

    :param epochs: Iterations

    :param pu: the frequency of weight adjustment

    :param v_cap: Vehicle capacity

    :param v_speed Vehicle free speed

    :param opt_type: Optimization type:0:Minimize the number of vehicles,1:Minimize travel distance

    :return:

    """

    model=Model()

    model.rand_d_max=rand_d_max

    model.rand_d_min=rand_d_min

    model.worst_d_min=worst_d_min

    model.worst_d_max=worst_d_max

    model.regret_n=regret_n

    model.r1=r1

    model.r2=r2

    model.r3=r3

    model.rho=rho

    model.vehicle_cap=v_cap

    model.opt_type=opt_type

    model.vehicle_speed=v_speed

    readCSVFile(demand_file,depot_file, model)

    calDistanceTimeMatrix(model)

    history_best_obj = []

    sol = Sol()

    sol.node_id_list = genInitialSol(model.demand_id_list)

    calObj(sol, model)

    model.best_sol = copy.deepcopy(sol)

    history_best_obj.append(sol.obj)

    for ep in range(epochs):

    T=sol.obj*0.2

    resetScore(model)

    for k in range(pu):

    destory_id,repair_id=selectDestoryRepair(model)

    model.d_select[destory_id]+=1

    model.r_select[repair_id]+=1

    reomve_list=doDestory(destory_id,model,sol)

    new_sol=doRepair(repair_id,reomve_list,model,sol)

    if new_sol.obj

    sol=copy.deepcopy(new_sol)

    if new_sol.obj

    model.best_sol=copy.deepcopy(new_sol)

    model.d_score[destory_id]+=model.r1

    model.r_score[repair_id]+=model.r1

    else:

    model.d_score[destory_id]+=model.r2

    model.r_score[repair_id]+=model.r2

    elif new_sol.obj-sol.obj

    sol=copy.deepcopy(new_sol)

    model.d_score[destory_id] += model.r3

    model.r_score[repair_id] += model.r3

    T=T*phi

    print("%s/%s:%s/%s, best obj: %s" % (ep,epochs,k,pu, model.best_sol.obj))

    history_best_obj.append(model.best_sol.obj)

    updateWeight(model)

    plotObj(history_best_obj)

    plotRoutes(model)

    outPut(model)

    print("random destory weight is {:.3f}\tselect is {}\tscore is {:.3f}".format(model.d_weight[0],

    model.d_history_select[0],

    model.d_history_score[0]))

    print("worse destory weight is {:.3f}\tselect is {}\tscore is {:.3f} ".format(model.d_weight[1],

    model.d_history_select[1],

    model.d_history_score[1]))

    print("random repair weight is {:.3f}\tselect is {}\tscore is {:.3f}".format(model.r_weight[0],

    model.r_history_select[0],

    model.r_history_score[0]))

    print("greedy repair weight is {:.3f}\tselect is {}\tscore is {:.3f}".format(model.r_weight[1],

    model.r_history_select[1],

    model.r_history_score[1]))

    print("regret repair weight is {:.3f}\tselect is {}\tscore is {:.3f}".format(model.r_weight[2],

    model.r_history_select[2],

    model.r_history_score[2]))

    if __name__=='__main__':

    demand_file = r'D:\code\py_projects\2021-05-24-algorithms-demos\datasets\MDVRPTW\demand.csv'

    depot_file = r'D:\code\py_projects\2021-05-24-algorithms-demos\datasets\MDVRPTW\depot.csv'

    run(demand_file=demand_file,depot_file=depot_file,rand_d_max=0.4,rand_d_min=0.1,

    worst_d_min=5,worst_d_max=20,regret_n=5,r1=30,r2=20,r3=10,rho=0.4,

    phi=0.9,epochs=5,pu=5,v_cap=80,v_speed=1,opt_type=0)

    差分进化算法(DE)主程序如下:

    def run(demand_file,depot_file,epochs,Cr,F,popsize,v_cap,opt_type):

    """

    :param demand_file: 需求节点文件路径

    :param depot_file: 车场节点文件路径

    :param epochs:迭代次数

    :param Cr:差分交叉概率

    :param F:缩放因子

    :param popsize:种群规模

    :param v_cap:车辆容量

    :param opt_type:优化类型:

    :return:

    """

    model=Model()

    model.vehicle_cap=v_cap

    model.Cr=Cr

    model.F=F

    model.popsize=popsize

    model.opt_type=opt_type

    readCSVFile(demand_file,depot_file,model)

    calDistanceTimeMatrix(model)

    best_sol = Sol()

    best_sol.obj = float('inf')

    model.best_sol = best_sol

    genInitialSol(model)

    history_best_obj = []

    for ep in range(epochs):

    for i in range(popsize):

    v1=random.randint(0,len(model.demand_id_list)-1)

    sol=model.sol_list[v1]

    mu_x=muSol(model,v1)

    u=crossSol(model,sol.node_id_list,mu_x)

    new_sol=Sol()

    new_sol.node_id_list=u

    calObj(new_sol,model)

    if new_sol.obj<=sol.obj:

    sol=copy.deepcopy(new_sol)

    if sol.obj

    model.best_sol=copy.deepcopy(sol)

    history_best_obj.append(model.best_sol.obj)

    print("%s/%s, best obj: %s" % (ep, epochs, model.best_sol.obj))

    plotObj(history_best_obj)

    plotRoutes(model)

    outPut(model)

    if __name__ == '__main__':

    demand_file=r'D:\code\py_projects\2021-05-24-algorithms-demos\datasets\MDVRPTW\demand.csv'

    depot_file=r'D:\code\py_projects\2021-05-24-algorithms-demos\datasets\MDVRPTW\depot.csv'

    run(demand_file,depot_file, epochs=100, Cr=0.6,F=0.5, popsize=100, v_cap=80, opt_type=0)

    粒子群算法(DPSO)主程序如下:

    def run(demand_file,depot_file,epochs,popsize,Vmax,v_cap,v_speed,opt_type,w,c1,c2):

    """

    :param demand_file: demand file path

    :param depot_file: depot file path

    :param epochs: 迭代次数

    :param popsize: 邻域规模

    :param v_cap: 车辆容量

    :param Vmax :最大速度

    :param opt_type: 优化类型:0:最小化车辆数,1:最小化行驶距离

    :param w: 惯性权重

    :param c1:学习因子

    :param c2:学习因子

    :return:

    """

    model=Model()

    model.vehicle_cap=v_cap

    model.Vmax=Vmax

    model.vehicle_speed=v_speed

    model.opt_type=opt_type

    model.w=w

    model.c1=c1

    model.c2=c2

    readCSVFile(demand_file,depot_file,model)

    calDistanceTimeMatrix(model)

    history_best_obj=[]

    genInitialSol(model,popsize)

    history_best_obj.append(model.best_sol.obj)

    for ep in range(epochs):

    updatePosition(model)

    history_best_obj.append(model.best_sol.obj)

    print("%s/%s: best obj: %s"%(ep,epochs,model.best_sol.obj))

    plotObj(history_best_obj)

    plotRoutes(model)

    outPut(model)

    if __name__ == '__main__':

    demand_file=r'D:\code\py_projects\2021-05-24-algorithms-demos\datasets\MDVRPTW\demand.csv'

    depot_file=r'D:\code\py_projects\2021-05-24-algorithms-demos\datasets\MDVRPTW\depot.csv'

    run(demand_file=demand_file,depot_file=depot_file,epochs=100,popsize=100,Vmax=2,

    v_cap=80,v_speed=1,opt_type=0,w=0.9,c1=1,c2=5)

    遗传算法主程序(GA)主程序如下:

    def run(demand_file,depot_file,epochs,pc,pm,popsize,n_select,v_cap,v_speed,opt_type):

    """

    :param demand_file: demand file path

    :param depot_file: depot file path

    :param epochs: Iterations

    :param pc: Crossover probability

    :param pm: Mutation probability

    :param popsize: Population size

    :param n_select: Number of excellent individuals selected

    :param v_cap: Vehicle capacity

    :param v_speed: Vehicle free speed

    :param opt_type: Optimization type:0:Minimize the cost of travel distance;1:Minimize the cost of travel time

    :return:

    """

    model=Model()

    model.vehicle_cap=v_cap

    model.pc=pc

    model.pm=pm

    model.popsize=popsize

    model.n_select=n_select

    model.opt_type=opt_type

    readCSVFile(demand_file,depot_file,model)

    calDistanceTimeMatrix(model)

    generateInitialSol(model)

    history_best_obj = []

    best_sol=Sol()

    best_sol.obj=float('inf')

    model.best_sol=best_sol

    for ep in range(epochs):

    calFitness(model)

    selectSol(model)

    crossSol(model)

    muSol(model)

    history_best_obj.append(model.best_sol.obj)

    print("%s/%s, best obj: %s" % (ep,epochs,model.best_sol.obj))

    plotObj(history_best_obj)

    plotRoutes(model)

    outPut(model)

    if __name__=='__main__':

    demand_file = r'D:\code\py_projects\2021-05-24-algorithms-demos\datasets\MDVRPTW\demand.csv'

    depot_file = r'D:\code\py_projects\2021-05-24-algorithms-demos\datasets\MDVRPTW\depot.csv'

    run(demand_file=demand_file,depot_file=depot_file,epochs=100,pc=0.8,pm=0.1,popsize=100,

    n_select=80,v_cap=80,v_speed=1,opt_type=0)

    模拟退火算法(SA)主程序如下:

    def run(demand_file,depot_file,T0,Tf,deltaT,v_cap,opt_type):

    """

    :param demand_file: 需求节点数据文件

    :param depot_file: 车场节点数据文件

    :param T0: 初始温度

    :param Tf: 终止温度

    :param deltaT: 温度下降步长或下降比例

    :param v_cap: 车辆容量

    :param opt_type: 优化类型:0:最小化车辆数,1:最小化行驶距离

    :return:

    """

    model=Model()

    model.vehicle_cap=v_cap

    model.opt_type=opt_type

    readCSVFile(demand_file,depot_file,model)

    calDistanceTimeMatrix(model)

    action_list=createActions(len(model.demand_id_list))

    history_best_obj=[]

    sol=Sol()

    sol.node_id_list=genInitialSol(model.demand_id_list)

    calObj(sol,model)

    model.best_sol=copy.deepcopy(sol)

    history_best_obj.append(sol.obj)

    Tk=T0

    nTk=len(action_list)

    while Tk>=Tf:

    for i in range(nTk):

    new_sol = Sol()

    new_sol.node_id_list = doAction(sol.node_id_list, action_list[i])

    calObj(new_sol, model)

    detla_f=new_sol.obj-sol.obj

    if detla_f<0 or math.exp(-detla_f/Tk)>random.random():

    sol=copy.deepcopy(new_sol)

    if sol.obj

    model.best_sol=copy.deepcopy(sol)

    if deltaT<1:

    Tk=Tk*deltaT

    else:

    Tk = Tk - deltaT

    history_best_obj.append(model.best_sol.obj)

    print("当前温度:%s,local obj:%s best obj: %s" % (Tk,sol.obj,model.best_sol.obj))

    plotObj(history_best_obj)

    plotRoutes(model)

    outPut(model)

    if __name__=='__main__':

    demand_file = r'D:\code\py_projects\2021-05-24-algorithms-demos\datasets\MDVRPTW\demand.csv'

    depot_file = r'D:\code\py_projects\2021-05-24-algorithms-demos\datasets\MDVRPTW\depot.csv'

    run(demand_file=demand_file,depot_file=depot_file,T0=6000,Tf=0.001,deltaT=0.9,v_cap=80,opt_type=0)

    禁忌搜索算法(TS)主程序如下:

    def run(demand_file,depot_file,epochs,v_cap,opt_type):

    """

    :param demand_file: demand file path

    :param depot_file: depot file path

    :param epochs: Iterations

    :param v_cap: Vehicle capacity

    :param opt_type: Optimization type:0:Minimize the number of vehicles,1:Minimize travel distance

    :return: 无

    """

    model=Model()

    model.vehicle_cap=v_cap

    model.opt_type=opt_type

    readCSVFile(demand_file,depot_file,model)

    calDistanceTimeMatrix(model)

    action_list=createActions(len(model.demand_id_list))

    model.tabu_list=np.zeros(len(action_list))

    history_best_obj=[]

    sol=Sol()

    sol.node_id_list=generateInitialSol(model.demand_id_list)

    calObj(sol,model)

    model.best_sol=copy.deepcopy(sol)

    history_best_obj.append(sol.obj)

    for ep in range(epochs):

    local_new_sol=Sol()

    local_new_sol.obj=float('inf')

    for i in range(len(action_list)):

    if model.tabu_list[i]==0:

    new_sol=Sol()

    new_sol.node_id_list=doAction(sol.node_id_list,action_list[i])

    calObj(new_sol,model)

    new_sol.action_id=i

    if new_sol.obj

    local_new_sol=copy.deepcopy(new_sol)

    sol=local_new_sol

    for i in range(len(action_list)):

    if i==sol.action_id:

    model.tabu_list[sol.action_id]=model.TL

    else:

    model.tabu_list[i]=max(model.tabu_list[i]-1,0)

    if sol.obj

    model.best_sol=copy.deepcopy(sol)

    history_best_obj.append(model.best_sol.obj)

    print("%s/%s: best obj: %s"%(ep,epochs,model.best_sol.obj))

    plotObj(history_best_obj)

    plotRoutes(model)

    outPut(model)

    if __name__=='__main__':

    demand_file = r'D:\code\py_projects\2021-05-24-algorithms-demos\datasets\MDVRPTW\demand.csv'

    depot_file = r'D:\code\py_projects\2021-05-24-algorithms-demos\datasets\MDVRPTW\depot.csv'

    run(demand_file=demand_file,depot_file=depot_file,epochs=100,opt_type=0,v_cap=80)

    05

    结果对比

    这里采用solomon开源数据对算法进行测试,数据文件结构如下图所示,共100个需求点,3个车场,以.csv文件储存网络数据。

    demand.csv文件内容如下图,其中第一行为标题栏,节点id从0开始递增编号。

    depot.csv文件内容如下图,其中第一行为标题栏,节点id建议采用图中命名方式,需要注意的是’ capacity’字段指的是车场配备的车辆数量。

    七大算法算法收敛图与优化路线图分别如下:

    06

    源码获取

    本文的算法程序和数据集可通过以下百度网盘链接获取:

    链接:https://pan.baidu.com/s/1DyK77M-qeeDIZn3fUvD1Fw(或点击【阅读原文】)

    提取码:xafr

    08

    参考

    [1].汪定伟. 智能优化方法[M]. 高等教育出版社, 2007.

    [2]Prins C. A simple and effective evolutionary algorithm for the vehicle routing problem[J]. Computers & Operations Research, 2004, 31(12): 1985-2002.

    [3]. Cheng L . A genetic algorithmfor the vehicle routing problem with time windows[J]. university of northcarolina wilmington, 2009.

    转自:交通科研Lab 2022-05-12 18:00

    文章来源于Python助力交通 ,作者Python助力交通


    浏览(1030)
    点赞(0)
    收藏(0)
  • 上一篇:这十年,我国科技进步最大、科技实力提升最快

    下一篇:3篇SCI定为A类博士,引进费85-140万,享副教授待遇,硕士可报,提供安家费及工作补贴

  • 首页

  • 文章

  • 期刊

  • 帮助

  • 我的

版权所有 Copyright@2023    备案号:豫ICP备2021036211号