Day and Night Shift Scheduling (QUBO)

Click cells of the roster to request days off and press Solve. QUBO++ builds a four-week roster in which every shift has exactly the required staff and the working days, night shifts and weekend work are spread as evenly as possible.

Explained in the docs: Case study: C++ (QUBO++)· Python (PyQBPP)· cons(): C++· Python

Required staff (exactly)
Rule violations–
Fairness (sum of squares)–
Lower bound–
Working days per person–
Night shifts per person–
Holiday work per person–

Click a cell to request a day off: paid leave on a weekday, no holiday work on a weekend day. Other days can be off too: QUBO++ decides who works so that every shift has exactly the required staff.

How it works

The roster covers four weeks. Every day each person works a day shift, a night shift, or is off. The staff are managers, skilled workers and regular staff. The rules are:

  1. Nobody works on a requested day off (paid leave on a weekday, no holiday work on a weekend day). Other days can be off too.
  2. Each shift has exactly the required number of staff.
  3. A weekday day shift has a manager (for customers); a night shift and a weekend day shift have a manager or a skilled worker.
  4. Nobody works more than 6 days in a row (adjustable).
  5. There is a day off between a day shift and a night shift, in either order.

Among the rosters that follow the rules, QUBO++ looks for the one that spreads the working days, the night shifts and the holiday work most evenly: it minimizes the sum of the squares of the number of working days of each person, plus those of the night shifts and of the holiday shifts.

The model uses binary variables day[i][d] and night[i][d] (person i works the day or night shift on day d). Every rule is a linear equation or inequality written with cons(), for example cons(Σt=d..d+6 (day[i][t] + night[i][t]) <= 6) and cons(night[i][d] + day[i][d+1] <= 1). QUBO++ handles these constraints directly, so the model needs no slack variables, and the squares make the objective quadratic. The search stops early when it reaches the lower bound, which proves optimality.

QUBO++ model
Press Solve to build the model.

How to use

The demo runs on AWS Lambda with limited resources; QUBO++ on a desktop PC is several times faster.

How the roster becomes a QUBO model

The binary variables $d_{i,t}$ and $n_{i,t}$ are 1 if person $i$ works the day or night shift on day $t$. No variables are made for requested days off, which are therefore off. Let $r^{\mathrm{D}}_t$ and $r^{\mathrm{N}}_t$ be the required staff of the day and night shifts on day $t$, and $K$ the limit on consecutive working days. The people who can lead the day shift on day $t$, $L_t$, are the managers on a weekday and the managers and skilled workers on a weekend day; the people who can lead a night shift, $L’$, are the managers and skilled workers. For every person $i$ and day $t$, the rules are

\[\begin{aligned} & d_{i,t} + n_{i,t} \le 1 && \text{at most one shift a day}\\ & \textstyle\sum_i d_{i,t} = r^{\mathrm{D}}_t, \qquad \sum_i n_{i,t} = r^{\mathrm{N}}_t && \text{required staff}\\ & \textstyle\sum_{i \in L_t} d_{i,t} \ge 1, \qquad \sum_{i \in L'} n_{i,t} \ge 1 && \text{shift leaders}\\ & \textstyle\sum_{u=t}^{t+K} (d_{i,u} + n_{i,u}) \le K && \text{consecutive days}\\ & n_{i,t} + d_{i,t+1} \le 1, \qquad d_{i,t} + n_{i,t+1} \le 1 && \text{day/night changes} \end{aligned}\]

A shift leader is not required on a shift whose required staff is 0. The objective is the sum of the squares of each person’s working days, night shifts and holiday work (shifts on weekend days):

\[\text{minimize}\quad \sum_i \Big(\sum_t (d_{i,t} + n_{i,t})\Big)^2 + \sum_i \Big(\sum_t n_{i,t}\Big)^2 + \sum_i \Big(\sum_{t\ \text{weekend}} (d_{i,t} + n_{i,t})\Big)^2 .\]

Because the required staff are exact, the three totals are the same for every roster, and with fixed totals the sum of squares is smaller when the counts are more even.

QUBO++ writes every rule with cons(). Their weight is larger than any value of the objective, so a roster that breaks a rule always has a higher energy than one that follows all of them. The solvers handle these constraints directly, so more than 1,000 inequalities need no slack variables: the model has only the variables $d_{i,t}$ and $n_{i,t}$ (598 for the sample). The model is solved by the ABS3 solver of QUBO++ running on the CPU. Spreading the three totals as evenly as possible over the staff gives a lower bound, and the search stops early if it reaches the bound, which proves that the roster is optimal.

Run it on your computer

PyQBPP, the Python version of QUBO++, runs on Linux (x86-64 and ARM64) and on Windows through WSL:

pip install pyqbpp

The day and night shift roster page solves the same problem as the sample of this demo with a short program (the C++ version is also available). The constraints page explains cons(). See Installation for details, and the other demos for more problems solved with QUBO++.