Jan Koekepan
Jan Koekepan

Reputation: 79

OR-Tools CP-SAT solver: count successive NewBoolVar occurrences

In a simple range I try to get the amount of successive assignments for a variable. The values should be between 6-12 or should be 0. For example in the case a hospital has 24 shifts and an employee should work between 6 and 12 hours or not at all.

# Build shifts
shifts = {}
for n in all_nurses:
    for d in all_days:
        for s in all_shifts:
            shifts[(n, d, s)] = model.NewBoolVar('shift_n%id%is%i' % (n, d, s))

# Count successive occurrences
for e_count in all_nurses:
    s_count = 0
    while s_count < len(all_shifts):
        model.Add(sum(shifts[e_count, s_count] for s in range(e_count, e_count + 6 == 6) #min
        model.Add(sum(shifts[e_count, s_count] for s in range(e_count, e_count + 12 <= 12) #min

Unfortunately this doesn't work since it increases the value with only one, what would be the best approach to check if how many hours have been assigned and increase s_count with that value?

Upvotes: 0

Views: 596

Answers (1)

Laurent Perron
Laurent Perron

Reputation: 11034

If you just want to constrain the sum, you should use this method

model.AddLinearExpressionInDomain(sum(bool_vars), cp_model.Domain.FromIntervals([0, 0], [6, 12]))

If you want to constrain the length of a sequence, you should look at the shift_scheduling example

In particular, the soft sequence constraint. The idea is the following, for every starting point, you want to forbid 010, 0110, 01110, ..., 0111110 and 01111111111110 (0110 means work[start] is false, work[start + 1] is true, work[start + 2] is true, work[start + 3] is false.

To forbid a sequence, just add a nogood, that is a clause (or AddBoolOr containing the negation of the pattern.

in my example bool_or(work[start], work[start + 1].Not(), work[start + 2].Not(), work[start + 3]).

Loop over all starting points and all patterns. And pay attention to the boundary conditions.

Upvotes: 3

Related Questions