Skip to content

Python api performance improvement#1615

Open
Iroy30 wants to merge 2 commits into
NVIDIA:mainfrom
Iroy30:python_api_performance
Open

Python api performance improvement#1615
Iroy30 wants to merge 2 commits into
NVIDIA:mainfrom
Iroy30:python_api_performance

Conversation

@Iroy30

@Iroy30 Iroy30 commented Jul 23, 2026

Copy link
Copy Markdown
Member

Description

  • improved populate_solution slack computation. Drops ~68 ms to ~6 ms
  • Selective datamodel update depending on the data updated (as long as structure remains the same) instead of rebuild CSR and model each time. Drops ~40 ms to ~2 ms

The 100ms shave off helps in consecutive solves of portfolio problems which solve in 300-500ms.

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

Iroy30 and others added 2 commits July 20, 2026 03:46
Reduce model refresh and solution-population overhead independently of solver session persistence.

Signed-off-by: Ishika Roy <iroy@ipp1-3302.aselab.nvidia.com>
Reuse cached model structures for value-only changes and avoid redundant solution invalidation across batched updates.
@Iroy30
Iroy30 requested a review from a team as a code owner July 23, 2026 23:35
@Iroy30
Iroy30 requested a review from tmckayus July 23, 2026 23:35
@copy-pr-bot

copy-pr-bot Bot commented Jul 23, 2026

Copy link
Copy Markdown

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

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Cache-aware linear programming and benchmark

Layer / File(s) Summary
CSR cache and staleness foundation
python/cuopt/cuopt/linear_programming/problem.py
Adds typed CSR storage, cached mappings, and category-specific staleness tracking for Problem and DataModel.
Mutation invalidation and value updates
python/cuopt/cuopt/linear_programming/problem.py
Updates variable, constraint, objective, and coefficient mutations to invalidate or refresh only affected cached data.
Model refresh and solution paths
python/cuopt/cuopt/linear_programming/problem.py
Uses conditional rebuilds for solving, MPS output, and CSR access, and computes available constraint slacks through CSR multiplication.
Portfolio problem and warm updates
script_perf_eval.py
Builds a portfolio QP, schedules parameter changes, and applies objective and RHS updates for repeated solves.
Benchmark execution and validation
script_perf_eval.py
Runs baseline and session modes, parses cache profiles, validates objectives and termination, and writes benchmark artifacts.

Estimated code review effort: 4 (Complex) | ~60 minutes

Suggested labels: non-breaking, P0

Suggested reviewers: tmckayus

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is related to the changes but too generic to convey the main optimization details. Use a more specific title that mentions the Python API performance optimizations for slack computation and selective datamodel refresh.
✅ Passed checks (4 passed)
Check name Status Explanation
Description check ✅ Passed The description clearly matches the performance and selective datamodel update changes in the pull request.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (1)
script_perf_eval.py (1)

210-218: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Avoid materializing the dense diagonal matrix.

np.diag(info["D_diag"]) allocates an n×n dense array (n≈5000 ⇒ ~200 MB) on every objective evaluation just to compute x @ D @ x. Use the elementwise form.

♻️ Elementwise diagonal quadratic term
     y = info["F"].T @ x_np
     z = np.abs(x_np - info["x0"])
-    d_matrix = np.diag(info["D_diag"])
     return (
         -info["mu"] @ x_np
         + info["gamma"]
-        * (x_np @ d_matrix @ x_np + y @ info["Omega"] @ y)
+        * (x_np @ (info["D_diag"] * x_np) + y @ info["Omega"] @ y)
         + info["tc_rate"] * np.sum(z)
     )
