# JuMP conditional constraint

**URL:** <https://discourse.julialang.org/t/jump-conditional-constraint/40575>\
**Category:** Optimization (Mathematical)\
**Created:** [June 1, 2020, 7:08pm UTC](https://discourse.julialang.org/t/jump-conditional-constraint/40575 "2020-06-01T19:08:48Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![m.lavaiyan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/m.lavaiyan/32/15846_2.png) [@m.lavaiyan](https://discourse.julialang.org/u/m.lavaiyan)\
**Post date:** [June 1, 2020, 7:08pm UTC](https://discourse.julialang.org/t/jump-conditional-constraint/40575/1 "2020-06-01T19:08:48Z")

</div>

I want to implement a conditional constraint to my model where each non-zero variable, force the next two variables to be zero. In other words, if x[t]=0 then x[t+1]=0 and x[t+2]=0.

I tried a quadratic constrain as below, but Gorubi, Cbc solvers could not solve it.  
**x[t] \* (x[t+1] + x[t+2]) == 0**

I tried also complementary constraint as below, but it gives an error.

```julia
@variable(model, x[1:T]>=0, Int)
@constraint(model, xx[t=1:T], complements((x[t+1]+x[t+2]), x[t]))

```

I also tried a loop with if statement, but do not work either.

How can I implement this constraint?

Thanks for all help 🙂

---

<div class="post-metadata">

**Author:** ![blegat](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/blegat/32/217090_2.png) [@blegat](https://discourse.julialang.org/u/blegat)\
**Post date:** [June 1, 2020, 7:23pm UTC](https://discourse.julialang.org/t/jump-conditional-constraint/40575/2 "2020-06-01T19:23:21Z")

</div>

Please post the error you get. Here I guess you have an out of bound error. Replace `t + i` by `((t - 1 + i) % T) + 1`

---

<div class="post-metadata">

**Author:** ![m.lavaiyan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/m.lavaiyan/32/15846_2.png) [@m.lavaiyan](https://discourse.julialang.org/u/m.lavaiyan)\
**Post date:** [June 1, 2020, 7:53pm UTC](https://discourse.julialang.org/t/jump-conditional-constraint/40575/3 "2020-06-01T19:53:23Z")

</div>

Here is the error:

**MethodError: objects of type VariableRef are not callable**

Do you mean like this?

```julia
@constraint(model, xx[t=1:T], complements((x[((t) % T) + 1] + x[((t+1) % T) + 1]), x[t]))

```

thank you!

---

<div class="post-metadata">

**Author:** ![blegat](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/blegat/32/217090_2.png) [@blegat](https://discourse.julialang.org/u/blegat)\
**Post date:** [June 1, 2020, 8:44pm UTC](https://discourse.julialang.org/t/jump-conditional-constraint/40575/4 "2020-06-01T20:44:39Z")

</div>

I do not get your error, it works for me. Here is what I get with your code on Julia v1.4.1:

```julia
julia> using JuMP

julia> model = Model();

julia> T = 3
3

julia> @variable(model, x[1:T]>=0, Int)
3-element Array{VariableRef,1}:
 x[1]
 x[2]
 x[3]

julia> @constraint(model, xx[t=1:T], complements((x[t+1]+x[t+2]), x[t]))
ERROR: BoundsError: attempt to access 3-element Array{VariableRef,1} at index [4]
Stacktrace:
 [1] getindex(::Array{VariableRef,1}, ::Int64) at ./array.jl:788
 [2] macro expansion at /home/blegat/.julia/packages/MutableArithmetics/ZGFsK/src/rewrite.jl:227 [inlined]
 [3] macro expansion at /home/blegat/.julia/packages/JuMP/MnJQc/src/macros.jl:381 [inlined]
 [4] (::var"#9#10")(::Int64) at /home/blegat/.julia/packages/JuMP/MnJQc/src/Containers/macro.jl:183
 [5] #26 at /home/blegat/.julia/packages/JuMP/MnJQc/src/Containers/container.jl:70 [inlined]
 [6] iterate at ./generator.jl:47 [inlined]
 [7] collect_to!(::Array{ConstraintRef{Model,MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64},MathOptInterface.Complements},VectorShape},1}, ::Base.Generator{JuMP.Containers.VectorizedProductIterator{Tuple{Base.OneTo{Int64}}},JuMP.Containers.var"#26#27"{var"#9#10"}}, ::Int64, ::Tuple{Tuple{Int64,Int64}}) at ./array.jl:711
 [8] collect_to_with_first!(::Array{ConstraintRef{Model,MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64},MathOptInterface.Complements},VectorShape},1}, ::ConstraintRef{Model,MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64},MathOptInterface.Complements},VectorShape}, ::Base.Generator{JuMP.Containers.VectorizedProductIterator{Tuple{Base.OneTo{Int64}}},JuMP.Containers.var"#26#27"{var"#9#10"}}, ::Tuple{Tuple{Int64,Int64}}) at ./array.jl:689
 [9] collect(::Base.Generator{JuMP.Containers.VectorizedProductIterator{Tuple{Base.OneTo{Int64}}},JuMP.Containers.var"#26#27"{var"#9#10"}}) at ./array.jl:670
 [10] map(::Function, ::JuMP.Containers.VectorizedProductIterator{Tuple{Base.OneTo{Int64}}}) at ./abstractarray.jl:2098
 [11] container at /home/blegat/.julia/packages/JuMP/MnJQc/src/Containers/container.jl:70 [inlined]
 [12] container(::Function, ::JuMP.Containers.VectorizedProductIterator{Tuple{Base.OneTo{Int64}}}) at /home/blegat/.julia/packages/JuMP/MnJQc/src/Containers/container.jl:65
 [13] top-level scope at /home/blegat/.julia/packages/JuMP/MnJQc/src/macros.jl:79

julia> @constraint(model, xx[t=1:T], complements((x[((t) % T) + 1] + x[((t+1) % T) + 1]), x[t]))
3-element Array{ConstraintRef{Model,MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64},MathOptInterface.Complements},VectorShape},1}:
 xx[1] : [x[2] + x[3], x[1]] ∈ MathOptInterface.Complements(1)
 xx[2] : [x[3] + x[1], x[2]] ∈ MathOptInterface.Complements(1)
 xx[3] : [x[1] + x[2], x[3]] ∈ MathOptInterface.Complements(1)

(@v1.4) pkg> st JuMP
Status `~/.julia/environments/v1.4/Project.toml`
  [4076af6c] JuMP v0.21.2

```

PS: See [Please read: make it easier to help you](https://discourse.julialang.org/t/psa-make-it-easier-to-help-you/14757) for how to format the code in your question.

---

<div class="post-metadata">

**Author:** ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)\
**Post date:** [June 1, 2020, 8:52pm UTC](https://discourse.julialang.org/t/jump-conditional-constraint/40575/5 "2020-06-01T20:52:18Z")

</div>

Don’t use a quadratic constraint or a complementary constraint for this. Cbc is a mixed-integer linear solver.

You should use a standard linear reformulation like the “big-M” method:

> **[Documentation - Gurobi Optimization](https://www.gurobi.com/documentation/9.0/refman/num_dealing_with_big_m_con.html)**
>
> Est. reading time: 1 minute

> **[Big M method](https://en.wikipedia.org/wiki/Big_M_method)**
>
> In operations research, the Big M method is a method of solving linear programming problems using the simplex algorithm. The Big M method extends the simplex algorithm to problems that contain "greater-than" constraints. It does so by associating the constraints with large negative constants which would not be part of any optimal solution, if it exists.
> The simplex algorithm is the original and still one of the most widely used methods for solving linear maximization problems. However, to appl...

---

<div class="post-metadata">

**Author:** ![m.lavaiyan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/m.lavaiyan/32/15846_2.png) [@m.lavaiyan](https://discourse.julialang.org/u/m.lavaiyan)\
**Post date:** [June 2, 2020, 10:25am UTC](https://discourse.julialang.org/t/jump-conditional-constraint/40575/6 "2020-06-02T10:25:27Z")

</div>

> [@blegat](#):
>
> `model = Model()`

thank you, it works without defining the solver but as @odow just mentioned, when I define the Cbc as a solver, it does not support this kind of constraint and gives this error:

```julia
model = Model(Cbc.Optimizer)
T = 3
@variable(model, x[1:T]>=0, Int)
@constraint(model, xx[t=1:T], complements((x[((t) % T) + 1] + x[((t+1) % T) + 1]), x[t]))

>>> Constraints of type MathOptInterface.VectorAffineFunction{Float64}-in-MathOptInterface.Complements are not supported by the solver and there are no bridges that can reformulate it into supported constraints.

```

---

<div class="post-metadata">

**Author:** ![m.lavaiyan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/m.lavaiyan/32/15846_2.png) [@m.lavaiyan](https://discourse.julialang.org/u/m.lavaiyan)\
**Post date:** [June 2, 2020, 10:28am UTC](https://discourse.julialang.org/t/jump-conditional-constraint/40575/7 "2020-06-02T10:28:58Z")

</div>

thank you, but I could not understand how I should change my constraint in “big-M” method. could you please give an example regarding my problem?

---

<div class="post-metadata">

**Author:** ![blegat](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/blegat/32/217090_2.png) [@blegat](https://discourse.julialang.org/u/blegat)\
**Post date:** [June 2, 2020, 11:02am UTC](https://discourse.julialang.org/t/jump-conditional-constraint/40575/8 "2020-06-02T11:02:27Z")

</div>

One alternative to the “big-M” is to use SOS1 constraints which are supported by Cbc.  
In fact, you can even use indicator constraints are they are automatically bridged to SOS1 constraints.  
With the following:

```julia
using JuMP, Cbc
model = Model(Cbc.Optimizer)
set_silent(model)
T = 3
@variable(model, x[1:T]>=0, Int)
next(t, i) = x[((t - 1 + i) % T) + 1]
@constraint(model, xx1[t=1:T], x[t] => {next(t, 1) + next(t, 2) == 0})
optimize!(model)
@show value.(x)
MOI.Bridges.print_graph(backend(model).optimizer)

```

I get

```julia
value.(x) = [0.0, 0.0, 0.0]
Bridge graph with 3 variable nodes, 7 constraint nodes and 0 objective nodes.
 [1] constrained variables in `MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE,MOI.EqualTo{Float64}}` are supported (distance 2) by adding free variables and then constrain them, see (2).
 [2] constrained variables in `MOI.Nonpositives` are supported (distance 2) by adding free variables and then constrain them, see (6).
 [3] constrained variables in `MOI.Nonnegatives` are supported (distance 2) by adding free variables and then constrain them, see (7).
 (1) `MOI.VectorAffineFunction{Float64}`-in-`MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE,MOI.EqualTo{Float64}}` constraints are bridged (distance 1) by MOIB.Constraint.IndicatorSOS1Bridge{Float64,MOI.EqualTo{Float64},Nothing}.
 (2) `MOI.VectorOfVariables`-in-`MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE,MOI.EqualTo{Float64}}` constraints are bridged (distance 1) by MOIB.Constraint.IndicatorSOS1Bridge{Float64,MOI.EqualTo{Float64},Nothing}.
 (3) `MOI.VectorAffineFunction{Float64}`-in-`MOI.Zeros` constraints are bridged (distance 1) by MOIB.Constraint.ScalarizeBridge{Float64,MOI.ScalarAffineFunction{Float64},MOI.EqualTo{Float64}}.
 (4) `MOI.VectorAffineFunction{Float64}`-in-`MOI.Nonnegatives` constraints are bridged (distance 1) by MOIB.Constraint.ScalarizeBridge{Float64,MOI.ScalarAffineFunction{Float64},MOI.GreaterThan{Float64}}.
 (5) `MOI.VectorAffineFunction{Float64}`-in-`MOI.Nonpositives` constraints are bridged (distance 1) by MOIB.Constraint.ScalarizeBridge{Float64,MOI.ScalarAffineFunction{Float64},MOI.LessThan{Float64}}.
 (6) `MOI.VectorOfVariables`-in-`MOI.Nonpositives` constraints are bridged (distance 1) by MOIB.Constraint.ScalarizeBridge{Float64,MOI.SingleVariable,MOI.LessThan{Float64}}.
 (7) `MOI.VectorOfVariables`-in-`MOI.Nonnegatives` constraints are bridged (distance 1) by MOIB.Constraint.ScalarizeBridge{Float64,MOI.SingleVariable,MOI.GreaterThan{Float64}}.

```

You see in (1) that the indicator constraint is bridged into SOS1 constraints.

---

<div class="post-metadata">

**Author:** ![m.lavaiyan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/m.lavaiyan/32/15846_2.png) [@m.lavaiyan](https://discourse.julialang.org/u/m.lavaiyan)\
**Post date:** [June 2, 2020, 12:19pm UTC](https://discourse.julialang.org/t/jump-conditional-constraint/40575/9 "2020-06-02T12:19:44Z")

</div>

It was a great idea, perfectly works. Thank you so much 🙂 👍

---

<div class="post-metadata">

**Author:** ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)\
**Post date:** [June 2, 2020, 2:21pm UTC](https://discourse.julialang.org/t/jump-conditional-constraint/40575/10 "2020-06-02T14:21:28Z")

</div>

Cool! I forgot this was working now.
