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
This commit is contained in:
Dubslow
2026-05-19 18:38:07 +02:00
committed by Joost VandeVondele
parent b82f5b59f7
commit 319d61effd
4 changed files with 14 additions and 0 deletions
+6
View File
@@ -853,6 +853,12 @@ Value Search::Worker::search(
else else
return ttData.value; 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 // Step 6. Tablebases probe
+6
View File
@@ -75,6 +75,7 @@ struct TTEntry {
private: private:
friend class TranspositionTable; friend class TranspositionTable;
friend struct TTWriter;
uint16_t key16; uint16_t key16;
uint8_t depth8; uint8_t depth8;
@@ -137,6 +138,11 @@ void TTWriter::write(
entry->save(k, v, pv, b, d, m, ev, curr_generation); 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 // 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 // of TTEntry. Each non-empty TTEntry contains information on exactly one position. The size of a Cluster should
+1
View File
@@ -68,6 +68,7 @@ struct TTData {
struct TTWriter { struct TTWriter {
public: public:
void write(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev, uint8_t generation8); 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: private:
friend class TranspositionTable; friend class TranspositionTable;
+1
View File
@@ -51,6 +51,7 @@ class TSAN:
""" """
race:Stockfish::TTEntry::read race:Stockfish::TTEntry::read
race:Stockfish::TTEntry::save race:Stockfish::TTEntry::save
race:Stockfish::TTWriter::penalize
race:Stockfish::TranspositionTable::probe race:Stockfish::TranspositionTable::probe
race:Stockfish::TranspositionTable::hashfull race:Stockfish::TranspositionTable::hashfull
""" """