🤖 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 `@script_perf_eval.py` around lines 210 - 218, Update the objective calculation
around the `d_matrix` expression to avoid constructing
`np.diag(info["D_diag"])`; compute the diagonal quadratic term elementwise as
the sum of `info["D_diag"]` multiplied by `x_np` squared, while preserving the
existing objective value and remaining terms.
🤖 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/problem.py`:
- Around line 2450-2457: Update Problem.solve to accept the session argument
used by script_perf_eval.py and pass it through to solver.Solve, preserving
existing settings behavior; alternatively, remove the session keyword from that
caller so the signatures remain aligned.

In `@script_perf_eval.py`:
- Line 778: Update the objective-record comparison loop over
baseline["objective_records"] and session["objective_records"] to use strict zip
semantics, ensuring differing record counts raise an error instead of silently
truncating. Preserve the existing per-record comparison logic.
- Around line 110-130: Update _capture_solver_output to drain the stderr pipe
concurrently while the yielded solve runs, using a reader thread or equivalent
that continuously consumes and stores output. Ensure cleanup restores fd 2,
waits for the reader to finish, closes descriptors, and preserves captured
output forwarding to sys.stderr.
- Around line 385-386: Initialize prob._session before the session-handling
logic in the relevant baseline/cold-session flow, ensuring it exists before
session_after_cold or any other read. Preserve the existing use_session behavior
that clears the session when enabled, and use a safe default of None for
uninitialized sessions.
- Around line 481-482: Update the Problem.solve invocation in the
_capture_solver_output block to pass only settings, removing the conditional
session keyword argument. Preserve the surrounding solver-output capture and
solution assignment behavior.

---

Nitpick comments:
In `@script_perf_eval.py`:
- Around line 210-218: Update the objective calculation around the `d_matrix`
expression to avoid constructing `np.diag(info["D_diag"])`; compute the diagonal
quadratic term elementwise as the sum of `info["D_diag"]` multiplied by `x_np`
squared, while preserving the existing objective value and remaining terms.
🪄 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: c3b79d8a-3433-4ba3-bd5c-d4c71b4790c7

📥 Commits

Reviewing files that changed from the base of the PR and between 9bba74f and 6834882.

📒 Files selected for processing (2)
  • python/cuopt/cuopt/linear_programming/problem.py
  • script_perf_eval.py

Comment on lines +2450 to +2457
if (
self.model is None
or self.constraint_csr_matrix is None
or self._stale["structure"]
):
self._to_data_model()
else:
self._refresh_data_model_values()

Copy link
Copy Markdown

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find solve() definitions and all call sites passing `session=`
ast-grep run --pattern 'def solve($$$):' --lang python python/cuopt/cuopt/linear_programming/problem.py
rg -nP '\.solve\s*\(' --type=py -g '!**/tests/**' -C1
rg -nP '\bsession\b' --type=py python/cuopt/cuopt/linear_programming/problem.py

Repository: NVIDIA/cuopt

Length of output: 150


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the solve signature and nearby implementation.
ast-grep outline python/cuopt/cuopt/linear_programming/problem.py --view expanded | sed -n '1,220p'

printf '\n--- solve signature/implementation ---\n'
rg -n "^\s*def solve\b|session\b|Solve\(" python/cuopt/cuopt/linear_programming/problem.py -n -C 3

printf '\n--- solve call sites with session kwarg ---\n'
rg -nP '\.solve\s*\(.*session\s*=' -g '!**/tests/**' -t py .

printf '\n--- _solve_one_objective definition ---\n'
rg -n "_solve_one_objective|session=" -g '!**/tests/**' -t py .

Repository: NVIDIA/cuopt

Length of output: 7291


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the benchmark caller and inspect its invocation.
fd -a "script_perf_eval.py|problem.py" .
rg -n "_solve_one_objective|prob\.solve\(" -g 'script_perf_eval.py' -g 'python/cuopt/cuopt/linear_programming/problem.py' -C 4 .

Repository: NVIDIA/cuopt

Length of output: 4821


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
import re

problem = Path("python/cuopt/cuopt/linear_programming/problem.py")
text = problem.read_text()

print("solve definitions:")
for m in re.finditer(r'^\s*def\s+solve\s*\(([^)]*)\)\s*:', text, re.M):
    start = text.count("\n", 0, m.start()) + 1
    print(start, m.group(1))

print("\nlines around solve:")
for i, line in enumerate(text.splitlines(), 1):
    if 2438 <= i <= 2470:
        print(f"{i}:{line}")

print("\ncall sites with session kwarg:")
for p in Path(".").rglob("*.py"):
    if "tests" in p.parts:
        continue
    s = p.read_text(errors="ignore")
    if ".solve(" in s and "session=" in s:
        for m in re.finditer(r'\.solve\s*\(([^)]*session\s*=)', s, re.S):
            ln = s.count("\n", 0, m.start()) + 1
            print(f"{p}:{ln}")
PY

Repository: NVIDIA/cuopt

Length of output: 1231


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find the benchmark caller and any solve invocations with session kwarg.
rg -n "_solve_one_objective|prob\.solve\(|session=" -g '*.py' .

Repository: NVIDIA/cuopt

Length of output: 3155


Align Problem.solve with its session caller.
Problem.solve still only accepts settings, but script_perf_eval.py calls it with session=..., which will raise TypeError at that path. Either add the session parameter and thread it through to solver.Solve, or drop the kwarg at the call site.

🤖 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/problem.py` around lines 2450 - 2457,
Update Problem.solve to accept the session argument used by script_perf_eval.py
and pass it through to solver.Solve, preserving existing settings behavior;
alternatively, remove the session keyword from that caller so the signatures
remain aligned.

