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}