diff options
| author | Scott Gasch <[email protected]> | 2026-10-25 10:16:16 -0700 |
|---|---|---|
| committer | Scott Gasch <[email protected]> | 2026-10-25 10:16:16 -0700 |
| commit | 3927a4cac6ec254a8e34a5e864300f75c3efc9f3 (patch) | |
| tree | d34d06481bd57276b3ef50bc5513f5bd65950a74 /src/search.c | |
| parent | 874ef0478078ef4eb436af7d2b68a353f61f4d70 (diff) | |
Make the FH% regression model the default; remove data.c's retired tables
Flips FH_USE_REGRESSION_MODEL from an opt-in safety toggle to the only
behavior: fhmodel.c's quantized logistic regressions are now always
used, with no build-time choice left between them and the old
histogram tables. Removes g_uJointFHThousandths/g_uBetaFHThousandths
and their _NNUE counterparts from data.c (4085 lines), their extern
declarations from chess.h, and the now-dead
_JointTablePredictedFHThousandths/_BetaTablePredictedFHThousandths
lookup functions and their supporting bucket helpers
(HangCpBucket/GapCpBucket/MoveNumBucket/DepthBucket/ImproveBucket/
GapBetaBucket/_ShipDepthBucket/_ShipLateBucket) from searchsup.c, along
with the uRawDepthB/uRawImproveB plumbing that only existed to feed
them (search.c, split.c, SearchOneMove's parameter list).
Also drops the beta-side static-nullmove skip threshold's provisional-
96000 #else branch -- 99000 is now simply the default, confirmed (not
provisional) by docs/REGRESSION.md's trust-audit sweep (+291 Elo over
96000 at 200 games, LOWER95=0.79).
Verified: clean release build, clean DEBUG=1 TEST=1 self-test run (no
asserts), and a fresh head_reference/ checkpoint
(head-reference-20261025 -> 874ef04's regression-model binary) with
sd10/sn5000000 solve counts on the three curated suites essentially
matching the previous table-based checkpoint (70/191 vs 71/191 sd10,
93/191 vs 96/191 sn5M).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Diffstat (limited to 'src/search.c')
| -rw-r--r-- | src/search.c | 75 |
1 files changed, 24 insertions, 51 deletions
diff --git a/src/search.c b/src/search.c index dc0fdc0..395a301 100644 --- a/src/search.c +++ b/src/search.c @@ -116,14 +116,12 @@ extern FLAG g_fCanSplit[MAX_PLY_PER_SEARCH]; // purely to minimize the original diff against HEAD's LMR. The move // loop below now just calls GetLMRReduction once and uses its result. // -// EstimateHangingMaterialCp/HangCpBucket/GapCpBucket/MoveNumBucket/ -// DepthBucket moved there too but are no longer file-static -- the -// measurement/collection block further below (gated on -// fMoveIsPruneReduceEligible alone, independent of the LMR decision -- this -// is what's still generating the next round of g_uJointFHThousandths -// data) still needs them, so they're declared in chess.h and called -// from here unchanged in behavior, just by their new (un-underscored) -// public names. +// EstimateHangingMaterialCp moved there too but is no longer +// file-static. 2026-10-25: the bucket helpers mentioned above +// (HangCpBucket/GapCpBucket/MoveNumBucket/DepthBucket) and the +// data.c-table lookups they fed are gone entirely -- see +// docs/REGRESSION.md -- replaced by fhmodel.c's quantized logistic +// regressions. #ifdef JOINT_EXTRA_VERIFY @@ -449,7 +447,6 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, BITBOARD bbMinorAttacksSnapshot[2]; BITBOARD bbRookAttacksSnapshot[2]; FLAG fMoveIsPruneReduceEligible = FALSE; - ULONG uRawDepthB; #ifdef MP FLAG fNodeSplitEligible; #endif @@ -637,7 +634,6 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, { iImprovement = (iEval - ctx->sPlyInfo[ctx->uPly - 2].iEval); } - ULONG uRawImproveB = ImproveBucket(iImprovement); SCORE iEnemyImprovement = 0; if (ctx->uPly > 2) { @@ -670,8 +666,7 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, iBeta, uDepth, iImprovement, - iEnemyImprovement, - uRawImproveB); + iEnemyImprovement); // One call, regardless of which (or neither) of the iEval>iBeta / // iEval<=iAlpha branches below ends up applying -- FhCollectNodeEntry @@ -694,7 +689,6 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, ((pos->uNonPawnMaterial[WHITE] - VALUE_KING) + (pos->uNonPawnMaterial[BLACK] - VALUE_KING))); -#ifdef FH_USE_REGRESSION_MODEL // HOISTED node-level precompute: FHM_NODE_BASE sFhAlphaNodeBase = (iEval <= iAlpha) ? FhModelAlphaNodeBaseQ16(iEval, @@ -706,7 +700,6 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, (pos->uNonPawnMaterial[BLACK] - VALUE_KING)), eNodeTypeGuessParent) : (FHM_NODE_BASE)FHM_MATE_GATED; -#endif // If the Eval call above was a full eval (i.e. not lazy or super // lazy), there are usable attack bitboards. We'll consult them @@ -819,44 +812,32 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, INC(ctx->sCounters.tree.u64QuickNullMoves); #ifndef FH_REGRESSION_COLLECTION // A collection build must NOT take this shortcut -- it - // would skip the real move loop based on the CURRENTLY - // LOADED (soon-to-be-replaced) data.c table, censoring - // exactly the population FhCollectNodeEntry/NodeExit - // (above/below) are trying to measure. Same reasoning as + // would skip the real move loop before FhCollectNodeEntry/ + // NodeExit (above/below) get a chance to log the + // population they're trying to measure. Same reasoning as // the LMP disable in searchsup.c. uNodeLocalFH was already // computed above by _RefineNodeTypeGuess via this exact - // same _BetaTablePredictedFHThousandths lookup (same - // depth/gap/improve bucket inputs, gated by the same - // iEval > iBeta branch) -- reuse it instead of consulting - // the table again. -#ifdef FH_USE_REGRESSION_MODEL + // same fhmodel.c beta-regression call (same iEval > iBeta + // branch) -- reuse it instead of consulting the model + // again. + // + // 99000 is the confirmed default (docs/REGRESSION.md's + // trust-audit section): a direct 200-game sweep against a + // looser 96000 threshold settled this decisively + // (LOWER95=0.79, +291 Elo) -- 96000 fires this shortcut + // ~2x as often as the old table did on real search trees + // (calibration is honest at both; this was a firing- + // frequency gap, not an accuracy one) and cost real + // strength. A 99500 follow-up sweep against 99000 came + // back inconclusive, so there's no case yet for moving + // off 99000. static ULONG uBetaSkipThreshold = 0; if (0 == uBetaSkipThreshold) { CHAR *pszThresh = getenv("FH_BETA_SKIP_THRESHOLD"); - // 2026-10-24: provisional default, NOT yet confirmed by - // match-play -- see docs/REGRESSION.md's "Static-nullmove - // shortcut firing-rate" section. 96000 (matching the old - // table's nominal threshold) empirically fires the - // shortcut ~2x as often as the table did on real search - // trees (calibration is honest at both; this is a - // firing-frequency gap, not an accuracy one) and costs a - // large chunk of ECM solve rate. 99000 recovers ECM - // parity. Per DEEPER_PRUNING.md's Category A/B framework, - // ECM is the WRONG instrument to pick this value with -- - // this is a Category B (deliberately-unsound, - // cluster-tested) pruning decision, and only - // match_play.py's LOWER95 gate can say whether the more - // aggressive 96000 is actually a net real-game win - // despite losing ECM solves. That sweep has not been run - // yet. 99000 is chosen here only as the closest-to-known- - // safe (table-matched) stand-in until it is. uBetaSkipThreshold = (pszThresh && atol(pszThresh) > 0) ? (ULONG)atol(pszThresh) : 99000; } -#else - #define uBetaSkipThreshold 96000 -#endif ULONG uBetaPredictedFHThousandths = uNodeLocalFH; if ((uBetaPredictedFHThousandths != 0xFFFF) && (uBetaPredictedFHThousandths > uBetaSkipThreshold)) @@ -868,9 +849,6 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, iBestScore = iBeta; goto end; } -#ifndef FH_USE_REGRESSION_MODEL - #undef uBetaSkipThreshold -#endif #endif } else if (iEval <= iAlpha) @@ -1041,7 +1019,6 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, } } uStage++; - uRawDepthB = DepthBucket(uDepth / ONE_PLY); #ifdef MP // See fNodeSplitEligible's declaration comment -- same // four conditions the move loop used to re-check on @@ -1231,13 +1208,9 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, fIsLeftoverMove, fThreat, (iBestScore == -INFINITY_SCORE), - uRawDepthB, - uRawImproveB, bbMinorAttacksSnapshot, bbRookAttacksSnapshot, -#ifdef FH_USE_REGRESSION_MODEL sFhAlphaNodeBase, -#endif #ifdef MOVE_ORDERING_EVIDENCE_COLLECTION fThisMoveIsCountermoveMatch, uCMEvidenceBucket, |
