Skip to content

Kestrel 2.3

Choose a tag to compare

@Alon-Berg Alon-Berg released this 02 Nov 14:01
· 12 commits to main since this release

Kestrel 2.3

A bug-fix release for two defects that were present since 2.0. Strength and speed are unchanged: the depth-12 bench gives the same 1,051,844 nodes in the same time.

What was fixed

  • An integer overflow in the evaluation of endgames. The second layer of the network adds up 1,536 products in a 32-bit integer. For a few strongly negative ("dead") neurons of the output bucket that is used with 5 pieces or fewer, the exact sum can fall below -2^31; the 32-bit sum then wraps around to a large positive number and the neuron is read as fully on instead of fully off. A sanitizer run on GitHub Actions found it (UBSan: signed integer overflow), and an instrumented run counted it in the depth-12 bench: 9 of 797,651 evaluations, all in endgames with at most 5 pieces, always the same two neurons of one output bucket. The plain C++ code and the AVX2 code wrapped in the same way, so every platform and every build was affected equally. The sums are now accumulated in 32-bit floats: they cannot overflow, they are exact whenever the sum lies in the range where the neuron is not clipped, and the AVX2 and the plain code still agree exactly (the same bench on all builds). The effect of the old error on play is expected to be very small (it did not change the node count of the bench), but the evaluation of these endgame positions was wrong.
  • Options with wrong defaults (this was the first fix of the day and is the whole of the unpublished 2.2). Kestrel 2.0 and 2.1 still declared options of the 1.x engines. NNBlend was declared with default 70 although the engine runs at 100, so a chess program that sends the declared default of every option (for example after "reset to defaults") made the engine mix the old hand-written evaluation into the search: scores changed by 20 to 25 % and some best moves changed. In a 600-game match at 3 + 0.03 that setting scored -6 +/- 17 Elo against the real default. NNBlend, Net2Share, UseNet2 and the development options (LazyMargin, EvalFlags, QsTT, CorrFlags, EvalCache, V31Flags, V31HistPrune, V31CutR, V31DE) are no longer declared, and the release builds ignore NNBlend. The 17 options that remain are listed in docs/OPTIONS.md. A new test (tests/options_test.py) sends every declared default and requires an identical search; 2.0 and 2.1 fail it, 2.2 and 2.3 pass.

What did not change

With the same settings, 2.3 and 2.2 search exactly alike in 16 of 18 test positions (one thread, 300,000 nodes each: best move, depth, score, node count and principal variation identical). The other two are endgames with few pieces, where the corrected evaluation changes the node count (a rook ending, same best move and score) or the score (a pawn ending: -584 instead of -544 centipawns, same best move), as expected from the fix. A 400-game match at 5 + 0.1 (one thread, the same openings for both sides) 2.3 against 2.2 scored +7 +/- 21 Elo (117 wins, 109 losses, 174 draws, all games ended normally). The depth-12 bench takes the same time (median of five runs: 770 ms for 2.3, 771 ms for 2.2). For the strength of this engine see the 2.0 release notes: about +37 +/- 11 Elo ahead of Kestrel 1.1 and +48 +/- 13 ahead of 1.0 over six time controls. No rating list has tested Kestrel.

Search ideas that did not help

I used a weekend of match time to test new search ideas and old switches against the same engine (3 + 0.03, one thread, 1,200 to 4,000 games each). None gave a measurable gain, so none is switched on; the table is in logs/fast_matches_2_2.txt. The code for the ideas stays in the source, switched off. It also turns the search constants into options (K22Flags and T_...), declared only in development builds (-DKESTREL_TUNE_OPTIONS). The multi-thread speed-up is modest (time to depth 14 with 2 / 4 / 8 threads: 1.11 / 1.20 / 1.35 times faster than with one), which is something to improve later.

Which file do I need?

File For
Kestrel-2.3-windows-x86-64-v3.zip Windows 64-bit, AVX2 + BMI2 CPUs (recommended)
Kestrel-2.3-windows-x86-64-v2.zip Windows 64-bit, SSE4.2 + POPCNT CPUs
Kestrel-2.3-windows-x86-64.zip Windows 64-bit, any CPU
Kestrel-2.3-linux-x86-64-v3.tar.gz Linux x86-64, AVX2 + BMI2 CPUs
Kestrel-2.3-linux-x86-64-v2.tar.gz Linux x86-64, SSE4.2 + POPCNT CPUs
Kestrel-2.3-linux-x86-64.tar.gz Linux x86-64, any CPU
Kestrel-2.3-linux-arm64.tar.gz Linux ARM64
Kestrel-2.3-macos-x86-64.tar.gz macOS, Intel Macs
Kestrel-2.3-macos-arm64.tar.gz macOS, Apple Silicon (M1 and newer)

The three Windows builds are also attached as plain .exe files (same program as in the zips; a plain exe has no opening book: put claude_book.txt next to it and switch OwnBook on if you want it). kestrel_net_2_0.bin is the network alone (the same file as in 2.0, 2.1 and 2.2; needed only to build from source or to load with EvalFile).

Only the x86-64-v3 builds have the AVX2 evaluation code (CPU with AVX2 and BMI2: most PCs since 2015). The v2 and generic builds work on older CPUs but are about 37 % slower.

Status of each build

  • Windows: all three builds were run here; each gives the same depth-12 bench (1,051,844 nodes), so the plain code and the AVX2 code agree exactly. On the x86-64-v3 exe the two black-box audits of 1.1 were repeated: 83 of 83 protocol and robustness cases and 31 of 31 rule checks against python-chess pass. The longer test suite of 1.1 was re-run on the 2.3 source as well: a GCC build and a clang AddressSanitizer + UBSan build (each also with 4 threads by default) pass 27 of 27 checks (accumulator self-test over 186,000 positions, perft, perft against python-chess, evaluation mirror symmetry, PV legality, UCI fuzzers, go infinite / stop races, MultiPV and ponder checks, bench), and the options test passes. The plain (non-AVX2) code is covered by the sanitizer job of the GitHub Actions workflow, which found the overflow. The logs are in logs/ of the repository.
  • Linux and macOS: compiled with Zig and checked for file format. The files of 2.1 were run on GitHub Actions machines (Linux x86-64, Linux ARM64, macOS Apple silicon: same bench, a UCI session, and for the Linux x86-64-v3 build the whole test suite); the workflow in .github/workflows/verify-release.yml can be started for the tag v2.3, and it also builds the source with AddressSanitizer and UBSan on Linux. The macOS Intel build has not been run.
  • The exe is about 88 MB and is not code-signed; some virus scanners are suspicious of big unsigned programs (1.0 had a false positive, see docs/BUILDING.md).

Building from source

src/kestrel_2_0.cpp (the file name is unchanged) embeds the network with .incbin "kestrel_net.bin", which the assembler looks up in the current directory: download kestrel_net_2_0.bin from this release, save it as kestrel_net.bin in the folder where you run the compiler, then for example

g++ -std=c++17 -O3 -march=x86-64-v3 -static -pthread -DNDEBUG -o kestrel.exe path/to/src/kestrel_2_0.cpp

The network is not stored in the git history (76 MB per version); see docs/BUILDING.md for the other targets.