Using logical constraints with gurobi

I’m trying to use logical constraints on JuMP, ex:
x5 = x1 AND x3 AND x4

In the doc of gurobi, there is a function that directly construct this constraint without having to linearize it manually :

model.addGenConstrAnd(x5, [x1, x3, x4], “andconstr”)

Is there an equivalent way when using Gurobi on JuMP ?
thank you

Welcome to the forum!

The general way to do this at the model level is described in the Mosek Cookbook (it’s just about the maths, not specific to the Mosek solver).

The JuMP model would look like

using JuMP
import Gurobi

n = 3  # number of "AND" terms

model = Model(Gurobi.Optimizer)
@variable(model, x[1:n], Bin)
@variable(model, z, Bin) # z is x[1] AND ... AND x[n]
@constraint(model, [i=1:n], x[i] >= z)
@constraint(model, z + (n-1)  >= sum(x))

Test it with:

julia> @objective(model, Max, sum(x))
julia> optimize!(model)
julia> value.(x)
3-element Vector{Float64}:

julia> value.(z)

julia> fix(x[3], 0)

julia> value.(x)
3-element Vector{Float64}:

julia> @objective(model, Max, sum(x))
julia> value.(z)

@raian you can also consider using DisjunctiveProgramming.jl:

using DisjunctiveProgramming
using Gurobi

model = GDPModel(Gurobi.Optimizer)
@variable(model, x[1:5], Logical)
@constraint(model, x[5] == (x[1] && x[3] && x[4]) := true)

Subject to
 x[4] - x[5] ≥ 0
 x[3] - x[5] ≥ 0
 -x[1] - x[3] - x[4] + x[5] ≥ -2
 x[1] - x[5] ≥ 0
 x[1] binary
 x[2] binary
 x[3] binary
 x[4] binary
 x[5] binary

The way this works is:

  • x[1:5] is a vector of LogicalVariable
  • you can then define logical propositions using Boolean algebra (unicode operators supported too)
  • you can then either call reformulate_model to transform the logical model into a MIP. Alternately, you can leave all the logical constraints and call optimize!(model), the model will be reformulated in the background by transforming the logical constraints into algebraic constraints with binary variables.

Note, the transformation creates binary variables from the logical variables and adds the 3 algebraic constraints @jd-foster gave above. The extra constraint x[1] + x[3] + x[4] - x[5] <= 2 forces the reverse implication on x[5]. Without it, the constraint being added is x5 implies x1 AND x3 AND x4 (instead of x5 iff x1 AND x3 AND x4).

Note: the code above works on master.

1 Like

Hi @raian,

You can also use Gurobi’s C API for this: GitHub - jump-dev/Gurobi.jl: Julia interface for Gurobi Optimizer

I didn’t test, but something like this should work:

using JuMP, Gurobi
model = direct_model(Gurobi.Optimizer())
@variable(model, x[1:5])
grb = backend(model)
c_cols = Gurobi.c_column.(grb, index.(x))
GRBaddgenconstrAnd(grb, "andconstr", c_cols[5], 3, c_cols[[1, 3, 4]])