VRPB(Vehicle Routing Problem Backhauls)说明+pythoncode

Vehicle Routing Problem Backhauls

  • 模型说明:Vehicle Routing Problem(VRP)+Backhauls

  1. VRP:即多个车辆从depot点出发,向客户customer配送货物,每个customer只能被一辆车配送一次,最后车辆回到depot点

  1. Backhauls:回程过程中取货的问题

  1. VRPB:送货(linehaul-delivery-L)后取货(backhauls-pickup-B),现实生活中:快递小哥配送件的同时+取件,且快递小哥不能全程只单纯取件不配件; 配件主要,取件附属品

  • 数学模型:

  1. 参数说明:

  1. A:边; V:所有的customer+depot(由0表示);

  1. : 进入i点的边(ex,.一个点,有进入i的边,和从i出去的边)

  1. : 和从i出去的边

  1. :代表边,是A的子集,: 代表S中最少的车的个数(如果求他是BPP问题)

  • (1)目标函数,总路程最小

  • (2,3)对于每一个点,只有一辆车经过一次

  • (4,5)对于depot(0),出去的车和进来的车都一个为K

  • (6,7)为capacity constraint cut, 比如(6):在S集合里的点,与剩余的除了depot的点相连的边的个数必须大于这个集合需要的最小的车数.(画一个圈把S里的点全部包含,从S出去/进来的点的边-即和S这个圈圈相交的边的个数和除以2)

  1. 问题分解

  • 通过分析问题,可以将模型分解为三部分

  • 第一部分:linehaul部分,即delivery的部分

  • 第二部分:backhaul部分,即pickup部分

  • 第三部分:connection部分,即delivery-pickup的连接弧的部分

  • 注意:depot进入linehaul的边,即总的车辆数>=backhaul 进入depot的边,因为车辆可以直接从linehaul回去,不进行pickup

  • 分解后的模型:

  • 点集合V被分为:L(linehaul点),B(backhaul点), L0(linehaul点+depot0),

B0(backhaul点+depot0)

  • 边集合A被分为:A_L(linehaul边,从L0到L),

A_B(从B到B0), A_C(L到B0)

1.linehaul

2.backhaul

3.connection

  • python code

  1. 小算列数据解释:
  • 车:capacity:2,K=2(车数量)

  • Linehaul(delivery点):L=[1,2,3] , L0=[0,1,2,3], d(demand)={},A_L: 从L0到L的边

  • backhaul(pickup点):B=[4,5],B0=[0,4,5],d(demand)={},A_B:从B到B0的边

  • connection:A_C:从L到B0的边

  1. 代码块

