From 319d61effdad40ac633425d6504a98f6d2ad0cd2 Mon Sep 17 00:00:00 2001 From: Dubslow Date: Tue, 19 May 2026 18:38:07 +0200 Subject: [PATCH] Penalize TTEs whose inexact value mismatches the current window Credit shared with @xu-shawn, who has done much of the work to instrument the search and investigate search explosions and endgame paralysis: https://github.com/official-stockfish/Stockfish/issues/6742#issuecomment-4386174472 This patch is a natural result of that commentary. It can also be seen as a refinement of more generalized secondary aging. Passed STC: https://tests.stockfishchess.org/tests/view/69fb18e8c91f9625ce325427 LLR: 2.93 (-2.94,2.94) <0.00,2.00> Total: 434784 W: 111417 L: 110528 D: 212839 Ptnml(0-2): 1089, 50675, 112949, 51616, 1063 Passed LTC: https://tests.stockfishchess.org/tests/view/6a0379588d9bd4cd7cd68edf LLR: 2.95 (-2.94,2.94) <0.50,2.50> Total: 81018 W: 20558 L: 20154 D: 40306 Ptnml(0-2): 35, 8554, 22939, 8934, 47 VVLTC *reversion*: https://tests.stockfishchess.org/tests/view/6a0622538d9bd4cd7cd69340 Ptnml(0-2): 2, 5159, 18107, 5050, 0 LLR: -2.94 <0.50,2.50> LLR: -2.47 <0.00,2.00> LLR: -2.24 <-0.25,1.75> closes https://github.com/official-stockfish/Stockfish/pull/6819 Bench: 2676789 --- src/search.cpp | 6 ++++++ src/tt.cpp | 6 ++++++ src/tt.h | 1 + tests/testing.py | 1 + 4 files changed, 14 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index babe6f05c..5988c23fd 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -853,6 +853,12 @@ Value Search::Worker::search( else return ttData.value; } + } // No cutoff, but why? Does the stored inexact value mismatch our aspiration window? + else if (!PvNode && !excludedMove && ttData.depth > depth - (ttData.value <= beta) + && is_valid(ttData.value) && ttData.bound != BOUND_EXACT + && ttData.bound & (ttData.value >= beta ? BOUND_UPPER : BOUND_LOWER) && depth > 5) + { // If a window-bound mismatch is the only reason cutoff failed, penalize the now-useless tte + ttWriter.penalize(1); } // Step 6. Tablebases probe diff --git a/src/tt.cpp b/src/tt.cpp index 359399347..7f7c5ab4e 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -75,6 +75,7 @@ struct TTEntry { private: friend class TranspositionTable; + friend struct TTWriter; uint16_t key16; uint8_t depth8; @@ -137,6 +138,11 @@ void TTWriter::write( entry->save(k, v, pv, b, d, m, ev, curr_generation); } +void TTWriter::penalize(int penalty) { + assert(entry->depth8 + DEPTH_NONE > penalty); + entry->depth8 -= penalty; +} + // A TranspositionTable is an array of Cluster, of size clusterCount. Each cluster consists of ClusterSize number // of TTEntry. Each non-empty TTEntry contains information on exactly one position. The size of a Cluster should diff --git a/src/tt.h b/src/tt.h index 584b92bff..2f8091725 100644 --- a/src/tt.h +++ b/src/tt.h @@ -68,6 +68,7 @@ struct TTData { struct TTWriter { public: void write(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev, uint8_t generation8); + void penalize(int penalty); // decrement stored depth by the penalty private: friend class TranspositionTable; diff --git a/tests/testing.py b/tests/testing.py index 619c8a59c..9711a43ba 100644 --- a/tests/testing.py +++ b/tests/testing.py @@ -51,6 +51,7 @@ class TSAN: """ race:Stockfish::TTEntry::read race:Stockfish::TTEntry::save +race:Stockfish::TTWriter::penalize race:Stockfish::TranspositionTable::probe race:Stockfish::TranspositionTable::hashfull """