车辆路径数据构建和结果(使用成本/时间矩阵)#
import json
累积问题数据#
json_data = {}
设置成本/行程时间矩阵
我们需要为成本/时间矩阵提供具有正浮点值的方阵。
成本矩阵表示从一个地点到另一个地点的出行成本。此成本可以在结果中累积,以找到最佳解决方案。默认情况下,此成本会被累积,可以通过将目标值设置为 0 来禁用它。
行程时间矩阵用于评估车辆和任务的时间窗口约束。因此,如果使用任何类型的时间相关约束,则时间矩阵是必需的。
当不同类型的车辆成本和时间不同时(例如,汽车和自行车),可以为不同类型的车辆提供多个成本和行程时间矩阵。
# Considering cost is half of travel time
# Car
car_cost_matrix = [
[0, 5, 4, 3, 5],
[5, 0, 6, 4, 3],
[4, 8, 0, 4, 2],
[1, 4, 3, 0, 4],
[3, 3, 5, 6, 0],
]
car_time_matrix = [
[ 0, 10, 8, 6, 10],
[10, 0, 12, 8, 6],
[ 8, 16, 0, 8, 4],
[ 2, 8, 6, 0, 8],
[ 6, 6, 10, 12, 0],
]
# 1 represents car type and 2 represents bike type
# Add cost matrix
json_data["cost_matrix_data"] = {
"data" : {
1:car_cost_matrix
}
}
# Add time matrix
json_data["travel_time_matrix_data"] = {
"data" : {
1:car_time_matrix
}
}
设置车队数据
提供车辆的起始和结束位置,以及车辆的功能和容量。
fleet_data = {
"vehicle_locations": [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0]],
"vehicle_ids": ["Car-A", "Car-B", "Car-C", "Car-D", "Car-E"],
"vehicle_types": [1, 1, 1, 1, 1],
"capacities": [[75, 75, 75, 75, 75]],
"vehicle_time_windows": [
[0, 100],
[0, 100],
[0, 100],
[0, 100],
[0, 100]
],
# Vehicle can take breaks in this time window as per break duration provided
"vehicle_break_time_windows":[
[
[20, 25],
[20, 25],
[20, 25],
[20, 25],
[20, 25]
]
],
"vehicle_break_durations": [[1, 1, 1, 1, 1]],
# 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]
}
json_data["fleet_data"] = fleet_data
设置任务数据
提供有关任务地点、需求和时间窗口的详细信息;还有其他选项。
task_data = {
"task_locations": [1, 2, 3, 4],
"demand": [[30, 40, 40, 30]],
"task_time_windows": [
[3, 20],
[5, 30],
[1, 20],
[4, 40],
],
"service_times": [3, 1, 8, 4],
"prizes": [50, 50, 100, 50]
}
json_data["task_data"] = task_data
设置求解器配置
更大的问题可能需要更多时间。
solver_config = {
"objectives": {
"cost": 1,
"travel_time": 1,
"prize": 2
}
}
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": -407.0,
"objective_values": {"cost": 25.0, "travel_time": 68.0, "prize": -250.0},
"vehicle_data": {
"Car-A": {
"task_id": ["Depot", "2", "Break", "3", "Depot"],
"arrival_stamp": [6.0, 12.0, 20.0, 29.0, 39.0],
"route": [0, 3, 3, 4, 0],
"type": ["Depot", "Delivery", "Break", "Delivery", "Depot"]
},
"Car-C": {
"task_id": [ "Depot", "0", "Break", "1", "Depot"],
"arrival_stamp": [0.0, 10.0, 25.0, 26.0, 35.0],
"route": [0, 1, 2, 2, 0],
"type": ["Depot", "Delivery", "Break", "Delivery", "Depot"]
}
},
"dropped_tasks": {
"task_id": [],
"task_index": []
},
"msg": ""
},
"perf_times": null
},
"reqId": "4a60ebbc-f582-4062-8258-43e2bf87a9e0"
}
解决方案成本为 -407.0
,这是由于目标值设置为奖励,该奖励从其他值中抵消。
如果车辆具有非统一休息时间,该如何处理?#
# Lets pop uniform breaks added earlier
del fleet_data["vehicle_break_time_windows"]
del fleet_data["vehicle_break_durations"]
车辆 2 和 3 请求额外增加 2 次休息,让我们根据请求更新休息时间
vehicle_breaks = [
{
"vehicle_id": 0,
"earliest": 20,
"latest": 25,
"duration": 1,
"locations": [0, 1, 2, 3, 4]
},
{
"vehicle_id": 1,
"earliest": 20,
"latest": 25,
"duration": 1,
"locations": [0, 1, 2, 3, 4]
},
{
"vehicle_id": 2,
"earliest": 12,
"latest": 15,
"duration": 1,
"locations": [0, 1, 2, 3, 4]
},
{
"vehicle_id": 2,
"earliest": 20,
"latest": 25,
"duration": 1,
"locations": [0, 1, 2, 3, 4]
},
{
"vehicle_id": 3,
"earliest": 10,
"latest": 14,
"duration": 1,
"locations": [0, 1, 2, 3, 4]
},
{
"vehicle_id": 3,
"earliest": 20,
"latest": 25,
"duration": 1,
"locations": [0, 1, 2, 3, 4]
},
{
"vehicle_id": 4,
"earliest": 20,
"latest": 25,
"duration": 1,
"locations": [0, 1, 2, 3, 4]
},
]
fleet_data["vehicle_breaks"] = vehicle_breaks
让我们测试非统一休息时间
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": -403.0,
"objective_values": {
"cost": 26.0,
"travel_time": 71.0,
"prize": -250.0
},
"vehicle_data": {
"Car-A": {
"task_id": [
"Depot",
"2",
"Break",
"3",
"Depot"
],
"arrival_stamp": [
6.0,
12.0,
20.0,
29.0,
39.0
],
"type": [
"Depot",
"Delivery",
"Break",
"Delivery",
"Depot"
],
"route": [
0,
3,
3,
4,
0
]
},
"Car-C": {
"task_id": [
"Depot",
"0",
"Break",
"Break",
"1",
"Depot"
],
"arrival_stamp": [
0.0,
10.0,
13.0,
22.0,
29.0,
38.0
],
"type": [
"Depot",
"Delivery",
"Break",
"Break",
"Delivery",
"Depot"
],
"route": [
0,
1,
1,
3,
2,
0
]
}
},
"dropped_tasks": {
"task_id": [],
"task_index": []
}
}
},
"reqId": "925a48cd-ef91-4180-9382-3f1188ef0de0"
}
正如您所看到的,对应于 Car-C 的汽车索引 2 正在获得 2 次休息。