pounce_algorithm/sqp/iterates.rs
1//! SQP iterate state — `(x, λ_g, λ_x)` plus the working set
2//! carried across QP subproblem solves for warm-starting (the
3//! §5/§6 design-note contract).
4//!
5//! Distinct from [`crate::iterates_vector::IteratesVector`] (which
6//! is IPM-shaped with slacks and barrier multipliers). The SQP
7//! iterate is simpler: primal `x`, constraint multipliers
8//! `λ_g`, packed bound multipliers `λ_x = z_l − z_u`, and the
9//! `pounce_qp::WorkingSet` from the previous QP solve.
10
11use pounce_common::Number;
12use pounce_qp::WorkingSet;
13
14///
15/// Inside the algorithm the fields are in its own space: `x` over the
16/// non-fixed variables (per-variable scaled), `lambda_g = [y_c; y_d]`
17/// (equality rows first) and both multipliers times the objective /
18/// constraint scale. What a caller hands
19/// `IpoptApplication::set_sqp_warm_start` is the *user* space instead —
20/// the layout `finalize_solution` reports — and the application converts.
21#[derive(Debug, Clone)]
22pub struct SqpIterates {
23 pub x: Vec<Number>,
24 pub lambda_g: Vec<Number>,
25 pub lambda_x: Vec<Number>,
26 pub working: Option<WorkingSet>,
27}
28
29impl SqpIterates {
30 pub fn cold(n: usize, m: usize) -> Self {
31 Self {
32 x: vec![0.0; n],
33 lambda_g: vec![0.0; m],
34 lambda_x: vec![0.0; n],
35 working: None,
36 }
37 }
38
39 pub fn n(&self) -> usize {
40 self.x.len()
41 }
42
43 pub fn m(&self) -> usize {
44 self.lambda_g.len()
45 }
46}