Skip to main content

PdSensBacksolver

Struct PdSensBacksolver 

Source
pub struct PdSensBacksolver { /* private fields */ }
Expand description

Adapter from PdFullSpaceSolver to SensBacksolver. Holds owning clones of the four pieces of the algorithm’s converged state, plus the 8-block iterate template used to allocate fresh RHS / LHS vectors.

The PD solver lives behind an Rc<RefCell<…>> because SensBacksolver::solve is &self but the upstream signature for PdFullSpaceSolver::solve is &mut self (it caches the last-solve dependency tags and the augsys-improved flag). The RefCell is single-thread-only, single-borrow, exactly matching the call pattern from pounce-sensitivity’s pipeline.

Owning (rather than borrowing) the four handles is what lets a PdSensBacksolver outlive the on_converged callback frame — required by the public Solver session API in pounce-algorithm, which retains the backsolver for repeated parametric_step / kkt_solve / compute_reduced_hessian calls after the IPM has returned. The data, cq, and nlp handles are already Rc<RefCell<…>> cheap-clone handles upstream, so this carries no allocation overhead.

Implementations§

Source§

impl PdSensBacksolver

Source

pub fn new( data: &IpoptDataHandle, cq: &IpoptCqHandle, nlp: &Rc<RefCell<dyn IpoptNlp>>, pd: Rc<RefCell<PdFullSpaceSolver>>, ) -> Result<Self, String>

Construct from the four handles handed in by the on_converged callback. Errors if data has no curr (i.e. the algorithm never reached an iterate — should not happen on SolveSucceeded) or the NLP reports scaling data inconsistent with the converged iterate (see Self::natural_units_conj).

Source

pub fn variable_scaling(&self) -> Option<&[Number]>

