-
Notifications
You must be signed in to change notification settings - Fork 225
docs(grpc): document the VRP gRPC client (RoutingClient) #1838
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
10ab62e
4ed2462
23d2937
a728703
638389a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,43 @@ | ||||||
| # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||||||
| # SPDX-License-Identifier: Apache-2.0 | ||||||
|
|
||||||
| """Minimal VRP demo for the NVIDIA cuOpt VRP gRPC client. | ||||||
|
|
||||||
| Unlike LP/MIP, routing has no ``CUOPT_REMOTE_HOST``/``CUOPT_REMOTE_PORT`` | ||||||
| transparent path yet -- build a :class:`cuopt.routing.DataModel` and solve it | ||||||
| with :class:`cuopt.grpc.routing.RoutingClient`, an explicit client (host and | ||||||
| port passed directly). | ||||||
|
|
||||||
| Start the server first:: | ||||||
|
|
||||||
| cuopt_grpc_server --port 5001 --workers 1 | ||||||
|
|
||||||
| Then:: | ||||||
|
|
||||||
| python remote_routing_demo.py | ||||||
| """ | ||||||
|
|
||||||
| import numpy as np | ||||||
| from cuopt import routing | ||||||
| from cuopt.grpc.routing import RoutingClient | ||||||
|
|
||||||
| dm = routing.DataModel(5, 2) | ||||||
| cost_matrix = np.array( | ||||||
| [ | ||||||
| [0, 1, 2, 2, 1], | ||||||
| [1, 0, 1, 2, 2], | ||||||
| [2, 1, 0, 1, 2], | ||||||
| [2, 2, 1, 0, 1], | ||||||
| [1, 2, 2, 1, 0], | ||||||
| ], | ||||||
| dtype=np.float32, | ||||||
| ) | ||||||
| dm.add_cost_matrix(cost_matrix) | ||||||
|
|
||||||
| client = RoutingClient("localhost", 5001) | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Force plain TCP for the plain-server example. The documented server starts without TLS, but this call leaves As per path instructions, documentation examples must be accurate and consistent. Proposed fix-client = RoutingClient("localhost", 5001)
+client = RoutingClient("localhost", 5001, tls=False)📝 Committable suggestion
Suggested change
🤖 Prompt for AI AgentsSource: Path instructions |
||||||
| solution = client.solve(dm, {"time_limit": 5.0}) | ||||||
|
|
||||||
| print("Status: ", solution["status_message"]) | ||||||
| print("Vehicles: ", solution["vehicle_count"]) | ||||||
| print("Objective: ", solution["total_objective_value"]) | ||||||
| print("Route: ", solution["route"]) | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,138 @@ | ||
| .. | ||
| SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| ============================= | ||
| VRP gRPC Client (Routing) | ||
| ============================= | ||
|
|
||
| ``cuopt.grpc.routing.RoutingClient`` is an explicit gRPC client for solving | ||
| **VRP** (vehicle routing, including TSP and PDP) problems on | ||
| ``cuopt_grpc_server``. It uses the same job lifecycle as the LP/MIP | ||
| :doc:`Python async gRPC client <python-async-client>`: **submit** → **wait** | ||
| → **result** → **delete**, plus a **solve** convenience method that does all | ||
| four. | ||
|
|
||
| There is no ``CUOPT_REMOTE_HOST``/``CUOPT_REMOTE_PORT`` transparent path for | ||
| routing yet (unlike LP/MIP/QP) -- always construct ``RoutingClient`` with an | ||
| explicit host and port. See :ref:`Limitations and Roadmap | ||
| <cuopt-grpc-routing-limitations>` below. | ||
|
|
||
| Prerequisites | ||
| ============= | ||
|
|
||
| A running ``cuopt_grpc_server`` on a GPU host (see :doc:`quick-start`): | ||
|
|
||
| .. code-block:: bash | ||
|
|
||
| cuopt_grpc_server --port 5001 --workers 1 | ||
|
|
||
| Connect and Solve | ||
| ================== | ||
|
|
||
| ``RoutingClient(host, port, *, tls=None)`` takes the same arguments as the | ||
| LP/MIP client's ``Client(host, port, tls=...)``; see :doc:`python-async-client` | ||
| for the ``tls`` options. | ||
|
Comment on lines
+33
to
+35
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- applicable repository conventions ---'
find /tmp/coderabbit-repo-knowledge/nvidia-cuopt-f5e5051e -type f -name '*.md' -print
printf '%s\n' '--- relevant documentation and example ---'
cat -n docs/cuopt/source/cuopt-grpc/routing.rst | sed -n '20,45p'
cat -n docs/cuopt/source/cuopt-grpc/advanced.rst | sed -n '115,140p'
cat -n docs/cuopt/source/cuopt-grpc/examples/remote_routing_demo.py | sed -n '25,45p'
printf '%s\n' '--- RoutingClient definitions and direct uses ---'
rg -n -C 5 'class RoutingClient|def __init__|RoutingClient\(' python docs/cuopt/source/cuopt-grpc --glob '*.py' --glob '*.rst'
printf '%s\n' '--- focused diff ---'
git diff -- docs/cuopt/source/cuopt-grpc/routing.rst docs/cuopt/source/cuopt-grpc/advanced.rst docs/cuopt/source/cuopt-grpc/examples/remote_routing_demo.pyRepository: NVIDIA/cuopt Length of output: 50368 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- documentation convention ---'
cat /tmp/coderabbit-repo-knowledge/nvidia-cuopt-f5e5051e/conventions/docs.md
printf '%s\n' '--- relevant learning ---'
cat /tmp/coderabbit-repo-knowledge/nvidia-cuopt-f5e5051e/learnings/python-cuopt-cuopt-routing.md
printf '%s\n' '--- grpc routing files ---'
fd -t f -i 'routing' python/cuopt | sort
printf '%s\n' '--- grpc routing module outline and implementation ---'
find python/cuopt -path '*grpc*' -type f -maxdepth 8 -print | sort
rg -n -C 8 'class RoutingClient|RoutingClient\s*=|def __init__' python/cuopt/cuopt/grpc python/cuopt/cuopt/tests/routing --glob '*.py'
printf '%s\n' '--- exact working-tree diff summary and focused diff ---'
git diff --stat
git diff --unified=15 -- docs/cuopt/source/cuopt-grpc/routing.rst docs/cuopt/source/cuopt-grpc/advanced.rst docs/cuopt/source/cuopt-grpc/examples/remote_routing_demo.pyRepository: NVIDIA/cuopt Length of output: 3573 🏁 Script executed: #!/bin/bash
set -u
printf '%s\n' '--- RoutingClient implementation ---'
wc -l python/cuopt/cuopt/grpc/routing/grpc_client.py python/cuopt/cuopt/tests/routing/test_routing_grpc_client.py
cat -n python/cuopt/cuopt/grpc/routing/grpc_client.py | sed -n '1,220p'
printf '%s\n' '--- routing test constructors ---'
cat -n python/cuopt/cuopt/tests/routing/test_routing_grpc_client.py | sed -n '1,90p'
printf '%s\n' '--- import/export chain ---'
cat -n python/cuopt/cuopt/grpc/routing/__init__.py
cat -n python/cuopt/cuopt/grpc/__init__.py | sed -n '1,120p'
printf '%s\n' '--- focused diff ---'
git diff --stat
git diff --unified=12 -- docs/cuopt/source/cuopt-grpc/routing.rst docs/cuopt/source/cuopt-grpc/advanced.rst docs/cuopt/source/cuopt-grpc/examples/remote_routing_demo.pyRepository: NVIDIA/cuopt Length of output: 5558 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- compiled client definitions ---'
rg -n -C 12 'RoutingClient|tls|host.*port|port.*host' python/cuopt/cuopt/grpc/client python/cuopt/cuopt/grpc --glob '*.pyx' --glob '*.pxd' --glob '*.py'
printf '%s\n' '--- client extension outline ---'
ast-grep outline python/cuopt/cuopt/grpc/client/grpc_client.pyx --view compact
printf '%s\n' '--- relevant compiled-client sections ---'
rg -n '^(cdef class|class| def| cdef| cpdef)|RoutingClient|__init__' python/cuopt/cuopt/grpc/client/grpc_client.pyxRepository: NVIDIA/cuopt Length of output: 47283 Merge the
📍 Affects 3 files
🤖 Prompt for AI AgentsSource: MCP tools |
||
|
|
||
| ``RoutingClient.submit()`` accepts a :class:`cuopt.routing.DataModel` built | ||
| the same way as for a local :func:`cuopt.routing.Solve`. ``solve()`` submits, | ||
| waits, and deletes the job's server-side state when done (pass | ||
| ``delete=False`` to keep it around for a later ``result()`` call). | ||
|
|
||
| :download:`remote_routing_demo.py <examples/remote_routing_demo.py>` | ||
|
|
||
| .. literalinclude:: examples/remote_routing_demo.py | ||
| :language: python | ||
| :linenos: | ||
|
|
||
| Job Lifecycle | ||
| ============= | ||
|
|
||
| * ``submit(data_model, settings=None)`` — serializes the problem and settings, returns a ``job_id``. | ||
| * ``wait(job_id, timeout=0)`` — blocks until the job reaches a terminal state; returns the status. | ||
| * ``result(job_id)`` — returns the solution dict, or ``None`` if the job has not finished. | ||
| * ``delete(job_id)`` — releases the job's server-side result. | ||
| * ``solve(data_model, settings=None, *, timeout=0, delete=True)`` — submit + wait + result, deleting the job afterward unless ``delete=False``. | ||
|
|
||
| A failed or non-completed job raises ``RoutingSolveError`` from ``submit``, | ||
| ``wait``, or ``solve``. | ||
|
|
||
| Settings | ||
| ======== | ||
|
|
||
| ``settings`` accepts a ``dict`` or a :class:`cuopt.routing.SolverSettings`. | ||
| Today only ``time_limit`` is forwarded to the remote solve; other | ||
| ``SolverSettings`` options (``verbose``, ``error_logging``, | ||
| ``dump_best_results_path``/``interval``) are not yet mapped over gRPC (see | ||
| :ref:`Limitations and Roadmap <cuopt-grpc-routing-limitations>`). A ``dict`` | ||
| key other than ``time_limit`` is silently ignored rather than raising an | ||
| error. | ||
|
|
||
| Solution Fields | ||
| ================ | ||
|
|
||
| ``result()`` and ``solve()`` return a ``dict`` with the same fields as a | ||
| local :class:`cuopt.routing.Assignment`, read directly off the wire: | ||
|
|
||
| .. list-table:: | ||
| :header-rows: 1 | ||
|
|
||
| * - Key | ||
| - Description | ||
| * - ``status`` / ``status_message`` | ||
| - Integer and human-readable solve status. | ||
| * - ``error_message`` | ||
| - Set when the solve failed. | ||
| * - ``vehicle_count`` | ||
| - Number of vehicles used. | ||
| * - ``total_objective_value`` / ``objective_values`` | ||
| - Overall cost and the per-objective breakdown. | ||
| * - ``route``, ``truck_id``, ``locations``, ``node_types``, ``arrival_stamp`` | ||
| - Per-stop route arrays, one entry per stop across all vehicles. | ||
| * - ``unserviced_nodes`` | ||
| - Orders that could not be served. | ||
| * - ``accepted`` | ||
| - Orders accepted, for prize-collection problems. | ||
|
|
||
| .. _cuopt-grpc-routing-limitations: | ||
|
|
||
| Limitations and Roadmap | ||
| ========================= | ||
|
|
||
| * **No transparent remote execution** — routing does not read | ||
| ``CUOPT_REMOTE_HOST``/``CUOPT_REMOTE_PORT``; always pass host and port to | ||
| ``RoutingClient`` explicitly. Tracked in `#1633 | ||
| <https://github.com/NVIDIA/cuopt/issues/1633>`_. | ||
| * **Settings surface** — only ``time_limit`` is forwarded today. Tracked in | ||
| `#1632 <https://github.com/NVIDIA/cuopt/issues/1632>`_. | ||
| * **No 2 GiB chunking** — VRP is unary-only; a cost/transit matrix or | ||
| ``RoutingSolution`` that exceeds the gRPC max message size cannot be sent | ||
| or retrieved (the LP/MIP client chunks automatically). Tracked in `#1629 | ||
| <https://github.com/NVIDIA/cuopt/issues/1629>`_. | ||
| * **No log or incumbent streaming** — unlike the LP/MIP client, there is no | ||
| ``start_log_stream``/``start_incumbent_stream`` equivalent yet. Tracked in | ||
| `#1630 <https://github.com/NVIDIA/cuopt/issues/1630>`_. | ||
| * **Input validation** — malformed problems may fail late or with a generic | ||
| error rather than an early, descriptive one. Tracked in `#1631 | ||
| <https://github.com/NVIDIA/cuopt/issues/1631>`_. | ||
|
|
||
| API Reference | ||
| ============= | ||
|
|
||
| Import path: ``cuopt.grpc.routing``. | ||
|
|
||
| .. autoclass:: cuopt.grpc.routing.RoutingClient | ||
| :members: | ||
| :undoc-members: | ||
|
|
||
| .. autoexception:: cuopt.grpc.routing.RoutingSolveError | ||
| :members: | ||
| :show-inheritance: | ||
|
|
||
| See Also | ||
| ======== | ||
|
|
||
| * :doc:`index` — when to use gRPC vs. the REST self-hosted server | ||
| * :doc:`python-async-client` — the LP/MIP/QP equivalent client | ||
| * :doc:`api` — how VRP rides ``CuOptRemoteService``'s RPCs | ||
| * :doc:`../cuopt-python/routing/index` — the local routing Python API | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Update the remaining LP/MIP-only API summary.
The new VRP text states that routing uses
SubmitJoband routing-specific protobufs. However, theSubmitJobrow at Line 38 still says that it submits only LP or MIP jobs, and the source-file list at Lines 11-12 omits the routing protobufs named here. Update both references so custom integrators receive one consistent wire-contract description.As per path instructions, documentation changes must meet the accuracy and completeness requirements for API changes.
Proposed documentation update
📝 Committable suggestion
🤖 Prompt for AI Agents
Source: Path instructions