From cdd43162040421eb9c2a002707e91510adbfbe41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Mon, 10 May 2021 07:42:20 -0400 Subject: [PATCH 1/2] Add throw_if_scalar_and_constant_not_zero --- src/Bridges/bridge_optimizer.jl | 21 ++++----------------- src/constraints.jl | 29 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/src/Bridges/bridge_optimizer.jl b/src/Bridges/bridge_optimizer.jl index 417c3a2b96..8277799b49 100644 --- a/src/Bridges/bridge_optimizer.jl +++ b/src/Bridges/bridge_optimizer.jl @@ -1742,23 +1742,10 @@ function bridged_constraint_function( if !Variable.has_bridges(Variable.bridges(b)) return func, set end - if func isa MOI.AbstractScalarFunction - constant = MOI.constant(func) - if !iszero(constant) - # We use the fact that the initial function constant was zero to - # implement getters for `MOI.ConstraintFunction` and - # `MOI.ConstraintSet`. See `unbridged_constraint_function`. - throw( - MOI.ScalarFunctionConstantNotZero{ - typeof(constant), - typeof(func), - typeof(set), - }( - constant, - ), - ) - end - end + # We use the fact that the initial function constant was zero to + # implement getters for `MOI.ConstraintFunction` and + # `MOI.ConstraintSet`. See `unbridged_constraint_function`. + MOI.throw_if_scalar_and_constant_not_zero(func, typeof(set)) f = bridged_function(b, func)::typeof(func) return MOIU.normalize_constant(f, set) end diff --git a/src/constraints.jl b/src/constraints.jl index 5867828021..47099cff76 100644 --- a/src/constraints.jl +++ b/src/constraints.jl @@ -103,6 +103,35 @@ function Base.showerror( ) end +""" + throw_if_scalar_and_constant_not_zero(func, S::Type) + +Throw a `ScalarFunctionConstantNotZero(index)` error `func` is a scalar function +whose constant is not zero. +""" +function throw_if_scalar_and_constant_not_zero( + func::AbstractScalarFunction, + ::Type{S}, +) where {S<:AbstractScalarSet} + cst = constant(func) + if !iszero(cst) + throw(ScalarFunctionConstantNotZero{typeof(cst),typeof(func),S}(cst)) + end + return +end +function throw_if_scalar_and_constant_not_zero( + ::SingleVariable, + ::Type{S}, +) where {S<:AbstractScalarSet} + return +end +function throw_if_scalar_and_constant_not_zero( + ::AbstractVectorFunction, + ::Type{S}, +) where {S<:AbstractVectorSet} + return +end + """ add_constraint(model::ModelLike, func::F, set::S)::ConstraintIndex{F,S} where {F,S} From 36de969f55af3b318561b7d866e09f7aa6475a37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Mon, 10 May 2021 23:37:46 -0400 Subject: [PATCH 2/2] Add tests --- test/constraints.jl | 23 +++++++++++++++++++++++ test/runtests.jl | 1 + 2 files changed, 24 insertions(+) create mode 100644 test/constraints.jl diff --git a/test/constraints.jl b/test/constraints.jl new file mode 100644 index 0000000000..0cd16f4c66 --- /dev/null +++ b/test/constraints.jl @@ -0,0 +1,23 @@ +using Test +using MathOptInterface +const MOI = MathOptInterface + +function constant_not_zero_test(::Type{T}) where {T} + S = MOI.EqualTo{T} + x = MOI.VariableIndex(1) + fx = MOI.SingleVariable(x) + @test nothing === MOI.throw_if_scalar_and_constant_not_zero(fx, S) + func1 = one(T) * fx + one(T) + @test_throws MOI.ScalarFunctionConstantNotZero begin + MOI.throw_if_scalar_and_constant_not_zero(func1, S) + end + func2 = one(T) * fx + @test nothing === MOI.throw_if_scalar_and_constant_not_zero(func2, S) + func = MOI.Utilities.operate(vcat, T, func1, func2) + @test nothing === MOI.throw_if_scalar_and_constant_not_zero(func, MOI.Zeros) +end + +@testset "Constant not zero" begin + constant_not_zero_test(Int) + constant_not_zero_test(Float64) +end diff --git a/test/runtests.jl b/test/runtests.jl index 9d9a8b6b30..0eb42c20b1 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -22,6 +22,7 @@ include("dummy.jl") include("functions.jl") include("sets.jl") include("attributes.jl") + include("constraints.jl") include("instantiate.jl") include("deprecate.jl") end