summaryrefslogtreecommitdiff
AgeCommit message (Collapse)Author
13 daysFix integer divide-by-zero in script.c's post-suite histogram printer.Scott Gasch
uMax (the largest histogram bucket count) can be 0 when a script run's positions are all unsolved -- ASSERT(uMax > 0) doesn't stop this in a non-DEBUG build, and the following loop unconditionally divides by uMax, crashing with SIGFPE. Hit repeatedly today running single-position diagnostic scripts (an isolated unsolved position naturally has an all-zero histogram) while investigating an LMR regression on ECM.213. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01YGSMkwjqiCk4XhbfN7ugD2
13 daysBaseline: uPositional data-calibrated fix, enprise/trapped hints, ↵Scott Gasch
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.
2026-08-26Replace ctx->uPositional with a data-calibrated Eval() return value.Scott Gasch
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]>
2026-08-26Don't [re-]consult the SEE when generator already just did so.Scott Gasch
2026-08-26Make EVAL_HASH optional.Scott Gasch
2026-08-26Segfault fix.Scott Gasch
2026-08-26Disable qsearch danger-detection (SideCanStandPat) as an experimentScott Gasch
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]>
2026-08-25Tame check-extension compounding; verified neutral in self-play (0.4955)Scott Gasch
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]>
2026-08-25Add LMR with PV-adjacency guard (v7), verified against saved binaryScott Gasch
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]>
2026-08-24Started doing texel eval tuning.Scott Gasch
2026-08-24Stop tracking pgn data files, ignore pgn/ going forwardScott Gasch
These are large generated/downloaded data files (twic.pgn alone is 3.5GB) that don't belong in version control.
2026-08-23Integrate new syzygy egtb code, lose the old Nalimov code.Scott Gasch
2026-08-23Clean X64 build and ported GetAttacks to x64.Scott Gasch
2026-08-22Bug fixes.Scott Gasch
2026-08-18Stop hanging on exit!Scott Gasch
2026-02-19MinorScott Gasch
2018-10-03Update codebase to remove clang warnings (and a couple of legit errorsScott Gasch
it found)
2016-06-01Add ignore files.Scott Gasch
2016-06-01Initial checkin for typhoon chess engine.Scott Gasch