车辆路径数据构建和带路径点矩阵的结果#
import json
累积问题数据#
json_data = {}
设置路径点图
需要提供偏移量、边和权重;权重不能为负值。
考虑到两种类型的车辆,厢式货车和卡车,厢式货车在较少的路径中会更快且成本更低,而卡车则会表现出旅行成本权重的变化。
类似地,也可以设置 travel_time_graph_data。
# Van
graph_data_1 = {
"offsets": [0, 3, 5, 9, 11, 13, 15, 17, 18, 19, 20, 21],
"edges": [1, 2, 9, 0, 7, 0, 3, 4, 10, 2, 4, 2, 5, 6, 9, 5, 8, 1, 6, 0, 5],
"weights": [1, 1, 2, 1, 2, 1, 1, 1, 3, 2, 3, 2, 1, 2, 1, 3, 4, 2, 3, 1, 1]
}
# Truck
graph_data_2 = graph_data_1.copy()
graph_data_2["weights"] = [2, 2, 3, 2, 3, 2, 2, 2, 4, 4, 4, 3, 2, 3, 2, 4, 5, 3, 4, 2, 1]
json_data["cost_waypoint_graph_data"] = {
'waypoint_graph': {
1: graph_data_1, # Van
2: graph_data_2 # Truck
}
}
# For simplicity, we are using the same graph data for travel time here.
# In a real use case this would likely be different
json_data["travel_time_waypoint_graph_data"] = {
'waypoint_graph': {
1: graph_data_1, # Van
2: graph_data_2 # Truck
}
}
设置车队数据
提供车辆起点和终点位置以及车辆特征和容量。
fleet_data = {
"vehicle_locations": [[0, 0], [1, 1], [0, 1], [1, 0], [0, 0]],
"vehicle_ids": ["Van-A", "Truck-A", "Van-B", "Truck-B", "Van-C"],
"vehicle_types": [1, 2, 1, 2, 1],
"capacities": [[10, 12, 15, 8, 10]],
"vehicle_time_windows": [
[0, 80],
[1, 40],
[3, 30],
[5, 80],
[20, 100]
],
# Vehicle can take breaks in this time window as per berak duration provided
"vehicle_break_time_windows":[
[
[20, 25],
[20, 25],
[20, 25],
[20, 25],
[20, 25]
]
],
"vehicle_break_durations": [[1, 1, 1, 1, 1]],
# Vehicle Id 0 can only serve Order 0 and 4
"vehicle_order_match": [
{
"vehicle_id": 0,
"order_ids": [0, 4]
}
], # 0th vehicle can only serve 0th and 4th order only
# Don't count trip from depot to first task location
"skip_first_trips": [False, True, True, False, False],
# Don't count trip from last task location to depot
"drop_return_trips": [False, True, True, False, False],
# Maximum cost a vehicle can incur while delivering
"vehicle_max_costs": [100, 100, 100, 100, 100],
# Maximum time a vehicle can be working
"vehicle_max_times": [120, 120, 120, 120, 120],
# Minimum 2 vehicles are required to be in solution
"min_vehicles": 2,
}
json_data["fleet_data"] = fleet_data
设置任务数据
提供有关任务位置、需求和时间窗口的详细信息;还有其他选项。
task_data = {
"task_locations": [1, 3, 4, 6, 8],
"demand": [[3, 4, 4, 3, 2]],
"task_time_windows": [
[3, 20],
[5, 30],
[1, 20],
[4, 40],
[0, 30],
],
"service_times": [3, 1, 8, 4, 0],
# Order Id 0 and 4 can be served only by vehicle with id 0
"order_vehicle_match": [
{
"order_id": 0,
"vehicle_ids": [0]
},
{
"order_id": 4,
"vehicle_ids": [0]
}
]
}
json_data["task_data"] = task_data
设置求解器配置
较大的问题可能需要更多时间。
solver_config = {
"time_limit": 1
}
json_data["solver_config"] = solver_config
解决问题#
对于托管服务,可以触发 cuOpt 端点,如 托管服务的瘦客户端示例 中所示。
对于自托管,可以触发 cuOpt 端点,如 自托管的瘦客户端示例 中所示。
使用此数据并调用 cuOpt 端点,这将返回路线。
如果响应状态为 0,
则 cuOpt 找到了一个可行解,在字典 “solver_response” 下。
如果状态为 1,
则表示它通过超出约束找到了不可行解。警告将列出哪些约束导致了不可行解,可以进一步分析。任何其他表明 cuOpt 失败的状态可能是由于无效数据或某些未处理的问题。这将位于字典 “solver_infeasible_response” 下。
以下示例使用本地托管服务器,
from cuopt_sh_client import CuOptServiceSelfHostClient
import json
# If cuOpt is not running on localhost:5000, edit ip and port parameters
cuopt_service_client = CuOptServiceSelfHostClient(
ip="localhost",
port=5000
)
optimized_routes = cuopt_service_client.get_optimized_routes(json_data)
print(json.dumps(optimized_routes, indent=4))
{
"response": {
"solver_response": {
"status": 0,
"num_vehicles": 2,
"solution_cost": 25.0,
"objective_values": {
"cost": 25.0
},
"vehicle_data": {
"Van-A": {
"task_id": ["Depot", "0", "Break", "4", "Depot"],
"arrival_stamp": [6.0, 7.0, 20.0, 21.0, 29.0],
"route": [0, 1, 0, 2, 4, 5, 6, 8, 8, 6, 5, 9, 0],
"type": ["Depot", "Delivery", "w", "w", "w", "w", "w", "Break", "Delivery", "w", "w", "w", "Depot"]
},
"Van-B": {
"task_id": ["1", "2", "Break", "3"],
"arrival_stamp": [8.0, 12.0, 20.0, 24.0],
"route": [3, 4, 4, 5, 6],
"type": ["Delivery", "Delivery", "Break", "w", "Delivery"]
}
},
"dropped_tasks": {
"task_id": [],
"task_index": []
},
"msg": ""
},
"perf_times": null
},
"reqId": "483d43b5-2730-413b-898d-a803da251530"
}
警告 将作为列表列在响应中,例如弃用或任何导致不可行结果的约束。