Skip to main content

pounce_algorithm/sqp/
problem.rs

1//! Minimal NLP-evaluation trait the SQP outer loop binds against.
2//!
3//! Distinct from [`crate::ipopt_nlp::IpoptNlp`] (the rich IPM-
4//! shaped interface with slacks, bound vector spaces, and
5//! IPM-specific initialization hooks). `SqpProblemSpec` is a thin
6//! evaluation surface — just what `SqpAlgorithm::optimize` calls
7//! per iteration.
8//!
9//! The adapter from `IpoptNlp` to `SqpProblemSpec` lives in
10//! [`crate::sqp::ipopt_adapter::IpoptNlpAdapter`], so the same
11//! benchmarks (CUTEst, `.nl` files, `pounce-py`) drive both
12//! algorithm paths via the `AlgorithmChoice` dispatch in
13//! `alg_builder`.
14
15use crate::sqp::qp_assembly::Triplet;
16use pounce_common::Number;
17
18pub trait SqpProblemSpec {
19    fn n(&self) -> usize;
20    fn m(&self) -> usize;
21
22    fn x_init(&self) -> Vec<Number>;
23
24    fn variable_bounds(&self) -> (Vec<Number>, Vec<Number>);
25    fn constraint_bounds(&self) -> (Vec<Number>, Vec<Number>);
26
27    fn eval_f(&mut self, x: &[Number]) -> Number;
28    fn eval_grad_f(&mut self, x: &[Number]) -> Vec<Number>;
29
30    /// `c(x)` — combined constraint values (length `m`). The
31    /// constraint bounds from `constraint_bounds` apply directly:
32    /// row `i` is a strict equality if `bl[i] == bu[i]`, an
33    /// inequality otherwise.
34    fn eval_c(&mut self, x: &[Number]) -> Vec<Number>;
35
36    /// `∇c(x)` as a sparse `m × n` triplet (1-based indices).
37    fn eval_jac_c(&mut self, x: &[Number]) -> Triplet;
38
39    /// `∇²L(x, λ_g) = ∇²f(x) + Σ λ_g_i · ∇²c_i(x)` as a sparse
40    /// symmetric `n × n` triplet.
41    fn eval_hess_lag(&mut self, x: &[Number], lambda_g: &[Number]) -> Triplet;
42}