Comment thread script_perf_eval.py
Comment on lines +110 to +130
@contextmanager
def _capture_solver_output():
"""Capture C++ solver logs written directly to stderr (fd 2)."""
read_fd, write_fd = os.pipe()
saved_stderr = os.dup(2)
capture = io.StringIO()
try:
os.dup2(write_fd, 2)
os.close(write_fd)
yield capture
finally:
os.dup2(saved_stderr, 2)
os.close(saved_stderr)
with os.fdopen(read_fd, "r", encoding="utf-8", errors="replace") as reader:
text = reader.read()
capture.write(text)
capture.seek(0)
if text:
sys.stderr.write(text)
sys.stderr.flush()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path

p = Path('script_perf_eval.py')
lines = p.read_text().splitlines()
for start, end in [(1, 170), (360, 520)]:
    print(f"\n--- {p}:{start}-{end} ---")
    for i, line in enumerate(lines[start-1:end], start):
        print(f"{i:4d}: {line}")
PY

Repository: NVIDIA/cuopt

Length of output: 13226


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path

p = Path('script_perf_eval.py')
lines = p.read_text().splitlines()

# quick structural checks
for needle in ["import threading", "_capture_solver_output", "prob.solve(", "CUOPT_CACHE_PROFILE", "_session"]:
    print(f"\n== {needle} ==")
    for i, line in enumerate(lines, 1):
        if needle in line:
            print(f"{i}: {line}")
PY

Repository: NVIDIA/cuopt

Length of output: 2710


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path

p = Path('script_perf_eval.py')
lines = p.read_text().splitlines()

print("Imports of interest:")
for needle in ["import threading", "from threading", "_capture_solver_output", "prob.solve(", "CUOPT_CACHE_PROFILE", "_session"]:
    matches = [f"{i}: {line}" for i, line in enumerate(lines, 1) if needle in line]
    if matches:
        print(f"\n{needle}")
        print("\n".join(matches))
PY

Repository: NVIDIA/cuopt

Length of output: 2683


Drain solver stderr while the solve is running. script_perf_eval.py:110-130 only reads the pipe after yield, so a verbose prob.solve() can fill the buffer, block on write(2), and hang this benchmark. Use a concurrent reader instead.

🤖 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 `@script_perf_eval.py` around lines 110 - 130, Update _capture_solver_output to
drain the stderr pipe concurrently while the yielded solve runs, using a reader
thread or equivalent that continuously consumes and stores output. Ensure
cleanup restores fd 2, waits for the reader to finish, closes descriptors, and
preserves captured output forwarding to sys.stderr.

Comment thread script_perf_eval.py
Comment on lines +385 to +386
if use_session:
prob._session = None

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm Problem initializes a `_session` attribute
fd -e py problem.py --full-path 'linear_programming' \
  | xargs rg -nP '_session' -C2

Repository: NVIDIA/cuopt

Length of output: 7174


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the portfolio problem builder and the Problem class definition that may initialize `_session`.
rg -n "def build_cuopt_portfolio_problem|class Problem|_session" script_perf_eval.py . -g '!**/.git/**' -g '!**/__pycache__/**' | sed -n '1,220p'

Repository: NVIDIA/cuopt

Length of output: 4679


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the relevant sections around run_cache_benchmark and the helper that constructs `prob`.
sed -n '340,470p' script_perf_eval.py

Repository: NVIDIA/cuopt

Length of output: 5112


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search the repository for any `_session` initialization on the portfolio problem path.
fd -a . . | sed -n '1,200p'

Repository: NVIDIA/cuopt

Length of output: 11899


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find the file that defines `build_cuopt_portfolio_problem` and inspect `_session` handling nearby.
file=$(rg -l "def build_cuopt_portfolio_problem" . -g '!**/.git/**' -g '!**/__pycache__/**' | head -n 1)
echo "FILE=$file"
if [ -n "${file:-}" ]; then
  rg -n "_session|class Problem|def build_cuopt_portfolio_problem" "$file" -C3
fi

Repository: NVIDIA/cuopt

Length of output: 6402


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for `_session` initialization in the repository, especially on portfolio-related objects.
rg -n "self\._session|_session\s*=|def build_cuopt_portfolio_problem|class Problem" . -g '!**/.git/**' -g '!**/__pycache__/**' | sed -n '1,240p'

Repository: NVIDIA/cuopt

Length of output: 1121


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the Problem class definition and any `_session` usage in the Python wrapper.
problem_file=python/cuopt/cuopt/linear_programming/problem.py
sed -n '1403,1565p' "$problem_file"
echo
rg -n "_session|session" "$problem_file" -C2

