Limit-number-of-switches-in-employee-scheduling-problem

2022-04-26
3 min read

This project is an answer project for stackoverflow per following link.

https://or.stackexchange.com/questions/4425/limit-number-of-switches-in-employee-scheduling-problem?rq=1

Specifications

Here is a scheduling problem I need to solve. Given the demand for 2 positions in 1 week with 3 shifts per position, I need to allocate the employees accordingly with some extra operational constraints. Note that each employee can work at any position but only one shift per day totally.The main objective here is to minimize the total shift switches within week. First I shall introduce my variables and the constarints and then how I formulated it mathematically.

  1. Maximum working days per employee (6 days): ∑jyi,j≤xi⋅Dmax ∀i=1:N
  2. Minimum working days per employee (5 days): ∑jyi,j≥xi⋅Dmin ∀i=1:N

Objective:

Minimize shift switches day over day across all employees:min∑i,j,ksi,j,k ∀i,j=2:7,k

Day Definition

For example, we defined “ThisMonth” for 7 days from Jun.1.2022 to Jun.7.2022.

Shift Definitions

The first is to define shifts, morning, afternoon, and night. In addition to explicit works, we should define the rest as a shift.

Staff definitions

We defined 16 staff.

Cover constraints

The values are estimated since the spec.says nothing.

Row constraints

We translated maximum and mininum working days to off-days.

Consideration for minimum switched shifts

List all the cases where shifts have a transition. M is Morning. A is Afternoon, N is Night and R is Rest. Here is a simple issue.

date date+1
A or M N
N or M A
A or N M

But we may have a Day-off between transitions.

date date+1 date+2
A or M R N
N or M R A
A or N R M

Also, consecutive Da-off may exist. Note this is the last issue due to a maximum of 2 days off in a week.

date date+1 date+2 date+3
A or M R R N
N or M R R A
A or N R R M

That’s all combinations, so we sum up the penalties by python.

import sc3
vlist=[]
for person in A_Member_in_All:
    for day in FromStartDateMinus3:
        vm0=sc3.GetShiftVar(person,day,'morning')
        va0=sc3.GetShiftVar(person,day,'afternoon')
        vn0=sc3.GetShiftVar(person,day,'Night Shift')
        vr0=sc3.GetShiftVar(person,day,'rest');

        vm_not0=sc3.GetShiftVar(person,day,'not morning')
        va_not0=sc3.GetShiftVar(person,day,'not afternoon')
        vn_not0=sc3.GetShiftVar(person,day,'not night shift')

        if day+3 in ThisMonth :
            vm1=sc3.GetShiftVar(person,day+1,'morning')
            va1=sc3.GetShiftVar(person,day+1,'afternoon')
            vn1=sc3.GetShiftVar(person,day+1,'Night Shift')
            vr1=sc3.GetShiftVar(person,day+1,'rest');

            vm_not1=sc3.GetShiftVar(person,day+1,'not morning')
            va_not1=sc3.GetShiftVar(person,day+1,'not afternoon')
            vn_not1=sc3.GetShiftVar(person,day+1,'not night shift')

            vm2=sc3.GetShiftVar(person,day+2,'morning')
            va2=sc3.GetShiftVar(person,day+2,'afternoon')
            vn2=sc3.GetShiftVar(person,day+2,'Night Shift')
            vr2=sc3.GetShiftVar(person,day+2,'rest');

            vm_not2=sc3.GetShiftVar(person,day+2,'not morning')
            va_not2=sc3.GetShiftVar(person,day+2,'not afternoon')
            vn_not2=sc3.GetShiftVar(person,day+2,'not night shift')

            vm3=sc3.GetShiftVar(person,day+3,'morning')
            va3=sc3.GetShiftVar(person,day+3,'afternoon')
            vn3=sc3.GetShiftVar(person,day+3,'Night Shift')

            diff_m= (vm_not2 & vm3)|(vr2 &vm_not1 &vm3) | (vr2 & vr1 & vm_not0 & vm3) 
            diff_a= (va_not2 & va3)|(vr2 &va_not1 &va3) | (vr2 & vr1 & va_not0 & va3) 
            diff_n= (vn_not2 & vn3)|(vr2 &vn_not1 &vn3) | (vr2 & vr1 & vn_not0 & vn3) 
            diff=diff_m| diff_a| diff_n
            vlist.append(diff) 
            sc3.print('Hi3\n')

        elif day+2 in ThisMonth :
            vm1=sc3.GetShiftVar(person,day+1,'morning')
            va1=sc3.GetShiftVar(person,day+1,'afternoon')
            vn1=sc3.GetShiftVar(person,day+1,'Night Shift')
            vr1=sc3.GetShiftVar(person,day+1,'rest');

            vm_not1=sc3.GetShiftVar(person,day+1,'not morning')
            va_not1=sc3.GetShiftVar(person,day+1,'not afternoon')
            vn_not1=sc3.GetShiftVar(person,day+1,'not night shift')

            vm2=sc3.GetShiftVar(person,day+2,'morning')
            vm_not2=sc3.GetShiftVar(person,day+2,'not morning')
            va2=sc3.GetShiftVar(person,day+2,'afternoon')
            vn2=sc3.GetShiftVar(person,day+2,'Night Shift')

            diff_m= (vm_not1 & vm2)| (vr1 &(vm_not0 &vm2)) 
            diff_a= (va_not1 & va2)| (vr1 &(va_not0 &va2))
            diff_n= (vn_not1 & vn2)| (vr1 &(vn_not0 &vn2)) 
            diff=diff_m| diff_a| diff_n
            vlist.append(diff) 
            sc3.print('Hi2\n')
            
        elif day+1 in ThisMonth:
            vm1=sc3.GetShiftVar(person,day+1,'morning')
            va1=sc3.GetShiftVar(person,day+1,'afternoon')
            vn1=sc3.GetShiftVar(person,day+1,'Night Shift')
            vr1=sc3.GetShiftVar(person,day+1,'rest');

            vm_not1=sc3.GetShiftVar(person,day+1,'not morning')
            va_not1=sc3.GetShiftVar(person,day+1,'not afternoon')
            vn_not1=sc3.GetShiftVar(person,day+1,'not night shift')

            diff_m= (vm_not0 & vm1)  
            diff_a= (va_not0 & va1) 
            diff_n= (vn_not0 & vn1)  
            diff=diff_m| diff_a| diff_n
            vlist.append(diff)
            sc3.print('Hi\n')
st="Error cumulative"
sc3.AddSoft(sc3.SeqError(0,0,30,vlist),st,1)

Solve it!

Solution

Project File

File → Open Project File from Github