diff --git a/docs/src/Examples/example.md b/docs/src/Examples/example.md index cdad637..813a4ca 100644 --- a/docs/src/Examples/example.md +++ b/docs/src/Examples/example.md @@ -353,7 +353,7 @@ MOI.set( ) ``` -To multiply a parameter in a quadratic term, the user will +To multiply a parameter in a quadratic term, the user will need to use the `POI.QuadraticObjectiveCoef` model attribute. ```@example moi2 @@ -415,7 +415,7 @@ We use the same MOI function to add the parameter multiplied to the quadratic te MOI.set(backend(model), POI.QuadraticObjectiveCoef(), (index(x),index(y)), 2index(p)+3) ``` -If the user print the `model`, the term `(2p+3)*xy` won't show. +If the user print the `model`, the term `(2p+3)*xy` won't show. It's possible to retrieve the parametric function multiplying the term `xy` with `MOI.get`. ```@example jump4 @@ -440,63 +440,3 @@ isapprox(objective_value(model), 128/9, atol=1e-4) isapprox(value(x), 4/3, atol=1e-4) isapprox(value(y), 4/3, atol=1e-4) ``` -## JuMP Example - Non Linear Programming (NLP) - -POI currently works with NLPs when users wish to add the parameters to the non-NL constraints or objective. This means that POI works with models like this one: - -```julia -@variable(model, x) -@variable(model, y) -@variable(model, z in MOI.Parameter(10)) -@constraint(model, x + y >= z) -@NLobjective(model, Min, x^2 + y^2) -``` - -but does not work with models that have parameters on the NL expressions like this one: - -```julia -@variable(model, x) -@variable(model, y) -@variable(model, z in MOI.Parameter(10)) -@constraint(model, x + y >= z) -@NLobjective(model, Min, x^2 + y^2 + z) # There is a parameter here -``` - -If users with to add parameters in NL expressions we strongly recommend them to read [this section on the JuMP documentation]((https://jump.dev/JuMP.jl/stable/manual/nlp/#Create-a-nonlinear-parameter)) - -Although POI works with NLPs there are some important information for users to keep in mind. All come from the fact that POI relies on the MOI interface for problem modifications and these are not common on NLP solvers, most solvers only allow users to modify variable bounds using their official APIs. This means that if users wish to make modifications on some constraint that is not a variable bound we are not allowed to call `MOI.modify` because the function is not supported in the MOI solver interface. The work-around to this is defining a [`POI.Optimizer`](@ref) on a caching optimizer: - -```julia -ipopt = Ipopt.Optimizer() -MOI.set(ipopt, MOI.RawOptimizerAttribute("print_level"), 0) -cached = - () -> MOI.Bridges.full_bridge_optimizer( - MOIU.CachingOptimizer( - MOIU.UniversalFallback(MOIU.Model{Float64}()), - ipopt, - ), - Float64, - ) -POI_cached_optimizer() = POI.Optimizer(cached()) -model = Model(() -> POI_cached_optimizer()) -@variable(model, x) -@variable(model, y) -@variable(model, z in MOI.Parameter(10)) -@constraint(model, x + y >= z) -@NLobjective(model, Min, x^2 + y^2) -``` - -This works but keep in mind that the model has an additional layer of between the solver and the [`POI.Optimizer`](@ref). This will make most operations slower than with the version without the caching optimizer. Keep in mind that since the official APIs of most solvers don't allow for modifications on linear constraints there should have no big difference between making a modification using POI or re-building the model from scratch. - -If users wish to make modifications on variable bounds the POI interface will help you save time between solves. In this case you should use the [`ParametricOptInterface.ConstraintsInterpretation`](@ref) as we do in this example: - -```julia -model = Model(() -> POI.Optimizer(Ipopt.Optimizer())) -@variable(model, x) -@variable(model, z in MOI.Parameter(10)) -MOI.set(model, POI.ConstraintsInterpretation(), POI.ONLY_BOUNDS) -@constraint(model, x >= z) -@NLobjective(model, Min, x^2) -``` - -This use case should help users diminsh the time of making model modifications and re-solve the model. To increase the performance users that are familiar with [JuMP direct mode](https://jump.dev/JuMP.jl/stable/manual/models/#Direct-mode) can also use it. diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 70f3aff..d99cdf8 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -948,18 +948,6 @@ function MOI.set( return end -# -# NLP -# - -function MOI.supports(model::Optimizer, ::MOI.NLPBlock) - return MOI.supports(model.optimizer, MOI.NLPBlock()) -end - -function MOI.set(model::Optimizer, ::MOI.NLPBlock, nlp_data::MOI.NLPBlockData) - return MOI.set(model.optimizer, MOI.NLPBlock(), nlp_data) -end - # # Other # @@ -1369,73 +1357,6 @@ function MOI.get( end end -# -# Copy -# - -function MOI.Utilities.default_copy_to( - dest::MOI.Bridges.LazyBridgeOptimizer{Optimizer{T,OT}}, - src::MOI.ModelLike, -) where {T,OT} - return _poi_default_copy_to(dest, src) -end - -function MOI.Utilities.default_copy_to( - dest::Optimizer{T,OT}, - src::MOI.ModelLike, -) where {T,OT} - return _poi_default_copy_to(dest, src) -end - -function _poi_default_copy_to(dest::T, src::MOI.ModelLike) where {T} - if !MOI.supports_incremental_interface(dest) - error("Model $(typeof(dest)) does not support copy_to.") - end - MOI.empty!(dest) - vis_src = MOI.get(src, MOI.ListOfVariableIndices()) - index_map = MOI.IndexMap() - # The `NLPBlock` assumes that the order of variables does not change (#849) - # Therefore, all VariableIndex and VectorOfVariable constraints are added - # seprately, and no variables constrained-on-creation are added. - - # This is not valid for NLPs with Parameters, they should enter - has_nlp = MOI.NLPBlock() in MOI.get(src, MOI.ListOfModelAttributesSet()) - constraints_not_added = if has_nlp - vcat( - Any[ - MOI.get(src, MOI.ListOfConstraintIndices{F,S}()) for - (F, S) in MOI.get(src, MOI.ListOfConstraintTypesPresent()) if - MOI.Utilities._is_variable_function(F) && - S != MOI.Parameter{Float64} - ], - Any[MOI.Utilities._try_constrain_variables_on_creation( - dest, - src, - index_map, - MOI.Parameter{Float64}, - )], - ) - else - Any[ - MOI.Utilities._try_constrain_variables_on_creation( - dest, - src, - index_map, - S, - ) for S in MOI.Utilities.sorted_variable_sets_by_cost(dest, src) - ] - end - MOI.Utilities._copy_free_variables(dest, index_map, vis_src) - # Copy variable attributes - MOI.Utilities.pass_attributes(dest, src, index_map, vis_src) - # Copy model attributes - MOI.Utilities.pass_attributes(dest, src, index_map) - # Copy constraints - MOI.Utilities._pass_constraints(dest, src, index_map, constraints_not_added) - MOI.Utilities.final_touch(dest, index_map) - return index_map -end - # # Optimize # diff --git a/test/jump_tests.jl b/test/jump_tests.jl index 2dd2799..8ee15e2 100644 --- a/test/jump_tests.jl +++ b/test/jump_tests.jl @@ -754,51 +754,12 @@ function test_jump_dual_delete_constraint() end function test_jump_nlp() - ipopt = Ipopt.Optimizer() - MOI.set(ipopt, MOI.RawOptimizerAttribute("print_level"), 0) - cached = - () -> MOI.Bridges.full_bridge_optimizer( - MOI.Utilities.CachingOptimizer( - MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()), - ipopt, - ), - Float64, - ) - POI_cached_optimizer() = ParametricOptInterface.Optimizer(cached()) - model = Model(() -> POI_cached_optimizer()) + model = Model(() -> ParametricOptInterface.Optimizer(Ipopt.Optimizer())) @variable(model, x) - @variable(model, y) @variable(model, z in MOI.Parameter(10.0)) - @constraint(model, x + y >= z) - @NLobjective(model, Min, x^2 + y^2) - optimize!(model) - objective_value(model) - @test value(x) ≈ 5 - MOI.get(model, ParametricOptInterface.ParameterDual(), z) - MOI.set(model, ParametricOptInterface.ParameterValue(), z, 2.0) - optimize!(model) - @test objective_value(model) ≈ 2 atol = 1e-3 - @test value(x) ≈ 1 - ipopt = Ipopt.Optimizer() - MOI.set(ipopt, MOI.RawOptimizerAttribute("print_level"), 0) - model = Model(() -> ParametricOptInterface.Optimizer(ipopt)) - @variable(model, x) - @variable(model, z in MOI.Parameter(10.0)) - MOI.set( - model, - ParametricOptInterface.ConstraintsInterpretation(), - ParametricOptInterface.ONLY_BOUNDS, - ) @constraint(model, x >= z) @NLobjective(model, Min, x^2) - optimize!(model) - objective_value(model) - @test value(x) ≈ 10 - MOI.get(model, ParametricOptInterface.ParameterDual(), z) - MOI.set(model, ParametricOptInterface.ParameterValue(), z, 2.0) - optimize!(model) - @test objective_value(model) ≈ 4 atol = 1e-3 - @test value(x) ≈ 2 + @test_throws ErrorException optimize!(model) return end