This project is an answer project for stackoverflow per following link.
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.
- Maximum working days per employee (6 days): ∑jyi,j≤xi⋅Dmax ∀i=1:N
- 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
