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

measureresultscale
Gap between the two engines (same tree, same target)7.1 ppnoise between two identical solver runs: 5.7 pp
PioSolver vs the converged reference10.1 pp
Pokalab vs the converged reference12.3 pppaired difference −2.2 ± 1.5 — a statistical tie
The two engines land within measurement noise of each other, and neither is significantly closer to the converged solution. This is the outcome you want from a validation: not “we win”, but no daylight — the same game, solved to the same place, by two independent implementations.

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

engineper boardconfiguration
PioSolver 3 (edge)310 s10 threads, 0.5% pot target
Pokalab DCFR, f32__F32S__ s10 threads, same boards, same target
Pokalab DCFR, 16-bit≈ samehalf the RAM, speed within ±10% (measured)
Speed differences at this scale are a matter of engineering polish, not correctness — and they wash out entirely against the real cost driver, which is how far you push the solve. Our 16-bit storage mode halves memory at no measurable speed cost, which is what lets a single machine keep several large solves resident at once.

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.

Method note. Head-to-head: NL200 3-bet pot (SB vs BTN), pot 24bb, effective 88.5bb, 5% rake capped at 1.5bb; tree exported from our builder into PioSolver’s native line format and verified action-for-action at the root; ranges identical to the combo. Ten boards spanning the check-frequency spectrum. Reference = the same game solved to 0.1% pot; distances are total variation of the range-weighted root strategy, in percentage points. Timings: PioSOLVER3-edge and the Pokalab engine on the same 20-core machine limited to 10 threads each, run sequentially, never concurrently.