Repository: NVIDIA/cuopt

Length of output: 5758


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Look for `Problem.__init__` details and whether attributes are initialized there.
problem_file=python/cuopt/cuopt/linear_programming/problem.py
rg -n "def __init__|self\._session|session" "$problem_file" -C4

Repository: NVIDIA/cuopt

Length of output: 1853


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the top of the class methods around initialization without loading the full file.
problem_file=python/cuopt/cuopt/linear_programming/problem.py
sed -n '1403,1495p' "$problem_file"

Repository: NVIDIA/cuopt

Length of output: 3073


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the beginning of `Problem` for attribute initialization and constructor behavior.
problem_file=python/cuopt/cuopt/linear_programming/problem.py
sed -n '1403,1515p' "$problem_file"

Repository: NVIDIA/cuopt

Length of output: 3741


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for any `_session` attribute initialization on `Problem` or its base classes.
rg -n "self\._session|_session\s*=|__slots__" python/cuopt/cuopt/linear_programming -g '*.py' -g '*.pyx' -g '*.pxd' -C3

Repository: NVIDIA/cuopt

Length of output: 150


Initialize _session before reading it script_perf_eval.py:385-445 Baseline mode never assigns _session, and Problem.__init__() doesn’t create it, so session_after_cold can raise AttributeError here.

🤖 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 `@script_perf_eval.py` around lines 385 - 386, Initialize prob._session before
the session-handling logic in the relevant baseline/cold-session flow, ensuring
it exists before session_after_cold or any other read. Preserve the existing
use_session behavior that clears the session when enabled, and use a safe
default of None for uninitialized sessions.

Comment thread script_perf_eval.py
Comment on lines +481 to +482
with _capture_solver_output():
solution = prob.solve(settings, session=session if use_session else None)

Copy link
Copy Markdown

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect the current solve() signature
fd -e py problem.py --full-path 'linear_programming' \
  | xargs ast-grep run --pattern 'def solve($$$):' --lang python

Repository: NVIDIA/cuopt

Length of output: 260


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Files:\n'
git ls-files | rg '(^|/)script_perf_eval\.py$|(^|/)problem\.py$'

printf '\n--- script_perf_eval.py around the cited lines ---\n'
sed -n '460,500p' script_perf_eval.py

printf '\n--- problem.py solve definitions ---\n'
ast-grep outline python/cuopt/cuopt/linear_programming/problem.py --view expanded || true
printf '\n--- solve signatures in problem.py ---\n'
ast-grep run --pattern 'def solve($$$):' --lang python python/cuopt/cuopt/linear_programming/problem.py || true

printf '\n--- text search for session usage in problem.py ---\n'
rg -n 'session' python/cuopt/cuopt/linear_programming/problem.py || true

Repository: NVIDIA/cuopt

Length of output: 6809


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Broaden search in case the file lives elsewhere or the path differs.
git ls-files | rg 'problem\.py$|script_perf_eval\.py$' || true

# Read only the relevant file sections if present.
for f in script_perf_eval.py python/cuopt/cuopt/linear_programming/problem.py; do
  if [ -f "$f" ]; then
    printf '\n### %s ###\n' "$f"
    wc -l "$f"
    if [ "$f" = "script_perf_eval.py" ]; then
      sed -n '470,490p' "$f"
    else
      sed -n '1,260p' "$f"
    fi
  fi
done

Repository: NVIDIA/cuopt

Length of output: 7819


🌐 Web query:

site:github.com NVIDIA cuopt "class Problem" solve session cuopt/linear_programming/problem.py

💡 Result:

The file cuopt/linear_programming/problem.py is a core component of the NVIDIA cuOpt Python API for numerical optimization [1][2][3]. It defines the Problem class, which serves as the primary interface for modeling and solving linear programming (LP), quadratic programming (QP), and mixed-integer linear programming (MILP) problems [4][5][6][7]. Key functionalities provided by the Problem class and managed within this file include: Modeling: Users can construct models by adding variables (addVariable) [5], defining constraints (addConstraint) [5], and setting objectives (setObjective) [5]. The API supports algebraic modeling, allowing for intuitive definitions of constraints and objectives [4][6]. Solver Interaction: The solve method triggers the underlying GPU-accelerated optimization engine [5][6]. After solving, results can be accessed through object attributes or utility functions like getIncumbentValues [8][5][9]. File I/O: The class provides methods for reading problem files (such as those in MPS format) via ParseProblem and the read method, which has been updated to handle various file formats efficiently [3][10]. Internal Helpers: The file contains internal utility logic for algebraic representation (e.g., str and repr for model visualization), formatting expressions, and handling parameter updates (such as allowing zero-valued updates for constraints and objectives) [2][4]. For those looking to use this module, it is recommended to follow the official Python API usage patterns: from cuopt.linear_programming.problem import Problem, CONTINUOUS, MAXIMIZE from cuopt.linear_programming.solver_settings import SolverSettings # Initialize and build model problem = Problem("MyProblem") x = problem.addVariable(lb=0, vtype=CONTINUOUS, name="x") problem.addConstraint(2x <= 10, name="c1") problem.setObjective(5x, sense=MAXIMIZE) # Solve settings = SolverSettings problem.solve(settings) If you encounter issues, the NVIDIA cuOpt GitHub repository serves as the primary source for documentation, issue tracking, and examples [7][11]. Specific tasks like retrieving solutions after a solve or using callbacks are addressed within the issue tracker and pull request discussions linked to this module [8][9].

