Constraint optimization in python with OR Tools: How to enforce a multi level constraint?

Viewed 312

I have an optimization problem where I have a list of lists of "BoolVar" objects. So something like this:

[[BoolVar1,BoolVar2],[BoolVar3, BoolVar4],[BoolVar5,BoolVar6]]

I need to evaluate the following:

(BoolVar1 && BoolVar2) || (BoolVar3 && BoolVar4) || (BoolVar5 && BoolVar6)

Do I have to do this as follows:

and12 = model.NewBoolVar("and12")
model.Add(and12 == True).OnlyEnforceIf([BoolVar1,BoolVar2])
and34 = model.NewBoolVar("and34")
model.Add(and34 == True).OnlyEnforceIf([BoolVar3,BoolVar4])
and56 = model.NewBoolVar("and56")
model.Add(and56 == True).OnlyEnforceIf([BoolVar5,BoolVar6])
model.AddBoolOr([and12,and34,and56])

I've tried this code and it seems to be working but I'm doubtful because of the "OnlyEnforceIf" function. What happens if it's not enforced? Is and12 then set to False or can it be either False or True, since then this equation is not enforced? I came to this code based on this post.

1 Answers
  1. OnlyEnforceIf is just an implication. You need to add the reverse direction.

  2. You should stay in the Boolean world:

from ortools.sat.python import cp_model

model = cp_model.CpModel()

and12 = model.NewBoolVar("and12")
BoolVar1 = model.NewBoolVar("b1")
BoolVar2 = model.NewBoolVar("b2")
model.AddBoolAnd([BoolVar1, BoolVar2]).OnlyEnforceIf(and12)
model.AddBoolOr([and12]).OnlyEnforceIf([BoolVar1, BoolVar2])

solver = cp_model.CpSolver()
solver.parameters.enumerate_all_solutions = True
solver.Solve(model, cp_model.VarArraySolutionPrinter([BoolVar1, BoolVar2, and12]))

outputs

Solution 0, time = 0.00 s
  b1 = 0   b2 = 0   and12 = 0 
Solution 1, time = 0.00 s
  b1 = 1   b2 = 0   and12 = 0 
Solution 2, time = 0.00 s
  b1 = 0   b2 = 1   and12 = 0 
Solution 3, time = 0.00 s
  b1 = 1   b2 = 1   and12 = 1 
Related