From 87ec5352d1b5d7e6e88e3bfeb37d532ed9a8927d Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 23 Jun 2021 11:35:18 -0300 Subject: [PATCH 1/5] Creation of necessary functions in order to interact with the JuMP interface, e.g MOI.is_empty, MOI.get, MOI.set, MOI.supports Creation of attribute 'parameters_name' in 'ParametricOptimizer' Creation of mutable struct 'ParameterRef' --- src/ParametricOptInterface.jl | 101 ++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/src/ParametricOptInterface.jl b/src/ParametricOptInterface.jl index 07bd4380..849a2a6f 100644 --- a/src/ParametricOptInterface.jl +++ b/src/ParametricOptInterface.jl @@ -32,6 +32,7 @@ ParametricOptInterface.ParametricOptimizer{Float64,GLPK.Optimizer} mutable struct ParametricOptimizer{T, OT <: MOI.ModelLike} <: MOI.AbstractOptimizer optimizer::OT parameters::Dict{MOI.VariableIndex, T} + parameters_name::Dict{MOI.VariableIndex, String} updated_parameters::Dict{MOI.VariableIndex, T} variables::Dict{MOI.VariableIndex, MOI.VariableIndex} last_index_added::Int @@ -51,6 +52,7 @@ mutable struct ParametricOptimizer{T, OT <: MOI.ModelLike} <: MOI.AbstractOptimi new{Float64, OT}( optimizer, Dict{MOI.VariableIndex, Float64}(), + Dict{MOI.VariableIndex, String}(), Dict{MOI.VariableIndex, Float64}(), Dict{MOI.VariableIndex, MOI.VariableIndex}(), 0, @@ -70,6 +72,105 @@ mutable struct ParametricOptimizer{T, OT <: MOI.ModelLike} <: MOI.AbstractOptimi end end +function MOI.is_empty(model::ParametricOptimizer) + return MOI.is_empty(model.optimizer) && + isempty(model.parameters) && + isempty(model.parameters_name) && + isempty(model.variables) && + isempty(model.updated_parameters) && + isempty(model.variables) && + model.last_index_added == 0 && + isempty(model.affine_constraint_cache) && + isempty(model.quadratic_constraint_cache_pv) && + isempty(model.quadratic_constraint_cache_pp) && + isempty(model.quadratic_constraint_cache_pc) && + isempty(model.quadratic_constraint_variables_associated_to_parameters_cache) && + isempty(model.quadratic_added_cache) && + model.last_quad_add_added == 0 && + isempty(model.affine_objective_cache) && + isempty(model.quadratic_objective_cache_pv) && + isempty(model.quadratic_objective_cache_pp) && + isempty(model.quadratic_objective_cache_pc) && + isempty(model.quadratic_objective_variables_associated_to_parameters_cache) +end + +function MOI.supports_constraint( + model::ParametricOptimizer, + F::Type{<:MOI.AbstractFunction}, + S::Type{<:MOI.AbstractSet}) + + return MOI.supports_constraint(model.optimizer, F, S) +end + +function MOI.supports( + model::ParametricOptimizer, + attr::Union{MOI.ObjectiveSense, + MOI.ObjectiveFunction{MOI.SingleVariable}, + MOI.ObjectiveFunction{MOI.ScalarAffineFunction{T}}, + }) where T + return MOI.supports(model.optimizer, attr) +end + +function MOI.empty!(model::ParametricOptimizer{T}) where T + MOI.empty!(model.optimizer) + model.parameters = Dict{MOI.VariableIndex, Float64}() + model.parameters_name = Dict{MOI.VariableIndex, String}() + model.updated_parameters = Dict{MOI.VariableIndex, Float64}() + model.variables = Dict{MOI.VariableIndex, MOI.VariableIndex}() + model.last_index_added = 0 + model.affine_constraint_cache = Dict{MOI.ConstraintIndex, Array{MOI.ScalarAffineTerm{Float64},1}}() + model.quadratic_constraint_cache_pv = Dict{MOI.ConstraintIndex, Array{MOI.ScalarQuadraticTerm{Float64},1}}() + model.quadratic_constraint_cache_pp = Dict{MOI.ConstraintIndex, Array{MOI.ScalarQuadraticTerm{Float64},1}}() + model.quadratic_constraint_cache_pc = Dict{MOI.ConstraintIndex, Array{MOI.ScalarAffineTerm{Float64},1}}() + model.quadratic_constraint_variables_associated_to_parameters_cache = Dict{MOI.ConstraintIndex, Array{MOI.ScalarAffineTerm{Float64},1}}() + model.quadratic_added_cache = Dict{MOI.ConstraintIndex, MOI.ConstraintIndex}() + model.last_quad_add_added = 0 + model.affine_objective_cache = Array{MOI.ScalarAffineTerm{Float64},1}() + model.quadratic_objective_cache_pv = Array{MOI.ScalarQuadraticTerm{Float64},1}() + model.quadratic_objective_cache_pp = Array{MOI.ScalarQuadraticTerm{Float64},1}() + model.quadratic_objective_cache_pc = Array{MOI.ScalarAffineTerm{Float64},1}() + model.quadratic_objective_variables_associated_to_parameters_cache = Array{MOI.ScalarAffineTerm{Float64},1}() + return +end + +function MOI.set(model::ParametricOptimizer, attr::MOI.VariableName, v::MOI.VariableIndex, name::String) + if haskey(model.parameters, v) + model.parameters_name[v] = name + else + return MOI.set(model.optimizer, attr, v, name) + end +end + +function MOI.get(model::ParametricOptimizer, attr::MOI.VariableName, v::MOI.VariableIndex) + if haskey(model.parameters, v) + return model.parameters_name[v] + else + return MOI.get(model.optimizer, attr, v) + end +end + +function MOI.supports(model::ParametricOptimizer, attr::MOI.VariableName, tp::Type{MOI.VariableIndex}) + MOI.supports(model.optimizer, attr, tp) +end + +function MOI.set(model::ParametricOptimizer, attr::MOI.ConstraintName, c::MOI.ConstraintIndex, name::String) + MOI.set(model.optimizer, attr, c, name) +end + +function MOI.get(model::ParametricOptimizer, attr::MOI.ConstraintName, c::MOI.ConstraintIndex) + MOI.get(model.optimizer, attr, c) +end + +function MOI.supports(model::ParametricOptimizer, attr::MOI.ConstraintName, tp::Type{MOI.ConstraintIndex}) + MOI.supports(model.optimizer, attr, tp) +end + +struct ParameterRef <: MOI.AbstractOptimizerAttribute end + +function MOI.get(model::ParametricOptimizer, attr::ParameterRef, v::MOI.VariableIndex) + MOI.ConstraintIndex{MOI.SingleVariable, POI.Parameter}(v.value) +end + function MOI.add_variable(model::ParametricOptimizer) model.last_index_added += 1 v_p = MOI.VariableIndex(model.last_index_added) From 65ab994a27437f0ae084f3a4f0a959d6a3b7b0f1 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 25 Jun 2021 12:14:47 -0300 Subject: [PATCH 2/5] Added Thomas' PR functions --- src/ParametricOptInterface.jl | 68 ++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/src/ParametricOptInterface.jl b/src/ParametricOptInterface.jl index 849a2a6f..bd4e4d95 100644 --- a/src/ParametricOptInterface.jl +++ b/src/ParametricOptInterface.jl @@ -98,10 +98,18 @@ function MOI.supports_constraint( model::ParametricOptimizer, F::Type{<:MOI.AbstractFunction}, S::Type{<:MOI.AbstractSet}) - + return MOI.supports_constraint(model.optimizer, F, S) end +function MOI.supports_constraint( + model::ParametricOptimizer, + F::Type{MOI.ScalarQuadraticFunction{T}}, + S::Type{<:MOI.AbstractSet}) where T + + return MOI.supports_constraint(model.optimizer, MOI.ScalarAffineFunction{T}, S) +end + function MOI.supports( model::ParametricOptimizer, attr::Union{MOI.ObjectiveSense, @@ -171,6 +179,64 @@ function MOI.get(model::ParametricOptimizer, attr::ParameterRef, v::MOI.Variable MOI.ConstraintIndex{MOI.SingleVariable, POI.Parameter}(v.value) end +function MOI.get(model::ParametricOptimizer, attr::MOI.ConstraintFunction, ci::MOI.ConstraintIndex{F, S}) where {F, S} + MOI.get(model.optimizer, attr, ci) +end + +function MOI.get(model::ParametricOptimizer, attr::MOI.ConstraintSet, ci::MOI.ConstraintIndex{F, S}) where {F, S} + if MOI.is_valid(model.optimizer, ci) + return MOI.get(model.optimizer, attr, ci) + else + return throw(MOI.InvalidIndex(ci)) + end +end + +function MOI.get(model::ParametricOptimizer, attr::MOI.ObjectiveSense) + MOI.get(model.optimizer, attr) +end + +function MOI.get(model::ParametricOptimizer, attr::MOI.ObjectiveFunctionType) + MOI.get(model.optimizer, attr) +end + +function MOI.get( + model::ParametricOptimizer, + attr::MOI.ObjectiveFunction{F}) where F <: Union{MOI.SingleVariable,MOI.ScalarAffineFunction{T}} where T + + MOI.get(model.optimizer, attr) +end + +function MOI.get(model::ParametricOptimizer, ::MOI.ListOfConstraints) + constraints = Set{Tuple{DataType, DataType}}() + inner_ctrs = MOI.get(model.optimizer, MOI.ListOfConstraints()) + for (F, S) in inner_ctrs + push!(constraints, (F,S)) + end + # error("TODO") + # deal with deleted parameters + collect(constraints) +end + +function MOI.get( + model::ParametricOptimizer, + attr::MOI.ListOfConstraintIndices{F, S} +) where {S, F<:Union{ + MOI.VectorOfVariables, + MOI.SingleVariable, +}} + MOI.get(model.optimizer, attr) +end + +function MOI.get( + model::ParametricOptimizer, + ::MOI.ListOfConstraintIndices{F, S} +) where {S<:MOI.AbstractSet, F<:Union{ + MOI.ScalarAffineFunction{T}, + MOI.VectorAffineFunction{T}, +}} where T + MOI.get(model.optimizer, MOI.ListOfConstraintIndices{F, S}()) +end + function MOI.add_variable(model::ParametricOptimizer) model.last_index_added += 1 v_p = MOI.VariableIndex(model.last_index_added) From 3dabe0c6227b29a8db0d182a66e092278b78300f Mon Sep 17 00:00:00 2001 From: Caio Luke Date: Fri, 25 Jun 2021 16:06:47 -0300 Subject: [PATCH 3/5] - Added a more user friendly set function for parameters - Corrected a bug in which a ScalarQuadraticFunction was not treated as a ScalarAffineFunction when the quadratic term was a product of 2 parameters --- src/ParametricOptInterface.jl | 76 ++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/src/ParametricOptInterface.jl b/src/ParametricOptInterface.jl index bd4e4d95..ba9ff05f 100644 --- a/src/ParametricOptInterface.jl +++ b/src/ParametricOptInterface.jl @@ -121,23 +121,23 @@ end function MOI.empty!(model::ParametricOptimizer{T}) where T MOI.empty!(model.optimizer) - model.parameters = Dict{MOI.VariableIndex, Float64}() - model.parameters_name = Dict{MOI.VariableIndex, String}() - model.updated_parameters = Dict{MOI.VariableIndex, Float64}() - model.variables = Dict{MOI.VariableIndex, MOI.VariableIndex}() + empty!(model.parameters) + empty!(model.parameters_name) + empty!(model.updated_parameters) + empty!(model.variables) model.last_index_added = 0 - model.affine_constraint_cache = Dict{MOI.ConstraintIndex, Array{MOI.ScalarAffineTerm{Float64},1}}() - model.quadratic_constraint_cache_pv = Dict{MOI.ConstraintIndex, Array{MOI.ScalarQuadraticTerm{Float64},1}}() - model.quadratic_constraint_cache_pp = Dict{MOI.ConstraintIndex, Array{MOI.ScalarQuadraticTerm{Float64},1}}() - model.quadratic_constraint_cache_pc = Dict{MOI.ConstraintIndex, Array{MOI.ScalarAffineTerm{Float64},1}}() - model.quadratic_constraint_variables_associated_to_parameters_cache = Dict{MOI.ConstraintIndex, Array{MOI.ScalarAffineTerm{Float64},1}}() - model.quadratic_added_cache = Dict{MOI.ConstraintIndex, MOI.ConstraintIndex}() + empty!(model.affine_constraint_cache) + empty!(model.quadratic_constraint_cache_pv) + empty!(model.quadratic_constraint_cache_pp) + empty!(model.quadratic_constraint_cache_pc) + empty!(model.quadratic_constraint_variables_associated_to_parameters_cache) + empty!(model.quadratic_added_cache) model.last_quad_add_added = 0 - model.affine_objective_cache = Array{MOI.ScalarAffineTerm{Float64},1}() - model.quadratic_objective_cache_pv = Array{MOI.ScalarQuadraticTerm{Float64},1}() - model.quadratic_objective_cache_pp = Array{MOI.ScalarQuadraticTerm{Float64},1}() - model.quadratic_objective_cache_pc = Array{MOI.ScalarAffineTerm{Float64},1}() - model.quadratic_objective_variables_associated_to_parameters_cache = Array{MOI.ScalarAffineTerm{Float64},1}() + empty!(model.affine_objective_cache) + empty!(model.quadratic_objective_cache_pv) + empty!(model.quadratic_objective_cache_pp) + empty!(model.quadratic_objective_cache_pc) + empty!(model.quadratic_objective_variables_associated_to_parameters_cache) return end @@ -173,11 +173,12 @@ function MOI.supports(model::ParametricOptimizer, attr::MOI.ConstraintName, tp:: MOI.supports(model.optimizer, attr, tp) end -struct ParameterRef <: MOI.AbstractOptimizerAttribute end +struct ParameterValue <: MOI.AbstractVariableAttribute end -function MOI.get(model::ParametricOptimizer, attr::ParameterRef, v::MOI.VariableIndex) - MOI.ConstraintIndex{MOI.SingleVariable, POI.Parameter}(v.value) -end +function MOI.set(model::ParametricOptimizer, ::ParameterValue, vi::MOI.VariableIndex, val) + cv = MOI.ConstraintIndex{MOI.SingleVariable, POI.Parameter}(vi.value) + MOI.set(model, MOI.ConstraintSet(), cv, POI.Parameter(val)) +end function MOI.get(model::ParametricOptimizer, attr::MOI.ConstraintFunction, ci::MOI.ConstraintIndex{F, S}) where {F, S} MOI.get(model.optimizer, attr, ci) @@ -262,17 +263,18 @@ function MOI.add_constrained_variable(model::ParametricOptimizer, set::Parameter model.last_index_added += 1 p = MOI.VariableIndex(model.last_index_added) model.parameters[p] = set.val - return p, MOI.ConstraintIndex{MOI.SingleVariable, typeof(set)}(model.last_index_added) + cp = MOI.ConstraintIndex{MOI.SingleVariable, typeof(set)}(model.last_index_added) + return p, cp end -function MOI.add_constraint(model::ParametricOptimizer, f::MOI.SingleVariable, set::MOI.AbstractScalarSet) +function MOI.add_constraint(model::ParametricOptimizer, f::MOI.SingleVariable, set::MOI.AbstractScalarSet) if haskey(model.parameters, f.variable) error("Cannot constrain a parameter") - elseif haskey(model.variables, f.variable) - return MOI.add_constraint(model.optimizer, f, set) - else - error("Variable not in the model") - end + elseif haskey(model.variables, f.variable) + return MOI.add_constraint(model.optimizer, f, set) + else + error("Variable not in the model") + end end function MOI.add_constraint(model::ParametricOptimizer, f::MOI.ScalarAffineFunction{T}, set::MOI.AbstractScalarSet) where T @@ -594,7 +596,7 @@ function MOI.set(model::ParametricOptimizer, attr::MOI.ObjectiveFunction{F}, f:: aux = MOI.ScalarQuadraticTerm(i.coefficient, i.variable_index_1, i.variable_index_2) push!(quad_aff_vars, aux) push!(aux_variables_associated_to_parameters, i.variable_index_2) - + elseif haskey(model.variables, i.variable_index_1) && haskey(model.parameters, i.variable_index_2) # Check convention defined above aux = MOI.ScalarQuadraticTerm(i.coefficient, i.variable_index_2, i.variable_index_1) @@ -659,21 +661,22 @@ function MOI.set(model::ParametricOptimizer, attr::MOI.ObjectiveFunction{F}, f:: const_term += j.coefficient * model.parameters[j.variable_index_1] * model.parameters[j.variable_index_2] end - - f_quad = if !isempty(quad_terms) - MOI.ScalarQuadraticFunction( + if !isempty(quad_terms) + f_quad = MOI.ScalarQuadraticFunction( aff_terms, quad_terms, const_term ) + + MOI.set(model.optimizer, attr, f_quad) else - MOI.ScalarAffineFunction( + f_quad = MOI.ScalarAffineFunction( aff_terms, const_term ) - end - MOI.set(model.optimizer, attr, f_quad) + MOI.set(model.optimizer, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), f_quad) + end model.quadratic_objective_cache_pv = quad_aff_vars model.quadratic_objective_cache_pp = quad_params @@ -839,7 +842,7 @@ function MOI.optimize!(model::ParametricOptimizer) end for (ci, fparam) in model.quadratic_constraint_variables_associated_to_parameters_cache - for j in fparam.terms + for j in fparam coef = j.coefficient if haskey(constraint_aux_dict, (ci, j.variable_index))# constraint_aux_dict[(ci, j.variable_index)] += coef @@ -849,8 +852,9 @@ function MOI.optimize!(model::ParametricOptimizer) end end - for (key, value) in constraint_aux_dict - MOI.modify(model.optimizer, key[1], MOI.ScalarCoefficientChange(key[2], value)) + for ((ci, vi), value) in constraint_aux_dict + old_ci = model.quadratic_added_cache[ci] + MOI.modify(model.optimizer, old_ci, MOI.ScalarCoefficientChange(vi, value)) end objective_aux_dict = Dict{Any,Any}() From 0beee56b970c1a31e505210f93bfd5d7c0afe51e Mon Sep 17 00:00:00 2001 From: Caio Luke Date: Thu, 1 Jul 2021 15:31:36 -0300 Subject: [PATCH 4/5] - Added JuMP as an extra dependency - Added tests interacting with JuMP - JuMP model with linear constraints now supports POI.Parameter if the parameter is not multiplying a variable --- Project.toml | 3 +- src/ParametricOptInterface.jl | 19 ++++++ test/jump_tests.jl | 119 ++++++++++++++++++++++++++++++++++ test/runtests.jl | 4 +- 4 files changed, 142 insertions(+), 3 deletions(-) create mode 100644 test/jump_tests.jl diff --git a/Project.toml b/Project.toml index 167beda2..5b8ebaa3 100644 --- a/Project.toml +++ b/Project.toml @@ -10,6 +10,7 @@ MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" GLPK = "60bf3e95-4087-53dc-ae20-288a0d20c6a6" Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +JuMP = "4076af6c-e467-56ae-b986-b466b2749572" [targets] -test = ["Test", "GLPK", "Ipopt"] +test = ["Test", "GLPK", "Ipopt", "JuMP"] diff --git a/src/ParametricOptInterface.jl b/src/ParametricOptInterface.jl index ba9ff05f..1b004619 100644 --- a/src/ParametricOptInterface.jl +++ b/src/ParametricOptInterface.jl @@ -238,6 +238,25 @@ function MOI.get( MOI.get(model.optimizer, MOI.ListOfConstraintIndices{F, S}()) end +# function MOI.supports_add_constrained_variables( +# model::ParametricOptimizer, ::Type{S}) where {S<:MOI.AbstractVectorSet} +# return MOI.supports_add_constrained_variables(model.optimizer, S) +# end +# function MOI.supports_add_constrained_variables( +# model::ParametricOptimizer, ::Type{S}) where {S<:MOI.AbstractScalarSet} +# return MOI.supports_add_constrained_variables(model.optimizer, S) +# end + +function MOI.supports_add_constrained_variable( + model::ParametricOptimizer, ::Type{Parameter}) + return true +end + +function MOI.supports_add_constrained_variables( + model::ParametricOptimizer, ::Type{MOI.Reals}) + return MOI.supports_add_constrained_variables(model.optimizer, MOI.Reals) +end + function MOI.add_variable(model::ParametricOptimizer) model.last_index_added += 1 v_p = MOI.VariableIndex(model.last_index_added) diff --git a/test/jump_tests.jl b/test/jump_tests.jl new file mode 100644 index 00000000..acb53bc1 --- /dev/null +++ b/test/jump_tests.jl @@ -0,0 +1,119 @@ +@testset "JuMP direct model - Linear Constraints - Affine parameters" begin + optimizer = POI.ParametricOptimizer(GLPK.Optimizer()) + + model = direct_model(optimizer) + + @variable(model, x[i=1:2] >= 0) + + @variable(model, y in POI.Parameter(0)) + @variable(model, w in POI.Parameter(0)) + @variable(model, z in POI.Parameter(0)) + + @constraint(model, 2*x[1] + x[2] + y <= 4) + @constraint(model, 1*x[1] + 2*x[2] + z <= 4) + + @objective(model, Max, 4*x[1] + 3*x[2] + w) + + optimize!(model) + + @test isapprox.(value(x[1]), 4.0/3.0, atol = ATOL) + @test isapprox.(value(x[2]), 4.0/3.0, atol = ATOL) + @test isapprox.(value(y), 0, atol = ATOL) + + # ===== Set parameter value ===== + MOI.set(model, POI.ParameterValue(), y, 2.0) + optimize!(model) + + @test isapprox.(value(x[1]), 0.0, atol = ATOL) + @test isapprox.(value(x[2]), 2.0, atol = ATOL) + @test isapprox.(value(y), 2.0, atol = ATOL) +end + +@testset "JuMP direct model - Linear Constraints - Parameter x variable" begin + optimizer = POI.ParametricOptimizer(GLPK.Optimizer()) + + model = direct_model(optimizer) + + @variable(model, x[i=1:2] >= 0) + + @variable(model, y in POI.Parameter(0)) + @variable(model, w in POI.Parameter(0)) + @variable(model, z in POI.Parameter(0)) + + @constraint(model, 2*x[1] + x[2] + y <= 4) + @constraint(model, (1+y)*x[1] + 2*x[2] + z <= 4) + + @objective(model, Max, 4*x[1] + 3*x[2] + w) + + optimize!(model) + + @test isapprox.(value(x[1]), 4.0/3.0, atol = ATOL) + @test isapprox.(value(x[2]), 4.0/3.0, atol = ATOL) + @test isapprox.(value(y), 0, atol = ATOL) + + # ===== Set parameter value ===== + MOI.set(model, POI.ParameterValue(), y, 2.0) + optimize!(model) + + @test isapprox.(value(x[1]), 0.0, atol = ATOL) + @test isapprox.(value(x[2]), 2.0, atol = ATOL) + @test isapprox.(value(y), 2.0, atol = ATOL) +end + +@testset "JuMP - Linear Constraints - Affine parameters" begin + model = Model(() -> POI.ParametricOptimizer(GLPK.Optimizer())) + + @variable(model, x[i=1:2] >= 0) + + @variable(model, y in POI.Parameter(0)) + @variable(model, w in POI.Parameter(0)) + @variable(model, z in POI.Parameter(0)) + + @constraint(model, 2*x[1] + x[2] + y <= 4) + @constraint(model, 1*x[1] + 2*x[2] + z <= 4) + + @objective(model, Max, 4*x[1] + 3*x[2] + w) + + optimize!(model) + + @test isapprox.(value(x[1]), 4.0/3.0, atol = ATOL) + @test isapprox.(value(x[2]), 4.0/3.0, atol = ATOL) + @test isapprox.(value(y), 0, atol = ATOL) + + # ===== Set parameter value ===== + MOI.set(model, POI.ParameterValue(), y, 2.0) + optimize!(model) + + @test isapprox.(value(x[1]), 0.0, atol = ATOL) + @test isapprox.(value(x[2]), 2.0, atol = ATOL) + @test isapprox.(value(y), 2.0, atol = ATOL) +end + +@testset "JuMP - Linear Constraints - Parameter x variable" begin + model = Model(() -> POI.ParametricOptimizer(GLPK.Optimizer())) + + @variable(model, x[i=1:2] >= 0) + + @variable(model, y in POI.Parameter(0)) + @variable(model, w in POI.Parameter(0)) + @variable(model, z in POI.Parameter(0)) + + @constraint(model, 2*x[1] + x[2] + y <= 4) + @constraint(model, (1+y)*x[1] + 2*x[2] + z <= 4) + + @objective(model, Max, 4*x[1] + 3*x[2] + w) + + optimize!(model) + + @test isapprox.(value(x[1]), 4.0/3.0, atol = ATOL) + @test isapprox.(value(x[2]), 4.0/3.0, atol = ATOL) + @test isapprox.(value(y), 0, atol = ATOL) + + # ===== Set parameter value ===== + MOI.set(model, POI.ParameterValue(), y, 2.0) + optimize!(model) + + @test isapprox.(value(x[1]), 0.0, atol = ATOL) + @test isapprox.(value(x[2]), 2.0, atol = ATOL) + @test isapprox.(value(y), 2.0, atol = ATOL) +end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index 60515213..b8b947d3 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,4 +1,4 @@ -using Test, ParametricOptInterface, MathOptInterface, GLPK, Ipopt +using Test, ParametricOptInterface, MathOptInterface, GLPK, Ipopt, JuMP const POI = ParametricOptInterface const MOI = MathOptInterface @@ -9,5 +9,5 @@ const ATOL = 1e-4 include("production_problem_test.jl") include("basic_tests.jl") include("quad_tests.jl") - +include("jump_tests.jl") From fd38e5b74f073810916a777c03da29428ad32012 Mon Sep 17 00:00:00 2001 From: Caio Luke Date: Mon, 5 Jul 2021 12:36:38 -0300 Subject: [PATCH 5/5] =?UTF-8?q?-=20Adress=20Beno=C3=AEt=20comments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ParametricOptInterface.jl | 96 ++++++++++++++++++----------------- test/jump_tests.jl | 16 +++--- 2 files changed, 57 insertions(+), 55 deletions(-) diff --git a/src/ParametricOptInterface.jl b/src/ParametricOptInterface.jl index 1b004619..ed512f25 100644 --- a/src/ParametricOptInterface.jl +++ b/src/ParametricOptInterface.jl @@ -96,9 +96,12 @@ end function MOI.supports_constraint( model::ParametricOptimizer, - F::Type{<:MOI.AbstractFunction}, - S::Type{<:MOI.AbstractSet}) - + F::Union{Type{MOI.SingleVariable}, + Type{MOI.ScalarAffineFunction{T}}, + Type{MOI.VectorOfVariables}, + Type{MOI.VectorAffineFunction{T}}}, + S::Type{<:MOI.AbstractSet}) where T + return MOI.supports_constraint(model.optimizer, F, S) end @@ -115,6 +118,7 @@ function MOI.supports( attr::Union{MOI.ObjectiveSense, MOI.ObjectiveFunction{MOI.SingleVariable}, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{T}}, + MOI.ObjectiveFunction{MOI.ScalarQuadraticFunction{T}} }) where T return MOI.supports(model.optimizer, attr) end @@ -169,7 +173,7 @@ function MOI.get(model::ParametricOptimizer, attr::MOI.ConstraintName, c::MOI.Co MOI.get(model.optimizer, attr, c) end -function MOI.supports(model::ParametricOptimizer, attr::MOI.ConstraintName, tp::Type{MOI.ConstraintIndex}) +function MOI.supports(model::ParametricOptimizer, attr::MOI.ConstraintName, tp::Type{<:MOI.ConstraintIndex}) MOI.supports(model.optimizer, attr, tp) end @@ -180,43 +184,48 @@ function MOI.set(model::ParametricOptimizer, ::ParameterValue, vi::MOI.VariableI MOI.set(model, MOI.ConstraintSet(), cv, POI.Parameter(val)) end -function MOI.get(model::ParametricOptimizer, attr::MOI.ConstraintFunction, ci::MOI.ConstraintIndex{F, S}) where {F, S} - MOI.get(model.optimizer, attr, ci) -end +# TODO +# This is not correct, you need to put the parameters back into the function +# function MOI.get(model::ParametricOptimizer, attr::MOI.ConstraintFunction, ci::MOI.ConstraintIndex{F, S}) where {F, S} +# MOI.get(model.optimizer, attr, ci) +# end function MOI.get(model::ParametricOptimizer, attr::MOI.ConstraintSet, ci::MOI.ConstraintIndex{F, S}) where {F, S} - if MOI.is_valid(model.optimizer, ci) - return MOI.get(model.optimizer, attr, ci) - else - return throw(MOI.InvalidIndex(ci)) - end + MOI.throw_if_not_valid(model, ci) + return MOI.get(model.optimizer, attr, ci) end function MOI.get(model::ParametricOptimizer, attr::MOI.ObjectiveSense) MOI.get(model.optimizer, attr) end -function MOI.get(model::ParametricOptimizer, attr::MOI.ObjectiveFunctionType) - MOI.get(model.optimizer, attr) -end +# TODO +# This is not correct, you might have transformed a quadratic function into an affine function, +# you need to give the type that was given by the user, not the type of the inner model. +# function MOI.get(model::ParametricOptimizer, attr::MOI.ObjectiveFunctionType) +# MOI.get(model.optimizer, attr) +# end -function MOI.get( - model::ParametricOptimizer, - attr::MOI.ObjectiveFunction{F}) where F <: Union{MOI.SingleVariable,MOI.ScalarAffineFunction{T}} where T +# TODO +# Same as ConstraintFunction getter. And you also need to convert to F +# function MOI.get( +# model::ParametricOptimizer, +# attr::MOI.ObjectiveFunction{F}) where F <: Union{MOI.SingleVariable,MOI.ScalarAffineFunction{T}} where T - MOI.get(model.optimizer, attr) -end +# MOI.get(model.optimizer, attr) +# end -function MOI.get(model::ParametricOptimizer, ::MOI.ListOfConstraints) - constraints = Set{Tuple{DataType, DataType}}() - inner_ctrs = MOI.get(model.optimizer, MOI.ListOfConstraints()) - for (F, S) in inner_ctrs - push!(constraints, (F,S)) - end - # error("TODO") - # deal with deleted parameters - collect(constraints) -end +# TODO +# You might have transformed quadratic functions into affine functions so this is incorrect +# function MOI.get(model::ParametricOptimizer, ::MOI.ListOfConstraints) +# constraints = Set{Tuple{DataType, DataType}}() +# inner_ctrs = MOI.get(model.optimizer, MOI.ListOfConstraints()) +# for (F, S) in inner_ctrs +# push!(constraints, (F,S)) +# end + +# collect(constraints) +# end function MOI.get( model::ParametricOptimizer, @@ -228,23 +237,16 @@ function MOI.get( MOI.get(model.optimizer, attr) end -function MOI.get( - model::ParametricOptimizer, - ::MOI.ListOfConstraintIndices{F, S} -) where {S<:MOI.AbstractSet, F<:Union{ - MOI.ScalarAffineFunction{T}, - MOI.VectorAffineFunction{T}, -}} where T - MOI.get(model.optimizer, MOI.ListOfConstraintIndices{F, S}()) -end - -# function MOI.supports_add_constrained_variables( -# model::ParametricOptimizer, ::Type{S}) where {S<:MOI.AbstractVectorSet} -# return MOI.supports_add_constrained_variables(model.optimizer, S) -# end -# function MOI.supports_add_constrained_variables( -# model::ParametricOptimizer, ::Type{S}) where {S<:MOI.AbstractScalarSet} -# return MOI.supports_add_constrained_variables(model.optimizer, S) +# TODO +# You might have transformed quadratic functions into affine functions so this is incorrect +# function MOI.get( +# model::ParametricOptimizer, +# ::MOI.ListOfConstraintIndices{F, S} +# ) where {S<:MOI.AbstractSet, F<:Union{ +# MOI.ScalarAffineFunction{T}, +# MOI.VectorAffineFunction{T}, +# }} where T +# MOI.get(model.optimizer, MOI.ListOfConstraintIndices{F, S}()) # end function MOI.supports_add_constrained_variable( diff --git a/test/jump_tests.jl b/test/jump_tests.jl index acb53bc1..7f724129 100644 --- a/test/jump_tests.jl +++ b/test/jump_tests.jl @@ -103,17 +103,17 @@ end @objective(model, Max, 4*x[1] + 3*x[2] + w) - optimize!(model) + @test_broken optimize!(model) - @test isapprox.(value(x[1]), 4.0/3.0, atol = ATOL) - @test isapprox.(value(x[2]), 4.0/3.0, atol = ATOL) - @test isapprox.(value(y), 0, atol = ATOL) + @test_broken isapprox.(value(x[1]), 4.0/3.0, atol = ATOL) + @test_broken isapprox.(value(x[2]), 4.0/3.0, atol = ATOL) + @test_broken isapprox.(value(y), 0, atol = ATOL) # ===== Set parameter value ===== MOI.set(model, POI.ParameterValue(), y, 2.0) - optimize!(model) + @test_broken optimize!(model) - @test isapprox.(value(x[1]), 0.0, atol = ATOL) - @test isapprox.(value(x[2]), 2.0, atol = ATOL) - @test isapprox.(value(y), 2.0, atol = ATOL) + @test_broken isapprox.(value(x[1]), 0.0, atol = ATOL) + @test_broken isapprox.(value(x[2]), 2.0, atol = ATOL) + @test_broken isapprox.(value(y), 2.0, atol = ATOL) end \ No newline at end of file