From b9e3e7921b638109bd19395fd201f87c9110614a Mon Sep 17 00:00:00 2001 From: Taras Vuk <117687515+TarasVuk@users.noreply.github.com> Date: Tue, 14 Oct 2025 21:16:34 +0200 Subject: [PATCH 01/15] Increase NMP reduction when improving Passed STC: LLR: 2.93 (-2.94,2.94) <0.00,2.00> Total: 52896 W: 13904 L: 13565 D: 25427 Ptnml(0-2): 186, 6022, 13706, 6335, 199 https://tests.stockfishchess.org/tests/view/68e67d02a017f472e763dfaf Passed LTC: LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 168354 W: 43750 L: 43163 D: 81441 Ptnml(0-2): 81, 18284, 46882, 18827, 103 https://tests.stockfishchess.org/tests/view/68e79d7ba017f472e763e352 closes https://github.com/official-stockfish/Stockfish/pull/6361 bench: 2537382 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index fa2355130..e6ee4274e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -869,7 +869,7 @@ Value Search::Worker::search( assert((ss - 1)->currentMove != Move::null()); // Null move dynamic reduction based on depth - Depth R = 6 + depth / 3; + Depth R = 6 + depth / 3 + improving; ss->currentMove = Move::null(); ss->continuationHistory = &continuationHistory[0][0][NO_PIECE][0]; From f434cc291892e826c675056bc5e770add7e004b3 Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Fri, 17 Oct 2025 15:53:49 -0700 Subject: [PATCH 02/15] Allow AccumulatorStack::size to point to one past the end this is guaranteed to be correct since we access the last element with `size - 1` closes https://github.com/official-stockfish/Stockfish/pull/6368 fixes https://github.com/official-stockfish/Stockfish/issues/6367 no functional change --- src/nnue/nnue_accumulator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nnue/nnue_accumulator.cpp b/src/nnue/nnue_accumulator.cpp index d13105aa4..3096758b9 100644 --- a/src/nnue/nnue_accumulator.cpp +++ b/src/nnue/nnue_accumulator.cpp @@ -75,7 +75,7 @@ void AccumulatorStack::reset() noexcept { } void AccumulatorStack::push(const DirtyPiece& dirtyPiece) noexcept { - assert(size + 1 < accumulators.size()); + assert(size < accumulators.size()); accumulators[size].reset(dirtyPiece); size++; } From 3bb01ce7a9f5bf60b4ce4e608b39f4a64a57e001 Mon Sep 17 00:00:00 2001 From: Timothy Herchen Date: Fri, 17 Oct 2025 23:39:45 -0700 Subject: [PATCH 03/15] prefetch earlier if checKEP is false Only a modest amount of work happens between the transposition table prefetch and the probe, so the probe still often stalls waiting for DRAM. The vast majority of the time (in particular, if !checkEP), the key is known much earlier in the do_move function and the latency can be better hidden. passed STC SMP https://tests.stockfishchess.org/tests/view/68f337c528e6d77fcffa066a LLR: 2.95 (-2.94,2.94) <0.00,2.00> Total: 65256 W: 16806 L: 16462 D: 31988 Ptnml(0-2): 76, 7386, 17362, 7726, 78 but failed to gain STC https://tests.stockfishchess.org/tests/view/68f3378328e6d77fcffa0665 LLR: -2.94 (-2.94,2.94) <0.00,2.00> Total: 109824 W: 28523 L: 28618 D: 52683 Ptnml(0-2): 311, 11799, 30788, 11702, 312 In local tests, the speedup grows with thread count closes https://github.com/official-stockfish/Stockfish/pull/6372 No functional change --- src/position.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/position.cpp b/src/position.cpp index d0cad3e7f..1551eb9df 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -858,6 +858,10 @@ DirtyPiece Position::do_move(Move m, st->minorPieceKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to]; } + // If en passant is impossible, then k will not change and we can prefetch earlier + if (tt && !checkEP) + prefetch(tt->first_entry(adjust_key50(k))); + // Set capture piece st->capturedPiece = captured; From 676456191607e2ea6ca84d83e130bab8afdd2ea6 Mon Sep 17 00:00:00 2001 From: Timothy Herchen Date: Tue, 14 Oct 2025 05:38:44 -0700 Subject: [PATCH 04/15] Improve index generation The speedup seems to vary by machine. The indexing function can be changed w/o needing to understand intrinsics. Result of 100 runs ================== base (...ish_baseline) = 1719637 +/- 3233 test (./stockfish ) = 1734245 +/- 3534 diff = +14608 +/- 4868 speedup = +0.0085 P(speedup > 0) = 1.0000 closes https://github.com/official-stockfish/Stockfish/pull/6366 No functional change --- src/nnue/nnue_accumulator.cpp | 66 +++++++++++++++++++++-------------- src/nnue/nnue_accumulator.h | 4 +-- src/position.h | 11 +++--- 3 files changed, 48 insertions(+), 33 deletions(-) diff --git a/src/nnue/nnue_accumulator.cpp b/src/nnue/nnue_accumulator.cpp index 3096758b9..b1743329f 100644 --- a/src/nnue/nnue_accumulator.cpp +++ b/src/nnue/nnue_accumulator.cpp @@ -18,9 +18,9 @@ #include "nnue_accumulator.h" +#include #include #include -#include #include #include "../bitboard.h" @@ -362,6 +362,29 @@ void update_accumulator_incremental( (target_state.acc()).computed[Perspective] = true; } +Bitboard get_changed_pieces(const Piece old[SQUARE_NB], const Piece new_[SQUARE_NB]) { +#if defined(USE_AVX512) || defined(USE_AVX2) + static_assert(sizeof(Piece) == 1); + Bitboard same_bb = 0; + for (int i = 0; i < 64; i += 32) + { + const __m256i old_v = _mm256_loadu_si256(reinterpret_cast(old + i)); + const __m256i new_v = _mm256_loadu_si256(reinterpret_cast(new_ + i)); + const __m256i cmp_equal = _mm256_cmpeq_epi8(old_v, new_v); + const std::uint32_t equal_mask = _mm256_movemask_epi8(cmp_equal); + same_bb |= static_cast(equal_mask) << i; + } + return ~same_bb; +#else + Bitboard changed = 0; + for (Square sq = SQUARE_ZERO; sq < SQUARE_NB; ++sq) + { + changed |= static_cast(old[sq] != new_[sq]) << sq; + } + return changed; +#endif +} + template void update_accumulator_refresh_cache(const FeatureTransformer& featureTransformer, const Position& pos, @@ -374,28 +397,23 @@ void update_accumulator_refresh_cache(const FeatureTransformer& feat auto& entry = cache[ksq][Perspective]; FeatureSet::IndexList removed, added; - for (Color c : {WHITE, BLACK}) - { - for (PieceType pt = PAWN; pt <= KING; ++pt) - { - const Piece piece = make_piece(c, pt); - const Bitboard oldBB = entry.byColorBB[c] & entry.byTypeBB[pt]; - const Bitboard newBB = pos.pieces(c, pt); - Bitboard toRemove = oldBB & ~newBB; - Bitboard toAdd = newBB & ~oldBB; + const Bitboard changed_bb = get_changed_pieces(entry.pieces, pos.piece_array()); + Bitboard removed_bb = changed_bb & entry.pieceBB; + Bitboard added_bb = changed_bb & pos.pieces(); - while (toRemove) - { - Square sq = pop_lsb(toRemove); - removed.push_back(FeatureSet::make_index(sq, piece, ksq)); - } - while (toAdd) - { - Square sq = pop_lsb(toAdd); - added.push_back(FeatureSet::make_index(sq, piece, ksq)); - } - } + while (removed_bb) + { + Square sq = pop_lsb(removed_bb); + removed.push_back(FeatureSet::make_index(sq, entry.pieces[sq], ksq)); } + while (added_bb) + { + Square sq = pop_lsb(added_bb); + added.push_back(FeatureSet::make_index(sq, pos.piece_on(sq), ksq)); + } + + entry.pieceBB = pos.pieces(); + std::copy_n(pos.piece_array(), SQUARE_NB, entry.pieces); auto& accumulator = accumulatorState.acc(); accumulator.computed[Perspective] = true; @@ -518,12 +536,6 @@ void update_accumulator_refresh_cache(const FeatureTransformer& feat std::memcpy(accumulator.psqtAccumulation[Perspective], entry.psqtAccumulation, sizeof(int32_t) * PSQTBuckets); #endif - - for (Color c : {WHITE, BLACK}) - entry.byColorBB[c] = pos.pieces(c); - - for (PieceType pt = PAWN; pt <= KING; ++pt) - entry.byTypeBB[pt] = pos.pieces(pt); } } diff --git a/src/nnue/nnue_accumulator.h b/src/nnue/nnue_accumulator.h index 10aadc917..56de0b7d0 100644 --- a/src/nnue/nnue_accumulator.h +++ b/src/nnue/nnue_accumulator.h @@ -71,8 +71,8 @@ struct AccumulatorCaches { struct alignas(CacheLineSize) Entry { BiasType accumulation[Size]; PSQTWeightType psqtAccumulation[PSQTBuckets]; - Bitboard byColorBB[COLOR_NB]; - Bitboard byTypeBB[PIECE_TYPE_NB]; + Piece pieces[SQUARE_NB]; + Bitboard pieceBB; // To initialize a refresh entry, we set all its bitboards empty, // so we put the biases in the accumulation, without any weights on top diff --git a/src/position.h b/src/position.h index dde496fe0..579121bf3 100644 --- a/src/position.h +++ b/src/position.h @@ -91,10 +91,11 @@ class Position { Bitboard pieces(PieceTypes... pts) const; Bitboard pieces(Color c) const; template - Bitboard pieces(Color c, PieceTypes... pts) const; - Piece piece_on(Square s) const; - Square ep_square() const; - bool empty(Square s) const; + Bitboard pieces(Color c, PieceTypes... pts) const; + Piece piece_on(Square s) const; + const Piece* piece_array() const; + Square ep_square() const; + bool empty(Square s) const; template int count(Color c) const; template @@ -208,6 +209,8 @@ inline Piece Position::piece_on(Square s) const { return board[s]; } +inline const Piece* Position::piece_array() const { return board; } + inline bool Position::empty(Square s) const { return piece_on(s) == NO_PIECE; } inline Piece Position::moved_piece(Move m) const { return piece_on(m.from_sq()); } From a49b52cf693aee554aa137244ac1f10a22590f87 Mon Sep 17 00:00:00 2001 From: shaowyx Date: Sat, 25 Oct 2025 17:23:04 +0900 Subject: [PATCH 05/15] Revert malus and associated coefficient parameters resulting from using only quiet moves Following #6226 and #6256, this patch ultimately corresponds to the revert of #6200. Parameters were tuned on 60k LTC games. STC (10+0.1 th1) was accepted: LLR: 2.95 (-2.94,2.94) <0.00,2.00> Total: 167488 W: 43573 L: 43063 D: 80852 Ptnml(0-2): 506, 19644, 43004, 20014, 576 https://tests.stockfishchess.org/tests/view/68f526a4637acd2a11e721c2 LTC (60+0.6 th1) was accepted: LLR: 2.99 (-2.94,2.94) <0.50,2.50> Total: 61068 W: 15882 L: 15510 D: 29676 Ptnml(0-2): 31, 6578, 16949, 6940, 36 https://tests.stockfishchess.org/tests/view/68fa1968637acd2a11e72a0a Non-regression VLTC (180+1.8 th1) was accepted: LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 50380 W: 13087 L: 12905 D: 24388 Ptnml(0-2): 5, 5018, 14962, 5200, 5 https://tests.stockfishchess.org/tests/view/68fdc6e5637acd2a11e72f33 closes https://github.com/official-stockfish/Stockfish/pull/6378 Bench: 2530552 --- src/search.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index e6ee4274e..ef87c828e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -137,7 +137,8 @@ void update_all_stats(const Position& pos, SearchedList& quietsSearched, SearchedList& capturesSearched, Depth depth, - Move TTMove); + Move TTMove, + int moveCount); } // namespace @@ -1391,7 +1392,7 @@ moves_loop: // When in check, search starts here else if (bestMove) { update_all_stats(pos, ss, *this, bestMove, prevSq, quietsSearched, capturesSearched, depth, - ttData.move); + ttData.move, moveCount); if (!PvNode) ttMoveHistory << (bestMove == ttData.move ? 809 : -865); } @@ -1801,41 +1802,42 @@ void update_all_stats(const Position& pos, SearchedList& quietsSearched, SearchedList& capturesSearched, Depth depth, - Move ttMove) { + Move ttMove, + int moveCount) { CapturePieceToHistory& captureHistory = workerThread.captureHistory; Piece movedPiece = pos.moved_piece(bestMove); PieceType capturedPiece; - int bonus = std::min(151 * depth - 91, 1730) + 302 * (bestMove == ttMove); - int malus = std::min(951 * depth - 156, 2468) - 30 * quietsSearched.size(); + int bonus = std::min(121 * depth - 77, 1633) + 375 * (bestMove == ttMove); + int malus = std::min(825 * depth - 196, 2159) - 16 * moveCount; if (!pos.capture_stage(bestMove)) { - update_quiet_histories(pos, ss, workerThread, bestMove, bonus * 957 / 1024); + update_quiet_histories(pos, ss, workerThread, bestMove, bonus * 881 / 1024); // Decrease stats for all non-best quiet moves for (Move move : quietsSearched) - update_quiet_histories(pos, ss, workerThread, move, -malus); + update_quiet_histories(pos, ss, workerThread, move, -malus * 1083 / 1024); } else { // Increase stats for the best move in case it was a capture move capturedPiece = type_of(pos.piece_on(bestMove.to_sq())); - captureHistory[movedPiece][bestMove.to_sq()][capturedPiece] << bonus; + captureHistory[movedPiece][bestMove.to_sq()][capturedPiece] << bonus * 1482 / 1024; } // Extra penalty for a quiet early move that was not a TT move in // previous ply when it gets refuted. if (prevSq != SQ_NONE && ((ss - 1)->moveCount == 1 + (ss - 1)->ttHit) && !pos.captured_piece()) - update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, -malus * 503 / 1024); + update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, -malus * 614 / 1024); // Decrease stats for all non-best capture moves for (Move move : capturesSearched) { movedPiece = pos.moved_piece(move); capturedPiece = type_of(pos.piece_on(move.to_sq())); - captureHistory[movedPiece][move.to_sq()][capturedPiece] << -malus * 1157 / 1024; + captureHistory[movedPiece][move.to_sq()][capturedPiece] << -malus * 1397 / 1024; } } From fa3b4ef5af7535b286e97d7296c788926e7c5203 Mon Sep 17 00:00:00 2001 From: pb00067 Date: Thu, 30 Oct 2025 14:31:23 +0100 Subject: [PATCH 06/15] Improve retrograde analisys and matefinding capability fixes https://github.com/official-stockfish/Stockfish/issues/6328 Before calling search(depth), the patch ensures that depth is at least 1 whenever we encounter a decisive score in the transposition table (TT). This prevents search(depth) from being executed by qsearch, which would otherwise ignore that information. Typically, decisive TT hits occur when analyzing a mating sequence backward. Due to the nature of Iterative Deepening (IID), such scores are usually first found at depth 0. Without this patch, valuable information can be lost because qsearch may overwrite the TT entry by replacing the value with a static evaluation, even though the node was already processed at a higher depth. This is also why the engine sometimes loses track of an already discovered mate. Using ..\sf\patch.exe on matetrack.epd with --nodes 1000000 Engine ID: Stockfish dev-20251015-nogit Total FENs: 6554 Found mates: 3437 Best mates: 2438 Using ..\sf\master.exe on matetrack.epd with --nodes 1000000 Engine ID: Stockfish dev-20251015-nogit Total FENs: 6554 Found mates: 3337 Best mates: 2407 Passed STC https://tests.stockfishchess.org/tests/view/68fa3fa7637acd2a11e72a79 LLR: 3.55 (-2.94,2.94) <0.00,2.00> Total: 134144 W: 34960 L: 34471 D: 64713 Ptnml(0-2): 376, 14199, 37459, 14636, 402 Failed LTC https://tests.stockfishchess.org/tests/view/68ffc1b5637acd2a11e73377 LLR: -3.10 (-2.94,2.94) <0.50,2.50> Total: 75360 W: 19423 L: 19519 D: 36418 Ptnml(0-2): 38, 7553, 22605, 7435, 49 closes https://github.com/official-stockfish/Stockfish/pull/6386 bench: 2530552 --- src/search.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index ef87c828e..151b4c6ee 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1260,7 +1260,10 @@ moves_loop: // When in check, search starts here (ss + 1)->pv[0] = Move::none(); // Extend move from transposition table if we are about to dive into qsearch. - if (move == ttData.move && ttData.depth > 1 && rootDepth > 8) + // decisive score handling improves mate finding and retrograde analysis. + if (move == ttData.move + && ((is_valid(ttData.value) && is_decisive(ttData.value) && ttData.depth > 0) + || (ttData.depth > 1 && rootDepth > 8))) newDepth = std::max(newDepth, 1); value = -search(pos, ss + 1, -beta, -alpha, newDepth, false); From 11ab4cde071be92d4fbd188c4741010833ab8340 Mon Sep 17 00:00:00 2001 From: Carlos Esparza Date: Thu, 9 Oct 2025 12:10:46 -0700 Subject: [PATCH 07/15] Avoid unnecessary allocations in AccumulatorStack replacing the vector with an array resulted in a .45+-.10 % speedup. closes https://github.com/official-stockfish/Stockfish/pull/6352 no functional change --- src/nnue/network.h | 2 -- src/nnue/nnue_accumulator.h | 11 +++-------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/nnue/network.h b/src/nnue/network.h index c9358823b..6855831d5 100644 --- a/src/nnue/network.h +++ b/src/nnue/network.h @@ -106,8 +106,6 @@ class Network { template friend struct AccumulatorCaches::Cache; - - friend class AccumulatorStack; }; // Definitions of the network types diff --git a/src/nnue/nnue_accumulator.h b/src/nnue/nnue_accumulator.h index 56de0b7d0..7ff95b6ef 100644 --- a/src/nnue/nnue_accumulator.h +++ b/src/nnue/nnue_accumulator.h @@ -25,7 +25,6 @@ #include #include #include -#include #include "../types.h" #include "nnue_architecture.h" @@ -48,7 +47,7 @@ template struct alignas(CacheLineSize) Accumulator { std::int16_t accumulation[COLOR_NB][Size]; std::int32_t psqtAccumulation[COLOR_NB][PSQTBuckets]; - std::array computed; + std::array computed = {}; }; @@ -142,10 +141,6 @@ struct AccumulatorState { class AccumulatorStack { public: - AccumulatorStack() : - accumulators(MAX_PLY + 1), - size{1} {} - [[nodiscard]] const AccumulatorState& latest() const noexcept; void reset() noexcept; @@ -178,8 +173,8 @@ class AccumulatorStack { const FeatureTransformer& featureTransformer, const std::size_t end) noexcept; - std::vector accumulators; - std::size_t size; + std::array accumulators; + std::size_t size = 1; }; } // namespace Stockfish::Eval::NNUE From 9e071f3561a624ac7f48356f5580e2c2dc755bc0 Mon Sep 17 00:00:00 2001 From: Daniel Monroe Date: Fri, 10 Oct 2025 13:23:08 -0400 Subject: [PATCH 08/15] Simplify best move effort Passed non-regression STC LLR: 2.96 (-2.94,2.94) <-1.75,0.25> Total: 44224 W: 11614 L: 11403 D: 21207 Ptnml(0-2): 147, 4936, 11726, 5165, 138 https://tests.stockfishchess.org/tests/view/68e9410ed323fd15c04e3a87 Passed non-regression LTC LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 109788 W: 28223 L: 28096 D: 53469 Ptnml(0-2): 60, 11493, 31657, 11628, 56 https://tests.stockfishchess.org/tests/view/68eb5ac0a23744016c14af1d closes https://github.com/official-stockfish/Stockfish/pull/6371 No functional change --- src/search.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 151b4c6ee..3cd10ad9b 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -479,9 +479,10 @@ void Search::Worker::iterative_deepening() { double reduction = (1.455 + mainThread->previousTimeReduction) / (2.2375 * timeReduction); double bestMoveInstability = 1.04 + 1.8956 * totBestMoveChanges / threads.size(); + double highBestMoveEffort = completedDepth >= 10 && nodesEffort >= 92425 ? 0.666 : 1.0; - double totalTime = - mainThread->tm.optimum() * fallingEval * reduction * bestMoveInstability; + double totalTime = mainThread->tm.optimum() * fallingEval * reduction + * bestMoveInstability * highBestMoveEffort; // Cap used time in case of a single legal move for a better viewer experience if (rootMoves.size() == 1) @@ -489,10 +490,6 @@ void Search::Worker::iterative_deepening() { auto elapsedTime = elapsed(); - if (completedDepth >= 10 && nodesEffort >= 92425 && elapsedTime > totalTime * 0.666 - && !mainThread->ponder) - threads.stop = true; - // Stop the search if we have exceeded the totalTime or maximum if (elapsedTime > std::min(totalTime, double(mainThread->tm.maximum()))) { From fd3c563f575c5ae1ce286749303eab2932609124 Mon Sep 17 00:00:00 2001 From: Daniel Monroe Date: Mon, 6 Oct 2025 05:01:17 -0400 Subject: [PATCH 09/15] Simplify r50 condition in cutoff Passed non-regression STC LLR: 3.11 (-2.94,2.94) <-1.75,0.25> Total: 114560 W: 29832 L: 29689 D: 55039 Ptnml(0-2): 332, 12302, 31869, 12445, 332 https://tests.stockfishchess.org/tests/view/68e38587fa806e2e8393d4a9 Passed non-regression LTC LLR: 2.99 (-2.94,2.94) <-1.75,0.25> Total: 256272 W: 65817 L: 65832 D: 124623 Ptnml(0-2): 137, 25528, 76817, 25521, 133 https://tests.stockfishchess.org/tests/view/68e69b47a017f472e763e065 closes https://github.com/official-stockfish/Stockfish/pull/6373 Bench: 2438327 --- src/search.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 3cd10ad9b..734372004 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -683,10 +683,7 @@ Value Search::Worker::search( if (!PvNode && !excludedMove && ttData.depth > depth - (ttData.value <= beta) && is_valid(ttData.value) // Can happen when !ttHit or when access race in probe() && (ttData.bound & (ttData.value >= beta ? BOUND_LOWER : BOUND_UPPER)) - && (cutNode == (ttData.value >= beta) || depth > 5) - // avoid a TT cutoff if the rule50 count is high and the TT move is zeroing - && (depth > 8 || ttData.move == Move::none() || pos.rule50_count() < 80 - || (!ttCapture && type_of(pos.moved_piece(ttData.move)) != PAWN))) + && (cutNode == (ttData.value >= beta) || depth > 5)) { // If ttMove is quiet, update move sorting heuristics on TT hit if (ttData.move && ttData.value >= beta) From 013d42914fa564c9aa69cc93f16aed6a6e3869b9 Mon Sep 17 00:00:00 2001 From: Daniel Monroe Date: Wed, 8 Oct 2025 00:11:20 -0400 Subject: [PATCH 10/15] Simplify static eval bonus Passed non-regression STC LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 176896 W: 45998 L: 45933 D: 84965 Ptnml(0-2): 609, 20845, 45451, 20958, 585 https://tests.stockfishchess.org/tests/view/68e5e48ba017f472e763dd21 Passed non-regression LTC LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 77682 W: 20046 L: 19884 D: 37752 Ptnml(0-2): 41, 8404, 21786, 8572, 38 https://tests.stockfishchess.org/tests/view/68ee71e328e6d77fcff9fd68 closes https://github.com/official-stockfish/Stockfish/pull/6374 bench 2101654 --- src/search.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 734372004..50585eb13 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -813,12 +813,11 @@ Value Search::Worker::search( // Use static evaluation difference to improve quiet move ordering if (((ss - 1)->currentMove).is_ok() && !(ss - 1)->inCheck && !priorCapture) { - int bonus = std::clamp(-10 * int((ss - 1)->staticEval + ss->staticEval), -2023, 1563) + 583; - mainHistory[~us][((ss - 1)->currentMove).from_to()] << bonus * 944 / 1024; + int evalDiff = std::clamp(-int((ss - 1)->staticEval + ss->staticEval), -200, 156) + 58; + mainHistory[~us][((ss - 1)->currentMove).from_to()] << evalDiff * 9; if (!ttHit && type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION) - pawnHistory[pawn_history_index(pos)][pos.piece_on(prevSq)][prevSq] - << bonus * 1438 / 1024; + pawnHistory[pawn_history_index(pos)][pos.piece_on(prevSq)][prevSq] << evalDiff * 14; } // Set up the improving flag, which is true if current static evaluation is From c9a2aff48529d5b624cb60c9e70354dacad39a57 Mon Sep 17 00:00:00 2001 From: Daniel Monroe Date: Tue, 7 Oct 2025 08:10:45 -0400 Subject: [PATCH 11/15] Simplify correction update condition Passed non-regression STC LLR: 2.96 (-2.94,2.94) <-1.75,0.25> Total: 95136 W: 24722 L: 24564 D: 45850 Ptnml(0-2): 307, 11139, 24522, 11289, 311 https://tests.stockfishchess.org/tests/view/68e5034ea017f472e763dc5a Passed non-regression LTC LLR: 2.96 (-2.94,2.94) <-1.75,0.25> Total: 256440 W: 65854 L: 65873 D: 124713 Ptnml(0-2): 144, 28287, 71375, 28272, 142 https://tests.stockfishchess.org/tests/view/68e71ae4a017f472e763e291 closes https://github.com/official-stockfish/Stockfish/pull/6375 bench 2216361 --- src/search.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 50585eb13..b9321de75 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1443,10 +1443,10 @@ moves_loop: // When in check, search starts here moveCount != 0 ? depth : std::min(MAX_PLY - 1, depth + 6), bestMove, unadjustedStaticEval, tt.generation()); - // Adjust correction history + // Adjust correction history if the best move is not a capture + // and the error direction matches whether we are above/below bounds. if (!ss->inCheck && !(bestMove && pos.capture(bestMove)) - && ((bestValue < ss->staticEval && bestValue < beta) // negative correction & no fail high - || (bestValue > ss->staticEval && bestMove))) // positive correction & no fail low + && (bestValue < ss->staticEval) == !bestMove) { auto bonus = std::clamp(int(bestValue - ss->staticEval) * depth / (8 + (bestValue > ss->staticEval)), From 035165299526cfd6d97cbe71c1220a4e9a7a8cce Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Sun, 19 Oct 2025 17:11:36 -0700 Subject: [PATCH 12/15] Simplify Pawn History Bonus Passed Non-regression STC: LLR: 2.98 (-2.94,2.94) <-1.75,0.25> Total: 122016 W: 31655 L: 31525 D: 58836 Ptnml(0-2): 388, 14317, 31474, 14435, 394 https://tests.stockfishchess.org/tests/view/68f57e66637acd2a11e7221d Passed Non-regression LTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 81348 W: 21016 L: 20858 D: 39474 Ptnml(0-2): 45, 8793, 22841, 8949, 46 https://tests.stockfishchess.org/tests/view/68f9e2d9637acd2a11e72997 closes https://github.com/official-stockfish/Stockfish/pull/6382 Bench: 2370893 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index b9321de75..4a55da301 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1869,7 +1869,7 @@ void update_quiet_histories( int pIndex = pawn_history_index(pos); workerThread.pawnHistory[pIndex][pos.moved_piece(move)][move.to_sq()] - << (bonus * (bonus > 0 ? 800 : 500) / 1024) + 70; + << bonus * (bonus > 0 ? 850 : 550) / 1024; } } From e9674a788843ea886d382e541b354f41a585df25 Mon Sep 17 00:00:00 2001 From: Carlos Esparza Date: Thu, 23 Oct 2025 15:54:38 -0700 Subject: [PATCH 13/15] simplify make_index() passed non-regression STC: https://tests.stockfishchess.org/tests/view/68fdb409637acd2a11e72f11 LLR: 3.08 (-2.94,2.94) <-1.75,0.25> Total: 95008 W: 24837 L: 24677 D: 45494 Ptnml(0-2): 268, 10024, 26775, 10154, 283 closes https://github.com/official-stockfish/Stockfish/pull/6384 no functional change --- src/nnue/features/half_ka_v2_hm.cpp | 7 ++++--- src/nnue/features/half_ka_v2_hm.h | 28 ++++++---------------------- 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/src/nnue/features/half_ka_v2_hm.cpp b/src/nnue/features/half_ka_v2_hm.cpp index 70e9beeb1..5bcfb0849 100644 --- a/src/nnue/features/half_ka_v2_hm.cpp +++ b/src/nnue/features/half_ka_v2_hm.cpp @@ -29,9 +29,10 @@ namespace Stockfish::Eval::NNUE::Features { // Index of a feature for a given king position and another piece on some square template -inline IndexType HalfKAv2_hm::make_index(Square s, Piece pc, Square ksq) { - return IndexType((int(s) ^ OrientTBL[Perspective][ksq]) + PieceSquareIndex[Perspective][pc] - + KingBuckets[Perspective][ksq]); +IndexType HalfKAv2_hm::make_index(Square s, Piece pc, Square ksq) { + const IndexType flip = 56 * Perspective; + return (IndexType(s) ^ OrientTBL[ksq] ^ flip) + PieceSquareIndex[Perspective][pc] + + KingBuckets[int(ksq) ^ flip]; } // Get a list of indices for active features diff --git a/src/nnue/features/half_ka_v2_hm.h b/src/nnue/features/half_ka_v2_hm.h index ba122adc8..b72bbbce4 100644 --- a/src/nnue/features/half_ka_v2_hm.h +++ b/src/nnue/features/half_ka_v2_hm.h @@ -75,45 +75,29 @@ class HalfKAv2_hm { #define B(v) (v * PS_NB) // clang-format off - static constexpr int KingBuckets[COLOR_NB][SQUARE_NB] = { - { B(28), B(29), B(30), B(31), B(31), B(30), B(29), B(28), + static constexpr IndexType KingBuckets[SQUARE_NB] = { + B(28), B(29), B(30), B(31), B(31), B(30), B(29), B(28), B(24), B(25), B(26), B(27), B(27), B(26), B(25), B(24), B(20), B(21), B(22), B(23), B(23), B(22), B(21), B(20), B(16), B(17), B(18), B(19), B(19), B(18), B(17), B(16), B(12), B(13), B(14), B(15), B(15), B(14), B(13), B(12), B( 8), B( 9), B(10), B(11), B(11), B(10), B( 9), B( 8), B( 4), B( 5), B( 6), B( 7), B( 7), B( 6), B( 5), B( 4), - B( 0), B( 1), B( 2), B( 3), B( 3), B( 2), B( 1), B( 0) }, - { B( 0), B( 1), B( 2), B( 3), B( 3), B( 2), B( 1), B( 0), - B( 4), B( 5), B( 6), B( 7), B( 7), B( 6), B( 5), B( 4), - B( 8), B( 9), B(10), B(11), B(11), B(10), B( 9), B( 8), - B(12), B(13), B(14), B(15), B(15), B(14), B(13), B(12), - B(16), B(17), B(18), B(19), B(19), B(18), B(17), B(16), - B(20), B(21), B(22), B(23), B(23), B(22), B(21), B(20), - B(24), B(25), B(26), B(27), B(27), B(26), B(25), B(24), - B(28), B(29), B(30), B(31), B(31), B(30), B(29), B(28) } + B( 0), B( 1), B( 2), B( 3), B( 3), B( 2), B( 1), B( 0), }; // clang-format on #undef B // clang-format off // Orient a square according to perspective (rotates by 180 for black) - static constexpr int OrientTBL[COLOR_NB][SQUARE_NB] = { - { SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1, + static constexpr IndexType OrientTBL[SQUARE_NB] = { SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1, SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1, SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1, SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1, SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1, SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1, - SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1 }, - { SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8, - SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8, - SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8, - SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8, - SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8, - SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8, - SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8, - SQ_H8, SQ_H8, SQ_H8, SQ_H8, SQ_A8, SQ_A8, SQ_A8, SQ_A8 } + SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1, + SQ_H1, SQ_H1, SQ_H1, SQ_H1, SQ_A1, SQ_A1, SQ_A1, SQ_A1 , }; // clang-format on From cd7880c030bc941a3014b4b9ea6a455b3a328c59 Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Sun, 19 Oct 2025 17:18:42 -0700 Subject: [PATCH 14/15] Simplify Corrhist Bonus Passed Non-regression STC: LLR: 2.96 (-2.94,2.94) <-1.75,0.25> Total: 187776 W: 48687 L: 48631 D: 90458 Ptnml(0-2): 570, 22327, 48090, 22279, 622 https://tests.stockfishchess.org/tests/view/68f58019637acd2a11e72233 Passed Non-regression LTC: LLR: 2.96 (-2.94,2.94) <-1.75,0.25> Total: 159378 W: 41027 L: 40946 D: 77405 Ptnml(0-2): 122, 17645, 44078, 17718, 126 https://tests.stockfishchess.org/tests/view/68fe7492637acd2a11e73090 closes https://github.com/official-stockfish/Stockfish/pull/6385 Bench: 2458738 --- src/search.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 4a55da301..212e14fcf 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1451,8 +1451,7 @@ moves_loop: // When in check, search starts here auto bonus = std::clamp(int(bestValue - ss->staticEval) * depth / (8 + (bestValue > ss->staticEval)), -CORRECTION_HISTORY_LIMIT / 4, CORRECTION_HISTORY_LIMIT / 4); - update_correction_history(pos, ss, *this, - (1088 - 180 * (bestValue > ss->staticEval)) * bonus / 1024); + update_correction_history(pos, ss, *this, bonus); } assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE); From bc9f08731f10896a306bcc34e30e5606087af79a Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Sat, 1 Nov 2025 03:36:04 +0300 Subject: [PATCH 15/15] Simplify Futility pruning formula Passed STC: LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 170112 W: 44266 L: 44193 D: 81653 Ptnml(0-2): 599, 20062, 43611, 20235, 549 https://tests.stockfishchess.org/tests/view/68f50b94637acd2a11e721ad Passed LTC: LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 164658 W: 42393 L: 42318 D: 79947 Ptnml(0-2): 120, 18127, 45747, 18228, 107 https://tests.stockfishchess.org/tests/view/68fa6683637acd2a11e72ac3 closes https://github.com/official-stockfish/Stockfish/pull/6389 bench: 2351426 --- src/search.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 212e14fcf..a0c6eafe3 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -847,7 +847,6 @@ Value Search::Worker::search( return futilityMult * d // - 2094 * improving * futilityMult / 1024 // - 1324 * opponentWorsening * futilityMult / 4096 // - + (ss - 1)->statScore / 331 // + std::abs(correctionValue) / 158105; };