From ddf12ecc783f93a06673704787d03aa19fffd217 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Wed, 6 Nov 2024 20:50:10 +0100 Subject: [PATCH] add_constrained_variable with 2 sets (#2574) --- src/Test/test_model.jl | 17 ++++++++++++ src/variables.jl | 59 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/src/Test/test_model.jl b/src/Test/test_model.jl index 4c67651198..587b7c9d16 100644 --- a/src/Test/test_model.jl +++ b/src/Test/test_model.jl @@ -1226,3 +1226,20 @@ function test_model_show(model::MOI.ModelLike, ::Config{T}) where {T} @test sprint(show, model) isa String return end + +function test_model_add_constrained_variable_tuple( + model::MOI.ModelLike, + ::Config{T}, +) where {T} + F = MOI.VariableIndex + set = (MOI.GreaterThan(zero(T)), MOI.LessThan(one(T))) + @requires MOI.supports_add_constrained_variable(model, typeof(set)) + x, (c_l, c_u) = MOI.add_constrained_variable(model, set) + @test c_l == MOI.ConstraintIndex{F,MOI.GreaterThan{T}}(x.value) + @test c_u == MOI.ConstraintIndex{F,MOI.LessThan{T}}(x.value) + @test MOI.get(model, MOI.ConstraintFunction(), c_l) == x + @test MOI.get(model, MOI.ConstraintSet(), c_l) == set[1] + @test MOI.get(model, MOI.ConstraintFunction(), c_u) == x + @test MOI.get(model, MOI.ConstraintSet(), c_u) == set[2] + return +end diff --git a/src/variables.jl b/src/variables.jl index 8bbbcc3db4..2b14216937 100644 --- a/src/variables.jl +++ b/src/variables.jl @@ -124,6 +124,65 @@ function add_constrained_variable(model::ModelLike, set::AbstractScalarSet) return variable, constraint end +""" + add_constrained_variable( + model::ModelLike, + set::Tuple{<:GreaterThan,<:LessThan}, + ) + +A special-case method to add a scalar variable with a lower and upper bound. + +This method should be implemented by optimizers which have native support for +adding a variable with bounds and which cannot performantly modify the variable +bounds after creation. + +## Example + +```jldoctest +julia> import MathOptInterface as MOI + +julia> model = MOI.Utilities.Model{Float64}(); + +julia> set = (MOI.GreaterThan(1.0), MOI.LessThan(2.0)); + +julia> x, (c_l, c_u) = MOI.add_constrained_variable(model, set); + +julia> c_l +MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.GreaterThan{Float64}}(1) + +julia> c_u +MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.LessThan{Float64}}(1) + +julia> print(model) +Feasibility + +Subject to: + +VariableIndex-in-GreaterThan{Float64} + v[1] >= 1.0 + +VariableIndex-in-LessThan{Float64} + v[1] <= 2.0 +``` +""" +function add_constrained_variable( + model::ModelLike, + set::Tuple{<:GreaterThan,<:LessThan}, +) + set_1, set_2 = set + x, c_1 = add_constrained_variable(model, set_1) + c_2 = add_constraint(model, x, set_2) + return x, (c_1, c_2) +end + +function supports_add_constrained_variable( + model::ModelLike, + ::Type{Tuple{L,U}}, +) where {L<:GreaterThan,U<:LessThan} + return supports_add_constrained_variable(model, L) && + supports_constraint(model, VariableIndex, U) +end + """ supports_add_constrained_variables( model::ModelLike,