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.