The per-variable factors the held solve ran under, in the algorithm’s var-x space (one entry per x-block KKT row), or None when no variable scaling was active (gh#486).

Source

pub fn variable_scaling_full(&self) -> Option<&[Number]>

Self::variable_scaling in the user TNLP’s full-x space: the shape of an n_full_x-length report, with the columns the solve dropped as fixed still present.

Source

pub fn obj_scaling_factor(&self) -> Number

Effective objective scaling factor df of the converged NLP (1.0 when no scaling is active).

Source

pub fn nlp_scaling(&self) -> (Number, Option<Vec<Number>>, Option<Vec<Number>>)

Effective NLP scaling at convergence: (obj_scaling_factor, c_scale, d_scale). The vectors are None when the corresponding block carries no row scaling.

Source

pub fn kkt_perturbations(&self) -> [Number; 4]

Inertia-correction perturbations (δ_x, δ_s, δ_c, δ_d) baked into the held KKT factor (the IPM’s current_perturbation state at convergence). All zero ⇔ the final factorization was unregularized and the natural-units back-solves invert the exact KKT matrix. Nonzero ⇔ the factor carries a (scaled-space) regularization, so sensitivity outputs — covariance in particular — are perturbed and no longer exactly scaling-invariant; consumers should check this before trusting -inv(reduced_hessian) on ill-conditioned problems (pounce#128 follow-up).

Source

pub fn pin_rows_and_c_scales( &self, pin_g_indices: &[Index], ) -> Result<(Vec<Index>, Vec<Number>), String>

Map user-facing 0-based g(x) indices of parameter-pin equality constraints to flat KKT rows and the pin rows’ dc_i scaling factors, in one pass. The KKT row of pin i is n_x + n_s + c_block_idx, i.e. the matching y_c slot, found through IpoptNlp::full_g_to_c_block so the c/d split’s row permutation is honored (pounce#128 follow-up: the previous direct n_x + n_s + g_idx mapping silently picked wrong rows when inequalities preceded the pins). The scales are 1.0 when no constraint scaling is active; they relate the natural and solver-space reduced Hessians via H̃_ij = (df / (dc_i·dc_j)) · H_ij. Errors when a pin index is out of range or refers to an inequality row.

Source

pub fn map_pin_g_to_kkt_rows( &self, pin_g_indices: &[Index], ) -> Result<Vec<Index>, String>

KKT-row half of Self::pin_rows_and_c_scales.

Source

pub fn pin_c_scales( &self, pin_g_indices: &[Index], ) -> Result<Vec<Number>, String>

Scaling half of Self::pin_rows_and_c_scales.

Source

pub fn block_dims(&self) -> [usize; 8]

Block dimensions of the compound KKT vector at convergence, in (x, s, y_c, y_d, z_l, z_u, v_l, v_u) order. Sum equals SensBacksolver::dim. Useful when a caller needs to compute the flat offset of a non-x block (e.g. n_x + n_s for the start of the equality-multiplier y_c block).

Source

pub fn full_g_to_c_block(&self, full_idx: Index) -> Option<Index>

Map a 0-based full-g index (user-TNLP g(x) order) to its 0-based position in the equality-multiplier y_c block, or None when the constraint is an inequality (it lives in the d block, not y_c). Delegates to the held NLP’s c/d-split map.

Pin-row construction must route through this: the flat KKT row of a pinned equality is n_x + n_s + full_g_to_c_block(g), NOT n_x + n_s + g — those differ whenever any inequality precedes the pinned equality in g(x).

Source

pub fn full_g_to_d_block(&self, full_idx: Index) -> Option<Index>

Map a 0-based full-g index to its 0-based position in the inequality-multiplier y_d block, or None when the constraint is an equality (it lives in y_c). The exact complement of Self::full_g_to_c_block, and the map gh#910 added so an inequality’s multiplier row can be addressed.

The flat KKT row is n_x + n_s + n_y_c + full_g_to_d_block(g), and the caveat is the same one full_g_to_c_block carries: it is NOT g, and it is not g offset by a constant either — each equality ahead of the row shifts it by one.

Source

pub fn full_x_to_var_x(&self, full_idx: Index) -> Option<Index>

Map a 0-based full-x index (user-TNLP variable order) to its 0-based position in the algorithm-side x block, or None when the solve removed the column because x_l == x_u under fixed_variable_treatment = make_parameter. Delegates to the held NLP’s fixed-variable map.

The x counterpart of Self::full_g_to_c_block, and it must be routed through for the same reason: the flat KKT row of a user variable is full_x_to_var_x(i), NOT i — those differ whenever any fixed variable precedes it in the user’s x. Reports and iterates are in full-x, the factor is in var-x, and nothing about the two spaces is distinguishable by length alone on a model that happens to have no fixed variables.

Source

pub fn n_full_x(&self) -> Index

The user TNLP’s variable count, the domain of Self::full_x_to_var_x. Distinct from the x block width whenever the solve removed a fixed variable.

Source

pub fn n_full_g(&self) -> Index

The user TNLP’s constraint count, the g counterpart of Self::n_full_x: the length of a full-g report and the domain of Self::full_g_to_c_block. Distinct from either KKT row block’s width, since the c/d split sends equalities to y_c and inequalities to s/y_d.

Source§

impl PdSensBacksolver

Source

pub fn solve_many( &self, rhs_flat: &[Number], lhs_flat: &mut [Number], n_rhs: usize, ) -> bool

Batched-RHS back-solve over the held factor. rhs_flat and lhs_flat are row-major (n_rhs, dim) buffers. Equivalent to looping SensBacksolver::solve over each row but reuses one frozen IteratesVector for the RHS and one IteratesVectorMut for the result across all n_rhs calls into PdFullSpaceSolver::solve. The pack step writes into the existing DenseVector storage via Rc::get_mut + set_values, and the unpack step reads it back via values() /scalar() — skipping the per-call 8-block make_new_zeroed (Box alloc) in pack and the per-block expanded_values() Vec alloc in unpack that otherwise dominate the held-factor back-solve cost under jax.jacrev over a JaxProblem solve (pounce#77 follow-up).

The matrix and perturbation state inside PdFullSpaceSolver are unchanged across calls, so each iteration hits the cached fast path in solve_once (uptodate && !pretend_singular).

Like SensBacksolver::solve, results are in natural (unscaled) units — see Self::solve_many_scaled_space for the raw solver-space back-solve.

Source

pub fn solve_many_scaled_space( &self, rhs_flat: &[Number], lhs_flat: &mut [Number], n_rhs: usize, ) -> bool

Batched-RHS back-solve against the held factor in the solver’s internal scaled space (no natural-units conjugation). Same buffer contract as Self::solve_many.

Source§

impl PdSensBacksolver

Source

pub fn solve_scaled_space(&self, rhs: &[Number], lhs: &mut [Number]) -> bool

Single-RHS back-solve against the held factor in the solver’s internal scaled space (no natural-units conjugation). This is the value SensBacksolver::solve returned before pounce#128; kept for callers that want the raw factor.

Trait Implementations§

Source§

impl BarrierIterate for PdSensBacksolver

Source§

fn barrier_residual( &self, point: &[Number], out: &mut [Number], ) -> Result<(), String>

Installs point as the trial iterate and reads the residual off the calculated quantities there, so scaling, fixed variables and the bound expansions are handled exactly as the solve handles them. Setting a trial point leaves curr alone.

Source§

fn corrector_operator<'a>( &'a self, predicted: &[Number], pinned: &[(usize, Number)], exact_hessian: bool, ) -> Result<Box<dyn KktOperator + 'a>, String>

Swaps the predicted point in as the current iterate for the life of the returned operator, so every block of the operator evaluates there, and builds the barrier diagonal after the swap. The stored base-point diagonal, which the ceiling (gh#737) or crossover (gh#654) would otherwise freeze, is never consulted: the frame rule and the ceiling are re-derived at the predicted point. See corrector_sigma.

The solve takes its Hessian from IpoptData::w, the matrix the algorithm last stored, so moving the iterate alone moves only the Jacobians and slacks. Under an exact-Hessian solve the matrix is re-evaluated at the predicted point, with the step’s own multipliers. A limited-memory solve keeps its quasi-Newton matrix, since there is no exact Hessian to evaluate anywhere.

Source§

fn model_maps(&self) -> Result<ModelMaps, String>

The NLP’s own maps. The inequality positions are its full_g_to_d_block, the exact complement of full_g_to_c_block: one ascending scan over the model’s rows assigns each to the next position of its block.

Source§

fn primal_bounds(&self) -> Result<(Vec<Number>, Vec<Number>), String>

The bounds the NLP holds, relaxed by bound_relax_factor when the solve relaxed them, expanded from its compressed bound vectors.

Source§

fn released_operator<'a>( &'a self, released: &[usize], ) -> Result<Box<dyn KktOperator + 'a>, String>

The released diagonals built once and held, so every solve passes the same objects and the factorization cache, which keys on the diagonal’s tag, factors the released system once.

Source§

fn block_dims(&self) -> [usize; 8]

Lengths of the eight blocks, in the order x, s, y_c, y_d, z_l, z_u, v_l, v_u. They sum to SensBacksolver::dim.
Source§

fn offsets(&self) -> [usize; 9]

Where each block starts in the flat vector, with the total length in the last entry.
Source§

fn barrier_mu(&self) -> Number

The barrier parameter the converged point sits on, as the level of the complementarity products of the slacks and multipliers this engine reports. These are the products Self::barrier_residual writes, at the point Self::converged_iterate writes, in the engine frame. Read more
Source§

fn converged_iterate(&self, out: &mut [Number]) -> Result<(), String>

Writes the converged iterate into out, in the engine frame. The error says why there is none, or that out is the wrong length.
Source§

fn scaled_rhs_factor(&self) -> Option<&[Number]>

Per-row factor E that takes a natural-units right-hand side into the engine frame, indexed like the compound vector. None is the identity. Read more
Source§

fn activity_data(&self) -> Result<ActivityData, String>

Everything the activity classification reads off the converged point.
Source§

fn scaling(&self) -> EngineScaling

The scaling the engine applied to the model. EngineScaling::none is the answer for an engine that applied none.
Source§

fn kkt_perturbations(&self) -> Option<[Number; 4]>

The perturbations (δ_x, δ_s, δ_c, δ_d) the engine added to its KKT matrix to correct its inertia, as its factor holds them. None when the engine does not report them, which is the default. Read more
Source§

impl Clone for PdSensBacksolver

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl SensBacksolver for PdSensBacksolver

Source§

fn natural_units_factor(&self) -> Option<&[Number]>

F itself, the vector Self::solve post-multiplies its result by, so a caller converting an iterate quantity uses the same numbers the back-solve used.

Source§

fn solve(&self, rhs: &[Number], lhs: &mut [Number]) -> bool

Solve K · lhs = rhs against the converged factor, in natural (unscaled) units (pounce#128): when the NLP carries active scaling (nlp_scaling_method, obj_scaling_factor, user scaling) the RHS is pre-multiplied by E and the result post-multiplied by F (see the conj field doc), so lhs = K_natural⁻¹ rhs for all eight blocks — including the z/v bound-multiplier rows. Use Self::solve_scaled_space for the raw factor.

Source§

fn dim(&self) -> usize

Size of the linear system in entries (length of lhs and rhs). The backsolver’s notion of “full state” — pounce’s IPM uses the compound (x, s, λ_c, λ_d, z_l, z_u, v_l, v_u) concatenation here.
Source§

fn solve_many(&self, rhs: &[Number], lhs: &mut [Number], n_rhs: usize) -> bool

Self::solve for n_rhs right-hand sides at once, each self.dim() long and stored one after another in rhs and lhs. Read more
Source§

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. Read more
Source§

fn supports_release(&self) -> bool

Whether Self::solve_released is implemented.
Source§

fn solve_released( &self, released: &[usize], rhs: &[Number], lhs: &mut [Number], ) -> bool

Solve against the system with the bounds named by released – compound multiplier rows – taken out of the active set. Read more
Source§

fn solve_released_step( &self, released: &[usize], rhs: &[Number], lhs: &mut [Number], ) -> bool

Self::solve_released against a parametric right-hand side, which additionally needs the released multipliers moved onto their variables’ x rows. Read more
Source§

fn solve_released_pinned( &self, released: &[usize], pinned: &[usize], rhs: &[Number], lhs: &mut [Number], ) -> bool

Self::solve_released with each primal KKT row in pinned carrying an extra diagonal stiff enough to hold that coordinate in place. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> ByRef<T> for T

Source§

fn by_ref(&self) -> &T

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Imply<T> for U
where T: ?Sized, U: ?Sized,

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more