Citations:


🌐 Web query:

cuOpt linear_programming Problem.solve session parameter python cuopt problem.py

💡 Result:

In the NVIDIA cuOpt Python API for linear programming, you do not directly pass a session parameter to the Problem.solve method. Instead, you use the cuopt.linear_programming.solver_settings.SolverSettings class to configure solver parameters and then pass that object to the solve method [1][2][3]. To configure and solve a problem, follow this standard pattern: 1. Import the necessary classes [2][3]. 2. Instantiate the SolverSettings object [2][3]. 3. Use the set_parameter(name, value) method on your settings object to define specific solver configurations (such as time_limit or mip_relative_gap) [1][2]. 4. Pass this settings object to the problem.solve method [1][4][3]. Example usage: from cuopt.linear_programming.problem import Problem from cuopt.linear_programming.solver_settings import SolverSettings # Create your problem instance problem = Problem("MyProblem") #... define variables and constraints... # Configure solver settings settings = SolverSettings settings.set_parameter("time_limit", 60) settings.set_parameter("mip_relative_gap", 0.01) # Solve the problem with the configured settings problem.solve(settings) When working with these parameters, note that if you are using the Server Thin client or CLI, you generally remove the CUOPT_ prefix from parameter names and convert them to lowercase (e.g., CUOPT_TIME_LIMIT becomes time_limit) [5][6][7]. For a complete list of available parameters and their valid ranges, refer to the official cuOpt documentation under the Solver Settings section [1][7].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the exact solve method definition and body around it.
sed -n '2428,2488p' python/cuopt/cuopt/linear_programming/problem.py

printf '\n--- any other solve defs in the file ---\n'
rg -n '^(\s*)def solve\(' python/cuopt/cuopt/linear_programming/problem.py

printf '\n--- any kwargs passthrough near solve ---\n'
rg -n 'kwargs|session|lp_solve_session|_session' python/cuopt/cuopt/linear_programming/problem.py

Repository: NVIDIA/cuopt

Length of output: 1538


Remove the session= keyword here. Problem.solve only accepts settings, so this call will raise TypeError whenever use_session is true.

🤖 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 `@script_perf_eval.py` around lines 481 - 482, Update the Problem.solve
invocation in the _capture_solver_output block to pass only settings, removing
the conditional session keyword argument. Preserve the surrounding solver-output
capture and solution assignment behavior.

Comment thread script_perf_eval.py
print("Cross-process objective check (baseline vs session)")
print("=" * 50)
all_ok = True
for b_rec, s_rec in zip(baseline["objective_records"], session["objective_records"]):

Copy link
Copy Markdown

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

Add strict=True to catch record-count mismatch.

If the two processes emit a different number of objective_records, zip silently truncates and the missing entries are never compared, defeating the cross-process check. strict=True surfaces the discrepancy.

💚 Proposed fix
-    for b_rec, s_rec in zip(baseline["objective_records"], session["objective_records"]):
+    for b_rec, s_rec in zip(
+        baseline["objective_records"], session["objective_records"], strict=True
+    ):
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for b_rec, s_rec in zip(baseline["objective_records"], session["objective_records"]):
for b_rec, s_rec in zip(
baseline["objective_records"], session["objective_records"], strict=True
):
🧰 Tools
🪛 Ruff (0.15.21)

[warning] 778-778: zip() without an explicit strict= parameter

Add explicit value for parameter strict=

(B905)

🤖 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 `@script_perf_eval.py` at line 778, Update the objective-record comparison loop
over baseline["objective_records"] and session["objective_records"] to use
strict zip semantics, ensuring differing record counts raise an error instead of
silently truncating. Preserve the existing per-record comparison logic.

Source: Linters/SAST tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant