Skip to content

Nurse Scheduling API Reference

Data

Data model for NurseScheduling use case.

NurseSchedulingData

Bases: UcData

Data for the Nurse Scheduling Problem use case.

This class encapsulates all necessary information to define and solve a Nurse Scheduling problem instance. The unified formulation supports both 2-shift and 3-shift systems. Given a set of nurses and shifts, the problem creates rotating rosters that satisfy workforce requirements while respecting nurse preferences and day-off requests.

Attributes:

  • name (Literal['nurse_scheduling']) –

    A constant identifier for this data type, always set to "nurse_scheduling". Used for registration and type identification in the use case registry.

  • n_nurses (int) –

    Number of nurses available for scheduling.

  • n_shifts (int) –

    Number of shifts in the schedule.

  • workforce (NumPyArray) –

    Required workforce W(d) for each shift d. 1D float array of length n_shifts.

  • effort (NumPyArray) –

    Effort level E(n) for each nurse n. 1D float array of length n_nurses.

  • max_shifts (NumPyArray) –

    Maximum number of (weighted) shifts F(n) each nurse can work. 1D int array of length n_nurses.

  • shift_weight (NumPyArray) –

    Weight for each shift indicating how much it "counts" toward a nurse's maximum shift allowance (used in constraint C3). A weight of 2.0 means the shift counts double — e.g., a night shift with weight 2.0 uses two of a nurse's allowed shifts. 1D float array of length n_shifts.

  • day_off_priority (NumPyArray) –

    Priority matrix g(n,d) for day-off requests. 2D float array of shape (n_nurses, n_shifts). 0 = no request, higher = stronger request.

Examples:

Create a simple nurse scheduling instance:

>>> data = NurseSchedulingData(
...     n_nurses=3,
...     n_shifts=6,
...     workforce=np.array([2.0, 2.0, 2.0, 2.0, 2.0, 2.0]),
...     effort=np.array([1.0, 1.0, 1.0]),
...     max_shifts=np.array([3, 3, 3]),
...     shift_weight=np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0]),
...     day_off_priority=np.zeros((3, 6)),
... )

plot(*, ax: Axes | None = None) -> Axes

Plot workforce requirements and shift weights.

Shows a bar chart of workforce requirements per shift with shift weights overlaid as a line.

Parameters:

  • ax (Axes | None, default: None ) –

    Matplotlib axes to draw on. Creates a new figure if None.

Returns:

  • Axes

    The axes with the plot.

to_string() -> str

Print the data.

Returns:

  • str

    String representation of the data.

from_values(n_nurses: int, n_shifts: int, workforce: np.ndarray | list[float], effort: np.ndarray | list[float], max_shifts: np.ndarray | list[int], shift_weight: np.ndarray | list[float], day_off_priority: np.ndarray | list[list[float]]) -> NurseSchedulingData staticmethod

Create a NurseSchedulingData instance from explicit values.

Parameters:

  • n_nurses (int) –

    Number of nurses available for scheduling.

  • n_shifts (int) –

    Number of shifts in the schedule.

  • workforce (ndarray | list[float]) –

    Required workforce W(d) for each shift d. 1D array of length n_shifts.

  • effort (ndarray | list[float]) –

    Effort level E(n) for each nurse n. 1D array of length n_nurses.

  • max_shifts (ndarray | list[int]) –

    Maximum number of (weighted) shifts F(n) each nurse can work. 1D array of length n_nurses.

  • shift_weight (ndarray | list[float]) –

    Weight for each shift. 1D array of length n_shifts.

  • day_off_priority (ndarray | list[list[float]]) –

    Priority matrix g(n,d) for day-off requests. 2D array of shape (n_nurses, n_shifts).

Returns:

generate_random(n_nurses: int = 10, n_shifts: int = 14, shift_system: str = 'two_shift', seed: int | None = None) -> NurseSchedulingData staticmethod

Generate a random Nurse Scheduling instance.

Parameters:

  • n_nurses (int, default: 10 ) –

    Number of nurses, by default 10.

  • n_shifts (int, default: 14 ) –

    Number of shifts, by default 14.

  • shift_system (str, default: 'two_shift' ) –

    Either "two_shift" or "three_shift", by default "two_shift". Controls how shift weights are generated.

  • seed (int | None, default: None ) –

    Random seed for reproducibility, by default None.

Returns:

Formulation

Formulation for NurseScheduling use case.

NurseSchedulingFormulation

