Skip to main content

Re-solving small saves

Small saves (no_rivers) and very small saves (no_turns) don't store the strategies of the later streets (see Saving trees for how they differ from full saves). When you browse such a save, PioSOLVER re-solves the missing streets as you open them. This page describes how that works and what affects its speed and accuracy.

How a river is re-solved​

When you open a river in a save without rivers, PioSOLVER rebuilds the rivers below that turn and solves the one you opened, from both players' ranges on that line and the values stored in the save. A save without turns does the same for the turns. The re-solve runs until it reaches the recalc accuracy (set_recalc_accuracy), so a stricter recalc accuracy gives more accurate rivers but slower browsing.

Since PioSOLVER 3.12 these re-solves use all your cores and stop as soon as they reach the recalc accuracy, so an ordinary river takes a fraction of a second. Rivers you have already opened stay solved while the tree is loaded.

Rarely reached lines​

An ordinary re-solve doesn't work well on a line that one player practically never takes. Say the out-of-position player never bets the turn with any hand. Their range after that bet is empty, so the solve says nothing about how the in-position player should respond to it, and the in-position player's strategy on the rivers below is never trained. Re-solved against an empty range it stays that way, and the out-of-position player could profit by making the bet they never make.

Since 3.12 PioSOLVER re-solves such a line as a whole: all the rivers below that turn at once, against every hand the out-of-position player could take the line with. Each of those hands can instead take the EV it gets from the actions the player really plays, so the in-position player's strategy is trained to make the line unprofitable for every hand. If the action that is never taken is on the flop or the turn, the whole subtree below it, every turn and river, is re-solved at once.

Lines that a player reaches with only a small part of their range (less than 5% by default), and lines that neither player reaches, are re-solved as a whole as well, so that neither player can gain by taking them.

This happens whenever PioSOLVER re-solves: when you browse a save without rivers or turns, in the automatic recalculation (set_always_recalc), in solve_partial and in solve_all_splits rivers. Saves without rivers or turns, and trees solved with algorithms that stop playing an action entirely (pio_cfr, or v4_small with purified strategies), have many such lines.

Waiting time​

Re-solving a whole line takes seconds instead of a fraction of a second, so browsing is sometimes slower than in 3.11. The other rivers of a re-solved line are solved with it, so opening them afterwards is instant.

On the user trees we measured, a typical save needed under 2 extra seconds per 100 browsed rivers on an 8-core machine, on top of the 3-9 seconds the ordinary re-solves of those rivers took. A single line's re-solve stops after 60 seconds at most and keeps its result, a safety net the re-solves rarely reach.

Settings​

PioViewer's configuration has an option to turn this off and to set the share of the range below which a line counts as rarely reached. In UPI it is set_zero_reach_resolve:

set_zero_reach_resolve on|off [rare R] [time S]
  • on (the default) or off. With off these lines are recalculated like any other river, as before 3.12.
  • rare R - lines a player reaches with less than R of their range are re-solved as a whole (default 0.05). A higher R re-solves more lines, which means more waiting while browsing.
  • time S - the longest a single line's re-solve may run while browsing, in seconds (default 60, 0 for no limit).

Nodes re-solved this way carry the flag RARE_LINE_RECALC in the output of show_node, together with ZERO_REACH_OOP or ZERO_REACH_IP when that player never reaches the node.