Caleb J. Gammon

schedlab

A public demo of a constraint scheduler, on generated data.

It generates a week of work, lets you break it, and then either repairs the schedule or tells you that no valid one exists.

Try the live demo Hosted. All data is generated.

Overview

What it does

Load a generated week of work. Break it with three controls. Watch a CP-SAT solver fix it or refuse.

Every block on the board is clickable. Clicking one shows the constraints that actually bound that assignment, rather than a summary of the model in general.

When there is no valid schedule, the demo says so. It names what binds, proposes candidate relaxations, and re-solves each one to check it, flagging any it could not verify. It never returns a plausible-looking schedule that violates a hard constraint.

  • OR-Tools CP-SAT
  • 3-second limit
  • 4 workers
  • Fixed-seed generation
Screens

What it looks like

The default schedlab board, with assignment blocks laid out row by row against a time axis.
Default The default board, seed 42. Rows are resources, the horizontal axis is time, and every block is an assignment the solver committed to.
The same page after two top-tier resources are disabled. No board is drawn; the demo reports that the problem is infeasible.
Infeasible Two top-tier resources disabled. There is no valid schedule, so no board is drawn. This is the one genuinely broken state on the page, and the demo reports it instead of drawing something that looks right.
An infeasible result with a named binding cause: a consumable that is never ready in time.
Binding cause The same refusal with a nameable cause: a consumable is never ready in time. Naming what binds is the difference between a failure you can act on and one you cannot.
The same two resources disabled, plus 120 minutes per day of overtime. A full board is drawn again.
Recovered The same two resources disabled, plus 120 minutes per day of overtime. The board comes back. The relaxation is not asserted, it is re-solved.
The lab_operations preset rendered on the same board, with instruments in place of technicians.
Lab preset The lab_operations preset. Different resources and different work, same engine and same constraint model.
The demo rendered at 400 pixels wide, controls stacked above the board.
At 400 px The demo at 400 pixels wide. Same controls, same board, no separate mobile version.
Provenance

Synthetic data, and where this came from

Everything in the demo is procedurally generated from a fixed seed. The same seed produces the same problem on any machine. There is no client, no real site, no real person, no real rate, and no figure taken from any real operation.

This is an independent implementation, written clean-room, informed by a production scheduling system built for a marine service company in South Florida. No code, no data, and no measurement from that system is present here.

Results

Measured results

50 seeds per preset, 3-second limit, 4 workers. Medians.

Marine service: 80 jobs, 10 technicians, 15 sites
invalid overdue travel balance spread
Greedy dispatch heuristic 65 1 40.2 h 863 min
Greedy, constraint-aware 0 (p90 2) 5 50.5 h 808 min
CP-SAT optimizer 0 2 49.2 h 644 min
Lab operations: 70 runs, 8 instruments, 12 suites
invalid overdue travel balance spread
Greedy dispatch heuristic 54 1 16.9 h 790 min
Greedy, constraint-aware 0 1 13.1 h 1358 min
CP-SAT optimizer 0 1 16.3 h 222 min
Head to head against the constraint-aware baseline
marine lab
the weighted objective both are scored on better on 30/30, median +23.7%, worst +8.5% better on 50/50, median +37.3%, worst +12.6%
overdue tasks better on 43/50 tied on 50/50
balance spread better on 42/50 better on 50/50
travel hours better on 23/50 better on 1/50

The last row is the one worth reading twice. The constraint-aware baseline beats the optimizer on travel hours, because it minimizes travel and nothing else while the optimizer also prices balance. Reporting the objective win without this line overstates the result.

Limits

What this demo does not claim

  • CP-SAT does not reach proven optimality in 3 seconds. The median optimality gap is 0.39 on marine and 0.34 on lab. It returns good feasible schedules under a hard deadline, which is what the demo claims and all it claims.
  • The naive baseline is constraint-blind by construction, so its invalid-assignment count is partly a tautology. That is why the third column exists.
  • The zero invalid count is itself partly tautological: tier, capability, availability, parts and pins are enforced by variable omission, so the model cannot express those violations. Capacity is the exception and the real test.
  • Skill tiers are ground truth here only because the generator wrote them. In real work-order data they usually are not. Nothing in the demo should be read as evidence that tiers can be inferred from data.
  • CP-SAT with more than one worker is not bitwise reproducible. Scenario generation is.
Build

How it is built

Python, FastAPI, Google OR-Tools CP-SAT, and a hand-written vanilla HTML/CSS/JS front end with no framework and no build step.

Open the live demo