diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index b5302628..a3c8aa63 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -323,6 +323,22 @@ function MOI.supports( return MOI.supports(model.optimizer, attr, tp) end +function MOI.get( + model::Optimizer, + attr::MOI.VariablePrimalStart, + v::MOI.VariableIndex, +) + if _variable_in_model(model, v) + return MOI.get(model.optimizer, attr, v) + elseif _parameter_in_model(model, v) + # this is effectivelly a no-op, but we do validation + _val = model.parameters[p_idx(v)] + return _val + else + error("Variable not in the model") + end +end + function MOI.set( model::Optimizer, attr::MOI.VariablePrimalStart, @@ -413,17 +429,25 @@ end function MOI.is_valid( model::Optimizer, c::MOI.ConstraintIndex{F,S}, -) where { - F<:Union{MOI.VariableIndex,MOI.VectorOfVariables,MOI.VectorAffineFunction}, - S<:MOI.AbstractSet, -} +) where {F<:Union{MOI.VariableIndex,MOI.VectorOfVariables},S<:MOI.AbstractSet} return MOI.is_valid(model.optimizer, c) end function MOI.is_valid( model::Optimizer, c::MOI.ConstraintIndex{F,S}, -) where {F<:MOI.ScalarAffineFunction,S<:MOI.AbstractSet} +) where { + F<:Union{ + MOI.ScalarAffineFunction, + MOI.ScalarQuadraticFunction, + MOI.VectorAffineFunction, + MOI.VectorQuadraticFunction, + }, + S<:MOI.AbstractSet, +} + if haskey(model.constraint_outer_to_inner, c) + return true + end return MOI.is_valid(model.optimizer, c) end diff --git a/test/jump_tests.jl b/test/jump_tests.jl index 807ca42a..7a370a2a 100644 --- a/test/jump_tests.jl +++ b/test/jump_tests.jl @@ -427,11 +427,10 @@ function test_jump_set_variable_start_value() @variable(model, p in MOI.Parameter(0.0)) set_start_value(x, 1.0) @test start_value(x) == 1 - err = ErrorException( - "MathOptInterface.VariablePrimalStart() is not supported for parameters", - ) - @test_throws err set_start_value(p, 1.0) - @test_throws err start_value(p) + @test_throws ErrorException( + "The parameter $(index(p)) value is 0.0, but trying to set VariablePrimalStart 1.0", + ) set_start_value(p, 1.0) + @test start_value(p) == 0.0 return end @@ -1275,14 +1274,51 @@ function test_parameter_Cannot_be_inf_2() return end -function test_jump_psd_cone_with_parameter() +function test_jump_psd_cone_with_parameter_pv() model = Model(SCS.Optimizer) @variable(model, x) @variable(model, p in MOI.Parameter(1.0)) - @constraint(model, [[0 (p * x + -1)]; [(p * x + -1) 0]] in JuMP.PSDCone()) + @constraint( + model, + con, + [[0 (p * x - 1)]; [(p * x - 1) 0]] in JuMP.PSDCone() + ) + # the above constraint is equivalent to + # - (p * x -1)^2 >=0 -> (p * x -1)^2 <= 0 -> (p * x -1) == 0 -> p*x == 1 + @test is_valid(model, con) optimize!(model) @test value(x) ≈ 1.0 atol = 1e-5 set_parameter_value(p, 3.0) optimize!(model) @test value(x) ≈ 1 / 3 atol = 1e-5 end + +function test_jump_psd_cone_with_parameter_pp() + model = Model(SCS.Optimizer) + @variable(model, x) + @variable(model, p in MOI.Parameter(1.0)) + @constraint( + model, + con, + [[0 (x - p * p)]; [(x - p * p) 0]] in JuMP.PSDCone() + ) + @test is_valid(model, con) + optimize!(model) + @test value(x) ≈ 1.0 atol = 1e-5 + set_parameter_value(p, 3.0) + optimize!(model) + @test value(x) ≈ 9.0 atol = 1e-5 +end + +function test_jump_psd_cone_with_parameter_p() + model = Model(SCS.Optimizer) + @variable(model, x) + @variable(model, p in MOI.Parameter(1.0)) + @constraint(model, con, [[0 (x - p)]; [(x - p) 0]] in JuMP.PSDCone()) + @test is_valid(model, con) + optimize!(model) + @test value(x) ≈ 1.0 atol = 1e-5 + set_parameter_value(p, 3.0) + optimize!(model) + @test value(x) ≈ 3.0 atol = 1e-5 +end