pythonscheduleor-toolscp-sat

Adding an or-statement to an OR-Tools constraint (CP-SAT solver)


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())

Solution

  • 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.