So I'm trying to build a scheduling tool in OR-tools similar to the employee scheduling example. However, in my case there are ten shifts to cover, and I would like to prevent people from having a ten hour workday by making sure either the first two shifts are off, or the last two shifts are off.
I would like to do something like this, but it keeps saying the solution is INFEASABLE.
all_nurses = range(5)
all_shifts = range(10)
all_days = range(20)
for n in all_nurses:
for d in all_days:
model.add(sum(shifts[(n,d,s)] for s in [0, 1]) == 0 or sum(shifts[(n,d,s)] for s in [8, 9]) == 0)
Is it really INFEASABLE or is this piece of code not doing what I think it is doing?
Thanks Laurent for helping me find the answer! For future references, in code it would look like this:
for n in all_nurses:
for d in all_days:
# Implement the contraint
b = model.NewBoolVar(f'constr_{n}_{d}')
model.add(sum(shifts[(n,d,s)] for s in [0, 1]) == 0).OnlyEnforceIf(b)
model.add(sum(shifts[(n,d,s)] for s in [0, 1]) > 0).OnlyEnforceIf(b.Not())
# Apply the contraint
model.add(sum(shifts[(n,d,s)] for s in [8, 9]) == 0).OnlyEnforceIf(b.Not())
Please read https://github.com/google/or-tools/blob/stable/ortools/sat/doc/channeling.md
In a nutshell, or, and, min, max python keywords are not correctly interpreted. In your case, sum() == 0, will be on object, thus always evaluated to True when the python code is parsed.
You need to create all intermediate Boolean variables, and add you bool_or constraint on those.