VRP规划的方案流程
VRP(Vehicle Routing Problem):
车辆路径问题,可以看成旅行商问题的推广
有N辆车,都从原点出发,每辆车访问一些点后回到原点,要求所有的点都要被访问到,求最短的车辆行驶距离或最少需要的车辆数
Thinking:有哪些应用领域,适用于VRP问题
快递公司,给司机分配送货线路
拼车软件,为司机分配接送乘客的路线
常见的限制要求:
车辆具有可携带的最大重量或数量
司机需要在指定时间窗口内访问某位置
使用RoutingModel进行路径规划管理
1)设置城市个数,车辆数,起点下标
2)设置距离回调函数 distance_callback
3)设置初始可行解算法
PATH_CHEAPEST_ARC,从start节点开始,找到CHEAPEST的路径
4)在初始可行解的基础上进行优化(使用local search)
search_parameters.local_search_metaheuristic = (
routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)
#搜索时间限制
search_parameters.time_limit.seconds = 120
车辆路径规划 步骤:
Step1, 创建参数字典data
Step2,创建路线索引管理器
Step3,创建路线模型
Step4,注册各种限制和约束条件
Step5,设置解决方案策略
Step6,计算解决方案
Step7,输出结果
Project B:指定城市的旅行商 TSP
Step1,数据预处理
1)所有城市的位置(经度、维度)
2)城市之间的距离矩阵
Step2,根据指定的城市,计算TSP,得到路径route
Step3,可视化交互
1)选择指定的城市
2)画出车辆行驶路径(基于百度地图API)
数据源:
1)cities.xlsx,需要指定地点的经度、纬度
2)distance.xlsx,通过compute_distance计算得到
调用高德API计算距离
{"status":"1","info":"OK","infocode":"10000","count":"1","results":[{"origin_id":"1","dest_id":"1","distance":"135381","duration":"6780"}]}
Step1,数据预处理
1)所有城市的位置(经度、维度)
2)城市之间的距离矩阵
针对常用的功能,可以封装为自己的工具包
from cylearn import common_tools
# 读取,写入指定的pickle
result = common_tools.load_pickle('result.pkl')
common_tools.save_pickle(result, 'result.pkl')
# 计算两点之间的距离
dist = common_tools.compute_distance(longitude1, latitude1, longitude2, latitude2)
Step2,根据指定的城市,计算TSP,得到路径route
创建tsp类
1)def __init__(self, city_names=None):
类初始化 __init__,定义常用的变量
2)def create_data_model(self):
初始化data,得到data字典,记录distance_matrix,num_vehicles,depot等数据
3)def get_solution(self, routing, solution):
返回路径(这里为index list,比如[0, 1, 2]) 以及 总距离
4)def work(self):
# 定义路由,比如10个节点,1辆车
manager = RoutingIndexManager(10, 1, starts_ends)
# 创建 Routing Model.
routing = pywrapcp.RoutingModel(manager)
# 计算两点之间的距离
def distance_callback(from_index, to_index):
# 将路由变量Index转化为 距离矩阵ditance_matrix的节点index
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)
# 定义每条边arc的代价
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)
# 设置启发式搜索
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.first_solution_strategy = (
routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)
# 求解路径规划
solution = routing.SolveWithParameters(search_parameters)
TSP类编写完后,可以进行测试
测试1:使用全量的城市,不对city_names进行筛选
测试2:city_names = ['北京', '天津', '南京']
Step3,可视化交互
1)选择指定的城市
// 表单提交
// checkbox使用
2)画出车辆行驶路径(基于百度地图API)
基于 map_line1.html 进行改写
多辆车的路径规划 VRP
条件:经过中国33个城市,一共4辆车,每辆车最大行驶10000公里
目标:1) 每辆车的行驶里程数更接近 2)总里程数更少
数据预处理:
1)设置 num_vehicles,代表一共多少量车
2)设置 depot,代表所有车的起始出发点一样,都是从节点depot开始
3)添加距离约束,即每辆车的最大行驶距离
需要注意:
1)在VRP问题中,路径上给点赋的index和点实际的index不一样,需要使用IndexToNode方法进行转换才能得到实际的index
# 添加距离约束
dimension_name = 'Distance'
routing.AddDimension(
transit_callback_index,
0, # no slack
10000, # 车辆最大行驶距离
True, # start cumul to zero
dimension_name)
distance_dimension = routing.GetDimensionOrDie(dimension_name)
# 尽量减少车辆之间的最大距离
distance_dimension.SetGlobalSpanCostCoefficient(100)
说明:车辆之间最大距离,最小化
global_span_cost = coefficient * (Max(dimension end value) - Min(dimension start value))
带有容量约束的VRP
现在有4辆车,均从原点出发,他们需要收16个客户点的货,如何安排使得总距离最短
1)从起始仓库出发,回到起始仓库
2)每辆车都有容量限制,每个客户点也有货物容量
distance_matrix,两点之间的距离
demands,每个客户点需要配送的货物量
num_vehicles,一共多少量车
vehicle_capacities,每辆车的容量
depot,起始原点的下标
带有时间窗口约束的VRP
现在有4辆车,均从原点出发,他们需要去16个配送点送货,如何安排使得总时间最短
1)起始出发仓库,最多只能同时装载/卸载 两辆车
2)每个配送点需要在指定时间窗口内完成
比如 点8 [5, 10],需要在第5-10分钟内完成配送
time_matrix,两点之间的行驶时间
time_windows,每个配送点的时间窗口
num_vehicles,一共多少量车
vehicle_load_time,车的装载所需时间
vehicle_unload_time,车的卸载所需时间
depot_capacity,起始仓库容量,同时装载/卸载的车数
depot,起始原点的下标
时间窗口约束限制 (根据距离换算出的时间矩阵)
routing.RegisterTransitCallback(time_callback)
routing.SetArcCostEvaluatorOfAllVehicles(time_callback_index)
添加时间变量 每天允许的时间
time_dimension = routing.GetDimensionOrDie(time)
添加时间变量的累积限制 时间窗限制
time_dimension.CumulVar(index).SetRange(time_window[0], time_window[1])
routing.AddVariableMinimizedByFinalizer(
time_dimension.CumulVar(routing.Start(i)))
routing.AddVariableMinimizedByFinalizer(
time_dimension.CumulVar(routing.End(i)))
Project F:带有指定拿起放下约束的VRP
现在有4辆车,均从原点出发,他们需要完成指定的任务,即帮指定的商家,送给指定的客户
1)一共8项任务,每项任务都有指定的(商家、客户)比如[1, 6],即为 商家1给客户6进行配送
2)所有车辆的总距离最小
distance_matrix,两点之间的行驶距离
num_vehicles,一共多少量车
pickups_deliveries,需要配送的商家、客户
depot,起始原点的下标
添加车载容量限制
demand_callback_index = routing.RegisterUnaryTransitCallback(
demand_callback)
routing.AddDimensionWithVehicleCapacity(
demand_callback_index,
0, # null capacity slack
data['vehicle_capacities'], # 车辆最大容量
True, # start cumul to zero
'Capacity')
VRP问题的求解
NP Hard问题,即使只有几百个客户节点,也很难在有限时间内找到最优解
研究工作分为两个流派
1)通过运筹学(Operations)
将VRP定义为数学优化问题,通过启发式算法达求近似最优解
2)通过深度学习
比如GCN,计算节点特征,边特征
OR-Tools工具:
• Google的运筹学工具,启发式求解器
• 在可接受的时间内可以求解较大规模的VRP问题
• 支持的应用场景:
1)VRP(一辆车或多辆车)
2)带有容量约束的VRP
3)带有时间窗口约束的VRP
4)指定拿起放下地点的VRP(pickups and deliveries)