Breaks

A break is a time window during which a machine or operator is unavailable. Three techniques cover most cases.

1. Break as a fixed interval in add_cumulative

For each break, build a new_fixed_size_interval_var and add it alongside task intervals with the full demand. Tasks are pushed around the break.

break_intervals = [
    model.new_fixed_size_interval_var(start=s, size=e - s, name="break")
    for (s, e) in breaks
]
all_intervals = task_intervals + break_intervals
demands = [1] * len(task_intervals) + [1] * len(break_intervals)
model.add_cumulative(all_intervals, demands, capacity=1)

Example: example_07_break_without_changeover.py.

2. Task duration stretched by overlapping breaks

When a task may run through a break and the break simply extends its total time on the machine, use per-time-slot booleans that indicate whether the task uses slot i, then add is_break[i] for each covered slot.

uses[t, i] = starts_before_i AND ends_after_i
duration[t] = base + sum(is_break[i] * uses[t, i] for i)
interval[t] = new_interval_var(start, duration, end, ...)

Example: example_14_task_delaying_break.py.

3. Break-aware start domains

If the break pattern is periodic, restrict task starts to the valid slots with add_linear_expression_in_domain. Much faster than per-slot booleans.

domain_no_break = cp_model.Domain.from_values([...])
model.add_linear_expression_in_domain(start[t], domain_no_break)

Example: example_29_linear_domain_for_breaks.py, example_33_conditional_duration_linear_domain.py.

Automatic jobs

Some "automatic" tasks don't consume the operator while running (think: a machine runs itself after a short manual setup). Model only the setup portion inside the cumulative, using a 1-unit interval at the task's start.

Example: example_12_an_automatic_job.py, example_13_automatic_jobs.py.