diff --git a/docs/src/extensions.md b/docs/src/extensions.md index c10ec1a8442..5e53d2a5dd8 100644 --- a/docs/src/extensions.md +++ b/docs/src/extensions.md @@ -51,6 +51,17 @@ The [`@constraint`](@ref) macro always calls the same three functions: Adding methods to these functions is the recommended way to extend the [`@constraint`](@ref) macro. +### Adding `parse_constraint` methods + +```@meta +# TODO(Benoît): Detail how `parse_constraint` works and show how `sense_to_set` +# fits into the picture. +``` + +```@docs +sense_to_set +``` + ### Adding `build_constraint` methods There is typically two choices when creating a [`build_constraint`](@ref) diff --git a/src/macros.jl b/src/macros.jl index 27217bbc929..bb626a627e4 100644 --- a/src/macros.jl +++ b/src/macros.jl @@ -358,6 +358,47 @@ end # two-argument build_constraint is used for one-sided constraints. # Right-hand side is zero. + +""" + sense_to_set(_error::Function, ::Val{sense_symbol}) + +Converts a sense symbol to a set `set` such that +`@constraint(model, func sense_symbol 0) is equivalent to +`@constraint(model, func in set)` for any `func::AbstractJuMPScalar`. + +## Example + +Once a custom set is defined you can directly create a JuMP constraint with it: +```jldoctest sense_to_set; setup = :(using JuMP) +julia> struct CustomSet{T} <: MOI.AbstractScalarSet + value::T + end + +julia> model = Model(); + +julia> @variable(model, x) +x + +julia> cref = @constraint(model, x in CustomSet(1.0)) +x ∈ CustomSet{Float64}(1.0) +``` + +However, there might be an appropriate sign that could be used in order to +provide a more convenient syntax: +```jldoctest sense_to_set +julia> JuMP.sense_to_set(::Function, ::Val{:⊰}) = CustomSet(0.0) + +julia> MOIU.shift_constant(set::CustomSet, value) = CustomSet(set.value + value) + +julia> cref = @constraint(model, x ⊰ 1) +x ∈ CustomSet{Float64}(1.0) +``` +Note that the whole function is first moved to the right-hand side, then the +sign is transformed into a set with zero constant and finally the constant is +moved to the set with `MOIU.shift_constant`. +""" +function sense_to_set end + sense_to_set(_error::Function, ::Union{Val{:(<=)}, Val{:(≤)}}) = MOI.LessThan(0.0) sense_to_set(_error::Function, ::Union{Val{:(>=)}, Val{:(≥)}}) = MOI.GreaterThan(0.0) sense_to_set(_error::Function, ::Val{:(==)}) = MOI.EqualTo(0.0)