| Age | Commit message (Collapse) | Author |
|
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.
|
|
uPositional was a per-thread EWMA of abs(material - true score) used to
size lazy-eval and futility margins. It was history-derived (reflecting
whatever recent, unrelated positions looked like) rather than derived
from the position actually being margined, and its update/consumption
was tangled with EVAL_HASH (now disabled).
Eval() now takes an optional SCORE *piPositional out-param and fills it
in on every return path: exact (abs(material-delta)) on a full eval,
or an estimate from a new EstimatePositionalScore() on a lazy exit.
EstimatePositionalScore()'s two terms (king-safety-defect-bucketed, and
a flat residual for mobility/passers/everything else) are calibrated
from ~1.6M measured full-eval samples (p90 of the actual swing), not
guessed -- an initial guessed version measurably regressed ECM solve
rate (630 vs a 650 baseline at sn=4M); the recalibrated version is back
at parity (649/879).
search.c's qsearch futility now reads the value Eval() just computed
instead of the stale/shared ctx field. Also removes QSearchInDangerNoStandPat
and SideCanStandPat, dead since the danger-hash check that fed them was
already commented out (e08387a) -- they depended on the same enprise/
trapped-piece data this conversation is about to move off of
g_PositionHash entirely.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
|
|
|
|
|
|
|
|
Profiling (pmcstat, sampled) showed SideCanStandPat as the single
hottest leaf function in the engine, ahead of Eval itself -- not from
expensive logic (it's a 3-line signature/lock/lookup), but from sheer
call volume (~95% of the tree is qsearch) combined with a likely-cold
16MB global hash table probe and an uncontended-but-nonzero lock/unlock
pair paid on every call even single-threaded.
Disabling it entirely: real bench nps was flat (~1.53M vs ~1.57M,
within noise -- the earlier "1.2M->1.75M" bench reading was itself an
uncontrolled, noisy single comparison on this shared box, not a real
effect). But ECM (sn 4M) came back at 655/879, the best result of the
whole session (vs 650 baseline) -- suggests the danger-detection
heuristic may have been net-negative for search quality on balance,
forcing exhaustive no-stand-pat search in some positions where
standing pat was actually fine. Speed claim didn't hold up; the
tactical-quality result is a genuine, unexpected positive worth
investigating further.
Not yet validated in self-play -- pending a clean match run.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
|
|
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]>
|
|
|
|
|
|
|
|
|
|
|
|
it found)
|
|
|