CP-SAT Rostering › Formula

Michael BrenndoerferAugust 26, 202518 min read
Machine Learning from ScratchAll chapters
Part 9 of 9Optimization
Chapter 65CP-SAT Rostering › Formula
Reading section 2 of 8 · Formula · 18 minSection 2 of 8 · 18 min

Book contents

Section 2 of 8 · 18 min read

CP-SAT Rostering › FormulaOne section · Sections in this chapter2 / 8 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Rostering comes down to a series of yes-or-no questions: should Alice work the morning shift on Monday? Should Bob cover the night shift on Friday? Each of these questions demands a binary answer. There's no such thing as "half an assignment." This fundamental observation leads us directly to the mathematical structure that makes CP-SAT rostering effective for this type of problem.

The Foundation: Binary Decision Variables

Imagine you're a manager creating next week's schedule. For every possible combination of employee, shift type, and day, you face a simple decision: assign them or don't. There are no shades of gray. An employee either works a shift or they don't. This binary nature of rostering decisions is precisely what we capture mathematically.

We represent each possible assignment as a binary decision variable:

xe,s,t∈{0,1}∀e∈E,s∈S,t∈Tx_{e,s,t} \in \{0, 1\} \quad \forall e \in E, s \in S, t \in T

where:

  • EE: the set of all employees (indexed by ee)
  • SS: the set of all shift types, such as Morning, Afternoon, Evening, or Night (indexed by ss)
  • TT: the set of all time periods, typically days of the week (indexed by tt)
  • xe,s,tx_{e,s,t}: binary decision variable equal to 1 if employee ee is assigned to shift ss in time period tt, and 0 otherwise

Why binary variables? Because rostering is inherently discrete. You cannot assign someone to "0.7 of a shift" or "part-time coverage." The binary representation forces our model to make clear, unambiguous decisions that match the reality of workforce scheduling. This mathematical choice isn't arbitrary. It directly reflects the nature of the problem we're solving.

Even a small roster produces an explosion of binary decisions. With 5 employees working across 4 shift types over 7 days, you're making 5×4×7=1405 \times 4 \times 7 = 140 independent yes-or-no decisions. Each decision variable can be either 0 or 1, giving a solution space with 21402^{140} possible combinations. This is an astronomically large number that makes brute-force search completely impractical.

To visualize the structure of these decision variables, imagine a three-dimensional space whose dimensions represent the employee, shift type, and time period of an assignment. Each point in this space corresponds to a binary decision variable that can take the value 0 (not assigned) or 1 (assigned).

Out[4]:
Visualization
3D scatter plot grid showing binary decision variables with green points for assigned shifts and red points for unassigned shifts across employees, shifts, and time periods.
Three-dimensional structure of decision variables in CP-SAT rostering. The visualization shows a 3D grid for x_{e,s,t}, where each cell is a binary choice: assign employee e to shift s in time period t (value 1, shown in green) or leave it unassigned (value 0, shown in red). The axes are employees (E), shifts (S), and time periods (T). The grid has |E| × |S| × |T| variables, so the solution space grows as 2^{|E| × |S| × |T|}.

Bringing Order to Chaos: Constraints

Having decision variables is just the beginning. Without rules, we could assign anyone to any shift at any time, but that would create chaos. Real-world rostering typically needs to satisfy multiple competing requirements simultaneously. These requirements become constraints in our mathematical model: rules that any valid solution should obey.

Think of constraints as the guardrails that keep our solution on track. They transform an impossibly large space of potential assignments into a manageable set of feasible solutions. Each constraint type addresses a different real-world concern, and together they ensure our roster is both operationally viable and legally compliant.

Coverage Constraints: The most fundamental requirement is that every shift should be staffed. Imagine a hospital emergency room that needs at least 3 nurses on the night shift, or a restaurant that requires 2 servers during dinner rush. Coverage constraints ensure we meet these minimum staffing levels:

∑e∈Exe,s,t=rs,t∀s∈S,t∈T\sum_{e \in E} x_{e,s,t} = r_{s,t} \quad \forall s \in S, t \in T

