Joseph Doob
Joseph Doob

Reputation: 173

Why doesn't this Boolean Variable in or-tools work?

I'm getting back into Google's OR tools and trying a (relatively) simple optimization. I'm using the CP SAT solver and I'm probably missing something elementary here. I have some variables x, y and some constant c. I'd like x to be equal to 1 if y is smaller than that c, and 0 otherwise.

from ortools.sat.python import cp_model

solver = cp_model.CpSolver()
model = cp_model.CpModel()
c = 50
x = model.NewBoolVar(name='x')
y = model.NewIntVar(name='y', lb=0, ub=2**10)

model.Add(x == (y < c))

model.Maximize(x+y)

status = solver.Solve(model)

I'm getting an error message

TypeError: bad operand type for unary -: 'BoundedLinearExpression'

It seems I'm misusing OR tools syntax for my constraint here. I'm having difficulties understanding the documentation for OR tools online, and I seem to have forgotten quite a bit more about it than I thought.

Upvotes: 5

Views: 3134

Answers (1)

Anatolii
Anatolii

Reputation: 14660

According to an example from here, you're almost there.

Build x == (y < c) constraint

Case 1: x = true

If x is true, then y < c must also be true. That's exactly what OnlyEnforceIf method is for. If an argument of OnlyEnforceIf is true, then the constraint in the Add method will be activated:

model.Add(y < c).OnlyEnforceIf(x) 

Case 2: x = false,

As mentioned in Case 1, OnlyEnforceIf won't activate the constraint, if its argument is not evaluated to true. Hence, you cannot just leave case y >= c on its own and hope that it will be implied if x = false. So, add a reverse constraint for this case as below:

model.Add(y >= c).OnlyEnforceIf(x.Not())

Since, for x = false, x.Not() will be true, the constraint y >= c will be activated and used when solving your equation.

Full Code

from ortools.sat.python import cp_model

solver = cp_model.CpSolver()
model = cp_model.CpModel()
c = 50
x = model.NewBoolVar(name='x')
y = model.NewIntVar(name='y', lb=0, ub=2**10)

model.Add(y < c).OnlyEnforceIf(x) 
model.Add(y >= c).OnlyEnforceIf(x.Not())

model.Maximize(x+y)

status = solver.Solve(model) 

Upvotes: 3

Related Questions