Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 46 additions & 24 deletions src/sets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1891,31 +1891,37 @@ Base.:(==)(a::SOS2{T}, b::SOS2{T}) where {T} = a.weights == b.weights
""",
ActivationCondition,
"""
The indicator constraint holds whhen the binary variable is zero.
The indicator constraint holds when the binary variable is zero.
""",
ACTIVATE_ON_ZERO,
"""
The indicator constraint holds whhen the binary variable is one.
The indicator constraint holds when the binary variable is one.
""",
ACTIVATE_ON_ONE,
)

"""
Indicator{A<:ActivationCondition,S<:AbstractScalarSet}(set::S)
Indicator{ACTIVATE_ON_ZERO}(set::AbstractScalarSet)
Indicator{ACTIVATE_ON_ONE}(set::AbstractScalarSet)

The set corresponding to an indicator constraint.

When `A` is [`ACTIVATE_ON_ZERO`](@ref), this means:
``\\{(y, x) \\in \\{0, 1\\} \\times \\mathbb{R}^n : y = 0 \\implies x \\in set\\}``
The type parameter must be an [`ActivationCondition`](@ref).

When `A` is [`ACTIVATE_ON_ONE`](@ref), this means:
``\\{(y, x) \\in \\{0, 1\\} \\times \\mathbb{R}^n : y = 1 \\implies x \\in set\\}``
When the type parameter is [`ACTIVATE_ON_ZERO`](@ref), this means:

``\\{(y, x) \\in \\{0, 1\\} \\times \\mathbb{R} : y = 0 \\implies x \\in set\\}``

When the type parameter is [`ACTIVATE_ON_ONE`](@ref), this means:

``\\{(y, x) \\in \\{0, 1\\} \\times \\mathbb{R} : y = 1 \\implies x \\in set\\}``

## Notes

Most solvers expect that the first row of the function is interpretable as a
variable index `x_i` (for example, `1.0 * x + 0.0`). An error will be thrown if this is
not the case.
[`VariableIndex`](@ref) (for example, `1.0 * x + 0.0`), and that the variable is
constrained to the [`ZeroOne`](@ref) set. An error will be thrown if this is not
the case.

## Example

Expand All @@ -1927,22 +1933,11 @@ julia> import MathOptInterface as MOI

julia> model = MOI.Utilities.Model{Float64}();

julia> x = MOI.add_variables(model, 2)
2-element Vector{MathOptInterface.VariableIndex}:
MOI.VariableIndex(1)
MOI.VariableIndex(2)
julia> x = MOI.add_variables(model, 2);

julia> y, _ = MOI.add_constrained_variable(model, MOI.ZeroOne())
(MOI.VariableIndex(3), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.ZeroOne}(3))
julia> y, _ = MOI.add_constrained_variable(model, MOI.ZeroOne());

julia> f = MOI.VectorAffineFunction(
[
MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, y)),
MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(1.0, x[1])),
MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(1.0, x[2])),
],
[0.0, 0.0],
)
julia> f = MOI.Utilities.vectorize([y, 1.0 * x[1] + 1.0 * x[2]])
┌ ┐
│0.0 + 1.0 MOI.VariableIndex(3) │
│0.0 + 1.0 MOI.VariableIndex(1) + 1.0 MOI.VariableIndex(2)│
Expand All @@ -1954,10 +1949,37 @@ MathOptInterface.Indicator{MathOptInterface.ACTIVATE_ON_ONE, MathOptInterface.Le
julia> MOI.add_constraint(model, f, s)
MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Indicator{MathOptInterface.ACTIVATE_ON_ONE, MathOptInterface.LessThan{Float64}}}(1)
```

The constraint
``\\{(y, x) \\in \\{0, 1\\} \\times \\mathbb{R} : y = 0 \\implies x = 0 \\}``
is defined as
```jldoctest
julia> import MathOptInterface as MOI

julia> model = MOI.Utilities.Model{Float64}();

julia> x = MOI.add_variable(model);

julia> y, _ = MOI.add_constrained_variable(model, MOI.ZeroOne());

julia> f = MOI.VectorOfVariables([y, x]);

julia> s = MOI.Indicator{MOI.ACTIVATE_ON_ZERO}(MOI.EqualTo(0.0))
MathOptInterface.Indicator{MathOptInterface.ACTIVATE_ON_ZERO, MathOptInterface.EqualTo{Float64}}(MathOptInterface.EqualTo{Float64}(0.0))

julia> MOI.add_constraint(model, f, s)
MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.Indicator{MathOptInterface.ACTIVATE_ON_ZERO, MathOptInterface.EqualTo{Float64}}}(1)
```
"""
struct Indicator{A,S<:AbstractScalarSet} <: AbstractVectorSet
set::S
Indicator{A}(set::S) where {A,S<:AbstractScalarSet} = new{A,S}(set)

function Indicator{ACTIVATE_ON_ONE}(set::S) where {S<:AbstractScalarSet}
return new{ACTIVATE_ON_ONE,S}(set)
end
function Indicator{ACTIVATE_ON_ZERO}(set::S) where {S<:AbstractScalarSet}
return new{ACTIVATE_ON_ZERO,S}(set)
end
end

dimension(::Indicator) = 2
Expand Down
Loading