Skip to content

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

@cafzal

Description

@cafzal

Is your feature request related to a problem? Please describe.
cuOpt's LP/QP solution exposes dual values (shadow prices) 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 tells you 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_costs() can't cleanly tell a genuine near-miss from an interior variable.

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 have to reconstruct it heuristically from the primal values + 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 + Python equivalents — returning a public basis-status enum (BASIC / NONBASIC_LOWER / NONBASIC_UPPER / FIXED / FREE). 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 + C API + cython bindings + tests.

Two design questions for maintainers:

  1. Public enum shape — how to present the internal statuses (e.g. whether to expose SUPERBASIC/FIXED or fold them).
  2. PDLP semantics — PDLP is basis-free, so the accessor would return UNKNOWN/unavailable unless the LP was solved by dual simplex (or crossover ran). Define the per-method behavior.

Describe alternatives you've considered

  • Reconstructing status downstream from the primal solution + 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 a small skills doc PR clarifying per-problem-type dual support: Note dual/sensitivity support per problem type in formulation skill #1393.
  • Natural predecessor to a sensitivity-ranging request (filed separately) — both build on the same dual-simplex basis and together complete the textbook LP sensitivity report (shadow price + reduced cost + status + ranges).
  • 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 (shadow prices + 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).

Metadata

Metadata

Assignees

Labels

awaiting responseThis expects a response from maintainer or contributor depending on who requested in last comment.

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions