Skip to content

How to add a Constraint

Adding a New Constraint to the Staff Scheduling System

This guide explains how to create and integrate a new constraint into the staff scheduling system.

Overview

Constraints are rules that must be satisfied in the generated shift plans. They ensure legal requirements and company policies. Also, specific customer rules can be implemented.

Step 1: Create the Constraint Class

Create a new Python file in the cp/constraints/ directory:

# cp/constraints/your_new_constraint.py
from ortools.sat.python.cp_model import CpModel

from src.day import Day
from src.employee import Employee
from src.shift import Shift

from ..variables import EmployeeWorksOnDayVariables, ShiftAssignmentVariables
from .constraint import Constraint


class YourNewConstraint(Constraint):
    @property
    def KEY(self) -> str:
        return "one-shift-per-day"

    def __init__(self, employees: list[Employee], days: list[Day], shifts: list[Shift]):
        """
        Initialize your constraint with the necessary data.
        """
        super().__init__(employees, days, shifts)
        # Add any additional initialization here

    def create(
        self,
        model: CpModel,
        shift_assignment_variables: ShiftAssignmentVariables,
        employee_works_on_day_variables: EmployeeWorksOnDayVariables,
 ):
        """
        Define the constraint logic using OR-Tools.
        This method is called during model creation.
        """
        # Your constraint implementation here
        pass

Step 2: Implement the Constraint Logic

The create method is where you define your constraint using OR-Tools CP-SAT API:

# an example constraint, which enforces that at most one shift can be assigned to an employee each day
def create(
    self,
    model: CpModel,
    shift_assignment_variables: ShiftAssignmentVariables,
    employee_works_on_day_variables: EmployeeWorksOnDayVariables,
):
    for employee in self._employees:
        for day in self._days:
            model.add_at_most_one(shift_assignment_variables[employee][day][shift] for shift in self._shifts)

Step 3: Export the Constraint

Add your constraint to the __init__.py files:

# cp/constraints/__init__.py
from .your_new_constraint import YourNewConstraint as YourNewConstraint
# cp/__init__.py
from .constraints import (
    # ... existing imports ...
    YourNewConstraint as YourNewConstraint
)

Step 4: Register in solve.py

Add your constraint to the main solver script:

# solve.py
from cp import (
    # ... existing imports ...
    YourNewConstraint,
)

def main():
    # ...

    constraints = [
        # ... existing constraints ...
        YourNewConstraint(employees, days, shifts),
    ]

    # ...