This formula says: for every shift type ss and every time period tt, the sum of all assignments (where xe,s,t=1x_{e,s,t} = 1) should equal the required number of employees rs,tr_{s,t}. The summation ∑e∈E\sum_{e \in E} counts how many employees are assigned. We're adding up the ones. Why equality rather than "at least"? Because we can also model "exactly rs,tr_{s,t} employees" if needed, though in practice you might use ≥\geq to allow overstaffing.

where:

  • rs,tr_{s,t}: the minimum number of employees required for shift ss in time period tt (also called the staffing requirement)

This constraint is non-negotiable. If coverage isn't met, operations fail. But coverage alone isn't enough. We also need to respect the reality that employees have lives outside work.

Employee Availability: People can't work when they're unavailable. Alice might have classes on Tuesday mornings, Bob might be on vacation, or Charlie might have childcare responsibilities. Availability constraints prevent impossible assignments:

xe,s,t=0∀(e,s,t)∈Ux_{e,s,t} = 0 \quad \forall (e,s,t) \in \mathcal{U}

where:

  • U\mathcal{U}: the set of all infeasible assignments (e,s,t)(e,s,t) where employee ee is unavailable for shift ss in period tt (a subset of E×S×TE \times S \times T)

By setting xe,s,t=0x_{e,s,t} = 0 for all (e,s,t)∈U(e,s,t) \in \mathcal{U}, we're telling the solver: "These assignments are off-limits. Don't even consider them." This significantly reduces the search space and helps prevent schedules that violate employee availability. The constraint applies to each infeasible triple individually, effectively removing those decision variables from consideration.

Maximum Shifts per Employee: Fairness matters. We can't have one employee working 10 shifts while another works 2. Maximum shift constraints ensure balanced workloads:

∑s∈S,t∈Txe,s,t≤me∀e∈E\sum_{s \in S, t \in T} x_{e,s,t} \leq m_e \quad \forall e \in E

where:

  • mem_e: the maximum number of shifts employee ee can work during the planning period (a non-negative integer, typically set based on labor regulations or organizational policies)

The summation ∑s∈S,t∈Txe,s,t\sum_{s \in S, t \in T} x_{e,s,t} counts all assignments for employee ee across all shifts and time periods. This sum equals the total number of shifts assigned to employee ee (since each xe,s,tx_{e,s,t} is either 0 or 1). By requiring this sum to be ≤me\leq m_e, we cap each employee's total workload. This constraint prevents burnout and ensures compliance with labor regulations that limit working hours.

Rest Periods: Perhaps the most critical constraint for employee well-being is that people need rest. Working consecutive shifts without adequate recovery time is unsafe, illegal in many jurisdictions, and leads to poor performance. The rest period constraint prevents this:

xe,s1,t+xe,s2,t+Δt≤1∀e∈E, where Δt<ρx_{e,s_1,t} + x_{e,s_2,t + \Delta t} \leq 1 \quad \forall e \in E, \text{ where } \Delta t < \rho

where:

  • Δt\Delta t: the time gap between consecutive shifts (measured in the same units as tt, typically hours or time periods)
  • ρ\rho: the minimum required rest period between shifts (often 8-12 hours, measured in the same units as Δt\Delta t)
  • s1,s2s_1, s_2: two different shift types (the constraint applies to any pair of shifts)
  • tt: the time period of the first shift
  • t+Δtt + \Delta t: the time period of the second shift, occurring Δt\Delta t time units after the first

The constraint xe,s1,t+xe,s2,t+Δt≤1x_{e,s_1,t} + x_{e,s_2,t + \Delta t} \leq 1 works as follows: if an employee works shift s1s_1 at time tt (so xe,s1,t=1x_{e,s_1,t} = 1), and the time gap Δt\Delta t is less than the minimum rest period ρ\rho, then they cannot work shift s2s_2 at time t+Δtt + \Delta t (forcing xe,s2,t+Δt=0x_{e,s_2,t + \Delta t} = 0). The sum of these two binary variables cannot exceed 1, meaning at most one of them can be 1. This mathematical relationship directly encodes the physical reality that people need time to rest.

The rest period constraint can be visualized as a timeline showing how consecutive shift assignments are restricted. When an employee works a shift at time tt, they cannot work another shift at time t+Δtt + \Delta t if the time gap Δt\Delta t is less than the minimum rest period ρ\rho.

