Skip to content

Implement UnboundedOrInfeasible termination status#941

Open
rg20 wants to merge 5 commits intoNVIDIA:mainfrom
rg20:issue_923
Open

Implement UnboundedOrInfeasible termination status#941
rg20 wants to merge 5 commits intoNVIDIA:mainfrom
rg20:issue_923

Conversation

@rg20
Copy link
Contributor

@rg20 rg20 commented Mar 6, 2026

Description

This PR adds a new termination enum for UnboundedOrInfeasible. This status is returned by presolvers PSLP and Papilo.

Issue

Closes #923

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

@rg20 rg20 requested review from a team as code owners March 6, 2026 17:27
@copy-pr-bot
Copy link

copy-pr-bot bot commented Mar 6, 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.

@rg20 rg20 added the bug Something isn't working label Mar 6, 2026
@rg20 rg20 added this to the 26.04 milestone Mar 6, 2026
@rg20 rg20 added the non-breaking Introduces a non-breaking change label Mar 6, 2026
@rg20
Copy link
Contributor Author

rg20 commented Mar 6, 2026

/ok to test da2b1a1

@coderabbitai
Copy link

coderabbitai bot commented Mar 6, 2026

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 a new termination status UnboundedOrInfeasible and propagates it through constants, C++ enums, presolve result types (optionals → concrete result with status and maps), solver handling, Python bindings, tests, and documentation; updates related formatting and string mappings.

Changes

Cohort / File(s) Summary
Termination Status Constant
cpp/include/cuopt/linear_programming/constants.h
Added CUOPT_TERIMINATION_STATUS_UNBOUNDED_OR_INFEASIBLE and adjusted formatting/alignment of existing status macros.
Solver Enums & Strings
cpp/include/cuopt/linear_programming/mip/solver_solution.hpp, cpp/include/cuopt/linear_programming/pdlp/solver_solution.hpp, cpp/src/mip_heuristics/solver_solution.cu, cpp/src/pdlp/solver_solution.cu
Added UnboundedOrInfeasible enum members, updated string mappings, and formatting changes in termination-status helpers.
Presolve API & Types
cpp/src/mip_heuristics/presolve/third_party_presolve.hpp, cpp/src/mip_heuristics/presolve/third_party_presolve.cpp
Added third_party_presolve_status_t; extended third_party_presolve_result_t with status and original_to_reduced_map; changed apply/apply_pslp to return concrete result objects (removed std::optional).
Presolve Consumers (MIP / PDLP)
cpp/src/mip_heuristics/solve.cu, cpp/src/pdlp/solve.cu
Replaced optional-based presolve handling with status-based branching; handle INFEASIBLE / UNBNDORINFEAS / UNBOUNDED distinctly and propagate maps/indices from result.
Presolve Helpers & Conversions
cpp/src/mip_heuristics/presolve/third_party_presolve.cpp
Added conversion helpers mapping external presolver statuses to third_party_presolve_status_t and updated control flow to return structured results carrying status and maps.
C++ Tests
cpp/tests/mip/presolve_test.cu
Updated test to use value-style access (result.reduced_problem, result.implied_integer_indices) and assert on result.status instead of optional presence.
Python Bindings
python/cuopt/cuopt/linear_programming/solver/solver.pxd, python/cuopt/cuopt/linear_programming/solver/solver_wrapper.pyx
Exposed new UnboundedOrInfeasible member in mip_termination_status_t and pdlp_termination_status_t and mapped to Python enums (MILPTerminationStatus, LPTerminationStatus).
Python Tests
python/cuopt/cuopt/tests/linear_programming/test_lp_solver.py
Added test_unbounded_problem asserting returned status UnboundedOrInfeasible; minor import reformatting.
Docs & Examples
docs/cuopt/source/cuopt-c/.../lp-qp-milp-c-api.rst, docs/cuopt/source/cuopt-c/.../examples/milp_mps_example.c, docs/.../examples/simple_qp_example.c
Documented new termination constant and example string mapping; example code now guards primal-solution retrieval and returns "Unbounded or infeasible" for the new status.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.26% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title 'Implement UnboundedOrInfeasible termination status' directly and clearly describes the main change in the changeset, which is the addition of a new UnboundedOrInfeasible termination enum across multiple layers (C, C++, and Python APIs).
Description check ✅ Passed The PR description explains the purpose ('adds a new termination enum for UnboundedOrInfeasible') and context (returned by presolvers PSLP and Papilo), and references the linked issue #923, all of which align with the changeset.
Linked Issues check ✅ Passed The PR successfully addresses issue #923 by implementing UnboundedOrInfeasible termination status across all API layers (C, C++, Python), allowing presolvers to communicate the 'infeasible or unbounded' outcome instead of collapsing it to 'infeasible', which resolves the core requirement.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the UnboundedOrInfeasible termination status. The addition of conversion helpers, result struct updates, and status handling align with the core objective. No unrelated changes detected.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

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

Tip

CodeRabbit can enforce grammar and style rules using `languagetool`.

Configure the reviews.tools.languagetool setting to enable/disable rules and categories. Refer to the LanguageTool Community to learn more.

Copy link

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cpp/src/mip_heuristics/presolve/third_party_presolve.cpp`:
- Around line 649-656: The early-return that maps Papilo presolve termination
misses papilo::PresolveStatus::kUnbounded: update the conditional that currently
checks kInfeasible || kUnbndOrInfeas to also include
papilo::PresolveStatus::kUnbounded and treat it the same as unbounded by mapping
to third_party_presolve_status_t::UNBNDORINFEAS before constructing the empty
optimization_problem_t and returning third_party_presolve_result_t; apply the
identical change to the matching pattern in apply_pslp() so kUnbounded is
handled the same way there.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2c6c62f9-8539-4496-8cb3-a00035724587

📥 Commits

Reviewing files that changed from the base of the PR and between 1c6f86b and d26c753.

📒 Files selected for processing (13)
  • cpp/include/cuopt/linear_programming/constants.h
  • cpp/include/cuopt/linear_programming/mip/solver_solution.hpp
  • cpp/include/cuopt/linear_programming/pdlp/solver_solution.hpp
  • cpp/src/mip_heuristics/presolve/third_party_presolve.cpp
  • cpp/src/mip_heuristics/presolve/third_party_presolve.hpp
  • cpp/src/mip_heuristics/solve.cu
  • cpp/src/mip_heuristics/solver_solution.cu
  • cpp/src/pdlp/solve.cu
  • cpp/src/pdlp/solver_solution.cu
  • cpp/tests/mip/presolve_test.cu
  • python/cuopt/cuopt/linear_programming/solver/solver.pxd
  • python/cuopt/cuopt/linear_programming/solver/solver_wrapper.pyx
  • python/cuopt/cuopt/tests/linear_programming/test_lp_solver.py

@rg20 rg20 requested review from chris-maes and removed request for akifcorduk and nguidotti March 6, 2026 17:35
Copy link

@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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/cuopt/source/cuopt-c/lp-qp-milp/examples/milp_mps_example.c`:
- Around line 32-33: The code unconditionally calls cuOptGetObjectiveValue and
cuOptGetPrimalSolution even for non-solution termination statuses; update the
example to check the termination status (CUOPT_TERIMINATION_STATUS_OPTIMAL,
CUOPT_TERIMINATION_STATUS_PRIMAL_FEASIBLE, or
CUOPT_TERIMINATION_STATUS_FEASIBLE_FOUND) before invoking cuOptGetObjectiveValue
and cuOptGetPrimalSolution and before printing objective/primal data; leave
other termination branches (e.g.,
CUOPT_TERIMINATION_STATUS_UNBOUNDED_OR_INFEASIBLE) to print a descriptive
message without reading solution values and ensure any existing calls to
cuOptGetObjectiveValue/cuOptGetPrimalSolution are moved inside the guarded
branch.

In `@docs/cuopt/source/cuopt-c/lp-qp-milp/lp-qp-milp-c-api.rst`:
- Line 266: Add explanatory documentation for the new
CUOPT_TERIMINATION_STATUS_UNBOUNDED_OR_INFEASIBLE by supplementing the existing
doxygendefine with a short paragraph (placed above the doxygendefine or in a
nearby "Return codes" / "Termination statuses" section) that states when the
status is returned (e.g., returned by presolvers when the solver determines the
model is either unbounded or infeasible but cannot distinguish which), what that
means for the user’s model, and recommended actions (inspect model formulation,
check bounds/constraints, try presolve diagnostics or relaxation techniques);
ensure the constant name CUOPT_TERIMINATION_STATUS_UNBOUNDED_OR_INFEASIBLE
appears verbatim in the text so it’s clear which status is being described.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e46c94d9-78f5-49b9-89d7-c5f667f1c17b

📥 Commits

Reviewing files that changed from the base of the PR and between d26c753 and da2b1a1.

📒 Files selected for processing (3)
  • docs/cuopt/source/cuopt-c/lp-qp-milp/examples/milp_mps_example.c
  • docs/cuopt/source/cuopt-c/lp-qp-milp/examples/simple_qp_example.c
  • docs/cuopt/source/cuopt-c/lp-qp-milp/lp-qp-milp-c-api.rst

.. doxygendefine:: CUOPT_TERIMINATION_STATUS_PRIMAL_FEASIBLE
.. doxygendefine:: CUOPT_TERIMINATION_STATUS_FEASIBLE_FOUND
.. doxygendefine:: CUOPT_TERIMINATION_STATUS_CONCURRENT_LIMIT
.. doxygendefine:: CUOPT_TERIMINATION_STATUS_UNBOUNDED_OR_INFEASIBLE
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add explanatory documentation for the new termination status.

The new CUOPT_TERIMINATION_STATUS_UNBOUNDED_OR_INFEASIBLE constant is documented only with a doxygendefine directive, which pulls the basic definition from the source code. However, users need context about when this status is returned and how to interpret it.

Consider adding explanatory text above the constant definition or in a dedicated section that describes:

  • When this status is returned (e.g., "Returned by presolvers when the problem is determined to be either unbounded or infeasible, but the specific outcome cannot be distinguished")
  • What it means for the user's problem
  • Recommended actions (e.g., "Review problem formulation for unboundedness or infeasibility")

As per coding guidelines: "Check if API changes (parameters, return values, errors) are documented. If PR changes public APIs without updating docs, flag as HIGH priority."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/cuopt/source/cuopt-c/lp-qp-milp/lp-qp-milp-c-api.rst` at line 266, Add
explanatory documentation for the new
CUOPT_TERIMINATION_STATUS_UNBOUNDED_OR_INFEASIBLE by supplementing the existing
doxygendefine with a short paragraph (placed above the doxygendefine or in a
nearby "Return codes" / "Termination statuses" section) that states when the
status is returned (e.g., returned by presolvers when the solver determines the
model is either unbounded or infeasible but cannot distinguish which), what that
means for the user’s model, and recommended actions (inspect model formulation,
check bounds/constraints, try presolve diagnostics or relaxation techniques);
ensure the constant name CUOPT_TERIMINATION_STATUS_UNBOUNDED_OR_INFEASIBLE
appears verbatim in the text so it’s clear which status is being described.

@rg20
Copy link
Contributor Author

rg20 commented Mar 6, 2026

/ok to test b8c02d3

Copy link

@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

♻️ Duplicate comments (1)
docs/cuopt/source/cuopt-c/lp-qp-milp/examples/milp_mps_example.c (1)

101-112: ⚠️ Potential issue | 🔴 Critical

Guard output paths when no primal solution is available.

has_primal_solution only guards retrieval, but Line 120 still prints objective_value, and Line 132-Line 135 still dereference solution_values. For statuses like UNBOUNDED_OR_INFEASIBLE, this can print uninitialized data or crash.

Proposed fix
@@
-  printf("Objective value: %f\n", objective_value);
+  if (has_primal_solution) {
+    printf("Objective value: %f\n", objective_value);
+  } else {
+    printf("Objective value: N/A\n");
+  }
@@
-  printf("\nSolution: \n");
-  for (cuopt_int_t i = 0; i < num_variables; i++) {
-    printf("x%d = %f\n", i + 1, solution_values[i]);
+  if (has_primal_solution) {
+    printf("\nSolution: \n");
+    for (cuopt_int_t i = 0; i < num_variables; i++) {
+      printf("x%d = %f\n", i + 1, solution_values[i]);
+    }
+  } else {
+    printf("\nSolution: N/A for termination status %s (%d)\n",
+           termination_status_to_string(termination_status),
+           termination_status);
   }

As per coding guidelines docs/**/*: Accuracy: Verify code examples compile and run correctly.

Also applies to: 123-130

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/cuopt/source/cuopt-c/lp-qp-milp/examples/milp_mps_example.c` around
lines 101 - 112, The example prints and dereferences solution output even when
no primal solution exists: wrap any uses of objective_value and solution_values
(including the call to cuOptGetObjectiveValue and the call that populates/reads
solution_values) behind the has_primal_solution check (the variable computed
from termination_status) so that when has_primal_solution is false you skip
printing objective_value and accessing solution_values (or print a clear "no
primal solution" message); ensure you only call cuOptGetObjectiveValue and the
function that gets solution values when has_primal_solution is true and
handle/report errors from those calls as currently done.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cpp/src/mip_heuristics/presolve/third_party_presolve.cpp`:
- Around line 479-490: The conversion functions
convert_papilo_presolve_status_to_third_party_presolve_status and
convert_pslp_presolve_status_to_third_party_presolve_status currently have
switches with no default, which can lead to UB if an unexpected enum value
appears; add a default branch to each switch that handles unknown values (e.g.,
assert or log an error) and returns a safe fallback
third_party_presolve_status_t (such as UNCHANGED or a designated UNKNOWN/ERROR
value) so the function always returns a valid enum and does not fall off the
end.

---

Duplicate comments:
In `@docs/cuopt/source/cuopt-c/lp-qp-milp/examples/milp_mps_example.c`:
- Around line 101-112: The example prints and dereferences solution output even
when no primal solution exists: wrap any uses of objective_value and
solution_values (including the call to cuOptGetObjectiveValue and the call that
populates/reads solution_values) behind the has_primal_solution check (the
variable computed from termination_status) so that when has_primal_solution is
false you skip printing objective_value and accessing solution_values (or print
a clear "no primal solution" message); ensure you only call
cuOptGetObjectiveValue and the function that gets solution values when
has_primal_solution is true and handle/report errors from those calls as
currently done.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 589ee1a2-61a7-48ef-bcb0-f9107a028231

📥 Commits

Reviewing files that changed from the base of the PR and between da2b1a1 and b8c02d3.

📒 Files selected for processing (5)
  • cpp/src/mip_heuristics/presolve/third_party_presolve.cpp
  • cpp/src/mip_heuristics/presolve/third_party_presolve.hpp
  • cpp/src/mip_heuristics/solve.cu
  • cpp/src/pdlp/solve.cu
  • docs/cuopt/source/cuopt-c/lp-qp-milp/examples/milp_mps_example.c

@rg20
Copy link
Contributor Author

rg20 commented Mar 6, 2026

/ok to test 165854c

Copy link

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cpp/src/mip_heuristics/presolve/third_party_presolve.cpp`:
- Around line 612-624: The early-return branches that construct empty
third_party_presolve_result_t (when ctx.status is INFEASIBLE/UNBNDORINFEAS and
the terminal Papilo return around 676-681) do not clear the instance-level
cached mappings/postsolve payloads (pslp_presolver_, pslp_stgs_, and the object
caches exposed by get_reduced_to_original_map()/get_original_to_reduced_map()),
causing stale mappings on reuse; fix by explicitly resetting/clearing
pslp_presolver_, pslp_stgs_ and any internal mapping/postsolve containers (or
calling the presolver's clear/reset method) before returning the empty
third_party_presolve_result_t so mappings and postsolve state are consistent for
subsequent calls.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ffb9b675-6e8a-411a-b593-3ab6ac0f0bc5

📥 Commits

Reviewing files that changed from the base of the PR and between b8c02d3 and 165854c.

📒 Files selected for processing (1)
  • cpp/src/mip_heuristics/presolve/third_party_presolve.cpp

@github-actions
Copy link

🔔 Hi @anandhkb, this pull request has had no activity for 7 days. Please update or let us know if it can be closed. Thank you!

If this is an "epic" issue, then please add the "epic" label to this issue.
If it is a PR and not ready for review, then please convert this to draft.
If you just want to switch off this notification, then use the "skip inactivity reminder" label.

@rg20
Copy link
Contributor Author

rg20 commented Mar 16, 2026

/ok to test 7eebe2b

Copy link

@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.

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

747-751: Make this test explicitly presolver-scoped and less brittle.

At Line 747, defaults are used; pinning presolve keeps this focused on the presolver regression. At Line 751, compare the enum directly instead of .name string matching.

♻️ Proposed refinement
 def test_unbounded_problem():
     problem = Problem("unbounded")
     x = problem.addVariable(lb=0.0, vtype=CONTINUOUS, name="x")
     y = problem.addVariable(lb=0.0, vtype=CONTINUOUS, name="y")

     problem.addConstraint(-1 * x + 2 * y <= 0, name="c1")

     problem.setObjective(-1 * x - 1 * y, sense=MINIMIZE)

     settings = SolverSettings()
+    settings.set_parameter(CUOPT_PRESOLVE, 1)

     problem.solve(settings)

-    assert problem.Status.name == "UnboundedOrInfeasible"
+    assert problem.Status == LPTerminationStatus.UnboundedOrInfeasible
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@python/cuopt/cuopt/tests/linear_programming/test_lp_solver.py` around lines
747 - 751, Pin the presolve mode on the SolverSettings instance used in this
test and compare the Status enum directly: set settings.presolve =
PresolveMode.ON (or the project-specific presolve enum value that enables the
presolver) before calling problem.solve(settings), and replace the string
comparison assert problem.Status.name == "UnboundedOrInfeasible" with a direct
enum comparison assert problem.Status == Status.UnboundedOrInfeasible; ensure
the test imports/uses SolverSettings, PresolveMode, and Status so the change is
explicit and presolver-scoped.
cpp/src/mip_heuristics/presolve/third_party_presolve.cpp (1)

617-620: Consider clearing cached state on early returns for defensive consistency.

When returning early due to INFEASIBLE or UNBNDORINFEAS status, the instance-level caches (papilo_post_solve_storage_, reduced_to_original_map_, original_to_reduced_map_) are not cleared. If this third_party_presolve_t instance was previously used for a successful presolve, callers accessing get_reduced_to_original_map() or get_original_to_reduced_map() could observe stale mappings from the prior run.

While undo() would not typically be called after an infeasible/unbounded result, clearing the state prevents potential confusion and aligns with the principle that the object's state should reflect the most recent apply() call. Based on learnings: Ensure variables and constraints are accessed from the correct problem context; verify index mapping consistency across problem transformations.

Suggested fix
     pslp_presolver_ = ctx.presolver;
     pslp_stgs_      = ctx.settings;
+    papilo_post_solve_storage_.reset();
+    reduced_to_original_map_.clear();
+    original_to_reduced_map_.clear();

     auto status = convert_pslp_presolve_status_to_third_party_presolve_status(ctx.status);
     if (ctx.status == PresolveStatus_::INFEASIBLE || ctx.status == PresolveStatus_::UNBNDORINFEAS) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cpp/src/mip_heuristics/presolve/third_party_presolve.cpp` around lines 617 -
620, Early-return on INFEASIBLE/UNBNDORINFEAS in
convert_pslp_presolve_status_to_third_party_presolve_status branch returns a
result without clearing instance-level caches, which can leave stale mappings;
before constructing and returning the third_party_presolve_result_t in that
branch, clear or reset papilo_post_solve_storage_, reduced_to_original_map_, and
original_to_reduced_map_ (and any other per-run caches used by apply()/undo())
so the object's state reflects the latest run and callers of
get_reduced_to_original_map()/get_original_to_reduced_map() do not see previous
mappings.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@cpp/src/mip_heuristics/presolve/third_party_presolve.cpp`:
- Around line 617-620: Early-return on INFEASIBLE/UNBNDORINFEAS in
convert_pslp_presolve_status_to_third_party_presolve_status branch returns a
result without clearing instance-level caches, which can leave stale mappings;
before constructing and returning the third_party_presolve_result_t in that
branch, clear or reset papilo_post_solve_storage_, reduced_to_original_map_, and
original_to_reduced_map_ (and any other per-run caches used by apply()/undo())
so the object's state reflects the latest run and callers of
get_reduced_to_original_map()/get_original_to_reduced_map() do not see previous
mappings.

In `@python/cuopt/cuopt/tests/linear_programming/test_lp_solver.py`:
- Around line 747-751: Pin the presolve mode on the SolverSettings instance used
in this test and compare the Status enum directly: set settings.presolve =
PresolveMode.ON (or the project-specific presolve enum value that enables the
presolver) before calling problem.solve(settings), and replace the string
comparison assert problem.Status.name == "UnboundedOrInfeasible" with a direct
enum comparison assert problem.Status == Status.UnboundedOrInfeasible; ensure
the test imports/uses SolverSettings, PresolveMode, and Status so the change is
explicit and presolver-scoped.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: aaed2208-42f9-449e-9d3f-fbb3300e0b4d

📥 Commits

Reviewing files that changed from the base of the PR and between 165854c and 7eebe2b.

📒 Files selected for processing (7)
  • cpp/include/cuopt/linear_programming/constants.h
  • cpp/src/mip_heuristics/presolve/third_party_presolve.cpp
  • cpp/src/mip_heuristics/solver_solution.cu
  • cpp/src/pdlp/solve.cu
  • cpp/src/pdlp/solver_solution.cu
  • docs/cuopt/source/cuopt-c/lp-qp-milp/lp-qp-milp-c-api.rst
  • python/cuopt/cuopt/tests/linear_programming/test_lp_solver.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • docs/cuopt/source/cuopt-c/lp-qp-milp/lp-qp-milp-c-api.rst
  • cpp/include/cuopt/linear_programming/constants.h

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

Labels

bug Something isn't working non-breaking Introduces a non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] unbounded problem solved at presolve wrongly reported infeasible

1 participant