NVIDIA / NVIDIA/cuopt

[FEA] Expose basis / variable status on the LP solution (companion to reduced costs)

Open
#1,394 2 comments 0 reactions 1 assignee View on GitHub

@chris-maes is already working on this.

Since Jun 9, 2026.

Dominant language
Cuda
Stars
1k
Forks
233
Avg merge
4d 4h
Merged PRs (30d)
95

Description

Is your feature request related to a problem? Please describe.

cuOpt's LP/QP solution exposes dual values and reduced costs, but not basis / variable status (basic vs. nonbasic-at-lower-bound vs. nonbasic-at-upper-bound). Basis status is the standard companion to reduced costs in an LP sensitivity report: it says which variables are at a bound, where a reduced cost is a meaningful "this would enter / change if its coefficient improved by X" signal, versus basic / interior, where the reduced cost is ~0. Without it, code reading get_reduced_cost() can't cleanly tell a genuine near-miss from an interior variable.

It is also the degeneracy signal: a basic variable at a bound flags a degenerate vertex, so a consumer can mark that dual directional rather than quote a non-unique number as precise. That trust-calibration is what matters most on large, degenerate models, and the prerequisite for any honest sensitivity layer.

This surfaced building solver-exact sensitivity/explainability on top of cuOpt (a downstream multi-objective decision layer): the at-bound-vs-basic distinction is load-bearing for interpreting reduced costs, and we currently reconstruct it heuristically from the primal values plus variable bounds.

Describe the solution you'd like

A public accessor on the LP solution, e.g. get_variable_status() / get_constraint_status() (C++), with C API and Python equivalents, returning a public basis-status enum (BASIC / NONBASIC_LOWER / NONBASIC_UPPER / FIXED / FREE, plus NO_BASIS when no basis exists). The data already exists internally: the dual-simplex solver computes a full basis (variable_status_t / vstatus, cpp/src/dual_simplex/initial_basis.hpp). So the work is mainly (a) a public enum, (b) plumbing vstatus from the dual-simplex result through to the public optimization_problem_solution, (c) the getter plus C API, cython bindings, and tests.

Two design points for maintainers:

  1. Public enum shape. The internal variable_status_t is {BASIC, NONBASIC_LOWER, NONBASIC_UPPER, NONBASIC_FREE, NONBASIC_FIXED, SUPERBASIC}. The call is whether to expose all of these or fold some (SUPERBASIC, or the FREE/FIXED split) into a leaner public enum.
  2. PDLP semantics. For the PDLP path the accessor should return an explicit NO_BASIS status rather than a heuristic reconstruction. Since PDLP frequently wins the concurrent race, "no basis exists" is the common case, and an honest signal there is most of the feature's value: it tells the consumer these duals are tolerance-accurate approximations, not basis-exact.

Describe alternatives you've considered

  • Reconstructing status downstream from the primal solution plus bounds (what we do now): brittle near bounds, and impossible to get right at degenerate points.
  • Inferring from reduced_cost == 0: unreliable under degeneracy (basic variables can have zero reduced cost, and vice versa).

Additional context

  • Companion to the merged skills-doc note on per-problem-type dual support: NVIDIA/cuopt#1393.
  • Basis status is the more fundamental of the two gaps. It pairs with ranging (#1395): a clean basis certifies the dual as a marginal rate valid within the current RHS range, and ranging supplies that range.
  • Prior art: Gurobi VBasis/CBasis, HiGHS HighsBasis (col_status/row_status).
  • Discovered via cuOpt × Frontier integration testing (solver-exact duals in a multi-objective decision layer).

Related: the diet LP duals example (dual values + reduced costs), NVIDIA/cuopt-examples#154, surfaces exactly the reduced costs this status accessor would annotate (which foods are at a bound = near-misses vs basic/interior).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.