Skip to main content

pounce_sensitivity/
lib.rs

1//! Sensitivity analysis for POUNCE — port of upstream Ipopt's `contrib/sIPOPT/`.
2//!
3//! # Status
4//!
5//! Phases A–C complete. Wired today:
6//!
7//! * [`schur_data::IndexSchurData`] + [`p_calculator::IndexPCalculator`]:
8//!   row-selector representation of the perturbation matrix `B`.
9//! * [`backsolver::DenseLuBacksolver`] + [`PdSensBacksolver`]: backsolves
10//!   against the converged KKT factor (test / live IPM, respectively).
11//! * [`schur_driver::DenseGenSchurDriver`]: dense Schur-complement
12//!   factor `S = -B K⁻¹ Bᵀ` with parallel right-hand-side solves.
13//! * [`step_calc::StdStepCalc`] + [`sens_app::SensApplication`]:
14//!   high-level `parametric_step(Δp, dx)` and
15//!   [`reduced_hessian::compute_reduced_hessian`] entry points.
16//! * [`SensSolve`] / [`SensResult`]: one-call builder (covers the
17//!   `on_converged` plumbing typically required to wire the above into
18//!   an `IpoptApplication`).
19//!
20//! Verified against upstream sIPOPT 3.14.19's `parametric_cpp` golden
21//! output to 1e-8 (see `tests/parametric_cpp.rs`); the standalone
22//! `pounce_sens` AMPL driver in `pounce-cli` matches `sensitivity_amplsolver`'s
23//! `_sens_sol` output on representative .nl problems.
24//!
25//! **Phase D progress** (per [pounce#7](https://github.com/jkitchin/pounce/issues/7)):
26//!
27//! * **Fixed-variable lifting** ✔ — `pounce_sens` handles `n_x != n_full`
28//!   via the `IpoptNlp::full_x_to_var_x` / `var_x_to_full_x` /
29//!   `full_g_to_c_block` trait methods (which delegate to
30//!   `BoundClassification.x_not_fixed_map` / `c_map`).
31//! * **Reduced-Hessian eigendecomposition** ✔ — pure-Rust cyclic Jacobi
32//!   in [`eigen::symmetric_eigen`]; surfaced via
33//!   [`SensApplication::compute_reduced_hessian_eigen`],
34//!   [`SensSolve::with_reduced_hessian_eigen`], the `pounce_sens
35//!   --rh-eigendecomp` flag, and the Python `solve_with_sens(rh_eigendecomp=True)`
36//!   kwarg.
37//! * **`sens_boundcheck` bound projection** ✔ (single-pass clamp) —
38//!   [`boundcheck::clamp_step_to_bounds`] /
39//!   [`boundcheck::clamp_with_nlp`] project the perturbed step onto
40//!   `[x_l, x_u]` after the linear solve. Surfaced via
41//!   [`SensSolve::with_boundcheck`], `pounce_sens --sens-boundcheck`,
42//!   and the Python `solve_with_sens(sens_boundcheck=True)` kwarg.
43//!   Upstream's iterative Schur refinement (re-factorize on each
44//!   violation) is **not** ported — see [`boundcheck`] module docs.
45//!
46//! # Algorithmic reference
47//!
48//! Pirnay, H., López-Negrete, R., and Biegler, L.T. (2012).
49//! *Optimal sensitivity based on IPOPT.*
50//! Mathematical Programming Computation, **4**(4), 307–331.
51//! [DOI: 10.1007/s12532-012-0043-2](https://doi.org/10.1007/s12532-012-0043-2).
52//!
53//! Verified 2026-05-14 via Crossref: title, authors (Hans Pirnay; Rodrigo
54//! López-Negrete; Lorenz T. Biegler), MPC volume 4 issue 4 pp 307–331.
55//!
56//! # Upstream source mirror
57//!
58//! Port targets `ref/Ipopt/contrib/sIPOPT/src/` in this repo
59//! (EPL-2.0, © Hans Pirnay 2009–2011 per the file headers). Each
60//! public item in this crate documents the upstream symbol it mirrors
61//! with file path and (where stable) line numbers.
62
63#![cfg_attr(test, allow(clippy::unwrap_used, clippy::expect_used))]
64
65pub mod algorithm_backsolver;
66pub mod backsolver;
67pub mod boundcheck;
68pub mod convenience;
69pub mod eigen;
70pub mod p_calculator;
71pub mod reduced_hessian;
72pub mod schur_data;
73pub mod schur_driver;
74pub mod sens_app;
75pub mod solver;
76pub mod step_calc;
77
78pub use algorithm_backsolver::PdSensBacksolver;
79pub use backsolver::{DenseLuBacksolver, SensBacksolver};
80pub use convenience::{SensResult, SensSolve};
81pub use eigen::symmetric_eigen;
82pub use p_calculator::{IndexPCalculator, PCalculator};
83pub use reduced_hessian::compute_reduced_hessian;
84pub use schur_data::{IndexSchurData, SchurData};
85pub use schur_driver::{DenseGenSchurDriver, SchurDriver};
86pub use sens_app::{register_options, SensApplication, SensOptions};
87pub use solver::{ConvergedState, Solver, SolverError};
88pub use step_calc::{SensStepCalc, StdStepCalc, WithBacksolver};