Skip to main content

pounce_algorithm/sqp/
options.rs

1//! SQP outer-loop options. Mirrors the spirit of
2//! `crate::alg_builder::ConvCheckOptions` but only what the SQP
3//! driver itself needs; QP-subproblem-specific options pass
4//! through `pounce_qp::QpOptions` (which `SqpAlgorithm` owns).
5
6use pounce_common::Number;
7
8/// Choice of SQP globalization strategy. Defaults to filter
9/// (Fletcher-Leyffer 2002) per the design note §4.1; l1-elastic
10/// merit (Han-Powell with adaptive penalty) is the alternative.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
12pub enum SqpGlobalization {
13    #[default]
14    Filter,
15    L1Elastic,
16}
17
18/// Hessian source for the SQP subproblem.
19///
20/// - `Exact`: use `nlp.eval_h(x, 1.0, λ_g, 0)` directly. Indefinite
21///   on nonconvex problems; the QP subproblem solver handles
22///   indefinite reduced Hessian via inertia control (§4.5).
23/// - `DampedBfgs`: dense `n×n` Powell-damped BFGS, guaranteed PSD
24///   (Powell 1978). See [`crate::sqp::bfgs::DampedBfgs`].
25/// - `Lbfgs`: limited-memory BFGS with a circular `(s, y)` buffer
26///   of `lbfgs_max_history` pairs (Nocedal-Wright §7.2; Byrd-
27///   Nocedal-Schnabel 1994). See [`crate::sqp::lbfgs::LBfgs`].
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
29pub enum SqpHessianSource {
30    #[default]
31    Exact,
32    DampedBfgs,
33    Lbfgs,
34}
35
36#[derive(Debug, Clone)]
37pub struct SqpOptions {
38    pub globalization: SqpGlobalization,
39    pub hessian: SqpHessianSource,
40
41    /// KKT tolerance (max-norm) on the stationarity residual.
42    pub tol: Number,
43    /// Tolerance on constraint violation (max-norm).
44    pub constr_viol_tol: Number,
45    /// Tolerance on stationarity residual (max-norm).
46    pub dual_inf_tol: Number,
47    /// Outer-iteration cap.
48    pub max_iter: u32,
49
50    /// l1-merit penalty parameter ν. Used only when
51    /// `globalization = L1Elastic`. Filter globalization ignores
52    /// this. Default is a moderate starting value; the Han-Powell
53    /// ν-adaptation in `l1_merit_line_search` grows ν to dominate
54    /// `‖λ_qp‖_∞ + l1_penalty_safety` on every iteration.
55    pub l1_penalty: Number,
56
57    /// Additive safety margin in the Han-Powell ν update:
58    /// `ν_new = max(ν, ‖λ_qp‖_∞ + l1_penalty_safety)`. Default 0.1
59    /// per Nocedal-Wright §18.4. Only consulted when
60    /// `globalization = L1Elastic`.
61    pub l1_penalty_safety: Number,
62
63    /// Upper clamp on ν. Prevents catastrophic Armijo failure on
64    /// pathological problems where `‖λ_qp‖` momentarily spikes.
65    /// Default 1e10 — large enough not to interfere with normal
66    /// runs, small enough to keep the merit numerically stable.
67    /// Only consulted when `globalization = L1Elastic`.
68    pub l1_penalty_max: Number,
69
70    /// Backtracking line-search reduction factor.
71    pub bt_reduction: Number,
72    /// Minimum step before declaring line-search failure.
73    pub bt_min_alpha: Number,
74
75    /// `print_level`: 0 = silent, 1 = per-iteration summary,
76    /// 2+ = trace (planned).
77    pub print_level: u8,
78
79    /// Number of `(s, y)` history pairs retained when
80    /// `hessian = Lbfgs`. Mirrors the upstream
81    /// `limited_memory_max_history` default of 6 (Nocedal-Wright
82    /// recommends 3–20). Ignored for `Exact` and `DampedBfgs`.
83    pub lbfgs_max_history: u32,
84}
85
86impl Default for SqpOptions {
87    fn default() -> Self {
88        Self {
89            globalization: SqpGlobalization::default(),
90            hessian: SqpHessianSource::default(),
91            tol: 1e-8,
92            constr_viol_tol: 1e-6,
93            dual_inf_tol: 1e-4,
94            max_iter: 200,
95            l1_penalty: 1.0,
96            l1_penalty_safety: 0.1,
97            l1_penalty_max: 1e10,
98            bt_reduction: 0.5,
99            bt_min_alpha: 1e-12,
100            print_level: 0,
101            lbfgs_max_history: 6,
102        }
103    }
104}