<feed xmlns='http://www.w3.org/2005/Atom'>
<title>typhoon.git/src/docs, branch master</title>
<subtitle>The typhoon chess playing engine.
</subtitle>
<id>https://git.acknak.org/cgit/typhoon.git/atom?h=master</id>
<link rel='self' href='https://git.acknak.org/cgit/typhoon.git/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git.acknak.org/cgit/typhoon.git/'/>
<updated>2026-10-25T16:55:30Z</updated>
<entry>
<title>Learned FH% logistic-regression model (alpha full, beta whole-node-only)</title>
<updated>2026-10-25T16:55:30Z</updated>
<author>
<name>Scott Gasch</name>
<email>scott@gasch.org</email>
</author>
<published>2026-10-25T16:55:30Z</published>
<link rel='alternate' type='text/html' href='https://git.acknak.org/cgit/typhoon.git/commit/?id=874ef0478078ef4eb436af7d2b68a353f61f4d70'/>
<id>urn:sha1:874ef0478078ef4eb436af7d2b68a353f61f4d70</id>
<content type='text'>
Replaces the data.c histogram tables (g_uJointFHThousandths/
g_uBetaFHThousandths and their _NNUE counterparts) with two quantized
logistic regressions as the default FH%-prediction mechanism under
FH_USE_REGRESSION_MODEL=1, trained against real collected search data
(fhcollect.c) per docs/REGRESSION.md.

Alpha side is a full per-move regression, validated against the old
table (0.119pp weighted mean deviation across 10,684 matched cells).
Beta side is whole-node-only (matching the old table's own scope --
no functionality lost), refit on the NO_MOVE population after an
earlier mixed-tier fit saturated and over-pruned; its skip threshold
(FH_BETA_SKIP_THRESHOLD=99000) was confirmed by direct self-play
sweeps, not just ECM solve-count intuition (see docs/REGRESSION.md's
"Category A vs B" discussion).

Gated by an overnight SPRT match (regression vs HEAD tables, same
NNUE eval, sd8): at 4120 games, llr=+2.53 (never dipped negative,
peaked +2.8), score=0.517, candidate reaching comparable depth at
higher nps/ebf than head. Did not cross the H1=+2.94 SPRT bound, but
the trend across the full run is unambiguous and the marginal value of
waiting out the remaining games was judged not worth it.

The data.c tables are left in place as the inactive #else branch of
FH_USE_REGRESSION_MODEL for now; a follow-up commit will flip the
build default and remove them once this commit's head_reference
baseline and ECM numbers are recorded.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>More aggressive move reductions; Wilson bound overrides static signal when available</title>
<updated>2026-10-24T16:07:03Z</updated>
<author>
<name>Scott Gasch</name>
<email>scott@gasch.org</email>
</author>
<published>2026-10-24T16:07:03Z</published>
<link rel='alternate' type='text/html' href='https://git.acknak.org/cgit/typhoon.git/commit/?id=5f901d737b17c5f99b6e456d6c0c7d5e3c093dc4'/>
<id>urn:sha1:5f901d737b17c5f99b6e456d6c0c7d5e3c093dc4</id>
<content type='text'>
SPRT playtest (2000 games, sd/depth matched): -535 =875 +590, score=0.514,
llr=+1.04 (floated around +1.0 the whole run, never went negative) toward
H1=+2.94. Not a confirmed win, but searches meaningfully deeper (avg depth
14.35 vs 13.50, EBF 3.131 vs 3.305) at no measurable strength cost -- worth
banking and continuing to accumulate games against.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>NNUE search integration: FH% tables, NODE_TYPE refinement, TREEDUMP rewrite</title>
<updated>2026-10-23T20:19:17Z</updated>
<author>
<name>Scott Gasch</name>
<email>scott@gasch.org</email>
</author>
<published>2026-10-23T20:19:17Z</published>
<link rel='alternate' type='text/html' href='https://git.acknak.org/cgit/typhoon.git/commit/?id=69525eb2f42ea9cca8255f6cc3b85e6b1312fd05'/>
<id>urn:sha1:69525eb2f42ea9cca8255f6cc3b85e6b1312fd05</id>
<content type='text'>
- data.c/chess.h: widen the joint FH% table's late axis 16-&gt;17, dedicating
  the new bucket 0 to a whole-node ("will something here fail high at
  all") sample rather than sharing it with the first-leftover-move curve.
  Add an NNUE-eval counterpart table (g_uJointFHThousandths_NNUE) and an
  NNUE counterpart of the beta-side table, selected at runtime based on
  whether NNUE eval is active.
- search.c/searchsup.c: add _RefineNodeTypeGuess, which uses the FH%
  tables (via g_NodeTypeGuessTable) to refine a node's NODE_TYPE guess
  instead of the old heuristic; thread uParentMoveFHEstimate through
  PLY_INFO so a node can see its parent's prediction for the move that
  led to it.
- generate.c: initialize sKillers[2]/[3].uBonus unconditionally (an
  uninitialized-stack read caught by valgrind under LTO; harmless today
  but a real bug).
- dumptree.c/chess.h/GNUmakefile: replace the long-dead DUMP_TREE XML
  tree dump (written for a GUI this project no longer has) with TREEDUMP,
  a flat, path-keyed move/result trace meant to diff against an
  identically-instrumented Stockfish build -- see docs/TREEDUMP_FORMAT.md.
- docs/DEEPER_PRUNING.md: notes on closing the search-efficiency gap vs
  Stockfish.
- crafty_egtb/stockfish_xboard/typhoon_nnue: wrapper scripts so
  match_play.py's Engine class can drive Crafty, Stockfish (via
  PolyGlot), and an NNUE-enabled typhoon the same way it drives HCE
  typhoon.
- tests/lop: rename lop.txt -&gt; lop.ep_; update compare_lop.cpp.
- annotate_pgns: add aggregate_marginsafety.py, dedup_pgn.py,
  fit_lazy_probe.py; update annotate.py/run_nnue_pipeline.py for the NNUE
  training pipeline.
- .gitignore: ignore compile_commands.json (clangd build DB) and
  eval.nnue (a symlink into the untracked head_reference/ comparison
  baseline), neither of which belongs in the repo.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>NNUE: re-fit raw-to-score calibration, NNU4 weight format, super-lazy default-on, lazy probe measured net-negative</title>
<updated>2026-10-21T01:37:20Z</updated>
<author>
<name>Scott Gasch</name>
<email>scott@gasch.org</email>
</author>
<published>2026-10-21T01:37:20Z</published>
<link rel='alternate' type='text/html' href='https://git.acknak.org/cgit/typhoon.git/commit/?id=9cf14e14e6999420f234cda951894337e034f57c'/>
<id>urn:sha1:9cf14e14e6999420f234cda951894337e034f57c</id>
<content type='text'>
Fits an affine (a + b*raw) correction into every exported .nnue file
(export_nnue_weights.py's CalibrateScoreMapping) so the engine's
consumed centipawn output tracks Stockfish's real score scale rather
than the net's nominal raw WDL-sigmoid output -- training variance
alone shifts this mapping across retrains even with an identical
recipe, so it's re-fit and baked in per export rather than assumed
constant. Weight format bumped to "NNU4" to carry the two new floats;
older NNU1/2/3 files are no longer readable.

Super-lazy (material-only) pre-filter promoted to default-on
(g_fUseNnueSuperLazy = TRUE) with a recalibrated per-material-bucket
margin table (measured against the recalibrated net, 16-shard
cross_sectional_200k.ep_ sample) -- real, measured nps win across all
three curated suites. The separate lazy-probe gate (accumulator-based
early exit) is measured net-negative on real search traffic at this
net's probe-vs-forward latency ratio and stays off by default
(g_fUseNnueLazyProbe = FALSE); code kept live since margin tuning
could still flip this, per docs/NNUE.md.

Also: direct per-call latency instrumentation for NnueProbeScore/
NnueForward (root.c, EVAL_TIME build) to make the lazy-probe
breakeven math measurable directly instead of inferred; QSearch
futility margins given real-data-derived NNUE_FULL/NNUE_LAZY
starting points.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Wire NNUE eval into search, build the training pipeline, and add a fast</title>
<updated>2026-10-20T16:26:44Z</updated>
<author>
<name>Scott Gasch</name>
<email>scott@gasch.org</email>
</author>
<published>2026-10-20T16:26:44Z</published>
<link rel='alternate' type='text/html' href='https://git.acknak.org/cgit/typhoon.git/commit/?id=c8c6bbc2c1a103e5b07b079a0f8bdf66c7724d80'/>
<id>urn:sha1:c8c6bbc2c1a103e5b07b079a0f8bdf66c7724d80</id>
<content type='text'>
move/eval-agreement benchmark against Stockfish (tests/lop)

Implements the architecture decisions in src/docs/NNUE.md: HalfKAv2_hm
feature set, int16/int8 quantization, per-ply accumulator backup for
king moves, and a lazy-eval-ready integration into search.c/eval.c.
Adds the full annotate_pgns/ training pipeline (extraction, K-fit/
labeling, quiet filtering, tensor building, training, export) plus an
end-to-end orchestrator (run_nnue_pipeline.py) and validation tooling
(sanity_check_net.py, compare_vs_stockfish_net.py). Adds tests/lop:
a 10k-position list-of-positions benchmark comparing engine eval rank
and move choice against pre-computed Stockfish/lc0 references, much
cheaper than a full self-play match for day-to-day progress checks.

First sd10-matched self-play result against classic HCE: LLR +2.28
(H1=+2.94), -72=119+169 over 360 games, confirming the net is
"smarter per node" at matched depth. A real-time (--st 4) match is
currently weaker (candidate loses ~3 plies of depth to a ~3.3-3.7x
nps gap against an unrecalibrated search), consistent with
NNUE.md's adoption-criterion section -- pruning/reduction constants
still need retuning for the new eval's score scale before a fair
real-time comparison is possible.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Phase A NNUE: feature-indexing spec, annotation/training pipeline, dump nnuefeatures</title>
<updated>2026-10-15T20:11:22Z</updated>
<author>
<name>Scott Gasch</name>
<email>scott@gasch.org</email>
</author>
<published>2026-10-15T20:11:22Z</published>
<link rel='alternate' type='text/html' href='https://git.acknak.org/cgit/typhoon.git/commit/?id=993b6eeb2a9ac7b659c473b6883fa53af1ad3a0b'/>
<id>urn:sha1:993b6eeb2a9ac7b659c473b6883fa53af1ad3a0b</id>
<content type='text'>
Builds out the NNUE Phase A prototype per docs/NNUE.md:

- src/nnuefeatures.c: standalone HalfKAv2_hm feature-index reference
  implementation (new `dump nnuefeatures` command), sourced from
  Stockfish's half_ka_v2_hm.{h,cpp} (sf_16 tag), including the 0x88-&gt;64
  square conversion typhoon's own board representation needs.
- annotate_pgns/: sharded TWIC/self-play annotation harness
  (annotate.py), position extraction, quiet-position filtering (flat
  and game-shaped, plus an upstream --prefilter-quiet option),
  train/holdout game-level stratified split, WDL-sigmoid K fitting,
  the Python HalfKAv2_hm reference encoder (nnue_feature_spec.py) and
  its bit-for-bit cross-checker against the C side
  (cross_check_features.py), and a first PyTorch training pipeline
  (nnue_model.py, nnue_train.py, build_training_tensors.py) -- a
  256x2-32-32-1-ish net trained locally on CPU against ~1.85M quiet
  TWIC positions as a pipeline/framework validation pass.
- Finish an in-progress InitMagic/InitLMRTable/InitEval -&gt;
  InitializeBitboardMagic/InitializeLMRTable/InitializeEval rename:
  chess.h's prototypes hadn't been updated to match the already-renamed
  definitions/call sites, leaving 4 implicit-function-declaration
  warnings.
- tests/arasan.epd: new curated EPD suite.
- docs/: add the project's design docs (previously untracked).

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
</feed>
