diff options
| author | Scott Gasch <[email protected]> | 2026-08-28 21:31:52 -0700 |
|---|---|---|
| committer | Scott Gasch <[email protected]> | 2026-08-28 21:31:52 -0700 |
| commit | bc8a3fddb01a3708be54e1b5453cbd13c7afaaeb (patch) | |
| tree | 654a568490f19ebf0f3c14bb272ef374f2197d3f /src/search.c | |
| parent | bb07fbd8612dbf2cfb6f257e8cba47b95c83c867 (diff) | |
Replace SEARCH_SORT_LIMIT's ply-indexed leftover-selection budget with
NumLeftoverMovesToSelect, indexed by remaining depth; make EFP's
leftover-only scope explicit.
SEARCH_SORT_LIMIT[ply] was a poor proxy for what actually matters here
-- how large the remaining subtree below this node is. Distance from
root only correlates with that when total search depth is roughly
fixed; it says nothing once extensions/reductions/iterative-deepening
are in play. NumLeftoverMovesToSelect(ctx, uDepth) uses remaining depth
instead, only ever consulted once every high-performer move (winning/
even capture, killer, killer-mate -- anything >= GOOD_MOVE) has already
been exhausted; this never limits how many of *those* get selected,
only how much further care to spend on the ordinary/leftover tail.
Table values carried over verbatim from the old one as an untuned
starting point, just reindexed.
Also adds an explicit (TRUE == fInLeftovers) gate to EFP's per-move
checklist (landed last commit) -- every high-performer move was already
excluded as a side effect of the capture/check/killer exemptions, but
this makes "EFP only ever touches leftovers" a real, direct condition
rather than an emergent property of unrelated checks.
Verified against HEAD (commit bb07fbd) at sd10:
ecm_ringers: 9/11 -> 10/11 (+1 solve), ~flat nodes (-0.04%)
ecm_confident_quick: 88/90 -> 88/90 (even), +0.43% nodes
ecm_hard_quick: 15/90 -> 18/90 (+3 solves), +4.4% nodes
Net +4 solves across 269 positions for a negligible node-count cost.
Diffstat (limited to 'src/search.c')
| -rwxr-xr-x | src/search.c | 24 |
1 files changed, 18 insertions, 6 deletions
diff --git a/src/search.c b/src/search.c index 02f4e85..b0bcafd 100755 --- a/src/search.c +++ b/src/search.c @@ -546,17 +546,18 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, // floor already baked into generate.c's own encoding, // not a new one). The first time a selection reveals a // move below that floor, we've hit "the rest of the - // team" -- from then on, apply a budget (borrowing - // SEARCH_SORT_LIMIT's existing table as an untuned - // starting point for this new meaning) on how many more - // full selections are worth the cost before just taking - // the remainder in place. + // team" -- from then on, apply a budget + // (NumLeftoverMovesToSelect, indexed by remaining + // depth, not distance from root -- see searchsup.c) + // on how many more full selections are worth the + // cost before just taking the remainder in place. if (TRUE == pi->fMovesRescoredByIID) { SelectBestNoHistory(ctx, x); } else if ((FALSE == fInLeftovers) || - (uLeftoverPicks < SEARCH_SORT_LIMIT(ctx->uPly))) + (uLeftoverPicks < + NumLeftoverMovesToSelect(ctx, uDepth))) { SelectBestWithHistory(ctx, x); if (FALSE == fInLeftovers) @@ -720,10 +721,21 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, // own null-move probe raised fThreat. See // lmr_testing/RESULTS.md for the individual experiments // that arrived at this checklist. + // + // Explicit leftover-only gate (fInLeftovers, set above once + // the first sub-GOOD_MOVE move is selected, true for every + // move after): every high-performer move (winning/even + // capture, killer, killer-mate) is excluded from pruning + // consideration by construction, not just as a side effect + // of the capture/check/killer exemptions above happening to + // cover the same ground. Belt-and-suspenders on purpose -- + // this is the one thing that must never be true of a move + // we skip outright. fThisMoveEFPPruned = FALSE; if ((x != 0) && (uLegalMoves > 1) && (uFutilityMargin) && + (TRUE == fInLeftovers) && (ComputeMoveScore(ctx, mv, (x - 1)) < uFutilityMargin) && (iExtend <= 0) && (!IS_ESCAPING_CHECK(mv)) && |
