Uno unfolding: Lagrange-Newton NLP presets (Uno port)#
The unfold_uno method is the Python analogue of the R package
Uno 2.x (B. Narasimhan, CRAN, MIT): the R package binds the C++
solver Uno — “Unifying Nonlinear Optimization” — described in
Vanaret & Leyffer (2024, arXiv:2406.13454), which expresses non-linearly
constrained optimisation as a Lagrange-Newton method whose building
blocks (constraint relaxation, inequality handling, Hessian and
globalisation strategies) are freely combined, reproducing classical
solvers such as filterSQP and IPOPT by presets.
Unfolding NLP#
The unfolding problem is posed as the smooth non-linear program
with the diagonal reading weights W (weights="uniform" |
"poisson" | array) and the relative second-difference ridge
regularization = lam (like in the other bssunfold methods).
Presets#
preset="filter_sqp"(default) — Lagrange-Newton SQP with the exact (constant) Hessian \(H = A^{\mathsf T} W^2 A + \lambda D_2^{\mathsf T} D_2\) and the Fletcher-Leyffer filter globalisation on the (objective f, constraint violation \(v(x) = \|\min(x,0)\|^2\)) pair. Because the unfolding NLP is a convex quadratic objective with box inequalities, the exact-Hessian SQP sub-problem is the QP itself: it is solved in one Lagrange-Newton step through the classical active-set (Lawson-Hanson NNLS) solver on the equivalent stacked least-squares system \([\,W A;\ \sqrt\lambda D_2\,]x = [\,W b;\ 0\,]\);preset="ipopt_like"— a primal-dual interior-point method in the IPOPT manner: the inequalities are handled by the log-barrier \(-\mu \sum \log x\), the Newton system is regularised with the barrier Hessian \(\operatorname{diag}(\mu / x^2)\), \(\mu\) follows a geometric schedule with a fraction-to-the-boundary rule. The Hessian building block is selectable:hessian="exact"(the convex default) orhessian="bfgs"(a dense quasi-Newton approximation updated from the gradient differences — Uno’s quasi-Newton block).
Diagnostics#
The solver reports Uno’s SolveStatistics-style quality measures in
the result: preset, hessian, objective
\(f(x^\*)\), constraint_violation, dual_infeasibility
(the infinity norm of the projected KKT stationarity residual,
relative to the initial gradient scale), n_iterations and
converged.
Example#
from bssunfold import Detector
det = Detector(RF_GSF)
result = det.unfold_uno(readings) # filterSQP
result = det.unfold_uno(readings, preset="ipopt_like") # IPOPT-style IPM
result = det.unfold_uno(
readings, preset="ipopt_like", hessian="bfgs",
regularization=1e-2, weights="poisson",
)
print(result["objective"], result["constraint_violation"])
Notes#
Pure NumPy/SciPy; the QP sub-solve uses the classical
scipy.optimize.nnlsactive-set routine.Both presets enforce \(x \ge 0\) by construction (projection / strictly feasible barrier iterates).
hessian="bfgs"is only meaningful withpreset="ipopt_like"(the SQP preset uses the exact constant Hessian).