pub trait SolverInterface: Send {
// Required methods
fn load_model(&mut self, template: &StageTemplate);
fn add_rows(&mut self, cuts: &RowBatch);
fn set_row_bounds(
&mut self,
indices: &[usize],
lower: &[f64],
upper: &[f64],
);
fn set_col_bounds(
&mut self,
indices: &[usize],
lower: &[f64],
upper: &[f64],
);
fn solve(&mut self) -> Result<SolutionView<'_>, SolverError>;
fn reset(&mut self);
fn get_basis(&mut self, out: &mut Basis);
fn solve_with_basis(
&mut self,
basis: &Basis,
) -> Result<SolutionView<'_>, SolverError>;
fn statistics(&self) -> SolverStatistics;
fn name(&self) -> &'static str;
}Expand description
Backend-agnostic interface for LP solver instances.
§Design
The trait is resolved as a generic type parameter at compile time
(compile-time monomorphization for FFI-wrapping trait; see docs/adr/003-compile-time-solver.md),
not as dyn SolverInterface. This monomorphization approach
eliminates virtual dispatch overhead on the hot path, where tens of millions
of LP solves occur during a single training run. The training loop is
parameterized as fn train<S: SolverInterface>(solver_factory: impl Fn() -> S, ...).
§Thread Safety
The trait requires Send but not Sync. Send allows solver instances to
be transferred to worker threads during thread pool initialization. The
absence of Sync prevents concurrent access, which matches the reality of
C-library solver handles (HiGHS, CLP): they maintain mutable internal state
(factorization workspace, working arrays) that is not thread-safe. Each
worker thread owns exactly one solver instance for the duration of the
training run, following the thread-local workspace pattern described in
Solver Workspaces SS1.1.
§Mutability Convention
- Mutating methods (
load_model,add_rows,set_row_bounds,set_col_bounds,solve,solve_with_basis,reset) take&mut self. - Methods that write to internal scratch buffers (
get_basis) take&mut self. - Read-only query methods (
statistics,name) take&self.
§Error Recovery Contract
When solve or solve_with_basis returns Err, the solver’s
internal state is unspecified. The caller is responsible for calling
reset() before reusing the instance for another solve sequence. Failing to
call reset() after an error may produce incorrect results or panics.
§Usage as a Generic Bound
use cobre_solver::{SolverInterface, SolutionView, SolverError};
fn run_solve<S: SolverInterface>(solver: &mut S) -> Result<SolutionView<'_>, SolverError> {
solver.solve()
}See Solver Interface Trait SS1 and Solver Interface Trait SS5 for the dispatch mechanism rationale.
Required Methods§
Sourcefn load_model(&mut self, template: &StageTemplate)
fn load_model(&mut self, template: &StageTemplate)
Bulk-loads a pre-assembled structural LP (first step of rebuild sequence).
Replaces any previous model. Validates template is a valid CSC matrix
with num_cols > 0 and num_rows > 0 (panic on violation).
See Solver Interface Trait SS2.1.
Sourcefn add_rows(&mut self, cuts: &RowBatch)
fn add_rows(&mut self, cuts: &RowBatch)
Appends constraint rows to the dynamic constraint region (step 2 of rebuild).
Requires load_model called first and cuts to have
valid CSR data with column indices in [0, num_cols) (panic on violation).
See Solver Interface Trait SS2.2.
Sourcefn set_row_bounds(&mut self, indices: &[usize], lower: &[f64], upper: &[f64])
fn set_row_bounds(&mut self, indices: &[usize], lower: &[f64], upper: &[f64])
Updates row bounds (step 3 of rebuild; patching for scenario realization).
indices, lower, and upper must have equal length, with all indices
referencing valid rows and bounds finite. For equality constraints, set
lower[i] == upper[i]. Panics if lengths differ or indices are out-of-bounds.
See Solver Interface Trait SS2.3.
Sourcefn set_col_bounds(&mut self, indices: &[usize], lower: &[f64], upper: &[f64])
fn set_col_bounds(&mut self, indices: &[usize], lower: &[f64], upper: &[f64])
Updates column bounds (per-scenario variable bound patching).
indices, lower, and upper must have equal length, with all indices
referencing valid columns and bounds finite. Panics if lengths differ or
indices are out-of-bounds.
See Solver Interface Trait SS2.3a.
Sourcefn solve(&mut self) -> Result<SolutionView<'_>, SolverError>
fn solve(&mut self) -> Result<SolutionView<'_>, SolverError>
Solves the LP, returning a zero-copy view or terminal error after retry exhaustion.
Hot-path method encapsulating internal retry logic. Requires Self::load_model
called first and scenario patches applied. On error, caller must call
Self::reset before reusing. The returned SolutionView borrows
solver-internal buffers and is valid until the next &mut self call. Call
SolutionView::to_owned when the solution must outlive the borrow.
§Errors
Returns Err(SolverError) when all internal retry attempts exhausted.
Possible variants: SolverError::Infeasible, SolverError::Unbounded,
SolverError::NumericalDifficulty, SolverError::TimeLimitExceeded,
SolverError::IterationLimit, or SolverError::InternalError.
See Solver Interface Trait SS2.4.
Sourcefn reset(&mut self)
fn reset(&mut self)
Clears internal solver state for error recovery or LP structure change.
Requires Self::load_model before next solve. Preserves SolverStatistics
counters; does not zero them.
See Solver Interface Trait SS2.6.
Sourcefn get_basis(&mut self, out: &mut Basis)
fn get_basis(&mut self, out: &mut Basis)
Writes solver-native i32 status codes into a caller-owned Basis buffer.
The caller pre-allocates a Basis with Basis::new and reuses it
across iterations, eliminating per-element enum translation overhead.
The buffer is not resized by this method. The implementation writes into
the first num_cols entries of out.col_status and the first num_rows
entries of out.row_status. Panics if no model is loaded.
See Solver Interface Trait SS2.7.
Sourcefn solve_with_basis(
&mut self,
basis: &Basis,
) -> Result<SolutionView<'_>, SolverError>
fn solve_with_basis( &mut self, basis: &Basis, ) -> Result<SolutionView<'_>, SolverError>
Injects a basis and solves, returning a zero-copy SolutionView.
Status codes in basis are injected directly without per-element enum
translation. On success the returned view borrows solver-internal buffers
and is valid until the next &mut self call. Call SolutionView::to_owned
when the solution must outlive the borrow.
§Errors
Same error contract as solve.
See Solver Interface Trait SS2.5.
Sourcefn statistics(&self) -> SolverStatistics
fn statistics(&self) -> SolverStatistics
Returns accumulated solve metrics (snapshot of monotonically increasing counters).
Statistics accumulate since construction; Self::reset does not zero them.
All fields non-negative.
See Solver Interface Trait SS2.8.