Skip to content

Follow-up for LP format#1251

Merged
rapids-bot[bot] merged 35 commits into
NVIDIA:release/26.06from
Iroy30:python-read-mps-lp
May 22, 2026
Merged

Follow-up for LP format#1251
rapids-bot[bot] merged 35 commits into
NVIDIA:release/26.06from
Iroy30:python-read-mps-lp

Conversation

@Iroy30
Copy link
Copy Markdown
Member

@Iroy30 Iroy30 commented May 20, 2026

Description

Deprecates Problem.readMPS and adds unified Problem.read for MPS and LP file formats.
Renaming

Layer Before After
C++ cuopt::linear_programming::io::parse_problem cuopt::linear_programming::io::read
C++ parse_mps read_mps
C++ parse_lp read_lp
C++ parse_mps_from_string read_mps_from_string
C++ parse_lp_from_string read_lp_from_string
Cython bridge cuopt::cython::call_parse_problem cuopt::cython::call_read
Python cuopt.linear_programming.ParseProblem cuopt.linear_programming.Read
Python cuopt.linear_programming.io.ParseProblem cuopt.linear_programming.io.Read

Follows after #1120

Issue

Checklist

  • I am familiar with the Contributing Guidelines.
  • Testing
    • New or existing tests cover these changes
    • Added tests
    • Created an issue to follow-up
    • NA
  • Documentation
    • The documentation is up to date with these changes
    • Added new documentation
    • NA

mlubin and others added 20 commits May 15, 2026 20:58
cuOptReadProblem, cuopt_cli, the Python ParseLp() wrapper, and the
self-hosted client now dispatch on the input filename: a case-insensitive
".lp" suffix routes to a new LP parser; everything else (including .mps,
.mps.gz, .mps.bz2, and extensionless inputs) continues to use parse_mps.

The LP parser supports LP, MIP, and QP problems in the conventional LP
dialect used by most commercial solvers (not the lpsolve variant). SOS,
PWL, semi-continuous, user-cut, and general-constraint sections raise a
ValidationError rather than silently mis-parsing. Quadratic-constraint
support (QCMATRIX) remains MPS-only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Miles Lubin <mlubin@nvidia.com>
The error message in cuopt_self_host_client.py was updated to say "MPS/LP
data" alongside the LP reader changes, but the matching assertion in
test_self_hosted_service.sh was not, causing CLI test 7 to fail.

Signed-off-by: Miles Lubin <mlubin@nvidia.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
parse_linear_expression silently accepted two malformed inputs:
- '2 [ x^2 ] / 2' parsed as objective_offset=2 plus quadratic x^2,
  rather than rejecting the unsupported scalar-multiplication-of-bracket
  form. Same shape occurs in quadratic constraint rows.
- '<number> *' followed by a relation, section header, or EOL silently
  dropped the '*' and turned the number into a bare constant.

Both now raise a ValidationError pointing at the offending line. Added
tests for both malformed forms plus the legitimate forms ('5 + [...]/2'
and '3 * x') to pin the boundary.

Signed-off-by: Miles Lubin <mlubin@nvidia.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
parser_finalize.hpp was designed as a shared finalization template but
only the LP parser ever called it; MPS keeps its own fill_problem.
Move the implementation into lp_parser.cpp's anonymous namespace
alongside flush_quadratic_constraints, since both serve the same caller
and run consecutively.

While inlining, drop the dormant requires-expression branches for
objective_scaling_factor_value, ranges_values, and qmatrix_entries —
none of these fields exist on lp_parser_t. The Parser template
parameter becomes a concrete lp_parser_t<i_t, f_t>&.

No behavior change for any caller.

Signed-off-by: Miles Lubin <mlubin@nvidia.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two block-level comments were framed in terms of how this PR rearranged
the code ("MPS-only tests preserved from mps_parser_test.cpp", "Extracted
from ParseMps"). Replace with descriptions of what the code actually does
today, independent of the refactor that produced it.

The MPS-only test header also incorrectly claimed the LP parser doesn't
support semi-continuous variables or quadratic constraints — it does;
those tests are preserved because they exercise MPS-specific syntax
(bound codes, QCMATRIX blocks), not because LP lacks the semantics.

Signed-off-by: Miles Lubin <mlubin@nvidia.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The 3-token 'Semi - Continuous' form was the only spelling recognized,
but both Gurobi and CPLEX LP-format references explicitly list bare
'Semi' and 'Semis' as documented synonyms:

  Gurobi: "Valid keywords for variable type headers are: binary,
          binaries, bin, general, generals, gen, semi-continuous,
          semis, or semi."
  CPLEX:  "The SEMI-CONTINUOUS section is preceded by the keyword
          SEMI-CONTINUOUS, SEMI, or SEMIS."

Accepted spellings (case-insensitive) are now: 'Semi-Continuous',
'Semi', and 'Semis'.

Signed-off-by: Miles Lubin <mlubin@nvidia.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cuOpt's set_quadratic_objective_matrix symmetrizes internally via
H = Q + Q^T before solving (1/2) x^T H x, so the parser does not need
to materialize the full symmetric Q. Switch the quadratic-objective
path to:

  parse_quadratic_bracket: apply LP's '/ 2' uniformly to diagonal and
  off-diagonal entries (instead of only halving off-diagonals).

  finalize_problem: emit the upper-triangular quadobj_entries as CSR
  directly (drop the mirror pass and the post-scale by 0.5).

End-to-end PDLP tests (cpp/tests/qp/unit_tests/lp_parser_solve_test.cu)
parse three small QP files (diagonal, positive cross term, negative
cross term) and verify objective values and primal solutions against
hand-computed optima.

Quadratic constraints are NOT changed: cuOpt's set_quadratic_constraints
does not symmetrize, so per-constraint Q must remain fully symmetric.
The MPS parser is also unchanged. LP and MPS now store the quadratic
objective in different equivalent forms (upper-tri vs full-sym × 0.5)
in mps_data_model_t; both produce the same H after cuOpt's symmetrize
step.

Signed-off-by: Miles Lubin <mlubin@nvidia.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per Gurobi's LP-format reference, the bracket reserved for the quadratic
portion of an objective or constraint expression accepts only squared
terms (e.g., '2 x ^ 2') and product terms (e.g., '3 x * y'). HiGHS's LP
reader (highs/io/filereaderlp/reader.cpp) likewise rejects anything
other than those four forms. The parser previously accepted bare linear
terms like '2 x' inside the bracket and folded them into the row's
linear part — an extension not supported by any LP reader I could find
documentation or source for. Tighten the parser to reject this and
prune the now-dead out_linear plumbing from parse_quadratic_bracket and
its two call sites.

One existing test (qc_outer_minus_sign_flips_quadratic_and_linear) used
the rejected form to verify outer-sign propagation. Rewrite it to use
the conventional spelling with the linear term outside the bracket, and
add two negative tests that pin the new rejection (one in objective,
one in constraint).

Signed-off-by: Miles Lubin <mlubin@nvidia.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Inline source comments and public docstrings shouldn't single out specific
solver vendors when describing LP-format conventions. Rephrase each spot
to describe the rule itself instead — the conventions are the same
whether or not a particular product is named.

Signed-off-by: Miles Lubin <mlubin@nvidia.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The argparse help string for the positional filename argument said only
"input MPS or LP file (dispatched by .lp / .mps extension)", which both
underspecified the supported set and omitted .qps and the compressed
variants. Update it to enumerate every extension parse_problem() accepts.

Signed-off-by: Miles Lubin <mlubin@nvidia.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The test wrote a temp .lp file and called cuOptReadProblem; cleanup
(cuOptDestroyProblem and std::filesystem::remove) ran only at the end
of the test body, so an assertion failure mid-test would leak both the
problem handle and the temp file. Introduce a small RAII guard whose
destructor unconditionally destroys the handle (if non-null) and removes
the temp file, so cleanup runs on every exit path.

std::filesystem::remove is called with std::error_code to avoid throwing
during stack unwinding.

Signed-off-by: Miles Lubin <mlubin@nvidia.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dispatch_parse() writes content to a temp file, then calls
parse_problem(tmp.string()), then removes the temp file. If
parse_problem throws (the unrecognized-extension test exercises exactly
this path), the std::filesystem::remove call is skipped and the file
leaks.

Replace the manual post-parse remove with an RAII guard whose destructor
removes the file on every scope exit — success, return, or exception.
std::error_code is passed to remove so the destructor never throws
during stack unwinding while a parse exception is propagating.

Signed-off-by: Miles Lubin <mlubin@nvidia.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ariants

The two extension-routing blocks in cuopt_self_host_client.py only
recognized literal '.lp' and '.mps' suffixes — '.qps' and the compressed
variants (.lp.gz, .lp.bz2, .mps.gz, .mps.bz2, .qps.gz, .qps.bz2) fell
through to the unparsed-upload path even though the underlying
mps_parser.ParseMps / ParseLp accept all of them via the same C++
file_to_string dispatch as the CLI.

Factor the extension check into a small helper that lowercases the path
and strips a single .gz / .bz2 compression suffix before matching, then
use it in both _parse_file_to_data_model (which picks ParseLp vs
ParseMps) and read_cuopt_problem_data (which decides whether to parse
client-side or ship to the server). QPS routes to ParseMps; that matches
the C++ parse_problem() dispatch table.

Signed-off-by: Miles Lubin <mlubin@nvidia.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The cuopt.linear_programming.mps_parser package now exposes both
ParseMps and ParseLp, so 'mps_parser' is no longer accurate. Rename
the directory to 'io' (mirroring the cpp/include/cuopt/linear_programming/io/
layout on the C++ side) and rename the decorator
catch_mps_parser_exception → catch_io_exception.

This package was added on this branch in 72ba054 (post-26.04) and has
not appeared in any release, so the rename is safe without a
compatibility shim.

Importing files that previously did 'from cuopt.linear_programming
import mps_parser' now import 'io as mps_parser' to keep the local
binding stable; user-facing docs/examples and the public top-level
import in cuopt/linear_programming/__init__.py use the new module
name directly. The C++ error tag MPS_PARSER_ERROR_TYPE that the
decorator parses out of RuntimeError messages is intentionally
unchanged — that tag is produced by the mps_parser_expects() macro,
which is shared between both parsers on the C++ side and would have
a much larger blast radius to rename.

Signed-off-by: Miles Lubin <mlubin@nvidia.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Annotate ParseLp with `lp_file_path: str` and `-> DataModel`, importing
DataModel from cuopt.linear_programming.data_model so the annotation
resolves at runtime.

The old docstring claimed unsupported-section input raises ValueError;
in practice the catch_io_exception decorator translates the C++
parser's tagged RuntimeError into typed Python exceptions
(InputValidationError / InputRuntimeError / OutOfMemoryError). Replace
the misleading sentence with a proper Raises section listing all three
typed exceptions and the conditions that trigger them.

Also expand the lp_file_path parameter description to mention the
compressed-input variants the parser accepts, and trim the Returns
phrasing so it points at lp_file_path explicitly.

Signed-off-by: Miles Lubin <mlubin@nvidia.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The mps_roundtrip and lp_roundtrip tests each used a fixed shared
/tmp path (e.g. /tmp/mps_roundtrip_lp_test.mps) and removed it
manually at the end of the test. Two problems:

  1. Parallel test runs writing to the same path race each other.
  2. An assertion failure or exception between write and remove
     leaks the file.

Add a small temp_file_t RAII helper that picks a unique path under
std::filesystem::temp_directory_path() using pid + an atomic counter,
and removes the file on every scope exit (std::error_code so the
destructor never throws). Adopt it in every test that previously
spelled a literal /tmp/*.mps path (the six mps/lp roundtrip tests and
the QCQP-QC1 roundtrip), and use it inside dispatch_parse too,
replacing the existing inline cleanup_t scope guard.

Signed-off-by: Miles Lubin <mlubin@nvidia.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The "This example demonstrates how to" bullet pointed at the package
path cuopt.linear_programming.io after the recent rename, but the
example code calls ParseMps directly (imported from the public
top-level). Update the bullet to name the actual function so the
prose matches the sample.

Signed-off-by: Miles Lubin <mlubin@nvidia.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The C API entry point previously dereferenced filename via
std::string(filename) without a null check and stored into *problem_ptr
without a null check on the out-pointer. A null filename would segfault
inside libstdc++'s string constructor, and a null problem_ptr would
segfault on assignment; an empty filename would advance into the
generic file-not-found / parse-error paths.

Validate filename != nullptr && filename[0] != '\0' && problem_ptr !=
nullptr up front, return CUOPT_INVALID_ARGUMENT immediately on
failure, and (importantly) skip the `new problem_and_stream_view_t`
allocation that would otherwise leak when the validation fails. The
existing parser exception path already handles cleanup for non-null
inputs.

Document the new return code on the public header docstring and add a
test (c_api.read_problem_null_or_empty_inputs_rejected) covering all
three invalid combinations.

Signed-off-by: Miles Lubin <mlubin@nvidia.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Expose parse_problem via Cython with fixed_mps_format support, add
Problem.read(), deprecate readMPS, and migrate callers/tests/docs from
ParseMps/ParseLp. Extend self-hosted CI and server examples for LP and
compressed inputs.

Co-authored-by: Cursor <cursoragent@cursor.com>
@Iroy30 Iroy30 requested review from a team as code owners May 20, 2026 00:19
@copy-pr-bot
Copy link
Copy Markdown

copy-pr-bot Bot commented May 20, 2026

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds LP parsing and a unified ParseProblem dispatcher (case-insensitive .mps/.qps/.lp, including .gz/.bz2) across C++ headers, Cython bindings, Python APIs (ParseProblem, Problem.read), self-hosted client parsing, tests, and documentation/examples.

Changes

Unified Problem File Parser with Extension-Based Dispatch

Layer / File(s) Summary
C++ LP parser and unified dispatch entry point
cpp/include/cuopt/linear_programming/io/parser.hpp, cpp/include/cuopt/linear_programming/io/utilities/cython_parser.hpp, cpp/src/io/utilities/cython_parser.cpp
Adds parse_lp(...) and parse_lp_from_string(...) templates and an inline parse_problem(...) that lowercases the path, dispatches to parse_mps for MPS/QPS or parse_lp for LP, and throws std::logic_error for unknown suffixes; updates Cython utility declaration and wrapper.
Cython externs and wrapper
python/cuopt/cuopt/linear_programming/io/parser.pxd, python/cuopt/cuopt/linear_programming/io/parser_wrapper.pyx
Replaces call_parse_mps/call_parse_lp externs with call_parse_problem, updates parser_wrapper to call call_parse_problem and marshal a full DataModel via _marshal_data_model.
Python module API and user interface
python/cuopt/cuopt/linear_programming/__init__.py, python/cuopt/cuopt/linear_programming/io/__init__.py, python/cuopt/cuopt/linear_programming/io/parser.py, python/cuopt/cuopt/linear_programming/problem.py, python/cuopt/cuopt/linear_programming/solver/solver.py
Re-exports ParseProblem; adds ParseProblem wrapper and Problem.read(file_path, fixed_mps_format=False) with validation and file-existence check; deprecates Problem.readMPS() to delegate to read; updates docstrings/examples to reference ParseProblem.
Self-hosted client file parsing
python/cuopt_self_hosted/cuopt_sh_client/cuopt_self_host_client.py
Adds helpers to strip .gz/.bz2, detect case-insensitive .lp/.mps/.qps, implements _parse_file_to_data_model using ParseProblem+toDict, and refactors get_LP_solve to conditionally parse inputs and reject local-file mode for client-parsed files.
Core parser tests
python/cuopt/cuopt/tests/linear_programming/test_parser.py
Switches tests to ParseProblem and adds LP parsing coverage (inline LP file), unsupported LP-section checks (SOS), LP/MPS equivalence checks, and extension-dispatch/error tests.
Integration test updates
python/cuopt/... tests, regression/benchmark_scripts/utils.py, python/libcuopt/libcuopt/tests/test_cli.sh
Updates many tests and utilities to use ParseProblem instead of mps_parser.ParseMps; expands CLI/CI tests to include .lp, .lp.gz, .lp.bz2, and compressed MPS variants; updates benchmark utility to call ParseProblem.
Documentation and examples
docs/cuopt/source/... and example scripts
Docs updated to document ParseProblem dispatch, added LP datamodel example lp_datamodel_example.py, updated MPS example to ParseProblem, added parser usage example, and updated API docs to include cuopt.linear_programming.io.ParseProblem.

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.63% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Follow-up for LP format' is too vague and generic. It does not clearly convey the main changes: deprecating Problem.readMPS and adding a unified Problem.read API. Consider a more specific title like 'Deprecate Problem.readMPS and add unified Problem.read for MPS/LP formats' to better describe the primary change.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The pull request description clearly describes the changes made: deprecating Problem.readMPS, adding unified Problem.read for both MPS and LP formats, and provides a comprehensive renaming table across C++, Cython, and Python layers.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread python/cuopt/cuopt/tests/linear_programming/test_lp_solver.py Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
python/cuopt/cuopt/tests/linear_programming/test_python_API.py (1)

342-355: ⚡ Quick win

Add compressed-input coverage for Problem.read.

This test validates .mps and .lp, but the new dispatch path also includes compressed extensions. Adding one .lp.gz/.lp.bz2 assertion here would better protect the new behavior.

As per coding guidelines, "python/**/tests/**: Focus on ... Edge cases" and this new path includes compressed-extension variants.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/cuopt/cuopt/tests/linear_programming/test_python_API.py` around lines
342 - 355, The test test_problem_read_mps_and_lp only checks .mps and .lp but
misses compressed-extension handling; update this test to also call Problem.read
on a compressed variant (e.g., change lp_path to lp_path + ".gz" or use a
separate lp_gz_path with ".lp.gz" or ".lp.bz2"), read it via Problem.read, and
assert the same properties (NumVariables == 2 and the VariableName set equals
{"VAR1", "VAR2"}) as done for lp_problem and mps_problem so the compressed
dispatch path is covered; reference the test name test_problem_read_mps_and_lp
and the Problem.read call to locate where to add the extra assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@python/cuopt/cuopt/linear_programming/io/parser.py`:
- Line 49: The new public function toDict(model, json=False) is missing type
hints and a complete API docstring; add annotations (e.g., def toDict(model:
Any, json: bool = False) -> Dict[str, Any]) using typing imports and document
params, returns and raises in the docstring for toDict, describing the expected
type/shape of model, the json flag behavior, the returned dictionary (or
JSON-serializable structure), and any exceptions raised (TypeError/ValueError if
input is invalid); update imports to include typing symbols used and ensure the
docstring follows project docstyle for public APIs.

---

Nitpick comments:
In `@python/cuopt/cuopt/tests/linear_programming/test_python_API.py`:
- Around line 342-355: The test test_problem_read_mps_and_lp only checks .mps
and .lp but misses compressed-extension handling; update this test to also call
Problem.read on a compressed variant (e.g., change lp_path to lp_path + ".gz" or
use a separate lp_gz_path with ".lp.gz" or ".lp.bz2"), read it via Problem.read,
and assert the same properties (NumVariables == 2 and the VariableName set
equals {"VAR1", "VAR2"}) as done for lp_problem and mps_problem so the
compressed dispatch path is covered; reference the test name
test_problem_read_mps_and_lp and the Problem.read call to locate where to add
the extra assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: c4a58e33-4aac-48b7-9fef-fc05a3b5c445

📥 Commits

Reviewing files that changed from the base of the PR and between 9f994d6 and 7d802b1.

📒 Files selected for processing (10)
  • cpp/src/io/utilities/cython_parser.cpp
  • docs/cuopt/source/cuopt-cli/cli-examples.rst
  • docs/cuopt/source/cuopt-python/lp-qp-milp/lp-qp-milp-api.rst
  • docs/cuopt/source/cuopt-server/examples/lp-examples.rst
  • docs/cuopt/source/cuopt-server/examples/lp/examples/mps_datamodel_example.py
  • python/cuopt/cuopt/linear_programming/io/parser.py
  • python/cuopt/cuopt/tests/linear_programming/test_cpu_only_execution.py
  • python/cuopt/cuopt/tests/linear_programming/test_lp_solver.py
  • python/cuopt/cuopt/tests/linear_programming/test_python_API.py
  • python/libcuopt/libcuopt/tests/test_cli.sh
💤 Files with no reviewable changes (2)
  • python/cuopt/cuopt/tests/linear_programming/test_cpu_only_execution.py
  • docs/cuopt/source/cuopt-server/examples/lp/examples/mps_datamodel_example.py
✅ Files skipped from review due to trivial changes (1)
  • docs/cuopt/source/cuopt-server/examples/lp-examples.rst

return parser_wrapper.ParseProblem(file_path, fixed_mps_format)


def toDict(model, json=False):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add type hints and full API docstring content for toDict.

toDict is a new public Python API and currently lacks type hints and docstring content (params/returns/raises).

Proposed patch
+from typing import Any
+
-def toDict(model, json=False):
+def toDict(model: parser_wrapper.DataModel, json: bool = False) -> dict[str, Any]:
+    """Convert a parser DataModel to a Python dictionary.
+
+    Parameters
+    ----------
+    model : parser_wrapper.DataModel
+        Parsed optimization model to serialize.
+    json : bool, default=False
+        If True, converts infinities to `"inf"`/`"ninf"` in list fields for JSON friendliness.
+
+    Returns
+    -------
+    dict[str, Any]
+        Dictionary containing matrix, bounds, objective, and variable metadata.
+
+    Raises
+    ------
+    ValueError
+        If `model` is not a `parser_wrapper.DataModel`.
+    """

As per coding guidelines, "**/*.py: Add type hints on all new public API functions and classes in Python" and "Include docstring content (params, returns, raises) on all new public Python APIs".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/cuopt/cuopt/linear_programming/io/parser.py` at line 49, The new
public function toDict(model, json=False) is missing type hints and a complete
API docstring; add annotations (e.g., def toDict(model: Any, json: bool = False)
-> Dict[str, Any]) using typing imports and document params, returns and raises
in the docstring for toDict, describing the expected type/shape of model, the
json flag behavior, the returned dictionary (or JSON-serializable structure),
and any exceptions raised (TypeError/ValueError if input is invalid); update
imports to include typing symbols used and ensure the docstring follows project
docstyle for public APIs.

@Iroy30
Copy link
Copy Markdown
Member Author

Iroy30 commented May 21, 2026

/ok to test 7d802b1

@Iroy30
Copy link
Copy Markdown
Member Author

Iroy30 commented May 21, 2026

/ok to test 1384e7b

@Iroy30 Iroy30 requested review from mlubin and removed request for kaatish and rg20 May 21, 2026 20:40
Comment thread python/cuopt/cuopt/linear_programming/problem.py
@mlubin
Copy link
Copy Markdown
Contributor

mlubin commented May 21, 2026

You may want to rebase and squash; the commit history on this PR is confusing.

Comment thread cpp/tests/routing/level0/l0_scross_test.cu Outdated
Comment thread python/cuopt/cuopt/linear_programming/io/parser.py
@Iroy30
Copy link
Copy Markdown
Member Author

Iroy30 commented May 22, 2026

/ok to test ca97a74

Copy link
Copy Markdown
Collaborator

@rgsl888prabhu rgsl888prabhu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few minor comments,rest looks good.

Comment thread docs/cuopt/source/cuopt-server/examples/lp/examples/lp_datamodel_example.py Outdated
Comment thread python/cuopt_self_hosted/cuopt_sh_client/cuopt_self_host_client.py Outdated
Iroy30 and others added 3 commits May 22, 2026 15:24
@Iroy30
Copy link
Copy Markdown
Member Author

Iroy30 commented May 22, 2026

/ok to test 89c6280

@Iroy30
Copy link
Copy Markdown
Member Author

Iroy30 commented May 22, 2026

/merge

@rapids-bot rapids-bot Bot merged commit f3dd013 into NVIDIA:release/26.06 May 22, 2026
98 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

improvement Improves an existing functionality non-breaking Introduces a non-breaking change P0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants