cuopt-routing-api-python
Vehicle routing (VRP, TSP, PDP) with cuOpt — Python API only. Use when the user is building or solving routing in Python.
Install
npx skills add https://github.com/NVIDIA/skills/tree/main/skills/cuopt-routing-api-python
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install nvidia-skills@llmmart
git clone https://github.com/NVIDIA/skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole nvidia/skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
cuOpt Routing — Python API
This skill is Python only. Routing has no C API in cuOpt.
Required questions
Ask these if not already clear:
- Problem type — TSP, VRP, or PDP?
- Locations — How many? Depot(s)? Cost or distance between pairs (matrix or derived)?
- Orders / tasks — Which locations must be visited? Demand or service per stop?
- Fleet — Number of vehicles, capacity per vehicle (and per dimension if multiple), start/end locations?
- Constraints — Time windows (earliest/latest arrival), service times, precedence (order A before B)?
Minimal VRP Example
import cudf
from cuopt import routing
cost_matrix = cudf.DataFrame([...], dtype="float32")
dm = routing.DataModel(n_locations=4, n_fleet=2, n_orders=3)
dm.add_cost_matrix(cost_matrix)
dm.set_order_locations(cudf.Series([1, 2, 3], dtype="int32"))
solution = routing.Solve(dm, routing.SolverSettings())
if solution.get_status() == 0:
solution.display_routes()
Adding Constraints
# Time windows
dm.add_transit_time_matrix(transit_time_matrix)
dm.set_order_time_windows(earliest_series, latest_series)
# Capacities
dm.add_capacity_dimension("weight", demand_series, capacity_series)
dm.set_order_service_times(service_times)
dm.set_vehicle_locations(start_locations, end_locations)
dm.set_vehicle_time_windows(earliest_start, latest_return)
# Pickup-delivery pairs
dm.set_pickup_delivery_pairs(pickup_indices, delivery_indices)
# Precedence
dm.add_order_precedence(node_id=2, preceding_nodes=np.array([0, 1]))
Solution Checking
status = solution.get_status() # 0=SUCCESS, 1=FAIL, 2=TIMEOUT, 3=EMPTY
if status == 0:
route_df = solution.get_route()
total_cost = solution.get_total_objective()
else:
print(solution.get_error_message())
print(solution.get_infeasible_orders().to_list())
Data Types (use explicit dtypes)
cost_matrix = cost_matrix.astype("float32")
order_locations = cudf.Series([...], dtype="int32")
demand = cudf.Series([...], dtype="int32")
Solver Settings
ss = routing.SolverSettings()
ss.set_time_limit(30)
ss.set_verbose_mode(True)
ss.set_error_logging_mode(True)
Common Issues
| Problem | Fix |
|---|---|
| Empty solution | Widen time windows or check travel times |
| Infeasible orders | Increase fleet or capacity |
| Status != 0 with time windows | Add add_transit_time_matrix() |
| Wrong cost | Check cost_matrix is symmetric |
compute_waypoint_sequence alters route_df |
It replaces the location column with waypoint ids in place — pass route_df.copy() if you still need cost-matrix indices (e.g. when iterating per truck) |
Debugging
When status != 0: print(solution.get_error_message()) and print(solution.get_infeasible_orders().to_list()) to see which orders are infeasible.
Data types: Use explicit dtypes (float32, int32) for matrices and series to avoid silent errors.
Examples
- examples.md — VRP, PDP, multi-depot
- server_examples.md — REST client (curl, Python)
- Reference models: This skill's
assets/— vrp_basic, pdp_basic. See assets/README.md.
Escalate
For contribution or build-from-source, see the developer skill.
Files (skills)
-
assets
-
pdp_basic
-
model.py 1.5 KB
# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 """ PDP: 2 pickup-delivery pairs, 2 vehicles. Pickup before delivery; capacity dimension. """ import cudf from cuopt import routing cost_matrix = cudf.DataFrame( [ [0, 10, 20, 30, 40], [10, 0, 15, 25, 35], [20, 15, 0, 10, 20], [30, 25, 10, 0, 15], [40, 35, 20, 15, 0], ], dtype="float32", ) transit_time_matrix = cost_matrix.copy(deep=True) n_fleet = 2 n_orders = 4 order_locations = cudf.Series([1, 2, 3, 4], dtype="int32") pickup_indices = cudf.Series([0, 2]) delivery_indices = cudf.Series([1, 3]) demand = cudf.Series([10, -10, 15, -15], dtype="int32") vehicle_capacity = cudf.Series([50, 50], dtype="int32") dm = routing.DataModel( n_locations=cost_matrix.shape[0], n_fleet=n_fleet, n_orders=n_orders, ) dm.add_cost_matrix(cost_matrix) dm.add_transit_time_matrix(transit_time_matrix) dm.set_order_locations(order_locations) dm.add_capacity_dimension("load", demand, vehicle_capacity) dm.set_pickup_delivery_pairs(pickup_indices, delivery_indices) dm.set_vehicle_locations( cudf.Series([0, 0], dtype="int32"), cudf.Series([0, 0], dtype="int32"), ) ss = routing.SolverSettings() ss.set_time_limit(10) solution = routing.Solve(dm, ss) print(f"Status: {solution.get_status()}") if solution.get_status() == 0: solution.display_routes() print(f"Total cost: {solution.get_total_objective()}") else: print(solution.get_error_message()) -
README.md 257 B
# Pickup-Delivery (PDP) 2 pickup-delivery pairs (4 orders), 2 vehicles. Pickup must occur before delivery; capacity dimension. **Run:** `python model.py` **See also:** [references/examples.md](../../references/examples.md) for more PDP and VRP patterns.
-
-
vrp_basic
-
model.py 838 B
# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 """ Minimal VRP: 4 locations, 1 vehicle, 3 orders. Cost matrix only. """ import cudf from cuopt import routing cost_matrix = cudf.DataFrame( [ [0, 10, 15, 20], [10, 0, 12, 18], [15, 12, 0, 10], [20, 18, 10, 0], ], dtype="float32", ) dm = routing.DataModel(n_locations=4, n_fleet=1, n_orders=3) dm.add_cost_matrix(cost_matrix) dm.set_order_locations(cudf.Series([1, 2, 3], dtype="int32")) solution = routing.Solve(dm, routing.SolverSettings()) if solution.get_status() == 0: solution.display_routes() print(f"Total cost: {solution.get_total_objective()}") else: print(f"Status: {solution.get_status()}", solution.get_error_message()) -
README.md 272 B
# Minimal VRP 4 locations (depot 0 + 3 customers), 1 vehicle, 3 orders. Cost matrix only; no time windows or capacity. **Run:** `python model.py` **See also:** [references/examples.md](../../references/examples.md) for VRP with time windows, capacity, and multi-depot.
-
-
README.md 553 B
# Assets — reference routing models Routing reference implementations (Python). Use as reference when building new applications; do not edit in place. | Model | Type | Description | |-------|------|-------------| | [vrp_basic](vrp_basic/) | VRP | Minimal VRP: 4 locations, 1 vehicle, 3 orders | | [pdp_basic](pdp_basic/) | PDP | Pickup-delivery pairs, capacity dimension | **Run:** From each subdir, `python model.py` (requires cuOpt and cudf). See [references/examples.md](../references/examples.md) for more patterns (time windows, multi-depot).
-
-
evals
-
evals.json 8.7 KB
[ { "id": "rt-py-eval-001-vrptw-api-call-sequence", "question": "For a VRP with time windows in cuopt (Python), list the API calls I need in order — name each method on routing.DataModel and routing.Solve, and one-line what each does. Don't write a full runnable script.", "expected_skill": "cuopt-routing-api-python", "expected_script": null, "ground_truth": "The agent produces an ordered list of API calls without writing executable code. The list, in order: (1) Construct routing.DataModel(n_locations, n_fleet, n_orders). (2) add_cost_matrix(cost_matrix) — pass as a cudf.DataFrame with float32 dtype. (3) add_transit_time_matrix(transit_time_matrix) — required when time windows are used; omitting it causes Solve to return a non-zero status. (4) set_order_locations(series) — cudf.Series of int32 node indices. (5) set_order_time_windows(earliest, latest) — two int32 cudf.Series. (6) Construct routing.SolverSettings(); call set_time_limit() and optionally set_verbose_mode(). (7) Call routing.Solve(dm, ss) to get a solution object. (8) Check solution.get_status() == 0 before reading the route; on a non-zero status, inspect solution.get_error_message() and solution.get_infeasible_orders().to_list(). (9) On success, retrieve the route via solution.get_route() or display it via solution.display_routes(). The agent mentions explicit dtypes (float32 for the matrices, int32 for index series) as a class-level note. Does not embed full executable code, does not invent method names that aren't in the skill (e.g. no fictitious set_time_windows or add_vehicle), and flags that the user must supply real numeric data.", "expected_behavior": [ "Lists the API methods in order without producing a full executable script", "Names routing.DataModel with n_locations / n_fleet / n_orders", "Names add_cost_matrix and add_transit_time_matrix, and flags that transit_time_matrix is required for time windows", "Names set_order_locations and set_order_time_windows", "Names routing.SolverSettings (and set_time_limit) and routing.Solve", "Mentions checking solution.get_status() == 0, and get_error_message / get_infeasible_orders for the failure path", "Mentions explicit dtypes (float32 for matrices, int32 for index series)", "Does not invent method names that are not in the skill" ] }, { "id": "rt-py-eval-002-status-codes-and-triage", "question": "routing.Solve came back and my route is empty. How do I find out what happened? What do the status values mean?", "expected_skill": "cuopt-routing-api-python", "expected_script": null, "ground_truth": "The agent explains that solution.get_status() must be checked first, and gives the meaning of the values: 0 = SUCCESS, 1 = FAIL, 2 = TIMEOUT, 3 = EMPTY. For any non-zero status it directs the user to solution.get_error_message() for the reason and solution.get_infeasible_orders().to_list() to see which specific orders could not be served. It also names the usual causes from the skill's issue table — an empty solution generally means time windows are too tight or the travel times are wrong, and infeasible orders generally mean insufficient fleet or capacity. It does not invent additional status codes.", "expected_behavior": [ "States that solution.get_status() == 0 means success and enumerates 1 = FAIL, 2 = TIMEOUT, 3 = EMPTY", "Directs the user to solution.get_error_message() and solution.get_infeasible_orders().to_list()", "Links an empty solution to over-tight time windows or wrong travel times, and infeasible orders to insufficient fleet or capacity", "Does not invent status codes beyond those documented" ] }, { "id": "rt-py-eval-003-capacity-dimension", "question": "My vehicles have a weight limit and each order has a weight. How do I express that in the cuOpt Python routing API?", "expected_skill": "cuopt-routing-api-python", "expected_script": null, "ground_truth": "The agent uses dm.add_capacity_dimension(name, demand_series, capacity_series) — a named dimension carrying the per-order demand and the per-vehicle capacity. It notes that the method is called once per capacity dimension, so multiple dimensions (e.g. weight and volume) mean multiple calls, and that the demand and capacity series should be int32. It does not invent a set_capacity or add_vehicle_capacity method.", "expected_behavior": [ "Names add_capacity_dimension with a dimension name, a per-order demand series, and a per-vehicle capacity series", "States that additional capacity dimensions require additional calls", "Mentions int32 dtype for the demand/capacity series", "Does not invent an alternative capacity method name" ] }, { "id": "rt-py-eval-004-pickup-delivery-pairs", "question": "I need each pickup to be served by the same vehicle that later makes the matching delivery. Which cuOpt Python routing call sets that up?", "expected_skill": "cuopt-routing-api-python", "expected_script": null, "ground_truth": "The agent names dm.set_pickup_delivery_pairs(pickup_indices, delivery_indices), which takes parallel index series pairing each pickup order with its delivery order and makes the problem a PDP. It notes the indices refer to order indices, that the pairing is what enforces same-vehicle and pickup-before-delivery behaviour, and that dm.add_order_precedence(node_id=..., preceding_nodes=...) is the separate mechanism for general precedence between nodes rather than pickup/delivery pairing.", "expected_behavior": [ "Names set_pickup_delivery_pairs with paired pickup and delivery index series", "Explains that the pairing is what ties a pickup and its delivery to the same vehicle in order", "Distinguishes it from add_order_precedence, which expresses general precedence" ] }, { "id": "rt-py-eval-005-explicit-dtypes", "question": "Do I need to care about dtypes when I build the cost matrix and order location series for cuOpt routing in Python, or will pandas/cudf defaults be fine?", "expected_skill": "cuopt-routing-api-python", "expected_script": null, "ground_truth": "The agent says dtypes must be set explicitly rather than left to defaults: the cost and transit time matrices should be float32, and index-like series such as order locations and demand should be int32. It explains that relying on defaults (e.g. float64 or int64) can produce silent errors rather than a clear exception, which is why the skill calls for explicit casts such as cost_matrix.astype('float32') and cudf.Series([...], dtype='int32').", "expected_behavior": [ "States that float32 is expected for the cost and transit time matrices", "States that int32 is expected for order location and demand series", "Explains that leaving dtypes to default risks silent errors, so explicit casting is required" ] }, { "id": "rt-py-eval-006-waypoint-sequence-mutates-route-df", "question": "I'm looping over trucks and calling compute_waypoint_sequence on the route dataframe for each one, but after the first truck my cost-matrix indices are wrong. What's going on?", "expected_skill": "cuopt-routing-api-python", "expected_script": null, "ground_truth": "The agent identifies the in-place mutation: compute_waypoint_sequence replaces the location column of the route dataframe with waypoint ids in place, so the original cost-matrix indices are destroyed after the first call and every later iteration reads waypoint ids instead. The fix is to pass route_df.copy() into the call whenever the cost-matrix indices are still needed afterwards, which is exactly the per-truck loop case.", "expected_behavior": [ "Identifies that compute_waypoint_sequence overwrites the location column with waypoint ids in place", "Explains that this is why later loop iterations see wrong indices", "Gives passing route_df.copy() as the fix" ] }, { "id": "rt-py-eval-007-no-c-api-for-routing", "question": "I'm writing a C application and want to call cuOpt's VRP solver directly from C. How do I do that?", "expected_skill": "cuopt-routing-api-python", "expected_script": null, "ground_truth": "The agent states that routing has no C API in cuOpt — the routing solver is exposed through the Python API only. It redirects the user to a workable alternative: drive routing from Python, or call the cuOpt REST server over HTTP from the C application, since the server is language-agnostic. It does not fabricate C routing entry points or header names.", "expected_behavior": [ "States clearly that cuOpt routing has no C API and is Python-only", "Offers the REST server as the language-agnostic route for a non-Python caller", "Does not invent C function or header names for routing" ] } ]
-
-
references
-
examples.md 6.9 KB
# Routing: Python API Examples ## VRP with Time Windows & Capacities ```python """ Vehicle Routing Problem with: - 1 depot (location 0) - 5 customer locations (1-5) - 2 vehicles with capacity 100 each - Time windows for each location - Demand at each customer """ import cudf from cuopt import routing # Cost/distance matrix (6x6: depot + 5 customers) cost_matrix = cudf.DataFrame([ [0, 10, 15, 20, 25, 30], # From depot [10, 0, 12, 18, 22, 28], # From customer 1 [15, 12, 0, 10, 15, 20], # From customer 2 [20, 18, 10, 0, 8, 15], # From customer 3 [25, 22, 15, 8, 0, 10], # From customer 4 [30, 28, 20, 15, 10, 0], # From customer 5 ], dtype="float32") # Also use as transit time matrix (same values for simplicity) transit_time_matrix = cost_matrix.copy(deep=True) # Order data (customers 1-5) order_locations = cudf.Series([1, 2, 3, 4, 5], dtype="int32") # Location indices for orders # Demand at each customer (single capacity dimension) demand = cudf.Series([20, 30, 25, 15, 35], dtype="int32") # Vehicle capacities (must match demand dimensions) vehicle_capacity = cudf.Series([100, 100], dtype="int32") # Time windows for orders [earliest, latest] order_earliest = cudf.Series([0, 10, 20, 0, 30], dtype="int32") order_latest = cudf.Series([50, 60, 70, 80, 90], dtype="int32") # Service time at each customer service_times = cudf.Series([5, 5, 5, 5, 5], dtype="int32") # Fleet configuration n_fleet = 2 # Vehicle start/end locations (both start and return to depot) vehicle_start = cudf.Series([0, 0], dtype="int32") vehicle_end = cudf.Series([0, 0], dtype="int32") # Vehicle time windows (operating hours) vehicle_earliest = cudf.Series([0, 0], dtype="int32") vehicle_latest = cudf.Series([200, 200], dtype="int32") # Build the data model dm = routing.DataModel( n_locations=cost_matrix.shape[0], n_fleet=n_fleet, n_orders=len(order_locations) ) # Add matrices dm.add_cost_matrix(cost_matrix) dm.add_transit_time_matrix(transit_time_matrix) # Add order data dm.set_order_locations(order_locations) dm.set_order_time_windows(order_earliest, order_latest) dm.set_order_service_times(service_times) # Add capacity dimension (name, demand_per_order, capacity_per_vehicle) dm.add_capacity_dimension("weight", demand, vehicle_capacity) # Add fleet data dm.set_vehicle_locations(vehicle_start, vehicle_end) dm.set_vehicle_time_windows(vehicle_earliest, vehicle_latest) # Configure solver ss = routing.SolverSettings() ss.set_time_limit(10) # seconds # Solve solution = routing.Solve(dm, ss) # Check solution status print(f"Status: {solution.get_status()}") # Display routes if solution.get_status() == 0: # Success print("\n--- Solution Found ---") solution.display_routes() # Get detailed route data route_df = solution.get_route() print("\nDetailed route data:") print(route_df) # Get objective value (total cost) print(f"\nTotal cost: {solution.get_total_objective()}") else: print("No feasible solution found (status != 0).") ``` ## Pickup and Delivery Problem (PDP) ```python """ Pickup and Delivery Problem: - Items must be picked up from one location and delivered to another - Same vehicle must do both pickup and delivery - Pickup must occur before delivery """ import cudf from cuopt import routing # Cost matrix (depot + 4 locations) cost_matrix = cudf.DataFrame([ [0, 10, 20, 30, 40], [10, 0, 15, 25, 35], [20, 15, 0, 10, 20], [30, 25, 10, 0, 15], [40, 35, 20, 15, 0], ], dtype="float32") transit_time_matrix = cost_matrix.copy(deep=True) n_fleet = 2 n_orders = 4 # 2 pickup-delivery pairs = 4 orders # Orders: pickup at loc 1 -> deliver at loc 2, pickup at loc 3 -> deliver at loc 4 order_locations = cudf.Series([1, 2, 3, 4], dtype="int32") # Pickup and delivery pairs (indices into order array) # Order 0 (pickup) pairs with Order 1 (delivery) # Order 2 (pickup) pairs with Order 3 (delivery) pickup_indices = cudf.Series([0, 2]) delivery_indices = cudf.Series([1, 3]) # Demand: positive for pickup, negative for delivery (must sum to 0 per pair) demand = cudf.Series([10, -10, 15, -15], dtype="int32") vehicle_capacity = cudf.Series([50, 50], dtype="int32") # Build model dm = routing.DataModel( n_locations=cost_matrix.shape[0], n_fleet=n_fleet, n_orders=n_orders ) dm.add_cost_matrix(cost_matrix) dm.add_transit_time_matrix(transit_time_matrix) dm.set_order_locations(order_locations) # Add capacity dimension dm.add_capacity_dimension("load", demand, vehicle_capacity) # Set pickup and delivery constraints dm.set_pickup_delivery_pairs(pickup_indices, delivery_indices) # Fleet setup dm.set_vehicle_locations( cudf.Series([0, 0]), # Start at depot cudf.Series([0, 0]) # Return to depot ) # Solve ss = routing.SolverSettings() ss.set_time_limit(10) solution = routing.Solve(dm, ss) print(f"Status: {solution.get_status()}") if solution.get_status() == 0: solution.display_routes() ``` ## Minimal VRP (Quick Start) ```python import cudf from cuopt import routing # Minimal 4-location problem cost_matrix = cudf.DataFrame([ [0, 10, 15, 20], [10, 0, 12, 18], [15, 12, 0, 10], [20, 18, 10, 0], ], dtype="float32") dm = routing.DataModel(n_locations=4, n_fleet=1, n_orders=3) dm.add_cost_matrix(cost_matrix) dm.set_order_locations(cudf.Series([1, 2, 3], dtype="int32")) solution = routing.Solve(dm, routing.SolverSettings()) if solution.get_status() == 0: solution.display_routes() ``` ## Multi-Depot VRP ```python import cudf from cuopt import routing # 6 locations: 2 depots (0, 1) + 4 customers (2, 3, 4, 5) cost_matrix = cudf.DataFrame([ [0, 5, 10, 15, 20, 25], [5, 0, 12, 8, 18, 22], [10, 12, 0, 6, 14, 16], [15, 8, 6, 0, 10, 12], [20, 18, 14, 10, 0, 8], [25, 22, 16, 12, 8, 0], ], dtype="float32") n_fleet = 2 dm = routing.DataModel(n_locations=6, n_fleet=n_fleet, n_orders=4) dm.add_cost_matrix(cost_matrix) dm.set_order_locations(cudf.Series([2, 3, 4, 5], dtype="int32")) # Vehicle 0 starts/ends at depot 0, Vehicle 1 at depot 1 dm.set_vehicle_locations( cudf.Series([0, 1]), # start locations cudf.Series([0, 1]) # end locations ) solution = routing.Solve(dm, routing.SolverSettings()) if solution.get_status() == 0: solution.display_routes() ``` --- ## Additional References (tested in CI) For more complete examples, read these files: | Example | File | Description | |---------|------|-------------| | Basic Routing | `docs/cuopt/source/cuopt-server/examples/routing/examples/basic_routing_example.py` | Server-based routing | | Initial Solution | `docs/cuopt/source/cuopt-server/examples/routing/examples/initial_solution_example.py` | Warm starting | | Smoke Test | `docs/cuopt/source/cuopt-python/routing/examples/smoke_test_example.sh` | Quick validation | These examples are tested by CI and represent canonical usage. **Note:** The Python routing API documentation is in `python/cuopt/cuopt/routing/vehicle_routing.py` (docstrings). -
server_examples.md 5.7 KB
# Routing: REST Server Examples ## Start the Server ```bash # Start server python -m cuopt_server.cuopt_service --ip 0.0.0.0 --port 8000 & # Wait and verify sleep 5 curl -s http://localhost:8000/cuopt/health ``` ## Basic VRP (curl) ```bash REQID=$(curl -s -X POST "http://localhost:8000/cuopt/request" \ -H "Content-Type: application/json" \ -H "CLIENT-VERSION: custom" \ -d '{ "cost_matrix_data": { "data": {"0": [[0,10,15,20],[10,0,12,18],[15,12,0,10],[20,18,10,0]]} }, "travel_time_matrix_data": { "data": {"0": [[0,10,15,20],[10,0,12,18],[15,12,0,10],[20,18,10,0]]} }, "task_data": { "task_locations": [1, 2, 3], "demand": [[10, 15, 20]], "task_time_windows": [[0, 100], [10, 80], [20, 90]], "service_times": [5, 5, 5] }, "fleet_data": { "vehicle_locations": [[0, 0], [0, 0]], "capacities": [[50, 50]], "vehicle_time_windows": [[0, 200], [0, 200]] }, "solver_config": { "time_limit": 5 } }' | jq -r '.reqId') echo "Request ID: $REQID" # Poll for solution sleep 2 curl -s "http://localhost:8000/cuopt/solution/$REQID" \ -H "Content-Type: application/json" \ -H "CLIENT-VERSION: custom" | jq . ``` ## VRP with Time Windows (Python requests) ```python import requests import time SERVER = "http://localhost:8000" HEADERS = {"Content-Type": "application/json", "CLIENT-VERSION": "custom"} payload = { "cost_matrix_data": { "data": { "0": [ [0, 10, 15, 20, 25], [10, 0, 12, 18, 22], [15, 12, 0, 10, 15], [20, 18, 10, 0, 8], [25, 22, 15, 8, 0] ] } }, "travel_time_matrix_data": { "data": { "0": [ [0, 10, 15, 20, 25], [10, 0, 12, 18, 22], [15, 12, 0, 10, 15], [20, 18, 10, 0, 8], [25, 22, 15, 8, 0] ] } }, "task_data": { "task_locations": [1, 2, 3, 4], "demand": [[20, 30, 25, 15]], "task_time_windows": [[0, 50], [10, 60], [20, 70], [0, 80]], "service_times": [5, 5, 5, 5] }, "fleet_data": { "vehicle_locations": [[0, 0], [0, 0]], "capacities": [[100, 100]], "vehicle_time_windows": [[0, 200], [0, 200]] }, "solver_config": { "time_limit": 10 } } # Submit request response = requests.post(f"{SERVER}/cuopt/request", json=payload, headers=HEADERS) response.raise_for_status() req_id = response.json()["reqId"] print(f"Request submitted: {req_id}") # Poll for solution for attempt in range(30): response = requests.get(f"{SERVER}/cuopt/solution/{req_id}", headers=HEADERS) result = response.json() if "response" in result: solver_response = result["response"].get("solver_response", {}) print(f"\nSolution found!") print(f"Status: {solver_response.get('status', 'N/A')}") print(f"Cost: {solver_response.get('solution_cost', 'N/A')}") if "vehicle_data" in solver_response: for vid, vdata in solver_response["vehicle_data"].items(): route = vdata.get("route", []) print(f"Vehicle {vid}: {' -> '.join(map(str, route))}") break else: print(f"Waiting... (attempt {attempt + 1})") time.sleep(1) ``` ## Pickup and Delivery (curl) ```bash REQID=$(curl -s -X POST "http://localhost:8000/cuopt/request" \ -H "Content-Type: application/json" \ -H "CLIENT-VERSION: custom" \ -d '{ "cost_matrix_data": { "data": {"0": [[0,10,20,30,40],[10,0,15,25,35],[20,15,0,10,20],[30,25,10,0,15],[40,35,20,15,0]]} }, "travel_time_matrix_data": { "data": {"0": [[0,10,20,30,40],[10,0,15,25,35],[20,15,0,10,20],[30,25,10,0,15],[40,35,20,15,0]]} }, "task_data": { "task_locations": [1, 2, 3, 4], "demand": [[10, -10, 15, -15]], "pickup_and_delivery_pairs": [[0, 1], [2, 3]] }, "fleet_data": { "vehicle_locations": [[0, 0]], "capacities": [[50]] }, "solver_config": { "time_limit": 10 } }' | jq -r '.reqId') echo "Request ID: $REQID" # Poll for solution sleep 2 curl -s "http://localhost:8000/cuopt/solution/$REQID" \ -H "Content-Type: application/json" \ -H "CLIENT-VERSION: custom" | jq . ``` ## Terminology Reference | Python API | REST Server API | |------------|-----------------| | `order_locations` | `task_locations` | | `set_order_time_windows()` | `task_time_windows` | | `set_order_service_times()` | `service_times` | | `add_transit_time_matrix()` | `travel_time_matrix_data` | | `set_pickup_delivery_pairs()` | `pickup_and_delivery_pairs` | ## Common Payload Mistakes ```json // ❌ WRONG field name "transit_time_matrix_data": {...} // ✅ CORRECT "travel_time_matrix_data": {...} ``` ```json // ❌ WRONG capacity format (per vehicle) "capacities": [[50], [50]] // ✅ CORRECT (per dimension across vehicles) "capacities": [[50, 50]] ``` --- ## Additional References (tested in CI) For more complete examples, read these files: | Example | File | Description | |---------|------|-------------| | Basic Routing (Python) | `docs/cuopt/source/cuopt-server/examples/routing/examples/basic_routing_example.py` | VRP via REST | | Basic Routing (curl) | `docs/cuopt/source/cuopt-server/examples/routing/examples/basic_routing_example.sh` | Shell script | | Initial Solution | `docs/cuopt/source/cuopt-server/examples/routing/examples/initial_solution_example.py` | Warm starting | | Initial Solution (curl) | `docs/cuopt/source/cuopt-server/examples/routing/examples/initial_solution_example.sh` | Warm start shell | These examples are tested by CI (`ci/test_doc_examples.sh`) and represent canonical usage.
-
-
BENCHMARK.md 4.6 KB
# Skill Benchmark: cuopt-routing-api-python > ✅ **Overall verdict: PASS — Recommended for publication** ## Publication Recommendation Recommended for publication based on the completed evaluation evidence in this report. ## Evaluation Metadata - Skill: `cuopt-routing-api-python` - Evaluation date: 2026-08-12 - Evaluator version: `1.2.4` - Agents: Claude Code (`aws/anthropic/bedrock-claude-opus-4-8`), Codex (`openai/openai/gpt-5.5`) - Tasks: 7 evaluation tasks (7 positive) - Dataset digest: `sha256:e13146ac43d578682f0a3d799837f67335d277ef722feb1d28fc526709b6ba4e` (skill-evaluator-dataset-snapshot/1) - Attempts per task: 1 - Environment: `k8s-sandbox` - Tier 3 evidence: required for publication Each task attempt ran in its own isolated sandbox pod. ## What This Report Answers The three-tier evaluation checks whether the skill: - is safe to use; - produces correct answers; - is discovered and activated when needed; - helps the agent complete the user's goal and expected workflow; and - avoids wasted skill and tool usage. ## Results at a Glance | Measure | Claude Code (Baseline → Skill Uplift) | Codex (Baseline → Skill Uplift) | |---|---:|---:| | Overall | 54% → 91% (+37 points) | 60% → 86% (+26 points) | | Security | 100% → 100% (±0 points) | 100% → 100% (±0 points) | | Correctness | 77% → 91% (+14 points) | 80% → 100% (+20 points) | | Discoverability | 21% → 93% (+71 points) | 50% → 88% (+38 points) | | Effectiveness | 66% → 87% (+21 points) | 65% → 86% (+21 points) | | Efficiency | 8% → 86% (+78 points) | 7% → 56% (+49 points) | **How to read this table:** baseline is the same task attempted without the target skill. Uplift is `skill score - baseline score`, shown in percentage points. Example: `47% → 92% (+45 points)` means the skill-assisted run scored 92%, 45 percentage points above its 47% no-skill baseline. ## Tier Status | Tier | Purpose | Status | Evidence | |---|---|---|---| | Tier 1 | Static validation | **PASSED WITH OBSERVATIONS** | 1 validator(s); 3 finding(s) | | Tier 2 | Semantic deduplication | **NOT RUN** | No result was recorded | | Tier 3 | Live agent evaluation | **PASS** | 2 agent(s); 7 task(s) | ## Findings and Observations <details> <summary>Show detailed findings and successful checks</summary> - **MEDIUM** SCHEMA/frontmatter_field_placement: Root field 'version' is ignored; use 'metadata.version' (`skills/cuopt-routing-api-python/SKILL.md`) - **MEDIUM** SCHEMA/body_recommended_section: Missing recommended section: '## Instructions' (`skills/cuopt-routing-api-python/SKILL.md`) - **LOW** SCHEMA/author_format: Author must be of the form 'Name <email@host>' (`skills/cuopt-routing-api-python/SKILL.md`) </details> ## Scoring Methodology <details> <summary>Show dimension definitions, source signals, and thresholds</summary> | Dimension | Question | Scored signals | |---|---|---| | Security | Is it safe to use? | `security` (100%) | | Correctness | Is the answer correct? | `accuracy` (100%) | | Discoverability | Was the right skill loaded when needed? | `skill_execution` (100%) | | Effectiveness | Did the skill help complete the task? | `goal_accuracy` (50%) + `behavior_check` (50%) | | Efficiency | Did it avoid wasted tool or skill usage? | `skill_efficiency` (100%) | - Dimension bands: PASS at 50% or above; NEUTRAL from 40% to below 50%; FAIL below 40%. - Overall Tier 3 lift: PASS at +5 points or more; FAIL at -10 points or less; values between those bands are NEUTRAL. - Overall verdict: PASS only when every configured dimension passes for at least one supported agent. Lift is reported as diagnostic evidence and does not override this gate. - The 50% attempt pass threshold is a separate per-task gate; it is not the dimension pass threshold. - Effectiveness is the equal-weight mean of goal completion (`goal_accuracy`) and expected workflow adherence (`behavior_check`). - Token efficiency is a separate report-only signal. It does not change a dimension score or the overall verdict. Signals present in this run: - `security` (Security): unsafe operations, secret leakage, and unauthorized access. - `skill_execution` (Skill Execution): whether the expected skill was found and executed. - `skill_efficiency` (Efficiency): routing quality, workspace-aware skill reads, and productive tool use. - `accuracy` (Accuracy): final-answer correctness against the reference answer. - `goal_accuracy` (Goal Accuracy): whether the user's goal was achieved. - `behavior_check` (Behavior Check): whether the expected workflow behavior was followed. </details> ## Freshness Regenerate this benchmark when the skill, evaluation dataset, target agent/model, evaluator version, environment, or scoring policy changes. -
skill-card.md 4 KB
## Description: <br> Vehicle routing (VRP, TSP, PDP) with cuOpt — Python API only. Use when the user is building or solving routing in Python. <br> This skill is ready for commercial/non-commercial use. <br> ## Owner NVIDIA <br> ### License/Terms of Use: <br> Apache-2.0 <br> ## Use Case: <br> Developers and engineers building or solving vehicle routing problems (VRP, TSP, PDP) using the NVIDIA cuOpt Python API. <br> ### Deployment Geography for Use: <br> Global <br> ## Requirements / Dependencies: <br> **Requires API Key or External Credential:** [Not Specified] <br> **Credential Type(s):** [None identified] <br> Do not include secrets in prompts/logs/output; use least-privilege credentials; rotate keys as appropriate. <br> ## Known Risks and Mitigations: <br> Risk: Review before execution as proposals could introduce incorrect or misleading guidance into skills. <br> Mitigation: Review and scan skill before deployment. <br> ## Reference(s): <br> - [examples.md](references/examples.md) <br> - [server_examples.md](references/server_examples.md) <br> - [cuOpt User Guide](https://docs.nvidia.com/cuopt/user-guide/latest/introduction.html) <br> - [cuOpt Examples](https://github.com/NVIDIA/cuopt-examples) <br> ## Skill Output: <br> **Output Type(s):** [Code, API Calls, Configuration instructions] <br> **Output Format:** [Markdown with inline Python code blocks] <br> **Output Parameters:** [1D] <br> **Other Properties Related to Output:** [None] <br> ## Evaluation Agents Used: <br> - Claude Code (`aws/anthropic/bedrock-claude-opus-4-8`) <br> - Codex (`openai/openai/gpt-5.5`) <br> ## Evaluation Tasks: <br> 7 evaluation tasks (7 positive) run in isolated sandbox pods. <br> ## Evaluation Metrics Used: <br> Reported benchmark dimensions: <br> - Security: Checks for unsafe operations, secret leakage, and unauthorized access. <br> - Correctness: Checks final-answer correctness against the reference answer. <br> - Discoverability: Checks whether the expected skill was found and executed when needed. <br> - Effectiveness: Checks whether the skill helped complete the user's goal and expected workflow. <br> - Efficiency: Checks routing quality, workspace-aware skill reads, and productive tool use. <br> Underlying evaluation signals used in this run: <br> - `security`: Detects unsafe operations, secret leakage, and unauthorized access. <br> - `skill_execution`: Verifies the expected skill was found and executed. <br> - `skill_efficiency`: Verifies routing quality, workspace-aware skill reads, and productive tool use. <br> - `accuracy`: Verifies final-answer correctness against the reference answer. <br> - `goal_accuracy`: Verifies whether the user's goal was achieved. <br> - `behavior_check`: Verifies whether the expected workflow behavior was followed. <br> ## Evaluation Results: <br> | Measure | Claude Code (Baseline → Skill Uplift) | Codex (Baseline → Skill Uplift) | |---|---:|---:| | Overall | 54% → 91% (+37 points) | 60% → 86% (+26 points) | | Security | 100% → 100% (±0 points) | 100% → 100% (±0 points) | | Correctness | 77% → 91% (+14 points) | 80% → 100% (+20 points) | | Discoverability | 21% → 93% (+71 points) | 50% → 88% (+38 points) | | Effectiveness | 66% → 87% (+21 points) | 65% → 86% (+21 points) | | Efficiency | 8% → 86% (+78 points) | 7% → 56% (+49 points) | ## Skill Version(s): <br> 26.10.00 (source: frontmatter) <br> ## Ethical Considerations: <br> NVIDIA believes Trustworthy AI is a shared responsibility and we have established policies and practices to enable development for a wide array of AI applications. When downloaded or used in accordance with our terms of service, developers should work with their internal team to ensure this skill meets requirements for the relevant industry and use case and addresses unforeseen product misuse. <br> (For Release on NVIDIA Platforms Only) <br> Please report quality, risk, security vulnerabilities or NVIDIA AI Concerns [here](https://app.intigriti.com/programs/nvidia/nvidiavdp/detail). <br> -
SKILL.md 3.6 KB
--- name: cuopt-routing-api-python version: "26.10.00" description: Vehicle routing (VRP, TSP, PDP) with cuOpt — Python API only. Use when the user is building or solving routing in Python. license: Apache-2.0 metadata: author: NVIDIA cuOpt Team tags: - cuopt - routing - vrp - tsp - python --- # cuOpt Routing — Python API This skill is **Python only**. Routing has no C API in cuOpt. ## Required questions Ask these if not already clear: 1. **Problem type** — TSP, VRP, or PDP? 2. **Locations** — How many? Depot(s)? Cost or distance between pairs (matrix or derived)? 3. **Orders / tasks** — Which locations must be visited? Demand or service per stop? 4. **Fleet** — Number of vehicles, capacity per vehicle (and per dimension if multiple), start/end locations? 5. **Constraints** — Time windows (earliest/latest arrival), service times, precedence (order A before B)? ## Minimal VRP Example ```python import cudf from cuopt import routing cost_matrix = cudf.DataFrame([...], dtype="float32") dm = routing.DataModel(n_locations=4, n_fleet=2, n_orders=3) dm.add_cost_matrix(cost_matrix) dm.set_order_locations(cudf.Series([1, 2, 3], dtype="int32")) solution = routing.Solve(dm, routing.SolverSettings()) if solution.get_status() == 0: solution.display_routes() ``` ## Adding Constraints ```python # Time windows dm.add_transit_time_matrix(transit_time_matrix) dm.set_order_time_windows(earliest_series, latest_series) # Capacities dm.add_capacity_dimension("weight", demand_series, capacity_series) dm.set_order_service_times(service_times) dm.set_vehicle_locations(start_locations, end_locations) dm.set_vehicle_time_windows(earliest_start, latest_return) # Pickup-delivery pairs dm.set_pickup_delivery_pairs(pickup_indices, delivery_indices) # Precedence dm.add_order_precedence(node_id=2, preceding_nodes=np.array([0, 1])) ``` ## Solution Checking ```python status = solution.get_status() # 0=SUCCESS, 1=FAIL, 2=TIMEOUT, 3=EMPTY if status == 0: route_df = solution.get_route() total_cost = solution.get_total_objective() else: print(solution.get_error_message()) print(solution.get_infeasible_orders().to_list()) ``` ## Data Types (use explicit dtypes) ```python cost_matrix = cost_matrix.astype("float32") order_locations = cudf.Series([...], dtype="int32") demand = cudf.Series([...], dtype="int32") ``` ## Solver Settings ```python ss = routing.SolverSettings() ss.set_time_limit(30) ss.set_verbose_mode(True) ss.set_error_logging_mode(True) ``` ## Common Issues | Problem | Fix | |---------|-----| | Empty solution | Widen time windows or check travel times | | Infeasible orders | Increase fleet or capacity | | Status != 0 with time windows | Add `add_transit_time_matrix()` | | Wrong cost | Check cost_matrix is symmetric | | `compute_waypoint_sequence` alters route_df | It replaces the `location` column with waypoint ids in place — pass `route_df.copy()` if you still need cost-matrix indices (e.g. when iterating per truck) | ## Debugging **When status != 0:** `print(solution.get_error_message())` and `print(solution.get_infeasible_orders().to_list())` to see which orders are infeasible. **Data types:** Use explicit dtypes (float32, int32) for matrices and series to avoid silent errors. ## Examples - [examples.md](references/examples.md) — VRP, PDP, multi-depot - [server_examples.md](references/server_examples.md) — REST client (curl, Python) - **Reference models:** This skill's `assets/` — [vrp_basic](assets/vrp_basic/), [pdp_basic](assets/pdp_basic/). See [assets/README.md](assets/README.md). ## Escalate For contribution or build-from-source, see the developer skill. -
skill.oms.sig 6.1 KB · in bundle
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.