or-tools: Possible bugs on shift_scheduling_sat.py example

I think

for start in range(len(works) - length - 1):

should be

for start in range(len(works) - length + 1):

https://github.com/google/or-tools/blob/master/examples/python/shift_scheduling_sat.py#L95

For a list of length 4 the possible sequences of length 2 are:

[1, 1, 0, 0], [0, 1, 1, 0], [0, 0, 1, 1]

The last start is 2 -> range(4-2+1) -> range(3) -> [0, 1, 2]

There are many lines where this appears, so maybe I am wrong.

Could test it and send a pull request.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 29

Commits related to this issue

Most upvoted comments

This should work:

  1. Remove the hard constraint for 0 and 6:
for length in range(1, hard_min):
    for start in range(len(works) - length + 1):
        if start == 0 or start == length-1:
            continue
        model.AddBoolOr(negated_bounded_span(works, start, length))
  1. Forbid patterns manually:
10xxxx0: or(not(x[0]), x[1], x[6])
0xxxx01: or(x[1], x[5], not(x[6]))

Hmm, I think hard min 2 means that sequences of ones have to have length >= 2.

So 1 1 0 1 does not pass because the first sequence of ones is correct but the second sequence (last single 1) is too short. Anyway, this actually depends on the definition of your constraint, maybe in your case you don’t mind having a shorter sequence at the end of the list or something like that.

PS: I think is kinda okay to discuss this here as it is related to the issue, but if not, sorry for the spam Laurent/Mizux

I’ve just used this this week to try and schedule an on-call roster.

182 days, exactly 2 shifts per day, one day, one night. Trying to schedule two consecutive nights and one day on its own, so each employee has exactly 3 shifts (2 nights and 1 day which isn’t possible)

https://gist.github.com/braindeaf/3d8503cca59d6e0d7c665479832b2ab3

The only thing I couldn’t fathom was to try and spread the shifts out as evenly in time as possible, say with almost 90 days gap between each set of shifts (if the grouping of 2 and 1 was indeed possible). The lowest cost solution is arrived at within 20 mins or so. I’m calling my Python script from Ruby by reading input / output via YAML, I’m not sure how to convert it to Ruby (or indeed C++) from this as Python is not my forte.

I still think it should be +1 though.

You want to forbid sequence of exactly 2 true variables, you need to construct 3 forbidden patterns

Therefore range(3) instead of range(2) to iterate 3 times right? Do not forget that range generates the list [0, arg) arg not included. range(3) == [0, 1, 2]

Btw, this line also has the same problem:

https://github.com/google/or-tools/blob/master/examples/python/shift_scheduling_sat.py#L101

Thanks for taking a look!