pub struct LowRankAugSystemSolver { /* private fields */ }Implementations§
Source§impl LowRankAugSystemSolver
impl LowRankAugSystemSolver
pub fn new(inner: Box<dyn AugSystemSolver>) -> Self
Sourcepub fn with_bypass_solver(
inner: Box<dyn AugSystemSolver>,
bypass: Box<dyn AugSystemSolver>,
) -> Self
pub fn with_bypass_solver( inner: Box<dyn AugSystemSolver>, bypass: Box<dyn AugSystemSolver>, ) -> Self
Same as Self::new but routes the Hessian-free solves through
their own inner solver.
Under limited-memory this solver drives its inner solver with two
different (1,1) shapes: an empty W for the least-square multiplier
initialization and the equality-multiplier estimates, and an
n-diagonal B0 for the main primal-dual solves.
StdAugSystemSolver keys its structure signature on W’s nonzero
count, so the two alternate and every alternation re-runs the
backend’s symbolic factorization — for MA57 with
ma57_pivot_order = 5 a full MeTiS nested dissection of the whole
KKT system, ~0.4 s per call on a 118 276-row model (gh#730).
Ipopt never pays this because its low-rank layer owns those
solves, so its inner solver sees one shape for its whole life —
IpTSymLinearSolver.cpp:182 asserts exactly that. Giving the
bypass its own solver reproduces that invariant on both sides
instead of on neither.
Deliberately not done by making the two shapes agree — e.g.
substituting a zeroed n-diagonal for the empty W, which is what
the shape proposed in gh#730 does. That is numerically exact, but
it changes the pattern the backend orders, and a different
ordering rounds differently: swept, it takes pooling_rt2stp
under MA57 from obj = -4391.83 to -3273.95 (both “Optimal”,
25% apart) and cresc4 from 110 to 267 iterations. Two solvers
hand each path exactly the matrix and the ordering it already
had, so the win is free of trajectory movement rather than paid
for with it.
The cost is one additional numeric factorization resident at
once. That is the deliberate trade: memory is measurable and
boundable, and a trajectory regression is what has repeatedly
shipped here undetected (dev-notes/trajectory-regressions-and-\ the-fixture-sweep.md).
Sourcepub fn augmented_system_requires_change(
&self,
coeffs: &AugSysCoeffs<'_>,
) -> bool
pub fn augmented_system_requires_change( &self, coeffs: &AugSysCoeffs<'_>, ) -> bool
Pure tag/scalar comparison — port of upstream
AugmentedSystemRequiresChange (IpLowRankAugSystemSolver.cpp:531-599).
pub fn first_call(&self) -> bool
pub fn cache(&self) -> &AugSysCache
Trait Implementations§
Source§impl AugSystemSolver for LowRankAugSystemSolver
impl AugSystemSolver for LowRankAugSystemSolver
Source§fn resolve(
&mut self,
coeffs: &AugSysCoeffs<'_>,
rhs: &AugSysRhs<'_>,
sol: &mut AugSysSol<'_>,
) -> ESymSolverStatus
fn resolve( &mut self, coeffs: &AugSysCoeffs<'_>, rhs: &AugSysRhs<'_>, sol: &mut AugSysSol<'_>, ) -> ESymSolverStatus
Back-substitution against the cached factor, plus the same SMW
corrections solve applies.
Without this override the trait default falls through to solve,
which re-factorizes — and because PdFullSpaceSolver’s iterative
refinement and its same-matrix fast path both come in through
resolve, that made the majority of the augmented-system solves
on the limited-memory path re-factorize a matrix that had not
changed. It also left LinearSystemBackSolve reading 0.000 s for
a whole run, since the only back-solve timer guard lives on the
path nothing reached (gh#698).
Every condition that cannot be served falls back to solve, so
this can lose an optimization but cannot change an answer — the
same defensive shape as StdAugSystemSolver::resolve’s own
have_factor fallback.
Source§fn provides_inertia(&self) -> bool
fn provides_inertia(&self) -> bool
Source§fn number_of_neg_evals(&self) -> Index
fn number_of_neg_evals(&self) -> Index
provides_inertia() first.Source§fn increase_quality(&mut self) -> bool
fn increase_quality(&mut self) -> bool
Source§fn last_solve_status(&self) -> ESymSolverStatus
fn last_solve_status(&self) -> ESymSolverStatus
solve call.Source§fn set_timing_stats(&mut self, timing: Rc<TimingStatistics>)
fn set_timing_stats(&mut self, timing: Rc<TimingStatistics>)
TimingStatistics so the
linear-system factor/back-solve calls are attributed to
linear_system_factorization / linear_system_back_solve.
Default impl is a no-op (timing disabled); the standard
solver overrides to record both fields, and composite solvers
(LowRank) forward to their inner solver.Source§fn set_slack_scaling(&mut self, nx: Index, s_scale: &[Number])
fn set_slack_scaling(&mut self, nx: Index, s_scale: &[Number])
linear_system_scaling=slack-based
down to the linear solver’s scaling method. Default no-op;
StdAugSystemSolver forwards to its TSymLinearSolver, and
composite solvers forward to their inner solver. Read moreSource§fn handles_low_rank_w(&self) -> bool
fn handles_low_rank_w(&self) -> bool
LowRankUpdateSymMatrix as
coeffs.w directly, applying it by Sherman-Morrison-Woodbury
rather than needing an assembled triplet matrix. Read moreSource§fn solve(
&mut self,
coeffs: &AugSysCoeffs<'_>,
rhs: &AugSysRhs<'_>,
sol: &mut AugSysSol<'_>,
check_neg_evals: bool,
num_neg_evals: Index,
) -> ESymSolverStatus
fn solve( &mut self, coeffs: &AugSysCoeffs<'_>, rhs: &AugSysRhs<'_>, sol: &mut AugSysSol<'_>, check_neg_evals: bool, num_neg_evals: Index, ) -> ESymSolverStatus
check_neg_evals=true asks the linsol to verify that the
observed inertia equals num_neg_evals; on mismatch the
status is WrongInertia and the solution is left untouched.Source§fn system_dim(&self) -> Index
fn system_dim(&self) -> Index
Source§fn kkt_triplets(&self) -> Option<(Index, Vec<Index>, Vec<Index>, Vec<Number>)>
fn kkt_triplets(&self) -> Option<(Index, Vec<Index>, Vec<Index>, Vec<Number>)>
(dim, irn, jcn, vals)
(1-based lower triangle), for the debugger’s viz kkt. Default
None for backends that don’t expose them.Source§fn l_factor(&self, _want_values: bool) -> Option<FactorPattern>
fn l_factor(&self, _want_values: bool) -> Option<FactorPattern>
LDLᵀ factor pattern (and optionally values) of the most
recent factorization, for the debugger’s viz L. Default None.Source§fn set_diagnostics(&mut self, _diag: Rc<DiagnosticsState>)
fn set_diagnostics(&mut self, _diag: Rc<DiagnosticsState>)
Source§fn multi_solve(
&mut self,
coeffs: &AugSysCoeffs<'_>,
rhs_list: &[&AugSysRhs<'_>],
sol_list: &mut [&mut AugSysSol<'_>],
check_neg_evals: bool,
num_neg_evals: Index,
) -> ESymSolverStatus
fn multi_solve( &mut self, coeffs: &AugSysCoeffs<'_>, rhs_list: &[&AugSysRhs<'_>], sol_list: &mut [&mut AugSysSol<'_>], check_neg_evals: bool, num_neg_evals: Index, ) -> ESymSolverStatus
nrhs right-hand sides. Default
impl loops [solve]; concrete backends override only when they
can amortize factorization across calls. Mirrors upstream’s
AugSystemSolver::MultiSolve (IpAugSystemSolver.hpp:113-150). Read moreSource§fn try_resolve_many_flat(
&mut self,
_coeffs: &AugSysCoeffs<'_>,
_packed_rhs: &mut [Number],
_nrhs: usize,
) -> Option<ESymSolverStatus>
fn try_resolve_many_flat( &mut self, _coeffs: &AugSysCoeffs<'_>, _packed_rhs: &mut [Number], _nrhs: usize, ) -> Option<ESymSolverStatus>
nrhs right-hand sides, packed in column-major layout in
packed_rhs. Each column has length dim = n_x + n_s + n_y_c + n_y_d (the aug-system dim — z/v blocks are not part of this
path; callers expand them via expand_bound_multipliers after
the fact). Solutions overwrite packed_rhs in place. Read moreSource§fn try_solve_many_flat(
&mut self,
_coeffs: &AugSysCoeffs<'_>,
_packed_rhs: &mut [Number],
_nrhs: usize,
_check_neg_evals: bool,
_num_neg_evals: Index,
) -> Option<ESymSolverStatus>
fn try_solve_many_flat( &mut self, _coeffs: &AugSysCoeffs<'_>, _packed_rhs: &mut [Number], _nrhs: usize, _check_neg_evals: bool, _num_neg_evals: Index, ) -> Option<ESymSolverStatus>
nrhs right-hand sides in a single
backend call, with packed_rhs in the same column-major layout
Self::try_resolve_many_flat uses. Solutions overwrite
packed_rhs in place. Read moreSource§fn multi_solve_matches_single_solve(&self, _nrhs: usize) -> bool
fn multi_solve_matches_single_solve(&self, _nrhs: usize) -> bool
Self::try_resolve_many_flat with nrhs columns returns
bit-identical results to nrhs separate Self::resolve calls. Read moreAuto Trait Implementations§
impl !Freeze for LowRankAugSystemSolver
impl !RefUnwindSafe for LowRankAugSystemSolver
impl !Send for LowRankAugSystemSolver
impl !Sync for LowRankAugSystemSolver
impl !UnwindSafe for LowRankAugSystemSolver
impl Unpin for LowRankAugSystemSolver
impl UnsafeUnpin for LowRankAugSystemSolver
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<T, U> Imply<T> for U
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more