pounce-rs 0.13.0

Single-crate facade for POUNCE from Rust: re-exports the TNLP trait, the IpoptApplication driver, and the supporting types in one place (plus a prelude), with feature-gated modules for the convex/LP/QP, active-set QP, and sensitivity paths.
Documentation
//! NLP sensitivity, parametric warm starts, and reduced Hessians — the
//! `pounce-sensitivity` port of Ipopt's sIPOPT, re-exported (feature
//! `sensitivity`).
//!
//! ```toml
//! [dependencies]
//! pounce-rs = { version = "0.9", features = ["sensitivity"] }
//! ```
//!
//! The problem shape sIPOPT assumes: the TNLP declares equality constraints
//! of the form `g_i(x) − p_i = 0`, and the 0-based row indices `i` of those
//! constraints are the *pins*. [`SensSolve`] solves the NLP once and then,
//! from the converged KKT factor, returns a first-order predictor
//! `Δx ≈ (∂x*/∂p)·Δp` for a perturbation of the pinned parameters — no
//! re-solve, one Schur complement.
//!
//! ```no_run
//! use pounce_rs::prelude::*;
//! use pounce_rs::sensitivity::SensSolve;
//! use std::cell::RefCell;
//! use std::rc::Rc;
//!
//! # fn demo(tnlp: Rc<RefCell<dyn TNLP>>) {
//! let mut app = IpoptApplication::new();
//! app.initialize().unwrap();
//!
//! let result = SensSolve::new(vec![2, 3])          // pinned constraint rows
//!     .with_deltas(vec![-0.5, 0.0])                // Δp
//!     .with_reduced_hessian()
//!     .run(&mut app, tnlp);
//!
//! assert_eq!(result.status, ApplicationReturnStatus::SolveSucceeded);
//! let dx = result.dx.expect("Δx populated when with_deltas was set");
//! # }
//! ```
//!
//! A sensitivity-stage failure is reported through [`SensResult::error`], not
//! through `status` — the underlying solve can converge while the post-solve
//! step fails (a pin that isn't an equality, a Schur setup error). Both
//! "sensitivity failed" and "sensitivity not requested" leave the outputs
//! `None`, so `error` is the only signal that separates them.
//!
//! [`compute_reduced_hessian`] gives the curvature on the null space of the
//! active constraints directly, and
//! [`SensSolve::with_reduced_hessian_eigen`] adds its eigendecomposition via
//! the shared [`symmetric_eigen`]. Over parameter-pin rows both report
//! **`−H_R`**, not `H_R` — so the ascending spectrum runs stiffest-first, and
//! an identifiability read has to negate. gh#937;
//! [`SensResult::reduced_hessian`] carries the reasoning.
//!
//! For the long form — [`SensApplication`] driven by an explicit
//! [`IndexSchurData`] / [`PdSensBacksolver`] / [`DenseGenSchurDriver`] stack —
//! every piece is re-exported below, and [`pounce_sensitivity`] itself is
//! re-exported for anything not listed.
//!
//! # The diagnostics, not just the drivers
//!
//! The facade used to name only the things you *call* — [`SensSolve`],
//! [`Solver`], the Schur stack — and none of the things they *return*. A
//! caller could reach `Solver::classify_activity` through the facade and then
//! had to name its result type through `pounce_sensitivity` directly, which is
//! the dependency the facade exists to remove. Every result and diagnostic
//! type on the session API is re-exported here now:
//!
//! * [`ActivityReport`] — what each bound is doing at the optimum. Read
//!   [`pounce_sensitivity::activity`]'s note on `AMBIGUOUS` before acting on a
//!   status: it is not "probably not a kink", and the reduced-curvature
//!   accessors ([`Solver::reduced_activity`], [`Solver::reduced_row_activity`])
//!   are what settle it.
//! * [`RefineStop`] — why `mode = fix_relax` stopped refining;
//!   [`PathSegment`] — one leg of a path-following step;
//!   [`WeakBound`] / [`BoundMultiplier`] / [`BoundRow`] — the bound-geometry
//!   records `boundcheck` reads and returns.
//! * [`CorrectorReport`] — what the corrector's iterations did, including the
//!   residual split that says whether they helped.
//! * [`SensOptionOverrides`] — the option layer between an `OptionsList` and
//!   the step.
//! * [`VarX`] / [`FullX`] / [`VarToFull`] / [`FullXSlice`] — the index
//!   newtypes. `FullX` has no public constructor by design: it is obtainable
//!   only by putting a `VarX` through a `VarToFull`, so "this number is in
//!   full-x" is asserted once per map rather than once per read.

pub use pounce_sensitivity::{
    ConvergedState, DEFAULT_ACTIVE_TOL, DenseGenSchurDriver, DenseLuBacksolver, DiffHandoff,
    IndexPCalculator, IndexSchurData, PCalculator, PdSensBacksolver, SchurData, SchurDriver,
    SensApplication, SensBacksolver, SensOptions, SensResult, SensSolve, SensStepCalc, Solver,
    SolverError, StdStepCalc, WithBacksolver, compute_reduced_hessian, register_options,
    symmetric_eigen,
};

/// Result and diagnostic types from the session API.
pub use pounce_sensitivity::activity::ActivityReport;
pub use pounce_sensitivity::backsolver::BoundRow;
pub use pounce_sensitivity::boundcheck::{BoundMultiplier, PathSegment, RefineStop, WeakBound};
pub use pounce_sensitivity::corrector::CorrectorReport;
pub use pounce_sensitivity::index::{FullX, FullXSlice, VarToFull, VarX};
pub use pounce_sensitivity::options::SensOptionOverrides;

/// The underlying crate, for anything not surfaced above.
pub use pounce_sensitivity;