Scheduling¶
Solvers in the interval-schedule shape place work on a timeline.
Shift scheduling¶
What it is: staff each (day, shift) to its required headcount, with at most one shift per worker per day, balancing the load fairly. When to use it: rostering, on-call rotas, staffing under coverage requirements.
import pandas as pd
import ortidy
requirements = pd.DataFrame({
"day": [0, 0, 1, 1, 2, 2],
"shift": ["am", "pm", "am", "pm", "am", "pm"],
"required": [1, 1, 1, 1, 1, 1],
})
workers = pd.DataFrame({"workerId": ["alice", "bob", "carol"]})
result = ortidy.shift_scheduling(requirements, workers)
result.objective # the peak per-worker shift count (minimized for fairness)
result.frame # one row per assigned (workerId, day, shift)
Optional min_shifts / max_shifts bound each worker’s total shifts.
Job shop¶
What it is: each job is a fixed sequence of tasks; each task runs on a specific
machine that can do one thing at a time; minimize the makespan (when the last task
finishes). When to use it: manufacturing, batch processing, any shared-resource
sequencing problem. Input is a tidy (jobId, step, machine, duration) frame.
tasks = pd.DataFrame({
"jobId": [0, 0, 1, 1],
"step": [0, 1, 0, 1], # order within the job
"machine": ["m0", "m1", "m1", "m0"],
"duration": [3, 2, 2, 4],
})
result = ortidy.job_shop(tasks)
result.objective # makespan
result.frame[["jobId", "machine", "start", "end"]]
The output adds start and end to each task — ready to drop into a Gantt chart (see
the scheduling.ipynb example).
Interval assignment¶
What it is: the tasks already have fixed start/end times — the question is how
few (or how cheap a set of) resources can cover them, given a minimum gap between
consecutive tasks on a resource, and optionally that a resource must be in the right
place to take its next task. When to use it: aircraft rotations (gap =
turnaround), crew lines, gate/stand allocation, driver duty chaining, machine
reservations. See the API page for the four-regime
table and the full worked walkthrough in tail_assignment.ipynb.
tasks = pd.DataFrame({
"taskId": ["b0", "b1", "b2"],
"start": [385, 400, 615],
"end": [580, 725, 810],
})
result = ortidy.interval_assignment(tasks, min_gap=25)
result.objective # number of resources used
result.frame[["taskId", "resourceId"]]
Opt into complexity with optional columns: start_location_column /
end_location_column add place-connection chaining; a resources frame
(resourceType, count, fixed_cost) plus an eligibility (taskId, resourceType)
frame turn it into a minimum-cost typed-fleet assignment (the objective becomes total
fixed_cost, and it can be INFEASIBLE when count caps bind).