I am using the pyworkforce package (https://pyworkforce.readthedocs.io/en/stable/index.html) to calculate required resources given a demand forecast. In the next step I am using the MinHoursRoster to assign resources to shifts to create a shift plan.
I started to adjust the constraints in MinHoursRoster since in my case it possible for a resource to be scheduled for more than 1 shift per day. Removing the restriction that a resource can be scheduled a maximum of 1 time per day has worked well.
Additionally, I want to adjust the non-sequential-shifts constraint. In the original version, this restriction is not checked within a day, as multiple shifts per day are prohibited. However, in my case, I need to enforce the restriction of non-sequential shifts within days as well. My adjustments here do not work:
I changed the code from:
# Create bool matrix of shifts dependencies
self.non_sequential_shifts_indices = np.zeros(shape=(self.num_shifts, self.num_shifts), dtype='object')
if self.non_sequential_shifts:
for dependence in self.non_sequential_shifts:
i_idx = self.shifts.index(dependence['origin'])
j_idx = self.shifts.index(dependence['destination'])
self.non_sequential_shifts_indices[i_idx][j_idx] = 1
# An resource can not have two consecutive shifts according to shifts dependencies
for n in range(self.num_resource):
for d in range(self._num_days - 1):
for s in range(self.num_shifts):
sch_model.Add(
sum(shifted_resource[n][d][s] * self.non_sequential_shifts_indices[s][j] +
shifted_resource[n][d + 1][j]
for j in range(self.num_shifts)) <= 1)
to this:
# Create bool matrix of shifts dependencies
self.non_sequential_shifts_indices = np.zeros(shape=(self.num_shifts, self.num_shifts), dtype='object')
if self.non_sequential_shifts:
for dependence in self.non_sequential_shifts:
i_idx = self.shifts.index(dependence['origin'])
j_idx = self.shifts.index(dependence['destination'])
self.non_sequential_shifts_indices[i_idx][j_idx] = 1
# An resource can not have two consecutive shifts according to shifts dependencies
for n in range(self.num_resource):
for d in range(self._num_days):
for s in range(self.num_shifts - 1):
sch_model.Add(
sum(shifted_resource[n][d][s] * self.non_sequential_shifts_indices[s][j] +
shifted_resource[n][d][j + 1]
for j in range(self.num_shifts - 1)) <= 1)
However, with this change the model never finds a result even when I define no non-sequential shifts. This doesn't make sense to me as it could find results before my changes.
I am completely new to constraint programming and OR-tools, so it would be great if somebody can help me with this!
The original code for the whole class can be found here: https://github.com/rodrigo-arenas/pyworkforce/blob/c1faec7cd3c2e9e515d078b837842ba7938abe92/pyworkforce/rostering/binary_programming.py