Out[5]:
Visualization
Timeline diagram showing rest period constraint with green bar indicating assigned shift, red X marking forbidden consecutive assignment, and blue box showing minimum rest period requirement.
Timeline visualization of the rest period constraint $x_{e,s_1,t} + x_{e,s_2,t+\Delta t} \leq 1$ where $\Delta t < \rho$. The diagram shows a timeline with two consecutive time periods (t and t+Δt). The constraint ensures that if an employee is assigned to shift s₁ at time t (green bar), they cannot be assigned to shift s₂ at time t+Δt if the time gap Δt is less than the minimum rest period ρ (shown as the red 'X' indicating the forbidden assignment). The minimum rest period ρ is visualized as a required gap between shifts. This constraint prevents overworking and ensures compliance with labor regulations.

Finding the Best Solution: The Objective Function

Constraints tell us what's allowed, but they don't tell us what's best. Among all feasible solutions, and there may be thousands, which one should we choose? This is where the objective function comes in. It quantifies what "best" means for our specific situation.

Most commonly, we want to minimize costs. Every assignment has a cost: regular wages, overtime premiums, or penalties for assigning someone to an undesirable shift. The objective function sums these costs across all assignments:

min⁡∑e∈E∑s∈S∑t∈Tce,s,t⋅xe,s,t\min \sum_{e \in E} \sum_{s \in S} \sum_{t \in T} c_{e,s,t} \cdot x_{e,s,t}

where:

  • ce,s,tc_{e,s,t}: the cost of assigning employee ee to shift ss in period tt (a non-negative real number, typically measured in currency units or preference scores)

The binary nature of xe,s,tx_{e,s,t} works well here: when xe,s,t=0x_{e,s,t} = 0 (no assignment), the term contributes nothing to the sum. When xe,s,t=1x_{e,s,t} = 1 (assignment made), the cost ce,s,tc_{e,s,t} is added. The triple summation ∑e∈E∑s∈S∑t∈T\sum_{e \in E} \sum_{s \in S} \sum_{t \in T} ensures we consider every possible assignment, but only the ones that occur (where xe,s,t=1x_{e,s,t} = 1) contribute to the total cost.

The cost ce,s,tc_{e,s,t} can encode various business priorities:

  • Labor costs: Base wages for the shift
  • Overtime premiums: Higher costs for shifts that push employees over their regular hours
  • Preference penalties: Costs that discourage assigning employees to shifts they dislike
  • Skill premiums: Costs that reflect the value of assigning highly skilled employees to critical shifts

By minimizing this sum, we find the schedule that satisfies all constraints while keeping total costs as low as possible. But cost isn't the only possible objective. We could maximize fairness, minimize schedule changes from previous periods, or balance multiple objectives simultaneously.

Understanding the Challenge: Mathematical Properties

Now that we've built our mathematical model, let's understand the scale of the problem we're solving. The properties we'll explore explain why sophisticated algorithms like CP-SAT are necessary and why naive approaches fail spectacularly.

Solution Space Size: The combinatorial explosion

With ∣E∣|E| employees, ∣S∣|S| shift types, and ∣T∣|T| time periods, we have ∣E∣×∣S∣×∣T∣|E| \times |S| \times |T| binary decision variables. Each variable can independently be 0 or 1, which means the total number of possible assignments is:

∣S∣=2∣E∣×∣S∣×∣T∣|\mathcal{S}| = 2^{|E| \times |S| \times |T|}

where:

  • S\mathcal{S}: the set of all possible solutions (before applying constraints)
  • ∣E∣|E|: the cardinality (size) of the employee set EE, i.e., the number of employees
  • ∣S∣|S|: the cardinality (size) of the shift type set SS, i.e., the number of shift types
  • ∣T∣|T|: the cardinality (size) of the time period set TT, i.e., the number of time periods
  • ∣E∣×∣S∣×∣T∣|E| \times |S| \times |T|: the total number of decision variables (the product of the three set sizes)

This exponential growth is the heart of the challenge. Consider a modest problem: 10 employees, 4 shift types, 7 days. That's 10×4×7=28010 \times 4 \times 7 = 280 decision variables, creating 2280≈10842^{280} \approx 10^{84} possible solutions. To put this in perspective, there are estimated to be 108010^{80} atoms in the observable universe. We're dealing with numbers so large that exhaustive enumeration is computationally infeasible. Even if we could check a billion solutions per second, it would take longer than the age of the universe to explore them all.

