Adjustments to Shift Rostering in pyworkforce/OR Tools - Non sequential Shifts

77 views Asked by At

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

0

There are 0 answers