Expand description
Build a pounce_qp::QpProblem from the NLP linearization at
the current SQP iterate (x, λ_g).
Standard SQP QP subproblem (Nocedal-Wright §18.1):
min ½ pᵀ ∇²L(x, λ) p + ∇f(x)ᵀ p
s.t. bl_c ≤ c(x) + ∇c(x) p ≤ bu_c
xl − x ≤ p ≤ xu − xThe QP’s general bounds are shifted RHSs: bl_qp = bl_c − c(x)
and bu_qp = bu_c − c(x) (treating equalities as
bl_c = bu_c = 0). The QP’s variable bounds are xl − x and
xu − x, so the QP primal p directly equals the SQP step.
SqpQpData owns the sparse storage and exposes a borrowed
QpProblem view; this is the analog of
pounce_qp::ElasticReformulation::as_qp.
§Low-rank Hessians (gh#1054)
A limited-memory Hessian B = σI + Σᵢ signᵢ vᵢ vᵢᵀ is dense, and handing
it to the QP as a dense triplet costs n² storage and turns every sparse
factorization dense — at n = 15 000 the first QP of a collocation model
did not finish. SqpQpData::build_low_rank instead lifts the QP with
one extra variable per term, wᵢ = vᵢᵀ p, held by an equality row:
min ½ σ‖p‖² + ½ Σᵢ signᵢ wᵢ² + ∇f(x)ᵀ p
s.t. wᵢ − vᵢᵀ p = 0 (r rows, always active)
... the original rows and bounds on p ...Its Hessian is diagonal and its extra rows are r dense rows of
length n, so the KKT stays sparse; eliminating w gives back exactly
½ pᵀ B p. The lifted Hessian is indefinite (the −1 terms) while its
restriction to the feasible set is B, positive definite, which is the
case the QP’s inertia control is built for, so the problem is posed as
HessianInertia::Indefinite. The SQP never sees the lift:
SqpQpData::lift_working_set and SqpQpData::unlift_solution map
working sets and solutions across it at every QP call.