In my last post about Fourier-Motzkin elimination I promised a real example involving baseball, and I keep my promises. This is the story of how a dusty 19th-century math trick ended up picking my daily fantasy lineups — and how I stumbled into a genuine Fourier-Motzkin elimination example without fully realizing that’s what I was doing until much later.
First, a confession: I don’t just play, I model
I’ve been playing daily fantasy baseball since 2012. Like most people with an Operations Research background, I lasted about two slates picking players by feel before I opened Excel. A DFS contest is an optimization problem wearing a jersey: every player has a salary and a projected score, you have a $50,000 cap and ten roster slots, and you want the legal lineup with the most projected points. That’s a knapsack problem, and I’ve built knapsacks for a living for years — cattle feed, aircraft parts, you name it (none of them ever hit a home run, though).
So I built the model in Excel. And here’s the honest part: even with the model, I kind of gave up on playing. DFS is full of sharks — people doing this professionally, with better projections, better bankroll discipline, and a lot more hours than a guy with a day job — and grinding against them stopped being fun. But while I was deciding what to do with the spreadsheet, a line I’d heard in a movie when I was much younger kept coming back to me: when there’s a gold rush, don’t dig for gold — sell picks and shovels. So that’s what I did. I took the model to Fiverr and started selling it to the people still digging. Which means strangers on the internet were paying me actual money for a workbook full of macros — and that the model had to be robust enough for someone who wasn’t me to run it, every single day, without me standing behind them. Keep that requirement in mind; it’s the whole reason this post exists.
The rule that almost broke the model
DraftKings’ MLB roster is: two pitchers, plus one each of C, 1B, 2B, 3B, SS, and three OF. Eight hitter slots. If every hitter played exactly one position, this would be trivial — count constraints per position, done. The problem is the website’s own eligibility rule: lots of hitters qualify at two or more positions. The Ben Zobrist types of the world can slide between second base and the outfield, and the moment that’s true, “pick a player” and “fill a slot” stop being the same decision.
The textbook formulation handles this with assignment variables: a yes/no variable for every legal player-slot pair. Player 57 at 2B, player 57 at OF, and so on. Mathematically beautiful. My first fight was with Excel’s built-in Solver, which caps you at 200 decision variables — a wall I ran into face-first (lesson learned: read the solver’s spec sheet before the fight, not after). Switching to the free OpenSolver add-in fixed that; it handles thousands of variables without complaint. Problem solved, right?
Not quite. The variable cap turned out to be the shallow problem. The deep one is that in a spreadsheet, the model is the formulas on the sheet, and an assignment model gives you two bad ways to write those formulas. Option one: create variables only for the legal player-position pairs. Compact — but which pairs are legal changes with every slate, because eligibility belongs to the players, and the players change daily. That means regenerating variable ranges and linking constraints every single morning, with macros, and hoping nothing shifts by one row. Fragile enough when I ran it myself; unthinkable in a workbook I was selling on Fiverr to people who just wanted to paste in a slate and hit a button. Option two: declare a variable for every player in every slot, all of them, and let an eligibility table of 0s and 1s switch the illegal ones off. Now the layout is static — but the model is dragging around ten binary variables per player, thousands in total, and integer programming punishes you for every binary you add. Slow solves, bloated sheet, and almost all of it dead weight. So the real dilemma was: compact but rebuilt daily, or static but bloated. I wanted compact and static.
The way out: stop asking who plays where
The insight that saved the model is that I don’t actually care which slot each player fills. I only care who is in the lineup. The slot assignment is bookkeeping — a feasibility question, not an optimization question. So the right move is to kick the assignment variables out of the model entirely, and that is precisely what Fourier-Motzkin elimination does: eliminate the variables you don’t care about, and it hands you the constraints that must hold among the ones you keep.
Here’s the model before, y’s and all:
maximize Σ pointsi · xi
subject to Σ salaryi · xi ≤ 50,000
Σs yi,s = xi for every player i (a picked player fills exactly one slot)
Σi yi,s = 1 for every slot s (every slot gets exactly one player)
where xi = 1 if player i is in the lineup, and yi,s = 1 if player i fills slot s (only defined where i is eligible for s).
Those y’s are the dead weight: hundreds of variables that exist only to certify feasibility. Eliminate them — pair the lower and upper bounds exactly as in the last post, just applied wholesale — and the projection that comes out the other side is a set of constraints on the x’s alone. And they turn out to be constraints a human can read:
For every subset S of the six hitter positions:
(number of picked hitters eligible at ≥ 1 position in S) ≥ (number of slots S needs)
So the model after elimination is:
maximize Σ pointsi · xi
subject to Σ salaryi · xi ≤ 50,000
Σ xi = 8 over hitters, Σ xi = 2 over pitchers
the 63 subset constraints above
where xi are the only variables left.
Sixty-three, because the six positions {C, 1B, 2B, 3B, SS, OF} have 63 non-empty subsets. A few concrete ones, so you can see how ordinary they look: picks eligible at SS must be ≥ 1. Picks eligible at 2B or SS must be ≥ 2. Picks eligible anywhere in {C, 1B, OF} must be ≥ 5 (one C, one 1B, three OF). Each one is just a SUMIF-style count over the lineup — exactly the kind of constraint Excel’s Solver is happy with. Readers who know their combinatorics will recognize the result: it’s Hall’s marriage condition (there’s a nice writeup on Wikipedia), which tells you when a set of candidates can be matched to a set of slots. Fourier-Motzkin doesn’t just tell you such conditions exist — it mechanically derives them for your specific problem.
Sixty-three constraints sounds worse than it is
On paper this trade looks bad. I swapped a clean assignment model for a wall of 63 counting constraints — more rows, more clutter, the kind of thing that makes a formulation look worse. But look at what the 63 constraints depend on: only the position list. Not the players. DraftKings’ six hitter positions are the same today, tomorrow, and next season, so the 63 subsets are the same too. The constraint block is static — I wrote a little VBA macro that loops over the subsets, checks which player eligibility groups intersect each one, and writes the counting formula into a cell, once. After that, a new slate means pasting in new player data and nothing else. The formulas never change; only the numbers flowing through them do. That’s the property that made the spreadsheet sellable: the buyer never touches the model, just the data. An uglier model that never has to be rebuilt beats a prettier one that has to be rebuilt every morning — a lesson that took me longer to accept than I’d like.
I’ll be honest about one thing: when I built this, I wasn’t consciously executing Fourier-Motzkin elimination. I got to the counting constraints the way practitioners usually get anywhere — squinting at small cases until the pattern held (I checked more two-position examples by hand than I will ever admit to). It was only when I sat down to write these posts and traced the algebra properly that I confirmed it: eliminate the assignment variables from the system above and the surviving inequalities are exactly those 63. The method I’d learned at Cargill and filed away as trivia had been running my baseball hobby the whole time.
There is, however, a catch — one I discovered the hard way the first time I tried to enter a lineup the model swore was legal. The optimizer now tells me who to play, but the DraftKings entry form still demands to know where each player goes. The feasibility certificate F-M threw away? The website wants it back. How I made Excel reconstruct it is the next post.
Things that I use, like, and am affiliated with:
Mint Mobile offers great cell phone service for $15 flat, get $15 off using the link. Get discounted phones with service activation and no contract.
I never spend money before I check Mr Rebates or Rakuten to get cashbacks, rebates, discounts, coupons or cheaper gift cards.