Bases: UcFormulation[NurseSchedulingData, NurseSchedulingSolution]

Constraint-based formulation for Nurse Scheduling Problem.

This formulation uses LunaModel's constraint system to create rotating rosters that satisfy workforce requirements while respecting nurse preferences and day-off requests. Supports both 2-shift and 3-shift systems through unified shift weight parameters.

Mathematical Formulation
Given:
    - N nurses with effort levels E(n) and max shifts F(n)
    - D shifts with workforce requirements W(d) and weights
    - Day-off priority matrix g(n,d)

Decision Variables:
    q[n,d] in {0,1} for each nurse n and shift d
    q[n,d] = 1 if nurse n is assigned to shift d

Objective:
    minimize sum_{n,d} g(n,d) * q[n,d]
    (minimize scheduling nurses on their day-off requests)

Constraints:
    1. No consecutive shifts:
       q[n,d] + q[n,d+1] <= 1 for each nurse n, shift d < D-1
    2. Workforce requirement:
       sum_n E(n)*q[n,d] >= W(d) for each shift d
    3. Max shift count (weighted):
       sum_d shift_weight(d)*q[n,d] <= F(n) for each nurse n
References
  • Nurse Scheduling Problem: https://en.wikipedia.org/wiki/Nurse_scheduling_problem

to_string(data: NurseSchedulingData) -> str staticmethod

Print the formulation.

Parameters:

Returns:

  • str

    String representation of the formulation.

formulate(data: NurseSchedulingData) -> Model staticmethod

Formulate the Nurse Scheduling Problem using constraint-based approach.

Creates a constraint-based formulation using binary decision variables for nurse-shift assignments with workforce, consecutive shift, and max shift count constraints.

Parameters:

Returns:

  • Model

    A LunaModel ready to be solved.

Raises:

  • EmptyDataError

    If there are no nurses or no shifts.

  • InvalidProblemStructureError

    If array dimensions do not match the declared sizes.

interpret(solution: Solution, data: NurseSchedulingData) -> NurseSchedulingSolution staticmethod

Extract solution from solver result.

Extracts the nurse-shift assignments from the solver solution and computes solution metrics including validity checks.

Parameters:

  • solution (Solution) –

    The solver solution containing variable assignments.

  • data (NurseSchedulingData) –

    The original Nurse Scheduling instance data.

Returns:

Raises:

Solution

Solution model for NurseScheduling use case.

NurseSchedulingSolution

Bases: UcSolution

Solution for the Nurse Scheduling Problem.

Attributes:

  • name (Literal['nurse_scheduling']) –

    Identifier for this solution type.

  • schedule (dict[int, list[int]]) –

    Maps nurse index to list of assigned shift indices.

  • n_shifts_assigned (int) –

    Total number of nurse-shift assignments.

  • is_valid (bool) –

    Whether constraints are satisfied (no consecutive shifts, workforce met).

plot(data: NurseSchedulingData | None = None, *, ax: Axes | None = None) -> Axes

Plot the nurse schedule as a grid.

Shows a heatmap where rows are nurses and columns are shifts. Assigned shifts are highlighted in color.

Parameters:

  • data (NurseSchedulingData | None, default: None ) –

    Problem data. When provided, workforce coverage info is shown.

  • ax (Axes | None, default: None ) –

    Matplotlib axes to draw on. Creates a new figure if None.

Returns:

  • Axes

    The axes with the plot.

to_string() -> str

Print the solution.

Returns:

  • str

    String representation of the solution.

Instance

Instance model for NurseScheduling use case.

NurseSchedulingInstance

Bases: UcInstance[NurseSchedulingData, NurseSchedulingFormulation, NurseSchedulingSolution]

Instance combining data and formulation for NurseScheduling.

Collection

Collection of NurseScheduling instances.

NurseSchedulingCollection

Bases: UcInstanceCollection[NurseSchedulingInstance]

Collection of Nurse Scheduling Problem instances.

This collection provides methods to generate benchmark instances with various characteristics for testing and evaluation, including random, two-shift, and three-shift system instances.

from_random(min_num_nurses: int | None = None, max_num_nurses: int | None = None, num_instances: int = 1, *, sizes: Sequence[int] | None = None, n_shifts: int = 14, shift_system: str = 'two_shift', seed: int | None = None) -> NurseSchedulingCollection classmethod

Generate random nurse scheduling instances.

Generates instances with varying nurse counts and random parameters.

