pub trait SensBacksolver {
// Required methods
fn dim(&self) -> usize;
fn solve(&self, rhs: &[f64], lhs: &mut [f64]) -> bool;
// Provided methods
fn natural_units_factor(&self) -> Option<&[f64]> { ... }
fn bound_rows(&self) -> Option<&[BoundRow]> { ... }
fn solve_released(
&self,
_released: &[usize],
_rhs: &[f64],
_lhs: &mut [f64],
) -> bool { ... }
fn solve_released_step(
&self,
_released: &[usize],
_rhs: &[f64],
_lhs: &mut [f64],
) -> bool { ... }
fn solve_released_pinned(
&self,
_released: &[usize],
_pinned: &[usize],
_rhs: &[f64],
_lhs: &mut [f64],
) -> bool { ... }
fn supports_release(&self) -> bool { ... }
}Expand description
Solve K · lhs = rhs against the converged KKT factor. Returns
false on failure (e.g. backend reports Singular).
Mirrors Ipopt::SensBacksolver::Solve
(SensBacksolver.hpp:28-31).
Pounce takes flat &[Number] / &mut [Number] rather than
upstream’s block-structured IteratesVector because the
sensitivity-side data is naturally flat; if the algorithm-side
wrapper in Phase B.2 needs the block layout it converts before
calling.
Required Methods§
Provided Methods§
Sourcefn natural_units_factor(&self) -> Option<&[f64]>
fn natural_units_factor(&self) -> Option<&[f64]>
Per-row factor carrying a quantity read off the converged
iterate into the units Self::solve answers in, indexed by
compound KKT row. None when the solve ran unscaled, which is
the identity.
This is the same F the natural-units back-solve applies to
its result, so a bound multiplier read raw off curr.z_l and
multiplied by f[row] agrees with the z rows of a step this
backsolver returns. The two disagree by d/df otherwise, and
mixing them puts a scaled right-hand side into a Schur
complement whose other rows are natural, which moves every
coordinate of the answer rather than one.
Sourcefn bound_rows(&self) -> Option<&[BoundRow]>
fn bound_rows(&self) -> Option<&[BoundRow]>
The variable behind each bound-multiplier row. None when the
backsolver cannot report it, which leaves
crate::boundcheck::refine_step_onto_bounds with no way to
release and so pinning only.
A release re-factors with that variable’s sigma removed, so it
needs to know which variable each row belongs to and which side
it bounds.
Sourcefn solve_released(
&self,
_released: &[usize],
_rhs: &[f64],
_lhs: &mut [f64],
) -> bool
fn solve_released( &self, _released: &[usize], _rhs: &[f64], _lhs: &mut [f64], ) -> bool
Solve against the system with the bounds named by released –
compound multiplier rows – taken out of the active set.
This re-factors, and has to. An active bound puts
sigma = z / s on the x diagonal, and on a tightly converged
bound that term is large enough to destroy the released system’s
information in the converged factor: recovering it from there
needs the difference of two quantities agreeing to about
eps * sigma, so the released answer comes out worse the
better the solve converged. Re-factoring with the term removed
is what buys those digits back, and one factorization still sits
an order of magnitude under a re-solve.
This solves in the released system and does nothing to the right-hand side, so it is the right call for every solve the refinement makes once a bound is out – including the unit vectors a Schur complement is built from, which carry no multiplier to move.
false by default, which leaves the refinement pinning only.
Sourcefn solve_released_step(
&self,
_released: &[usize],
_rhs: &[f64],
_lhs: &mut [f64],
) -> bool
fn solve_released_step( &self, _released: &[usize], _rhs: &[f64], _lhs: &mut [f64], ) -> bool
Self::solve_released against a parametric right-hand side,
which additionally needs the released multipliers moved onto
their variables’ x rows.
Dropping sigma gives the released matrix; this gives the
released right-hand side to go with it. Only the step itself
gets this treatment – applying it to a Schur complement’s unit
vectors would shift a right-hand side that has no multiplier in
it to begin with.
Sourcefn solve_released_pinned(
&self,
_released: &[usize],
_pinned: &[usize],
_rhs: &[f64],
_lhs: &mut [f64],
) -> bool
fn solve_released_pinned( &self, _released: &[usize], _pinned: &[usize], _rhs: &[f64], _lhs: &mut [f64], ) -> bool
Self::solve_released with each primal KKT row in
pinned carrying an extra diagonal stiff enough to hold that
coordinate in place.
This is not the pin the walk applies – that one is a Schur row
on top of the factored system, and it is exact. This is the
operator that pin is applied to, for the case where the
released system on its own has no inverse for a Schur
complement to be built from: releasing a bound takes its
Sigma off the diagonal, and on a model with no curvature two
released variables sharing a constraint are left with linearly
dependent stationarity rows (gh#930).
Adding the diagonal back regularizes exactly those rows, and
costs nothing in accuracy, because the Schur pin then holds the
same coordinates at zero: Eᵀw = 0 annihilates the term that
was added, so the pinned system solved is the released one
after all. The diagonal has to be reachable – large enough
that the regularized operator is invertible, small enough that
the row’s own couplings survive it, which is the gh#737
ceiling.
false by default, which leaves the caller reporting the
Schur pin’s failure.
Sourcefn supports_release(&self) -> bool
fn supports_release(&self) -> bool
Whether Self::solve_released is implemented.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".