This is why constraints are so powerful: they eliminate vast swaths of this solution space. But even with constraints, the remaining feasible space can be enormous. We need algorithms that can intelligently search this space without exploring every possibility.

The exponential growth of the solution space can be visualized to understand why exhaustive search becomes infeasible even for moderately-sized problems. As the number of decision variables increases, the solution space grows at an exponential rate, making it computationally intractable to explore all possibilities.

Out[6]:
Visualization
Semi-logarithmic plot showing exponential growth of the solution space from 1 to 30 variables, highlighting the 18-variable small roster and noting that 140-variable medium and 560-variable large rosters lie beyond the displayed range.
Exponential growth of solution space in CP-SAT rostering. The graph shows how the solution space size $|\mathcal{S}| = 2^{|E| \times |S| \times |T|}$ grows exponentially as the number of decision variables increases. The x-axis represents the total number of decision variables (|E| × |S| × |T|), and the y-axis shows the solution space size on a logarithmic scale. The displayed range highlights a small problem (3×2×3 = 18 variables); medium (5×4×7 = 140 variables) and large (10×4×14 = 560 variables) problems lie far beyond the plotted range and are summarized in the chart. Even a modest increase in problem size leads to an astronomical number of possible solutions: with 20 variables there are over 1 million solutions, and with 30 variables there are over 1 billion. This visualization explains why efficient constraint propagation and search algorithms are useful for practical rostering applications.

Constraint Satisfaction Structure: Putting it all together

We can now see the complete mathematical structure. The rostering problem is a constraint satisfaction problem (CSP): we're searching for assignments that satisfy all constraints simultaneously. Formally:

Find xe,s,t∈{0,1}∀e∈E,s∈S,t∈Ts.t. ∑e∈Exe,s,t=rs,t∀s∈S,t∈T(coverage)xe,s,t=0∀(e,s,t)∈U(availability)∑s∈S,t∈Txe,s,t≤me∀e∈E(maximum shifts)xe,s1,t+xe,s2,t+Δt≤1∀e∈E,Δt<ρ(rest periods)\begin{aligned} \text{Find } &x_{e,s,t} \in \{0,1\} \quad \forall e \in E, s \in S, t \in T \\ \text{s.t. } &\sum_{e \in E} x_{e,s,t} = r_{s,t} \quad \forall s \in S, t \in T \quad \text{(coverage)} \\ &x_{e,s,t} = 0 \quad \forall (e,s,t) \in \mathcal{U} \quad \text{(availability)} \\ &\sum_{s \in S, t \in T} x_{e,s,t} \leq m_e \quad \forall e \in E \quad \text{(maximum shifts)} \\ &x_{e,s_1,t} + x_{e,s_2,t + \Delta t} \leq 1 \quad \forall e \in E, \Delta t < \rho \quad \text{(rest periods)} \end{aligned}

This formulation reveals the structure that CP-SAT exploits. Each constraint type operates on different subsets of variables:

  • Coverage constraints link variables across employees for a given shift-time combination
  • Availability constraints fix specific variables to zero
  • Maximum shift constraints aggregate variables across shifts and times for each employee
  • Rest period constraints create relationships between variables at different time points

The power of constraint programming comes from how these constraints interact. When the solver sets one variable, it can immediately infer consequences for related variables through constraint propagation. For example, if Alice is the only available employee for a shift that requires 2 people, the solver immediately knows the problem is infeasible, without exploring millions of other assignments.

Computational Complexity: Why sophisticated algorithms matter

The exponential solution space means that naive approaches, such as trying every combination or even random sampling, are doomed to failure. But the constraint structure gives us hope: by propagating constraints intelligently, CP-SAT can eliminate huge portions of the search space without explicitly exploring them. The solver uses techniques like:

  • Constraint propagation: Inferring variable values from constraints
  • Conflict-driven learning: Remembering why certain assignments failed to avoid repeating mistakes
  • Branching heuristics: Choosing which variables to set first to maximize constraint propagation

These techniques transform an intractable search into a manageable optimization problem. For most practical rostering problems, CP-SAT can find optimal or near-optimal solutions in seconds to minutes, even when the underlying solution space contains trillions of possibilities.