import numpy as np
import time
from docplex.mp.model import Model
##############################################################################
'''
This dataset corresponds to our small-scale dataset with 6 nodes including depot
and 5 customers/nodes in which customer 3 requires both delivery and pickup, i.e.,
simultaneous demand. 

For instance: one node can be delivery and pickup

We use the CPLEX optimization solver, the academic version, to solve this problem.
'''
##############################################################################
# function that solves VRPB
def CVRPB():

    mdl = Model('CVRPB')

    # linhaul decision Variables
    x = mdl.binary_var_dict (A_L,name='x')
    u = mdl.continuous_var_dict (L, name = 'u')
    
    #bakchaul decision variables
    y = mdl.binary_var_dict (A_B,name='y')
    w = mdl.continuous_var_dict (B,name = 'w')
    
    #connection decision variables
    z = mdl.binary_var_dict (A_C,name='z')
    #####################################
    ##### linhaul constraints
    #truck constraint
    mdl.add_constraint(mdl.sum(x[0,j]for j in L)==k )
    #degree constraints
    mdl.add_constraints(mdl.sum(x[i,j]for i in L_0 if i!=j)==1 for j in L )     
    #truck capacity 
    mdl.add_constraints(u[i]-u[j]+Q*x[i,j]<= Q-d_L[j] for i,j in A_L if i!=0 and j!=0)
        
    ##### bakchaul constraints
    #truck constraints
    mdl.add_constraint(mdl.sum(y[i,0]for i in B)+mdl.sum(z[i,0] for i in L)==k )
    #mdl.add_constraint(mdl.sum(y[i,0]for i in B)<=k )
    #degree constraints
    mdl.add_constraints(mdl.sum(y[i,j]for j in B_0 if j!=i)==1 for i in B)    
    #truck capacity
    mdl.add_constraints(w[i]-w[j]+Q*y[i,j]<=Q-d_B[j] for i,j in A_B if i!=0 and j!=0)
           
    ####### connection constraints
    #truck constraints
    mdl.add_constraint(mdl.sum(z[i,j]for i,j in A_C )==k)
    #degree constraints
    mdl.add_constraints(mdl.sum(x[i,j] for j in L if j!=i )+ mdl.sum(z[i,j] for j in B_0 )==1 for i in L)
    mdl.add_constraints(mdl.sum(y[i,j] for i in B if i!=j )+ mdl.sum(z[i,j] for i in L )==1 for j in B)
    ###################################
    ####objective functions
    obj_Linhaul = mdl.sum(c[i,j]*x[i,j]for i,j in A_L)
    mdl.add_kpi(obj_Linhaul, 'Linehaul Cost')
    
    obj_Backhaul = mdl.sum(c[i,j]*y[i,j]for i,j in A_B)
    mdl.add_kpi(obj_Backhaul, 'Backhaul Cost')
    
    obj_Connection = mdl.sum(c[i,j]*z[i,j]for i,j in A_C)
    mdl.add_kpi(obj_Connection, 'Connection Cost')
    
    objective = obj_Linhaul+obj_Backhaul+obj_Connection
    mdl.add_kpi(objective, 'Total Cost')
    #######################################
    #solving model
    mdl.minimize(objective)
    #mdl.parameters.timelimit=5 
    solution =mdl.solve(log_output=False) #true if you need to see the steps of slover
    #mdl.report_kpis()
    if not solution:
        print('fail in solving, there is no feasible solution')
    #mdl.export_as_lp()
    ########################################
    #Collect optimal solution
    x_opt=[a for a in A_L if x[a].solution_value> 0.9]
    y_opt=[a for a in A_B if y[a].solution_value> 0.9]
    z_opt=[a for a in A_C if z[a].solution_value> 0.9]
    obj_opt=round(solution.objective_value,2)
    
    return obj_opt, x_opt, y_opt, z_opt
##############################################################################
#### step 1: preparing data
# location of nodes
loc_x = {0:0, 1:0, 2:2, 3:2, 4:0.5, 5:1.5}
loc_y = {0:0, 1:2, 2:2, 3:0, 4:1, 5:1}

# vehicles capacity and number of available vehicles at the depot
Q = 2
k = 2

# all nodes, where 0 states the depot. all links and symetric distance matrix
V = [0, 1, 2, 3, 4, 5]
A = [(i,j) for i in V for j in V]
c = {(i,j): round(np.sqrt((loc_x[j]-loc_x[i])**2 + (loc_y[j]-loc_y[i])**2),2) for i,j in A}

# all nodes and links related to linehaul customers
L = [1, 2, 3]
L_0 = [0] +L
d_L = {1:1, 2:1, 3:1}
A_L = [(i,j) for i in L_0 for j in L if i!=j]

# all nodes and links related to backhaul customers
B = [1,3, 4, 5]
B_0 = B + [0]
d_B = {1:1 ,3:1, 4:1, 5:1}
A_B = [(i,j) for i in B for j in B_0 if i!=j]

# all links related to connecting linehaul routes to backhaul routes or to the depot
A_C= [(i,j) for i in L for j in B_0]

#### step 2:  solve the problem
start = time.clock()
obj_opt, x_opt, y_opt, z_opt = CVRPB()
stop = time.clock()
CPU_running_time = round(stop - start,2)

#### step 3:  print the solution
print ('The solution for VRPB with simultaneous demand for small-scale dataset is:',
       '\nObjective value = ', obj_opt, '\nCPU running time in second = ', CPU_running_time)

print('\n the route sequence is', '\nlinehau = ', x_opt, '\nconnection = ', z_opt, '\nbaclhaul = ', y_opt )

