timefold.ai
Geoffrey De Smet
by Geoffrey De Smet
Less than 5%
Optimized for KPIs
CPLEX 1.0 in 1988
Expected: -1% driving time
Result: -25% driving time
⇒ -10 million kg CO² emission per year
⇒ -100 million $ cost per year
Our mission
Open source
pythonfor i in range(num_employees):
for j in range(num_shifts):
for k in range(j + 1, num_shifts):
(model.Add(s[i][j] + d[j] + r[i] <= s[i][k])
.OnlyEnforceIf([x[i][j], x[i][k]]))
javafor (int i = 0; i < numEmployees; i++) {
for (int j = 0; j < numShifts; j++) {
for (int k = j + 1; k < numShifts; k++) {
model.addConstraint(
LinearExpr.sum(new IntVar[]{s[i][j], d[j], r[i]})
.leq(s[i][k])
).onlyEnforceIf(new IntVar[]{x[i][j], x[i][k]});
}
}
}
python(f.for_each(Shift)
.join(Shift, equal(lambda shift: shift.employee.id),
less_than_or_equal(lambda shift1: shift1.end,
lambda shift2: shift2.start))
.filter(lambda shift1, shift2:
((shift2.start - shift1.end)
< shift1.employee.rest_duration))
.penalize(ONE_HARD)
.as_constraint("Enough rest between shifts"))
javaf.forEach(Shift.class)
.join(Shift.class, equal(Shift::employee),
lessThanOrEqual(Shift::end, Shift::start))
.filter((shift1, shift2) ->
Duration.between(shift1.end, shift2.start)
.compareTo(shift1.employee.restDuration) < 0)
.penalize(ONE_HARD)
.asConstraint("Enough rest between shifts");
A scaling problem
pythonfor i in range(num_employees): # 10k loop
for j in range(num_shifts): # 50k loops
for k in range(j + 1, num_shifts): # 25k loops
model.Add(...).OnlyEnforceIf(...)
2 500 000 000 000 CPU loops
2 500 000 000 000 constraints
in memory
Out of memory error
python(f.for_each(Shift) # 50k
.join(Shift, equal(shift.employee), ...) # ~250k tuples
.filter(...) # 0-10 tuples
.penalize(...)
.as_constraint("Enough rest between shifts"))
1 constraint
Only 250k tuples
in memory
Lazy, incremental and indexed
Check the Timefold log:
log08:27:00.867 INFO Solving started: ...
08:27:02.528 INFO Construction Heuristic ended: ...
move evaluation speed (39580/sec) ...
08:27:21.313 INFO Local Search ended: ...
move evaluation speed (101701/sec) ...
08:27:21.317 INFO Solving ended: ...
move evaluation speed (101461/sec) ...
It looks at 100 000 solutions per second
Why not plain python/java code?
pythonann = Employee(name="Ann", ...)
(v.verify_that(employee_minimal_rest)
.given(ann,
Shift(start=..., end=..., employee=ann),
Shift(start=..., end=..., employee=ann))
.penalizes())
Isolated per constraint
docs.timefold.ai
REST API
app.timefold.ai
Much more than
VRP with Time Windows
One example...
REST API
We call it ...
Join the PlanningAI revolution
Contact us for assistance,
questions or self-hosting.
Learn more | timefold.ai |
---|---|
Documentation | docs.timefold.ai |
Quickstarts | github.com/TimefoldAI/timefold-quickstarts |
REST APIs | app.timefold.ai |
Feedback |
![]() ![]() |