Bluesky @tomcools.be
Timefold timefold.ai

Optimizing Santa's Travels 🎄

by Tom Cools

Holidays are behind us...
...but Santa is already planning for 2026
Toys need to be created
Workers need to be assigned shifts
Santa needs to figure out the route to all children

These are all
planning problems

🎯 Optimize goals

📦 with limited resources

⚖️ under constraints

Our focus for today: Optimized Route

🎯 Goal: Minimize travel time!

📦 Resources: 1 (magical) sleigh!

⚖️ Constraints: Santa things!

Tackling the problem

In our favorite programming language!

Greedy Algorithms

Greedy algorithms make locally optimal choices at each step, but do not consider effects on follow up steps.

Greedy code

                    var remaining = new ArrayList<>(allVisits); //copy
var visitOrder = new ArrayList<>();

Visit latest = remaining.getFirst();
visitOrder.add(latest);
remaining.remove(latest);

int remainingSize = remaining.size();
for (int i = 0; i < remainingSize-1; i++) {
    Visit closestVisit = findClosest(latest, remaining);
    visitOrder.add(closestVisit);
    remaining.remove(closestVisit);
    latest = closestVisit;
}
                    
                
Greed != Good

Algorithm comparison

Greedy
Fast
Scalable
Far from optimal

Let's try everything!
Brute Force 💪

How big is the search space?

Search space for n 🎁: n!

Search space for 5 🎁: 120

Search space for 10 🎁: 3628800

Search space for 100 🎁: 10157

Search space for 1000 🎁: 102567

Search space for 1000 🎁: 102567

Atoms in the observable universe: 1080

10^2567: 2487 more zeroes

😱

Algorithm comparison

Greedy Brute Force
Fast Slow
Scalable Not scalable
Far from optimal Optimal

How good are humans?

Result comparison

Humans Greedy Brute Force
Slow Fast Slow
? Scalable Not scalable
Far from optimal Far from optimal Optimal

Christmas Magic

or math.. probably math.

Mathematical Optimization

Group of techniques to find the ideal inputs from a set
in order to maximize or minimize a real function.
$\begin{aligned} & \quad \sum_{s \in S} \sum_{e \in E} \mathrm{pref}(s,e) \, a_{s,e} \\ \end{aligned} $

Planning optimization made easy


  • Optimization problems in domain code
  • Open Source (Apache license)
  • JVM based!

Easy score calculator

public HardSoftLongScore calculateScore(VehicleRoutePlan plan) {
    long totalDrivingTime = 0;

    for(Vehicle v : plan.getVehicles()) {
        totalDrivingTime += v.getTotalDrivingTimeSeconds();
    }

    return HardSoftLongScore.of(0, totalDrivingTime*-1);
}
Demo Time

Metaheuristics

  1. Make a fast initial solution
  2. Exploring alternatives by moving things around

How many solutions per second?

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

Algorithm comparison

Greedy Brute Force Metaheuristics
Fast Slow Fast
Scalable Not scalable Scalable
Far from optimal Optimal (Near) Optimal
We still have a challenge! 🔥
"Minimize travel time" is a very simplistic view.

In reality

  • Drivers can only visit locations when they are open
  • Trucks have limited capacity
  • Multiple trucks scheduled at the same time
  • ...

Constraints

How do you define constraints?


Constraint minimizeTravelTime(ConstraintFactory factory) {
    return factory.forEach(Vehicle.class)
            .penalizeLong(HardSoftLongScore.ONE_SOFT,
                    Vehicle::getTotalDrivingTimeSeconds)
            .asConstraint("Minimize Travel Time");
}
                

More elaborate example

                
Constraint vehicleCapacity(ConstraintFactory factory) {
    return factory.forEach(Visit.class)
        .filter(visit -> visit.getVehicle() != null)
        .groupBy(Visit::getVehicle, sum(Visit::giftAmount))
        .filter((v, sum) -> sum > v.getCapacity())
        .penalizeLong(HardSoftLongScore.ONE_HARD,
                (v, sum) -> sum - v.getCapacity())
        .asConstraint("Vehicle Capacity");
}
                
                

Why use constraints?

  • Read like business rules
  • Explainable Score
  • Incremental Score Calculation

Incremental Score Calculation

Adding one new package 🎁

Before
🎁 🎁 🎁 🎁 🎁 🎁 🎁 🎁
After
🎁 🎁 🎁 🎁 🎁 🎁 🎁 🎁 🎁

Only the impacted 🎁 are recalculated

Our focus for today: Optimized Route

🎯 Goal: Minimize travel time!

📦 Resources: 1 or more Santas!

⚖️ Constraints: Capacity, Time Windows

🖊 Model domain

⚖️ Define constraints

🚀 Run!

Algorithm comparison

Greedy Brute Force Metaheuristics (Timefold)
Fast Slow Fast
Scalable Not scalable Scalable
Far from optimal Optimal (Near) Optimal

GenAI

Can't solve these kinds of problems

but can be used to write Timefold code.

Start coding today

  1. Go to https://timefold.ai/open-source-solver
  2. Click Run a Quickstart.
  3. Pick a quickstart from the README.
  4. Run it: 🚀
Toys need to be created

Quickstart: Food Packaging

Workers need to be assigned shifts

Quickstart: Employee Scheduling

Santa needs to figure out the route to all children

Quickstart: Vehicle Routing

In Conclusion

Solving these sorts of planning problems is hard!

Planning problems are about people.

Optimization helps you take care of them. 🎁

Give the 🎁 of optimization!