Every GTO number in Pokalab — every frequency in the library, every baseline the leak finder compares you against — comes out of a solver we build and run ourselves. That raises a fair question: why should you trust it? This note answers with measurements rather than adjectives.
What the engine is
The postflop engine is a Discounted CFR solver that plays the game board-exact: for a given flop, every turn card and every river card is enumerated and solved — no bucketing, no card abstraction, no “strategically similar” grouping anywhere in the tree. Each iteration updates the entire range as a vector, and the reported strategy is the discounted average with the standard DCFR schedule (the averaging window restarts periodically, so early noise never survives into the output). Rake is modeled exactly as the room charges it — percentage with a cap, applied only when a flop is seen — because a solution that ignores rake is a solution to a different game.
Every library solution is pushed to 0.25%-pot exploitability — past the threshold where strategies stop being artificially mixed. Why that number and not the industry-standard 0.5% is a story of its own: The Exploitability Threshold.
Validated against PioSolver — on an identical tree
Cross-solver comparisons usually founder on a detail: the two engines quietly solve different trees, and every disagreement can be blamed on that. We removed the excuse. Our tree builder exports its game line-for-line into PioSolver’s own tree format, so both engines solve the same game — same actions, same ranges, same pot, same rake — verified action-for-action at the root before solving.
Two engines, one tree, one judge
10 boards · comparable stopping targets (~0.4–0.5% pot) · judged against the same fully-converged reference
| measure | result | scale |
|---|---|---|
| Gap between the two engines (same tree, same target) | 7.1 pp | noise between two identical solver runs: 5.7 pp |
| PioSolver vs the converged reference | 10.1 pp | |
| Pokalab vs the converged reference | 12.3 pp | paired difference −2.2 ± 1.5 — a statistical tie |
Speed, measured the boring way
Same ten boards, same tree, same 10 threads on the same machine, both engines running to their comparable targets:
Wall-clock per board, like for like
Mean seconds per board · 10 boards · 10 threads · NL200 3-bet pot, full multi-size tree
| engine | per board | configuration |
|---|---|---|
| PioSolver 3 (edge) | 310 s | 10 threads, 0.5% pot target |
| Pokalab DCFR, f32 | __F32S__ s | 10 threads, same boards, same target |
| Pokalab DCFR, 16-bit | ≈ same | half the RAM, speed within ±10% (measured) |
Why build it at all?
Because the library is not the product — the pipeline is. Owning the engine means every solution ships with its true exploitability attached, trees are regenerated the moment a rake structure or sizing scheme changes, and the same binary that builds the GTO baseline also powers node-locking against measured population tendencies — things a GUI solver cannot do unattended, a thousand boards at a time. The solver is validated so you never have to think about it again; the interesting work happens on top of it.