Parameters:

  • min_num_nurses (int | None, default: None ) –

    Minimum number of nurses per instance.

  • max_num_nurses (int | None, default: None ) –

    Maximum number of nurses per instance.

  • num_instances (int, default: 1 ) –

    Number of instances per size, by default 1.

  • n_shifts (int, default: 14 ) –

    Number of shifts per instance, by default 14.

  • shift_system (str, default: 'two_shift' ) –

    Either "two_shift" or "three_shift", by default "two_shift".

  • seed (int | None, default: None ) –

    Random seed for reproducibility, by default None.

  • sizes (Sequence[int] | None, default: None ) –

    Explicit sizes to generate, e.g. [10, 50, 100], instead of a range. Mutually exclusive with min_num_nurses/max_num_nurses, by default None.

Returns:

Examples:

>>> collection = NurseSchedulingCollection.from_random(
...     min_num_nurses=5,
...     max_num_nurses=10,
...     num_instances=2,
...     seed=42,
... )

from_two_shift(min_num_nurses: int | None = None, max_num_nurses: int | None = None, num_instances: int = 1, *, sizes: Sequence[int] | None = None, n_shifts: int = 14, seed: int | None = None) -> NurseSchedulingCollection classmethod

Generate 2-shift system nurse scheduling instances.

Shift weights are based on h_1(n)*h_2(d) pattern where alternating shifts have different weights (e.g., day/night).

Parameters:

  • min_num_nurses (int | None, default: None ) –

    Minimum number of nurses per instance.

  • max_num_nurses (int | None, default: None ) –

    Maximum number of nurses per instance.

  • num_instances (int, default: 1 ) –

    Number of instances per size, by default 1.

  • n_shifts (int, default: 14 ) –

    Number of shifts per instance, by default 14.

  • seed (int | None, default: None ) –

    Random seed for reproducibility, by default None.

  • sizes (Sequence[int] | None, default: None ) –

    Explicit sizes to generate, e.g. [10, 50, 100], instead of a range. Mutually exclusive with min_num_nurses/max_num_nurses, by default None.

Returns:

Examples:

>>> collection = NurseSchedulingCollection.from_two_shift(
...     min_num_nurses=5,
...     max_num_nurses=10,
...     seed=42,
... )

from_three_shift(min_num_nurses: int | None = None, max_num_nurses: int | None = None, num_instances: int = 1, *, sizes: Sequence[int] | None = None, n_shifts: int = 21, seed: int | None = None) -> NurseSchedulingCollection classmethod

Generate 3-shift system nurse scheduling instances.

Shift weights are based on day_type*shift_type pattern: - shift_type: daytime=1.0, early_night=1.5, late_night=2.0 - day_type: weekday=1.0, weekend=2.0

Parameters:

  • min_num_nurses (int | None, default: None ) –

    Minimum number of nurses per instance.

  • max_num_nurses (int | None, default: None ) –

    Maximum number of nurses per instance.

  • num_instances (int, default: 1 ) –

    Number of instances per size, by default 1.

  • n_shifts (int, default: 21 ) –

    Number of shifts per instance, by default 21 (7 days * 3 shifts).

  • seed (int | None, default: None ) –

    Random seed for reproducibility, by default None.

  • sizes (Sequence[int] | None, default: None ) –

    Explicit sizes to generate, e.g. [10, 50, 100], instead of a range. Mutually exclusive with min_num_nurses/max_num_nurses, by default None.

Returns:

Examples:

>>> collection = NurseSchedulingCollection.from_three_shift(
...     min_num_nurses=8,
...     max_num_nurses=15,
...     seed=42,
... )

filter_infeasible(max_runtime: float = 3600, *, quiet: bool = True) -> list[bool]

Drop the instances of this collection that have no feasible solution.

Every instance is formulated and handed to SCIP, which stops as soon as it finds the first feasible solution. An instance is removed from the collection when SCIP proves the model infeasible, when no solution turns up within max_runtime, or when formulating it fails altogether. This keeps randomly generated instances from breaking a downstream pipeline.

Parameters:

  • max_runtime (float, default: 3600 ) –

    SCIP time limit per instance in seconds. Must be positive. Defaults to 3600 seconds.

  • quiet (bool, default: True ) –

    Suppress the SCIP solver output.

Returns:

  • list[bool]

    Feasibility mask over the instances as they were before filtering, in that order: True where the instance was kept, False where it was removed.

Raises: