My NHL Lineup Optimizer Now Skips the Solver (Mostly)

My NHL lineup optimizer used to build every lineup the same way: hand the whole problem to a solver and wait. It now skips the solver for most of the work. It lists the stacks that are allowed, scores them, and picks the best one, and it does that for a whole batch on a DraftKings or FanDuel slate in about a tenth of a second. The solver I have always reached for is still in the tool, but as the referee rather than the player.

Horizontal bar chart on a log scale. Time to build a batch of lineups with the solver versus the enumeration fast path: DraftKings 3-3 stacks 2.3 versus 0.1 seconds, FanDuel 3-2 stacks with cooldown off 44.9 versus 0.15 seconds.
Time to build the whole batch. The 3-3 rows were run through the app code on tonight’s DraftKings and FanDuel slates; the 3-2 rows were run against the engine directly on a FanDuel slate. FanDuel leaves its own projections blank this early in the season, so I used stand-ins, which do not change the timing. In every row the two methods produced the same lineup totals.
Continue reading “My NHL Lineup Optimizer Now Skips the Solver (Mostly)”

Yahoo DFS NHL Optimizer: Two Goalies, New Rules

My free NHL lineup optimizer now builds lineups for Yahoo, the third site after DraftKings and FanDuel. I expected a Yahoo DFS NHL optimizer to be a matter of a new file parser and a new roster shape. It was mostly that, except for one line in Yahoo’s roster that broke three of my assumptions: two goalies. This post is about what had to change, which settings would have quietly made every lineup impossible, and the one new rule I added because of it: never repeat the same goalie pair.

Bar chart of distinct goalie pairs. 6 lineups: 4 pairs with the limit off, 6 with it on. 20 lineups: 6 pairs off, 20 on.
Same Yahoo slate, same settings. Without a limit the solver keeps coming back to the same two or three goalie pairs.
Continue reading “Yahoo DFS NHL Optimizer: Two Goalies, New Rules”

What an MIT DFS Paper Taught My NHL Lineup Optimizer

An MIT NHL DFS paper found win probability was the only goalie predictor that mattered. So I rebuilt my NHL lineup optimizer around goalies.

Last week I came across a paper from three MIT operations research people — David Scott Hunter, Juan Pablo Vielma and Tauhid Zaman — called Picking Winners in Daily Fantasy Sports Using Integer Programming. It is about building a set of NHL DFS lineups with a solver, which is exactly what my free NHL lineup optimizer does, so I read it with a pencil in hand. They did not just run simulations: they entered real DraftKings contests and report that “we are able to rank in the top-ten multiple times in hockey and baseball contests with thousands of competing entries.” Then they donated the money — “around $15,000” — to the Greater Boston Food Bank, which I thought was a classy touch.

A good chunk of the paper is theorems and proofs about submodular functions. I skipped those. What I wanted was the strategy: what they stacked, what they found, and whether any of it should change my tool. One thing did, and it made the tool more than twice as fast.

Two bar charts. Seconds per lineup: 2.1 when the solver picks the goalie, 0.9 with the goalie fixed. Lineups built from 150 asked in 240 seconds: 70 versus 115.
Same FanDuel slate, same settings, same machine. Fixing the goalie before the solve cut the time per lineup by more than half.
Continue reading “What an MIT DFS Paper Taught My NHL Lineup Optimizer”

The Textbook Fix That Made My MILP Twice As Slow

The textbook move, when a mixed-integer program solves slowly, is to tighten the linear relaxation. Add the constraint that makes the LP bound closer to the integer optimum, give branch and bound less room to wander, watch it finish faster.

I did that to the stacking constraint in my hockey lineup optimizer last week. It got twice as slow. Same slate, same solver, same lineups out the other end — 2.20 seconds a lineup before, 4.38 after. I reverted it and left a comment telling future-me not to helpfully fix it again.

Bar chart of seconds per lineup by stacking formulation: naive 3.00, cover inequalities 2.20, two-sided counters 4.38
Three formulations of the same constraint, same slate and solver. The textbook tightening is the slowest of the three.

Continue reading “The Textbook Fix That Made My MILP Twice As Slow”

My Free Route Optimizer Now Tracks Three Capacities

The free vehicle routing optimizer at routing.kindoflost.com used to think about a vehicle’s capacity as a single number. Fine for a lot of routes, but real fleets rarely run out of just one thing. A cargo van can be full on volume with plenty of weight capacity left, or maxed out on weight while the cargo area still has room, or simply out of pallet slots. I added a fix: the tool now supports three independent vehicle capacity constraints per route, plus a route time limit you can set per vehicle instead of one setting for the whole fleet.

Vehicles sheet with capacity1, capacity2, capacity3, and route_time_limit columns
Continue reading “My Free Route Optimizer Now Tracks Three Capacities”