Agents: read llms.txt
Simon Spoorendonk

Work

The optimization problems worth solving are usually the ones that stopped being solvable at some size. Three things I keep coming back to: making the bottleneck fast, finding a formulation — or a method — that survives scale, and finishing the job — turning a result into software someone else can actually run.

Performance

Making the pricing subproblem fast

Column generation solves a hard problem by repeatedly asking a smaller one — the pricing subproblem — for the next promising column. In vehicle routing that subproblem is a shortest path with resource constraints, and it is where the solver spends almost all of its time. Everything downstream is bounded by how fast you can answer it.

Subset-row inequalities

Operations Research 56(2) · 2008

Closed 8 Solomon benchmark instances that had stood unsolved.

pP1kiSaipλpSk,SR,  0<kS\sum_{p \in P} \left\lfloor \tfrac{1}{k} \sum_{i \in S} a_{ip} \right\rfloor \lambda_p \le \left\lfloor \tfrac{|S|}{k} \right\rfloor, \quad S \subseteq R,\; 0 < k \le |S|

With Mads Jepsen, Bjørn Petersen and David Pisinger; 600+ citations. The cuts tighten the bound, but each active one adds a resource to the pricing problem — a better bound bought with a harder subproblem, which only pays if you can absorb the cost. We folded the cut contribution into the dominance criterion, so a label carrying cut state could still dominate one that did not.

In the paper's own assessment the result was “competitive and in most cases superior to earlier algorithms within this field”. The cuts are now a standard component of state-of-the-art solvers: the idea outlived our implementation of it, which is the outcome you want.

doi:10.1287/opre.1070.0449 →

Parallel pull labelling

arXiv · 2025

Around 18× over a baseline version of the same algorithm on hard instances, up to 274× at best, and 1.9–2.4× faster than an open implementation of the bucket-graph algorithm on the same hardware.

With Bjørn Petersen. Classical labelling pushes labels forward from each vertex, which makes it awkward to parallelise — the writes collide. Pulling instead, so that each bucket gathers the labels reaching it, turns the same computation into something that parallelises cleanly at the bucket level, with a dynamic bidirectional midpoint and a vectorised dominance check on top.

doi:10.48550/arXiv.2511.01397 →

Bucket-graph labelling

arXiv · 2026

1.3–2.35× faster than PathWyse, the main open-source comparator, in shifted geometric mean at an identical bound.

bucket-graph-spprc is a header-only C++23 library implementing the bucket-graph labelling algorithm of Sadykov, Uchoa and Pessoa — their algorithm, and the pricing algorithm behind VRPSolver. The design decision that matters is a compile-time resource concept: a new variant is added by implementing a fixed seven-function interface, and resources compose into a label state with no runtime dispatch. Rank-1 cuts ship as one of those resources, which is to say the 2008 cuts are a built-in feature of a library written eighteen years later.

doi:10.48550/arXiv.2606.30847 →GitHub →

Scale

What gives way first

Two things decide whether a problem is still solvable at size: how you write it down, and which family of method you point at it. Both tend to be settled early, at whatever scale was available when someone first asked, and then quietly inherited. Both are worth re-opening when the instances grow.

Tree-based multi-commodity flow

arXiv · 2025

Three commodities routed over a shared capacitated network
Three commodities sharing a capacitated network

Reverses a 1993 wall-clock conclusion at three orders of magnitude more scale: 1.4–1.9× faster on shifted geometric mean, 99× on the largest instance, solving 43–44 of 44 where the path-based formulation solves 38–42.

With Bjørn Petersen, implemented in mcfcg. Jones et al. found in 1993 that path-based decomposition converged in fewer iterations and ran faster. The convergence result still holds — tree-based still needs two to three times as many iterations. The wall-clock conclusion does not, because the master problem is 87–99% of the runtime — here, unlike in routing, the master dominates and not the subproblem — and the tree-based master is up to 32 times smaller at termination. Iterations were the wrong thing to count, and the bottleneck is not always where it was last time you looked.

doi:10.48550/arXiv.2509.24656 →GitHub →

Routing in coso

Open source · 2026

A hybrid genetic search, in the manner of HGS-CVRP and PyVRP: no optimality proof, and instance sizes an exact method cannot reach at all.

Exact methods prove optimality, and that proof is expensive: it bounds the instance sizes you can reach at all. This takes the opposite trade deliberately. For a great many real routing problems the proof is not worth its price — nobody is going to act on the bound, they want a good route by Tuesday. Knowing which trade a problem deserves is most of the work. coso is early development, and the routing engine is the part furthest along.

GitHub →

Capacitated profitable tour

arXiv · 2026

A component study on a fully open MIP stack, with every separator and all benchmark scripts released, isolating what actually helps.

cptp is a branch-and-cut solver for the capacitated profitable tour problem, where you choose which customers to serve as well as how to route them. The point of the paper is less the solver than the method: build it on an entirely open stack, release every separator and every script, and then take the pieces out one at a time to see which ones were carrying the result.

doi:10.48550/arXiv.2607.04497 →GitHub →

Primal heuristics for MIP

Open source · 2026

Four modern primal heuristics — FeasibilityJump, FPR, LocalMIP and Scylla — implemented and benchmarked inside HiGHS.

Neither of those levers, and no change of method at all. Branch-and-bound finds the optimum eventually; under a time limit what actually matters is how good the incumbent is when the clock stops. Primal heuristics hunt for good feasible solutions alongside the search tree instead of waiting for it — using the relaxation and the solver's own machinery rather than working around them. mip-heuristics implements the four inside HiGHS, so the comparison between them is like for like.

GitHub →

Software

From result to working code

A result that only exists in a paper is unfinished, and most optimization research ships no code at all — which makes it hard to build on and impossible to check independently. What is below is released, documented and benchmarked, so that someone else can install it, re-run the numbers and disagree with them.

Flowty

Founder & CEO · 2019 – 2026

Scheduling delivered in production with the Ørsted team, with industry pilots at DHL, Svitzer and Unifeeder.

An optimization solver for planning and scheduling in logistics: multi-commodity flow, vehicle routing and resource-constrained shortest path, solved by branch-cut-and-price. Tech lead on the solver and its architecture. The pricing work above is what made it fast enough to matter; the master LP is solved with a GPU-accelerated PDLP and barrier hybrid.

flowty.ai →

Research engineering

2026 – present

Four preprints — two written since February, two rewritten from the ground up in the same period — with the solvers and benchmark scripts released open source.

Working full time inside coding agents, implementing algorithms directly from research papers. Alongside the libraries above: mipx, a branch-and-cut MIP solver written from scratch; cbls, a constraint-based local search engine for mixed discrete-continuous problems; and md2mip, which compiles a model written in prose into a standalone solver CLI.

Method

Why any of this is checkable

Operations research has a property most of computing does not: you can prove a solution is optimal, and the instances everyone benchmarks on are public, with best known results anyone can look up. A claim is reproducible or it is not. That makes the field unforgiving in a way I have come to like — you rarely end up arguing about whether something actually got better.

So the multi-commodity flow paper runs five LP backends spanning open-source and commercial, CPU and GPU, because a result that only holds under one solver is a property of that solver. It quantifies the mechanism rather than asserting it, publishes the counterexample where the method loses by a factor of eight along with the reason, and corrects a memory claim from the previous version down from 5× to 1.09× because the first number did not survive a closer look.

The capacitated profitable tour study applies the same instinct to a whole solver: every separator and all benchmark scripts released on a fully open MIP stack, so that what actually helps can be told apart from what merely accompanies it.

This is also what makes working quickly defensible. The pace is a fact rather than a boast only because each result is measured against public instances at a stated bound, by anyone who cares to re-run it. Speed without verification just accumulates error faster. The verification is the part that lets the pace mean something.

Multi-commodity flow
doi:10.48550/arXiv.2509.24656 →GitHub →
Capacitated profitable tour
doi:10.48550/arXiv.2607.04497 →GitHub →

A selected publication list, the open-source index and advisory work are on the CV. Every paper, with current citation counts, is on Google Scholar; every repository is on GitHub.