Dynamic root score ema2

Improves calculation of root move score averages by dynamically calculating weight based on effort

Passed STC
https://tests.stockfishchess.org/tests/view/6a4ada97f97ff95f78795d5a
```
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 157248 W: 41003 L: 40515 D: 75730
Ptnml(0-2): 419, 18320, 40644, 18836, 405
```

Passed LTC
```
LLR: 3.03 (-2.94,2.94) <0.50,2.50>
Total: 197460 W: 51626 L: 50982 D: 94852
Ptnml(0-2): 85, 20849, 56237, 21455, 104
```

closes https://github.com/official-stockfish/Stockfish/pull/6960

Bench: 2388656
This commit is contained in:
tony
2026-07-10 20:17:55 +02:00
committed by Joost VandeVondele
parent 9700f6f206
commit 93ed4b53c4
+26 -5
View File
@@ -24,6 +24,7 @@
#include <cassert>
#include <chrono>
#include <cmath>
#include <cstdint>
#include <cstdlib>
#include <initializer_list>
#include <iostream>
@@ -1408,12 +1409,32 @@ moves_loop: // When in check, search starts here
rm.effort += nodes - nodeCount;
rm.averageScore =
rm.averageScore != -VALUE_INFINITE ? (value + rm.averageScore) / 2 : value;
u64 N = nodes - nodeCount;
u64 E_prev = std::max(u64(1), rm.effort - N);
rm.meanSquaredScore = rm.meanSquaredScore != -VALUE_INFINITE * VALUE_INFINITE
? (value * std::abs(value) + rm.meanSquaredScore) / 2
: value * std::abs(value);
// Dynamic EMA parameters for root move
constexpr u64 Scale = 32;
constexpr u64 ChiNumerator = 3;
constexpr u64 ChiDenominator = 2; // Chi = 3/2 = 1.5
constexpr u64 MinWeight = 12; // 37.5% minimum weight
constexpr u64 MaxWeight = 24; // 75% maximum weight
u64 w = std::clamp((Scale * N * ChiDenominator)
/ (N * ChiDenominator + ChiNumerator * E_prev),
MinWeight, MaxWeight);
u64 w_mss = std::min(w, u64(16));
i64 v2 = i64(value) * std::abs(value);
if (rm.averageScore == -VALUE_INFINITE)
rm.averageScore = value;
else
rm.averageScore = Value((value * w + rm.averageScore * (Scale - w)) / Scale);
if (rm.meanSquaredScore == -VALUE_INFINITE * VALUE_INFINITE)
rm.meanSquaredScore = value * std::abs(value);
else
rm.meanSquaredScore =
Value((v2 * w_mss + int64_t(rm.meanSquaredScore) * (Scale - w_mss)) / Scale);
// PV move or new best move?
if (moveCount == 1 || value > alpha)