Skip to content

Use MOI.Nonlinear.QPBlockData - #640

Open
blegat wants to merge 12 commits into
madsuite-org:masterfrom
blegat:bl/qp_block_data
Open

Use MOI.Nonlinear.QPBlockData#640
blegat wants to merge 12 commits into
madsuite-org:masterfrom
blegat:bl/qp_block_data

Conversation

@blegat

@blegat blegat commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

A net line deletion of 685 lines. Needs

Two adaptations:

  • MOI's QPBlockData treats a variable as a parameter if and only if its index is a key of the parameters dictionary, instead of the index-offset convention, so parameters are registered when the constrained variable is added (the value is still re-synced before every solve).
  • eval_constraint_jacobian and eval_hessian_lagrangian now return the number of entries written instead of a one-indexed cursor, so the callers drop the offset adjustment.

Delete the local QPBlockData (MOI_utils.jl) in favor of the copy that
moved to MathOptInterface, which includes the Jacobian and Hessian
product callbacks this copy had added. Two adaptations:

- MOI's QPBlockData treats a variable as a parameter if and only if its
  index is a key of the parameters dictionary, instead of the
  index-offset convention, so parameters are registered when the
  constrained variable is added (the value is still re-synced before
  every solve).
- eval_constraint_jacobian and eval_hessian_lagrangian now return the
  number of entries written instead of a one-indexed cursor, so the
  callers drop the offset adjustment.
blegat added 10 commits August 13, 2026 14:16
The evaluator methods of MOI.Nonlinear.QPBlockData now return nothing,
following the documented contract of MOI.eval_constraint_jacobian and
MOI.eval_hessian_lagrangian, so the offsets of the oracle and NLP
blocks are computed once in _setup_model instead.
Follow-up to the rename in MathOptInterface: the accumulating product
functions of QPBlockData are no longer methods of the MOI.eval_...
generic functions.
The fused MOI.eval_constraint_jacobian_transpose_product called the
nonlinear-expressions evaluator LAST with the full output vector.
Implementations of that function store the result (ReverseAD zeroes the
output before writing), so the contributions of the QP block and of the
vector-nonlinear-oracle constraints accumulated beforehand were erased
whenever the model also had ScalarNonlinearFunction constraints. Call
the evaluator first and accumulate the other blocks afterwards, like
the fused Jacobian and Hessian products already did.
Store the affine and quadratic objective and constraints in a
MOI.Nonlinear.ModelWithQuad whose inner model is the nonlinear model
(nlp_model now aliases quad_data.inner), and evaluate everything through a
MOI.Nonlinear.EvaluatorWithQuad built in _setup_model. The evaluator owns
the QP block entry counts, so the qp_nnzj/qp_nnzh fields are removed. The
inner evaluator is a new _OracleNLPEvaluator that stacks the
VectorNonlinearOracle rows before the NLPBlock rows; it extends the private
MOI.Nonlinear._constraint_bounds so that the constraint bounds of the whole
stack are assembled by the evaluator, and it owns the transposed-Jacobian
product fallback of the oracles. The jprod/hprod/hess availability flags now
read directly off MOI.features_available of the evaluator, which performs
the same oracle filtering.
MOI.Nonlinear.ModelWithQuad no longer implements MOI.set for the objective;
Nonlinear.set_objective is the single way to set it.
MOI.Nonlinear.ModelWithQuad now owns the variables (with indices guaranteed
to be 1:n) and the parameters of the model, so the variables, parameters,
quad_data and nlp_model fields collapse into a single model field that most
of the MOI API forwards to. The parameter convention is back to the simple
_PARAMETER_OFFSET test, now defined in MOI.Nonlinear, and the parameter
values are stored once, in the inner nonlinear model, aliased by the QP
block: the per-solve parameter sync is gone. A uses_nlp_block flag replaces
the nlp_model !== nothing test to tell the legacy MOI.NLPBlock API apart,
because optimize! overwrites nlp_data; the NLPBlock is rebuilt on every
setup unless that flag is set, so that a stale objective cannot survive an
objective switch.
Defining the term methods on a local alias of the function pirated it; the
term methods are in MOI.Nonlinear now.
The generic add_constraint and set_objective of the layer replace the offset
parameter indices by ParameterIndex, so forward nonlinear constraints to the
layer instead of its inner model and drop _replace_parameters.

@frapac frapac left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! We can merge this PR once the PR has been merged en released in MOI.

@amontoison

Copy link
Copy Markdown
Member

Please do exactly the sme modifications in Ipopt.jl and MadNLP.jl such that it is easier to maintain.
I will also do the same modifications in UnoSolver.jl.

@blegat

blegat commented Aug 18, 2026

Copy link
Copy Markdown
Contributor Author

I can take care of Uno as well, I am doing Ipopt first but I plan to do MadNLP the same way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants