I am trying to solve a scheduling problem. As input I have the number of workers and the number of shifts.
After that I place all the constraints, including:
- everyone has to work around the same amount of shifts,
- everyone has to take all the given holiday days,
- ...etc.
I then try to maximize a given sequence of shifts.
For example, I can receive the sequence: 123BBBB. This means that I must maximize the appearance of this sequence for each worker in their calendar.
- 1 means the worker works shift 1,
- 2 for shift 2,
- 3 for shift 3, and
- B for break.
I calculate the schedule for the whole year (so let's say 365 days) for each worker. I tried to make bools for each possible sequence: so for the days in range(1, length(sequence)), in range(2, length(sequence))), etc.
And then I add as a constraint that the sum of shifts from today to len(sequence)
is len(sequence)
. So I have the shifts represented as bools too (shifts[(w, d, s)]
) meaning for shifts[(0, 3, 0)]
that worker 1 in day 3 works shift 1.
The constraint for the given sequence is OnlyEnforcedIf the bool created for that sequence is true. And then I try to maximize the sum of the bools created for each sequence.
The problem: I tried running this and after 8 hours of running I gave up. It found me about 62 sequences, but then took too long to stop or find another one. My question is: how to do this more efficiently?
The code:
shift_requests = []
requiredShift = "111222333BBBBBB"
appearences_for_1 = 0
appearences_for_2 = 0
appearences_for_3 = 0
appearences_for_L = 0
for i in requiredShift:
if i == '1':
appearences_for_1 += 1
for i in requiredShift:
if i == '2':
appearences_for_2 += 1
for i in requiredShift:
if i == '3':
appearences_for_3 += 1
for i in requiredShift:
if i == 'B':
appearences_for_B += 1
print(appearences_for_1, appearences_for_2, appearences_for_3, appearences_for_B)
for w in range(worker):
shift_requests.append([])
poz = 0
dayz = 1
while dayz + len(requiredShift) <= 365:
shift_requests[w].append(model.NewBoolVar(f'{w}_{dayz}_{dayz + len(requiredShift)}'))
first_range = dayz + appearences_for_1
second_range = first_range + appearences_for_2
third_range = second_range + appearences_for_3
fourth_range = third_range + appearences_for_B
#shift = 5 ( 0 is shift 1, 1 is shift 2, 2 is shift 3, 3 is break, 4 is holiday)
model.Add(sum(shifts[(w, d, shift - 2 - 3)] for d in range(dayz, first_range))+
sum(shifts[(w, d, shift - 2 - 2)] for d in range(first_range, second_range))+
sum(shifts[(w, d, shift - 2 - 1)] for d in range(second_range, third_range))+
sum(shifts[(w, d, shift - 2)] for d in range(third_range, fourth_range)) == len(requiredShift))\
.OnlyEnforceIf(shift_requests[w][poz])
dayz += 1
poz += 1
model.Maximize(sum(shift_requests[w][poz] for w in range(worker) for poz in range(len(shift_requests[w]))))