From be7d3507cee72799115eb3f4fd1aef95672bea56 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Sat, 2 Nov 2024 09:51:04 +1300 Subject: [PATCH] Use MOI.add_constrained_variable when creating variables (#3863) --- src/variables.jl | 92 ++++++++++++++++++++++++++++++------------- test/test_variable.jl | 38 ++++++++++++++++++ 2 files changed, 102 insertions(+), 28 deletions(-) diff --git a/src/variables.jl b/src/variables.jl index 8237fcc280f..07912a8c5c4 100644 --- a/src/variables.jl +++ b/src/variables.jl @@ -1965,20 +1965,68 @@ function add_variable(model::GenericModel, v::ScalarVariable, name::String = "") return _moi_add_variable(backend(model), model, v, name) end +function _moi_add_constrained_variable( + moi_backend::MOI.ModelLike, + ::Nothing, + set::MOI.AbstractScalarSet, +) + x, _ = MOI.add_constrained_variable(moi_backend, set) + return x +end + +function _moi_add_constrained_variable( + moi_backend::MOI.ModelLike, + x::MOI.VariableIndex, + set::MOI.AbstractScalarSet, +) + MOI.add_constraint(moi_backend, x, set) + return x +end + function _moi_add_variable( moi_backend, model::GenericModel{T}, v::ScalarVariable, name::String, ) where {T} - index = MOI.add_variable(moi_backend) - var_ref = GenericVariableRef(model, index) - _moi_constrain_variable(moi_backend, index, v.info, T) - if !isempty(name) && - MOI.supports(moi_backend, MOI.VariableName(), MOI.VariableIndex) - set_name(var_ref, name) + # We don't call the _moi* versions (for example, _moi_set_lower_bound) + # because they have extra checks that are not necessary for newly created + # variables. + index = nothing + info = v.info + if info.has_lb + set_lb = + MOI.GreaterThan{T}(_to_value(T, info.lower_bound, "lower bound")) + index = _moi_add_constrained_variable(moi_backend, index, set_lb) end - return var_ref + if info.has_ub + set_ub = MOI.LessThan{T}(_to_value(T, info.upper_bound, "upper bound")) + index = _moi_add_constrained_variable(moi_backend, index, set_ub) + end + if info.has_fix + set_eq = MOI.EqualTo{T}(_to_value(T, info.fixed_value, "fixed value")) + index = _moi_add_constrained_variable(moi_backend, index, set_eq) + end + if info.binary + index = _moi_add_constrained_variable(moi_backend, index, MOI.ZeroOne()) + end + if info.integer + index = _moi_add_constrained_variable(moi_backend, index, MOI.Integer()) + end + if index === nothing + index = MOI.add_variable(moi_backend) + end + x = GenericVariableRef(model, index::MOI.VariableIndex) + if info.has_start && info.start !== nothing + start = _to_value(T, info.start, "start value") + MOI.set(moi_backend, MOI.VariablePrimalStart(), index, start) + end + if !isempty(name) + if MOI.supports(moi_backend, MOI.VariableName(), MOI.VariableIndex) + set_name(x, name) + end + end + return x end _to_value(::Type{T}, value::T, ::String) where {T} = value @@ -2012,25 +2060,16 @@ function _moi_constrain_variable( # because they have extra checks that are not necessary for newly created # variables. if info.has_lb - _moi_add_constraint( - moi_backend, - index, - MOI.GreaterThan{T}(_to_value(T, info.lower_bound, "lower bound")), - ) + lb = _to_value(T, info.lower_bound, "lower bound") + _moi_add_constraint(moi_backend, index, MOI.GreaterThan{T}(lb)) end if info.has_ub - _moi_add_constraint( - moi_backend, - index, - MOI.LessThan{T}(_to_value(T, info.upper_bound, "upper bound")), - ) + ub = _to_value(T, info.upper_bound, "upper bound") + _moi_add_constraint(moi_backend, index, MOI.LessThan{T}(ub)) end if info.has_fix - _moi_add_constraint( - moi_backend, - index, - MOI.EqualTo{T}(_to_value(T, info.fixed_value, "fixed value")), - ) + eq = _to_value(T, info.fixed_value, "fixed value") + _moi_add_constraint(moi_backend, index, MOI.EqualTo{T}(eq)) end if info.binary _moi_add_constraint(moi_backend, index, MOI.ZeroOne()) @@ -2039,13 +2078,10 @@ function _moi_constrain_variable( _moi_add_constraint(moi_backend, index, MOI.Integer()) end if info.has_start && info.start !== nothing - MOI.set( - moi_backend, - MOI.VariablePrimalStart(), - index, - _to_value(T, info.start, "start value"), - ) + start = _to_value(T, info.start, "start value") + MOI.set(moi_backend, MOI.VariablePrimalStart(), index, start) end + return end """ diff --git a/test/test_variable.jl b/test/test_variable.jl index 22b5ff2ba93..1ac9440c0a7 100644 --- a/test/test_variable.jl +++ b/test/test_variable.jl @@ -1662,4 +1662,42 @@ function test_value_number() return end +function test_add_constrained_variable() + model = Model() + @variable(model, x1 >= 0) + @test has_lower_bound(x1) + @variable(model, x2 <= 0) + @test has_upper_bound(x2) + @variable(model, x3 == 0) + @test is_fixed(x3) + @variable(model, x4, Int) + @test is_integer(x4) + @variable(model, x5, Bin) + @test is_binary(x5) + @variable(model, x6 >= 0, Int) + @test has_lower_bound(x6) + @test is_integer(x6) + return +end + +function test_add_variable_in_set() + model = Model() + @variable(model, x1 >= 0, set = MOI.Integer()) + @test has_lower_bound(x1) + @test is_integer(x1) + @variable(model, x2 <= 0, set = MOI.Integer()) + @test has_upper_bound(x2) + @test is_integer(x2) + @variable(model, x3 == 0, set = MOI.Integer()) + @test is_fixed(x3) + @test is_integer(x3) + @variable(model, x4 in MOI.EqualTo(3.0), Int) + @test is_fixed(x4) + @test is_integer(x4) + @variable(model, x5 in MOI.EqualTo(3.0), Bin) + @test is_fixed(x5) + @test is_binary(x5) + return +end + end # module TestVariable