Skip to content

Add ModelWithQuad and privatize the product functions of QPBlockData - #3053

Open
blegat wants to merge 7 commits into
bl/qp_block_datafrom
bl/model_with_quad
Open

Add ModelWithQuad and privatize the product functions of QPBlockData#3053
blegat wants to merge 7 commits into
bl/qp_block_datafrom
bl/model_with_quad

Conversation

@blegat

@blegat blegat commented Aug 15, 2026

Copy link
Copy Markdown
Member

As discussed in #3048 (comment), it might be better to directly go for ModelWithQuad and have the solver use that directly so that we don't have to make the interface to QPBlockData public and we can change it later.

Github is suggesting me to "Start a pull request stack", I didn't know this feature, let's try.

blegat added 2 commits August 15, 2026 13:42
Making a first release with public add_constraint_jacobian_product,
add_constraint_jacobian_transpose_product, and
add_hessian_lagrangian_product commits MOI to three new function names.
Instead, rename them _add_... and add ModelWithQuad/EvaluatorWithQuad:
the evaluator implements the standard MOI.AbstractNLPEvaluator
interface (including the product callbacks, composed inner-first so
that store-semantics inner implementations such as ReverseAD do not
clobber the QP contribution), so consumers only rely on existing
generic functions and the QPBlockData internals stay private.

ModelWithQuad routes affine and quadratic objectives and constraints
to a QPBlockData and everything else to an inner model, forwards the
MOI attribute queries of the QP block, and tracks where the objective
lives. EvaluatorWithQuad remaps the variables of the QP block to their
consecutive index in ordered_variables during MOI.initialize (variables
absent from ordered_variables are parameters and keep their index,
with the parameters dictionary aliased so per-solve value syncs are
visible), and MOI.NLPBlockData(evaluator) assembles the combined
constraint bounds.
No solver passes `inner = nothing`: the consumers all wrap an eager inner
`Nonlinear.Model`, so drop the `set_objective(::Nothing, ::Nothing)` hook
and the docstring sentence advertising it. A solver that manages its own
nonlinear storage can still define `set_objective` for its inner type.
blegat added 5 commits August 15, 2026 15:20
Nonlinear.set_objective is the single way to set the objective: it does
everything the MOI.set method did, and it also accepts nothing to clear the
objective, which the MOI attribute interface cannot express. The MOI getters
stay since the function API has no counterpart for them.
ModelWithQuad now owns a MOI.Utilities.VariablesContainer and implements
MOI.add_variable, guaranteeing variable indices 1:n like
MOI.Utilities.MatrixOfConstraints, so the EvaluatorWithQuad no longer remaps
the QP block. Parameters are added with MOI.add_constrained_variable: their
indices are offset by _PARAMETER_OFFSET (moved here from Ipopt), QPBlockData
is back to the simple offset-based _is_parameter instead of the parameters
dictionary, and its parameters vector aliases the parameter storage of the
inner Nonlinear.Model, so solvers no longer sync parameter values before a
solve.
Sharing only when the inner model is a Nonlinear.Model silently left
qp.parameters empty for any other inner model type. Assume instead that the
inner model exposes its parameter values as parameters::Vector{T}, like
Nonlinear.Model does, and always alias it; an inner model without that field
fails loudly at construction.
They belong next to the convention; Ipopt and MadNLP defined them on their
local alias of the function, which pirates it.
The substitution of the offset parameter indices by ParameterIndex before
the inner model parses a function is index arithmetic tied to the parameter
convention of the layer, so it belongs here: the generic add_constraint and
set_objective now perform it, and the solvers just forward.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant