Vehicle Routing Data Construction and Result with Waypoint Matrix#
import json
Accumulate Problem Data#
json_data = {}
Set Waypoint Graph
Need to provide offsets, edges, and weights; weights can’t be negative values.
Considering 2 types of vehicle, a Van and a Truck, the Van would be faster and cost less in fewer paths compared to Trucks, which would depict a change in weights of the cost of travel.
Similarly, travel_time_graph_data can also be set.
# 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
}
}
Set Fleet Data
Provide vehicle start and end locations along with vehicle features and capacity.
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
Set Task Data
Provide details on task locations, demand, and time window; there are other options as well.
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
Set Solver Config
Larger problems might require more time.
solver_config = {
"time_limit": 1
}
json_data["solver_config"] = solver_config
Solve the Problem#
For managed service, cuOpt endpoints can be triggered as shown in the thin client example for managed service.
For self-hosted, cuOpt endpoints can be triggered as shown in the thin client example for self-hosted.
Use this data and invoke the cuOpt endpoint, which would return routes.
If the response status is 0,
then cuOpt found a feasible solution, under dictionary “solver_response”.
if status is 1,
then it found an infeasible solution by going over constraints. The warnings will list which constraints caused an infeasible solution which can be analyzed further. Any other state indicating that cuOpt failed may be due to invalid data or some unhandled issue. This will be under dictionary “solver_infeasible_response”.
Following example is using locally hosted server,
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"
}
Warnings will be listed as a list in the response, such as deprecation or any contstraints causing infeasible results.