| Age | Commit message (Collapse) | Author |
|
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.
|
|
Finishes work left half-done in 7857096 ("Replace ctx->uPositional with
a data-calibrated Eval() return value"): that commit added Eval()'s new
piPositional out-param but never migrated GetRoughEvalScore onto it, so
GetRoughEvalScore's mid/deep-tree fallback kept reading the old
ctx->uPositional field -- a per-thread EWMA written only on full-eval
calls and never touched by the (far more common) lazy-eval path, so it
carried a stale value from whatever unrelated position last triggered a
full eval, potentially many nodes/plies away. Combined with EVAL_HASH
being long since disabled (its probe branch already dead), every
GetRoughEvalScore call past ply 4 was effectively "material + garbage."
Fixed by having GetRoughEvalScore just call Eval() directly -- its own
lazy-exit machinery already is the cheap, calibrated estimate this
function exists to provide, so there's no separate estimator to
maintain. Removed ctx->uPositional entirely (struct field, its EWMA
update in eval.c, both root.c init sites, split.c's cross-split
propagation, testeval.c's reset) along with the entire EVAL_HASH
subsystem (struct, table, Probe/StoreEvalHash, main.c's now-dead
reporting branch, the GNUmakefile flag) -- confirmed unused elsewhere
and explicitly being cut for good, not coming back in this form.
Also fixed GetRoughEvalScore's prototype being wrongly declared inside
#ifdef EVAL_HASH in chess.h even though the function itself is defined
and called unconditionally -- this was the source of the recurring
"call to undeclared function 'GetRoughEvalScore'" implicit-declaration
warning seen throughout this session's builds.
Separately, fixed QSearch to match its own documented intent: the
en-prise/trapped-piece "don't let this side stand pat" check now only
fires if the side hasn't already been allowed to stand pat earlier in
this qsearch line (matching the comment above it, which already said
this but the code never implemented it).
Verified against baseline/typhoon_baseline (pristine, pre-session) on
ecm_ringers.ep_ (4), ecm_hard_quick.ep_ (50-sample), and
ecm_confident_quick.ep_ (40) at sn=5M, --cpus 1, book disabled:
pristine baseline solves 3/50 on the hard sample; this commit solves
6/50, with the stand-pat fix and GetRoughEvalScore fix each
contributing +1 independently confirmed. No regressions on the other
two suites (4/4 and 40/40 unchanged throughout).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YGSMkwjqiCk4XhbfN7ugD2
|
|
EBF/beta-cutoff/counter-move stats, script.c FPE fix.
No LMR, no counter-move-driven move ordering (both explored separately,
kept out for now -- counter-move measured worse, ~655->647 solved on
ecm879 @ sn=4M with a leaner tree beforehand). Futility pruning restored.
Verified: 647/879 solved, EBF 4.609 @ sn=4M; 684/879 solved, EBF 3.995
@ 20s/move, 1cpu, 256m hash (typhoon_baseline.log).
The counter-move table is still written and its stats still tracked
(dynamic.c) for diagnostic purposes, but generate.c no longer reads it
for move ordering, so it has no effect on search behavior in this
commit.
lmr_testing/ holds the in-flight graded-LMR + counter-move code (not
applied here) with notes on what was already tried and measured, so a
future session can resume without re-deriving it.
|
|
|
|
Fixes a real pathology: checks along a long unbroken forcing line could
extend for free (net zero cost against the qsearch boundary), letting
tree size blow up multiple orders of magnitude on positions like a
near-all-check forced mate (ECM.089: 4.5B nodes / 31min at depth 12
before this change).
- Main-search check extension: gate on SEE soundness (a losing
sacrifice check gets a small consolation QUARTER_PLY instead of the
full bonus a sound check gets), and flatten the sound-check bonus to
a flat THREE_QUARTERS_PLY instead of a near-free ONE_PLY.
- Lower the qsearch entry threshold to match (THREE_QUARTERS_PLY
instead of ONE_PLY) so a lone check still buys one extra full-width
ply as before; root.c trims QUARTER_PLY off the per-iteration depth
budget so this doesn't add a blanket 1/4 ply to every search.
- Qsearch's own check-widening (QSearchFromCheckNoStandPat) now relies
on fCouldStandPat history plus a g_uIterateDepth/4 ceiling instead of
an unconditional per-check grant, and QPLIES_OF_NON_CAPTURE_CHECKS
moved from 1 to 2 to cover both "enter qsearch already in check" and
"opponent's reply is the first real check" cases with one baseline
window instead of ad hoc attacker-color tracking.
Net effect on ECM.089 (sn 4M canary): ~7.5x fewer nodes and ~4x less
time at depth 12 versus the original, unbounded behavior. Costs solve
count on the full ECM suite (879 pos, sn 4M): 650 baseline -> 636 here
-- expected and accepted, since ECM is unusually check-extension-heavy
tactics and not representative of real games. Self-play vs baseline
(1000 games, st 1) came back at B_SCORE=0.4955, ELO=-3.1+/-21.5 --
statistically neutral, confirming the fix costs nothing in real play.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
|
|
Late Move Reductions using a depth x movecount table (Ethereal-style
formula), gated off PV nodes and the ply directly below a PV node
(PLY_INFO.fIsPVNode), with magnitude-aware re-search on fail-high.
Verified node-for-node identical to the previously tested-good v7
binary on a canary position (sd 10) after reconstructing from a ZFS
snapshot of search.c/root.c/split.c taken just before that binary was
built.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
|
|
|
|
|
|
|