Use MOI.Nonlinear.QPBlockData - #548
Conversation
Delete the local QPBlockData (utils.jl) in favor of the copy that moved to MathOptInterface. 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 in copy_parameters 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.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #548 +/- ##
===========================================
- Coverage 100.00% 99.55% -0.45%
===========================================
Files 5 4 -1
Lines 1192 899 -293
===========================================
- Hits 1192 895 -297
- Misses 0 4 +4 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
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.
| any(isequal(_kFunctionTypeScalarQuadratic), model.qp_data.function_type) | ||
| any( | ||
| isequal(MOI.Nonlinear._kFunctionTypeScalarQuadratic), | ||
| model.qp_data.function_type, |
There was a problem hiding this comment.
Is this part of the public API of qp_data?
There was a problem hiding this comment.
I think QPBlockData should be internal and we should only expose ModelWithQuad, see #548
| # is a key of `parameters`, so the parameter must be registered before | ||
| # any structure query. The value is re-synced in `copy_parameters` before | ||
| # every solve. | ||
| model.qp_data.parameters[p.value] = set.value |
| # in the LICENSE.md file or at https://opensource.org/licenses/MIT. | ||
|
|
||
| include("utils.jl") | ||
| const QPBlockData = MOI.Nonlinear.QPBlockData |
There was a problem hiding this comment.
Strongly prefer that we use explicit prefixes instead of these extra constants. It's only needed in a few places, and using the explicit prefix makes the code much easier to read.
| using Pkg | ||
| Pkg.add([ | ||
| PackageSpec(name="MathOptInterface", rev="bl/qp_block_data"), | ||
| ]) |
There was a problem hiding this comment.
[sources]
MathOptInterface = {url = "https://github.com/jump-dev/MathOptInterface.jl", rev = "bl/qp_block_data"}
There was a problem hiding this comment.
That doesn't work on Julia v1.10
* Use MOI.Nonlinear.ModelWithQuad instead of QPBlockData 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. * MOI * Set the quadratic objective with Nonlinear.set_objective MOI.Nonlinear.ModelWithQuad no longer implements MOI.set for the objective; Nonlinear.set_objective is the single way to set it. * Merge the variables, parameters and nonlinear model into one field 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. * Use the _is_parameter of MOI.Nonlinear directly Defining the term methods on a local alias of the function pirated it; the term methods are in MOI.Nonlinear now. * Fix * Get rid of list_of_variable_indices
A net line deletion of 534 lines. Needs