diff --git a/docs/src/apireference.md b/docs/src/apireference.md index b56cf5c5b0..97b47e9ef5 100644 --- a/docs/src/apireference.md +++ b/docs/src/apireference.md @@ -1073,6 +1073,7 @@ The following utilities are available for moving the function constant to the set for scalar constraints: ```@docs Utilities.shift_constant +Utilities.supports_shift_constant Utilities.normalize_and_add_constraint Utilities.normalize_constant ``` diff --git a/src/Utilities/sets.jl b/src/Utilities/sets.jl index 23418d201e..167b980922 100644 --- a/src/Utilities/sets.jl +++ b/src/Utilities/sets.jl @@ -1,24 +1,54 @@ """ - shift_constant(set::MOI.AbstractScalarSet, - offset) + shift_constant(set::MOI.AbstractScalarSet, offset) Returns a new scalar set `new_set` such that `func`-in-`set` is equivalent to `func + offset`-in-`new_set`. +Only define this function if it makes sense to! + +Use [`supports_shift_constant`](@ref) to check if the set supports shifting: +```Julia +if supports_shift_constant(typeof(old_set)) + new_set = shift_constant(old_set, offset) + f.constant = 0 + add_constraint(model, f, new_set) +else + add_constraint(model, f, old_set) +end +``` + +See also [`supports_shift_constant`](@ref). + ## Examples The call `shift_constant(MOI.Interval(-2, 3), 1)` is equal to `MOI.Interval(-1, 4)`. """ +function shift_constant end + +""" + supports_shift_constant(::Type{S}) where {S<:MOI.AbstractSet} + +Return `true` if [`shift_constant`](@ref) is defined for set `S`. + +See also [`shift_constant`](@ref). +""" +supports_shift_constant(::Type{S}) where {S<:MOI.AbstractSet} = false + function shift_constant( set::Union{MOI.LessThan{T},MOI.GreaterThan{T},MOI.EqualTo{T}}, offset::T, ) where {T} return typeof(set)(MOI.constant(set) + offset) end +supports_shift_constant(::Type{<:MOI.LessThan}) = true +supports_shift_constant(::Type{<:MOI.GreaterThan}) = true +supports_shift_constant(::Type{<:MOI.EqualTo}) = true + function shift_constant(set::MOI.Interval, offset) return MOI.Interval(set.lower + offset, set.upper + offset) end +supports_shift_constant(::Type{<:MOI.Interval}) = true const ScalarLinearSet{T} = Union{MOI.EqualTo{T},MOI.LessThan{T},MOI.GreaterThan{T}} diff --git a/test/Utilities/sets.jl b/test/Utilities/sets.jl index b6d633f72e..3df517ce8a 100644 --- a/test/Utilities/sets.jl +++ b/test/Utilities/sets.jl @@ -33,10 +33,16 @@ end end @testset "Shifts" begin + @test MOIU.supports_shift_constant(MOI.EqualTo{Int}) @test MOIU.shift_constant(MOI.EqualTo(3), 1) == MOI.EqualTo(4) + @test MOIU.supports_shift_constant(MOI.GreaterThan{Int}) @test MOIU.shift_constant(MOI.GreaterThan(6), -1) == MOI.GreaterThan(5) + @test MOIU.supports_shift_constant(MOI.LessThan{Int}) @test MOIU.shift_constant(MOI.LessThan(2), 2) == MOI.LessThan(4) + @test MOIU.supports_shift_constant(MOI.Interval{Int}) @test MOIU.shift_constant(MOI.Interval(-2, 3), 1) == MOI.Interval(-1, 4) + @test MOIU.supports_shift_constant(MOI.ZeroOne) == false + @test_throws MethodError MOIU.shift_constant(MOI.ZeroOne(), 1.0) end @testset "Dimension" begin