https://github.com/IrandokhtPVZ/Vehicle-Routing-Problem-with-Backhaul
引用的代码
An Exact Algorithm for the Vehicle Routing Problem with Backhauls Author(s): PAOLO TOTH and DANIELE VIGO

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Here is a basic implementation of CVRP in Python using the Google OR-Tools library: ```python from ortools.constraint_solver import routing_enums_pb2 from ortools.constraint_solver import pywrapcp def create_data_model(): """Stores the data for the problem.""" data = {} data['distance_matrix'] = [ [0, 548, 776, 696, 582, 274, 502, 194, 308, 194, 536, 502], [548, 0, 684, 308, 194, 502, 730, 354, 696, 742, 1084, 594], [776, 684, 0, 992, 878, 502, 274, 810, 468, 742, 400, 1278], [696, 308, 992, 0, 114, 650, 878, 502, 844, 890, 1232, 514], [582, 194, 878, 114, 0, 536, 764, 388, 730, 776, 1118, 400], [274, 502, 502, 650, 536, 0, 228, 308, 194, 240, 582, 810], [502, 730, 274, 878, 764, 228, 0, 536, 194, 468, 354, 1016], [194, 354, 810, 502, 388, 308, 536, 0, 342, 388, 730, 468], [308, 696, 468, 844, 730, 194, 194, 342, 0, 274, 388, 810], [194, 742, 742, 890, 776, 240, 468, 388, 274, 0, 342, 650], [536, 1084, 400, 1232, 1118, 582, 354, 730, 388, 342, 0, 878], [502, 594, 1278, 514, 400, 810, 1016, 468, 810, 650, 878, 0] ] data['num_vehicles'] = 3 data['vehicle_capacities'] = [100, 100, 100] data['depot'] = 0 return data def print_solution(data, manager, routing, solution): """Prints solution on console.""" total_distance = 0 total_load = 0 for vehicle_id in range(data['num_vehicles']): index = routing.Start(vehicle_id) plan_output = 'Route for vehicle {}:\n'.format(vehicle_id) route_distance = 0 route_load = 0 while not routing.IsEnd(index): node_index = manager.IndexToNode(index) route_load += data['demands'][node_index] plan_output += ' {} Load({}) -> '.format(node_index, route_load) previous_index = index index = solution.Value(routing.NextVar(index)) route_distance += routing.GetArcCostForVehicle( previous_index, index, vehicle_id) plan_output += ' {} Load({})\n'.format(manager.IndexToNode(index), route_load) plan_output += 'Distance of the route: {}m\n'.format(route_distance) plan_output += 'Load of the route: {}\n'.format(route_load) print(plan_output) total_distance += route_distance total_load += route_load print('Total distance of all routes: {}m'.format(total_distance)) print('Total load of all routes: {}'.format(total_load)) def main(): """Entry point of the program.""" data = create_data_model() manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']), data['num_vehicles'], data['depot']) routing = pywrapcp.RoutingModel(manager) def distance_callback(from_index, to_index): """Returns the distance between the two nodes.""" from_node = manager.IndexToNode(from_index) to_node = manager.IndexToNode(to_index) return data['distance_matrix'][from_node][to_node] transit_callback_index = routing.RegisterTransitCallback(distance_callback) routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index) dimension_name = 'Capacity' routing.AddDimension( transit_callback_index, 0, # no slack 100, # vehicle maximum capacities True, # start cumul to zero dimension_name) capacity_dimension = routing.GetDimensionOrDie(dimension_name) for i, demand in enumerate(data['demands']): index = manager.NodeToIndex(i) capacity_dimension.SetDemand(index, demand) for vehicle_id in range(data['num_vehicles']): index = routing.Start(vehicle_id) capacity_dimension.CumulVar(index).SetRange(data['vehicle_capacities'][vehicle_id], data['vehicle_capacities'][vehicle_id]) search_parameters = pywrapcp.DefaultRoutingSearchParameters() search_parameters.first_solution_strategy = ( routing_enums_pb2.FirstSolutionStrategy.PARALLEL_CHEAPEST_INSERTION) solution = routing.SolveWithParameters(search_parameters) if solution: print_solution(data, manager, routing, solution) if __name__ == '__main__': main() ``` Note that this is just a basic implementation and can be modified to suit specific requirements and constraints of individual problem instances.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值