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). 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 questions for maintainers:
- 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.
- 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 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
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).
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). 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) plumbingvstatusfrom the dual-simplex result through to the publicoptimization_problem_solution, (c) the getter plus C API, cython bindings, and tests.Two design questions for maintainers:
variable_status_tis{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.Describe alternatives you've considered
reduced_cost == 0: unreliable under degeneracy (basic variables can have zero reduced cost, and vice versa).Additional context
VBasis/CBasis, HiGHSHighsBasis(col_status/row_status).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).