Skip to main content

Resource Types Overview

OptalCP has three types of resource constraints for modeling different scheduling scenarios. Each type serves distinct use cases and has different semantics.

Resource Type Comparison

Disjunctive Resources (No Overlap)

Use case: Resources that can execute only one task at a time.

Constraint: no_overlap(intervals)

Examples:

  • Single machine or tool (saw, oven, robot)
  • Meeting room
  • Single-threaded processor
  • Any resource with capacity = 1

Key features:

  • Binary occupancy (free or busy)
  • Tasks cannot overlap in time
  • Supports sequence variables for ordering control
  • Supports transition times between tasks

Cumulative Resources

Use case: Resources with limited capacity that can handle multiple tasks simultaneously.

Constraint: sum(pulse expressions) <= capacity

Examples:

  • Workers or staff (e.g., 5 workers available)
  • Memory or storage (e.g., 16 GB RAM)
  • Bandwidth (e.g., 100 Mbps network)
  • Parallel processing units

Key features:

  • Integer capacity constraint (can be variable or fixed)
  • Multiple tasks can execute simultaneously if total demand ≤ capacity
  • Variable or fixed demand per task

Reservoir Resources

Use case: Resources that are produced and consumed over time, with level tracking.

Constraint: level >= min_level and level <= max_level

Examples:

  • Inventory (parts produced and consumed)
  • Fuel or energy (generated and used)
  • Budget or credits (earned and spent)
  • Buffer or queue (items added and removed)

Key features:

  • Level changes in instantaneous steps (not continuous)
  • Production increases level (positive steps)
  • Consumption decreases level (negative steps)
  • Level bounds enforced throughout horizon
  • Initial level can be specified

Comparison Table

FeatureDisjunctiveCumulativeReservoir
CapacityBinary (0 or 1)Integer (0 to N)Level with step changes
Tasks overlapNoYes, if demand ≤ capacityN/A
Demand1 per taskInteger per taskN/A
ProductionN/AN/APositive steps
ConsumptionN/AN/ANegative steps
Level trackingNoNoYes
Transition timesYesNoNo
Sequence controlYes (SequenceVar)NoNo

Choosing the Right Resource Type

Use Disjunctive (no_overlap) when:

  • Resource handles one task at a time
  • Task ordering matters
  • Transition or setup times exist between tasks
  • You need to query task positions in sequence

Use Cumulative when:

  • Resource has capacity > 1
  • Multiple tasks can execute simultaneously
  • Total demand must not exceed capacity
  • Tasks have different resource requirements
  • You have multiple equivalent resources (e.g., 5 identical workers)

Use Reservoir when:

  • Resource is produced and consumed
  • Level must stay within bounds
  • Production and consumption are decoupled in time
  • You need to track resource availability over time

Combining Resource Types

Multiple resource types can be used in the same model:

import optalcp as cp

model = cp.Model()

# Tasks
task1 = model.interval_var(length=10, name="task1")
task2 = model.interval_var(length=15, name="task2")
task3 = model.interval_var(length=20, name="task3")
charging = model.interval_var(length=10, name="charging")

# Disjunctive: tasks 1 and 2 need the same machine
model.no_overlap([task1, task2])

# Cumulative: all tasks need workers (capacity = 3)
workers = model.sum([
model.pulse(task1, 2), # task1 needs 2 workers
model.pulse(task2, 1), # task2 needs 1 worker
model.pulse(task3, 2), # task3 needs 2 workers
])
model.enforce(workers <= 3)

# Reservoir: battery level (starts at 50)
battery = model.sum([
model.step_at(cp.IntervalMin, 50), # Initial level
model.step_at_start(task1, -15), # task1 drains battery
model.step_at_start(task2, -20), # task2 drains battery
model.step_at_start(task3, -10), # task3 drains battery
model.step_at_end(charging, 30), # charging adds energy
])
model.enforce(battery >= 10) # Keep 10% reserve
model.enforce(battery <= 100) # Maximum capacity

result = model.solve()

See also