I'm developing a nurse scheduling program in Python for one of the departments of the hospital I work with. Various examples of such programs already exist and are shared online. One of these is the following: https://github.com/google/or-tools/blob/master/examples/python/shift_scheduling_sat.py
So far I have adapted the code in the link above to include various types of labour regulations as well as individual nurse preferences. Now I would like to use this tailored script to produce rosters for a workforce of 25 nurses over a 7 week period (5 shift types, can be reduced to 4).
However, implementing particular types of constraints leads to a significant increase in run-time. These constraints are:
Constraint on length of series of morning/evening/night shift:
shift_constraints = [ #Morning shifts (1, 2, 2, 0, 4, 4, 0), #Evening shifts (2, 2, 2, 0, 4, 4, 0), Night shifts (3, 1, 2, 2, 5, 5, 0) ]
Constraint on days off. I would like to prevent the scheduling of single days off by adding to the list of shift constraints:
(0, 1, 2, 2, 10, 10, 0)
Force that weekends, both Saturday & Sunday, are scheduled off:
for e in range(num_employees): for d in range(num_days): if ( ( d in weekend_day ) & ( ( d+1 ) in weekend_day) ): model.Add(work[e, 0, d + 1] == 1 ).OnlyEnforceIf(work[e, 0, d])
Force that employees have 2 days off after a series of 3 consecutive night-shifts
for e in range(num_employees): for d in range(num_days): if ((d > 3) and (d<45)): model.Add(work[e, 0, d] == 1).OnlyEnforceIf(work[e, 3, d-3] and work[e, 3, d-2] and work[e, 3, d-1]) model.Add(work[e, 0, d + 1] == 1).OnlyEnforceIf(work[e, 3, d-3] and work[e, 3, d-2] and work[e, 3, d-1])
Force that employees cannot work more than 7 consecutive days:
max_seq_length = 7 for e in range(num_employees): works = [work[e, 0, d].Not() for d in range(num_days)] variables, coeffs = add_soft_sequence_constraint( model, works, 0, 0, 0, max_seq_length, max_seq_length, 0, 'shift_constraint(employee %i, shift %i)' % (e, 0)) # model, works, hard_min, soft_min, min_cost, soft_max, hard_max, #max_cost, 'shift_constraint(employee %i, shift %i)' % (23 shift)) obj_bool_vars.extend(variables) obj_bool_coeffs.extend(coeffs)
Running the script without any of these constraints takes less than 1 minute. However, when adding all of them to the script simultaneously, it may take more than 48 hours to find a solution. Therefore I was wondering whether it is possible to reduce run-time? If it helps, I don't necessarily require an optimal solution. Since I don't make use of penalized constraints much, any solution that satsfies the specified constraints will do.