From 3a2a5552931108fb42b26326e6539f21410be024 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Mon, 8 Jun 2020 13:34:20 +0200 Subject: [PATCH] Fix constrained variables for caching optimizer --- src/Utilities/cachingoptimizer.jl | 19 ++++++++--- test/Utilities/cachingoptimizer.jl | 55 ++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/src/Utilities/cachingoptimizer.jl b/src/Utilities/cachingoptimizer.jl index f06b340535..4401b16f8a 100644 --- a/src/Utilities/cachingoptimizer.jl +++ b/src/Utilities/cachingoptimizer.jl @@ -239,6 +239,9 @@ function MOI.add_variables(m::CachingOptimizer, n) return vindices end +function MOI.supports_add_constrained_variable(m::CachingOptimizer, S::Type{<:MOI.AbstractScalarSet}) + return MOI.supports_add_constrained_variable(m.model_cache, S) && (m.state == NO_OPTIMIZER || MOI.supports_add_constrained_variable(m.optimizer, S)) +end function MOI.add_constrained_variable(m::CachingOptimizer, set::MOI.AbstractScalarSet) if m.state == MOIU.ATTACHED_OPTIMIZER if m.mode == MOIU.AUTOMATIC @@ -257,8 +260,7 @@ function MOI.add_constrained_variable(m::CachingOptimizer, set::MOI.AbstractScal MOI.add_constrained_variable(m.optimizer, set) end end - vindex = MOI.add_variable(m.model_cache) - cindex = MOI.add_constraint(m.model_cache, MOI.SingleVariable(vindex), set) + vindex, cindex = MOI.add_constrained_variable(m.model_cache, set) if m.state == MOIU.ATTACHED_OPTIMIZER m.model_to_optimizer_map[vindex] = vindex_optimizer m.optimizer_to_model_map[vindex_optimizer] = vindex @@ -268,6 +270,16 @@ function MOI.add_constrained_variable(m::CachingOptimizer, set::MOI.AbstractScal return vindex, cindex end +function _supports_add_constrained_variables(m::CachingOptimizer, S::Type{<:MOI.AbstractVectorSet}) + return MOI.supports_add_constrained_variables(m.model_cache, S) && (m.state == NO_OPTIMIZER || MOI.supports_add_constrained_variables(m.optimizer, S)) +end +# Split in two to solve ambiguity +function MOI.supports_add_constrained_variables(m::CachingOptimizer, ::Type{MOI.Reals}) + return _supports_add_constrained_variables(m, MOI.Reals) +end +function MOI.supports_add_constrained_variables(m::CachingOptimizer, S::Type{<:MOI.AbstractVectorSet}) + return _supports_add_constrained_variables(m, S) +end function MOI.add_constrained_variables(m::CachingOptimizer, set::MOI.AbstractVectorSet) if m.state == ATTACHED_OPTIMIZER if m.mode == AUTOMATIC @@ -286,8 +298,7 @@ function MOI.add_constrained_variables(m::CachingOptimizer, set::MOI.AbstractVec MOI.add_constrained_variables(m.optimizer, set) end end - vindices = MOI.add_variables(m.model_cache, MOI.dimension(set)) - cindex = MOI.add_constraint(m.model_cache, MOI.VectorOfVariables(vindices), set) + vindices, cindex = MOI.add_constrained_variables(m.model_cache, set) if m.state == ATTACHED_OPTIMIZER for (vindex, vindex_optimizer) in zip(vindices, vindices_optimizer) m.model_to_optimizer_map[vindex] = vindex_optimizer diff --git a/test/Utilities/cachingoptimizer.jl b/test/Utilities/cachingoptimizer.jl index 54d2c5a5dc..511bec494b 100644 --- a/test/Utilities/cachingoptimizer.jl +++ b/test/Utilities/cachingoptimizer.jl @@ -479,3 +479,58 @@ for state in (MOIU.NO_OPTIMIZER, MOIU.EMPTY_OPTIMIZER, MOIU.ATTACHED_OPTIMIZER) end end end + +mutable struct NoFreeVariables <: MOI.AbstractOptimizer + inner::MOIU.Model{Float64} + function NoFreeVariables() + return new(MOIU.Model{Float64}()) + end +end +MOI.is_empty(model::NoFreeVariables) = MOI.is_empty(model.inner) +MOI.empty!(model::NoFreeVariables) = MOI.empty!(model.inner) +MOI.get(model::NoFreeVariables, attr::MOI.AnyAttribute, idx::Vector) = MOI.get(model.inner, attr, idx) +MOI.get(model::NoFreeVariables, attr::MOI.AnyAttribute, args...) = MOI.get(model.inner, attr, args...) +MOI.supports_add_constrained_variables(::NoFreeVariables, ::Type{MOI.Reals}) = false +MOI.supports_add_constrained_variable(::NoFreeVariables, ::Type{<:MOI.AbstractScalarSet}) = true +function MOI.add_constrained_variable(model::NoFreeVariables, set::MOI.AbstractScalarSet) + return MOI.add_constrained_variable(model.inner, set) +end +MOI.supports_add_constrained_variables(::NoFreeVariables, ::Type{<:MOI.AbstractVectorSet}) = true +function MOI.add_constrained_variables(model::NoFreeVariables, set::MOI.AbstractVectorSet) + return MOI.add_constrained_variables(model.inner, set) +end + +MOI.Utilities.supports_default_copy_to(::NoFreeVariables, names::Bool) = !names +function MOI.copy_to(dest::NoFreeVariables, src::MOI.ModelLike; kwargs...) + return MOI.Utilities.automatic_copy_to(dest, src; kwargs...) +end + +function constrained_variables_test(model) + @test !MOI.supports_add_constrained_variables(model, MOI.Reals) + @test MOI.supports_add_constrained_variable(model, MOI.ZeroOne) + @test !MOI.supports_constraint(model, MOI.SingleVariable, MOI.ZeroOne) + @test MOI.supports_add_constrained_variables(model, MOI.Nonnegatives) + @test !MOI.supports_constraint(model, MOI.VectorOfVariables, MOI.Nonnegatives) + scalar_set = MOI.ZeroOne() + x, cx = MOI.add_constrained_variable(model, scalar_set) + vector_set = MOI.Nonnegatives(2) + y, cy = MOI.add_constrained_variables(model, vector_set) + constraint_types = Set([(MOI.SingleVariable, MOI.ZeroOne), (MOI.VectorOfVariables, MOI.Nonnegatives)]) + @test Set(MOI.get(model.model_cache, MOI.ListOfConstraints())) == constraint_types + if MOIU.state(model) == MOIU.EMPTY_OPTIMIZER + MOIU.attach_optimizer(model) + end + @test Set(MOI.get(model.optimizer, MOI.ListOfConstraints())) == constraint_types +end + +@testset "Constrained Variables" begin + cache = NoFreeVariables() + optimizer = NoFreeVariables() + model = MOIU.CachingOptimizer(cache, optimizer) + constrained_variables_test(model) + MOI.empty!(cache) + MOI.empty!(optimizer) + model = MOIU.CachingOptimizer(cache, MOIU.AUTOMATIC) + MOIU.reset_optimizer(model, optimizer) + constrained_variables_test(model) +end