Update Elo estimates for terms in search

This updates estimates from 2yr ago #2401, and adds missing terms.
All tests run at 10+0.1 (STC), 20000 games, error bars +- 1.8 Elo, book 8moves_v3.png.

A table of Elo values with the links to the corresponding tests can be found at the PR

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

Non-functional Change
This commit is contained in:
bmc4
2021-12-20 16:20:08 -03:00
committed by Joost VandeVondele
parent 22e92d23d2
commit 88f17a814d
2 changed files with 29 additions and 29 deletions
+1 -1
View File
@@ -1083,7 +1083,7 @@ Value Eval::evaluate(const Position& pos) {
Value v; Value v;
// Deciding between classical and NNUE eval: for high PSQ imbalance we use classical, // Deciding between classical and NNUE eval (~10 Elo): for high PSQ imbalance we use classical,
// but we switch to NNUE during long shuffling or with high material on the board. // but we switch to NNUE during long shuffling or with high material on the board.
if ( !useNNUE if ( !useNNUE
+28 -28
View File
@@ -671,20 +671,20 @@ namespace {
&& (ttValue >= beta ? (tte->bound() & BOUND_LOWER) && (ttValue >= beta ? (tte->bound() & BOUND_LOWER)
: (tte->bound() & BOUND_UPPER))) : (tte->bound() & BOUND_UPPER)))
{ {
// If ttMove is quiet, update move sorting heuristics on TT hit // If ttMove is quiet, update move sorting heuristics on TT hit (~1 Elo)
if (ttMove) if (ttMove)
{ {
if (ttValue >= beta) if (ttValue >= beta)
{ {
// Bonus for a quiet ttMove that fails high // Bonus for a quiet ttMove that fails high (~3 Elo)
if (!ttCapture) if (!ttCapture)
update_quiet_stats(pos, ss, ttMove, stat_bonus(depth)); update_quiet_stats(pos, ss, ttMove, stat_bonus(depth));
// Extra penalty for early quiet moves of the previous ply // Extra penalty for early quiet moves of the previous ply (~0 Elo)
if ((ss-1)->moveCount <= 2 && !priorCapture) if ((ss-1)->moveCount <= 2 && !priorCapture)
update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + 1)); update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + 1));
} }
// Penalty for a quiet ttMove that fails low // Penalty for a quiet ttMove that fails low (~1 Elo)
else if (!ttCapture) else if (!ttCapture)
{ {
int penalty = -stat_bonus(depth); int penalty = -stat_bonus(depth);
@@ -773,7 +773,7 @@ namespace {
if (eval == VALUE_DRAW) if (eval == VALUE_DRAW)
eval = value_draw(thisThread); eval = value_draw(thisThread);
// Can ttValue be used as a better position evaluation? // ttValue can be used as a better position evaluation (~4 Elo)
if ( ttValue != VALUE_NONE if ( ttValue != VALUE_NONE
&& (tte->bound() & (ttValue > eval ? BOUND_LOWER : BOUND_UPPER))) && (tte->bound() & (ttValue > eval ? BOUND_LOWER : BOUND_UPPER)))
eval = ttValue; eval = ttValue;
@@ -787,7 +787,7 @@ namespace {
tte->save(posKey, VALUE_NONE, ss->ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, eval); tte->save(posKey, VALUE_NONE, ss->ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, eval);
} }
// Use static evaluation difference to improve quiet move ordering // Use static evaluation difference to improve quiet move ordering (~3 Elo)
if (is_ok((ss-1)->currentMove) && !(ss-1)->inCheck && !priorCapture) if (is_ok((ss-1)->currentMove) && !(ss-1)->inCheck && !priorCapture)
{ {
int bonus = std::clamp(-16 * int((ss-1)->staticEval + ss->staticEval), -2000, 2000); int bonus = std::clamp(-16 * int((ss-1)->staticEval + ss->staticEval), -2000, 2000);
@@ -804,7 +804,7 @@ namespace {
improving = improvement > 0; improving = improvement > 0;
// Step 7. Futility pruning: child node (~50 Elo). // Step 7. Futility pruning: child node (~25 Elo).
// The depth condition is important for mate finding. // The depth condition is important for mate finding.
if ( !ss->ttPv if ( !ss->ttPv
&& depth < 9 && depth < 9
@@ -812,7 +812,7 @@ namespace {
&& eval < 15000) // 50% larger than VALUE_KNOWN_WIN, but smaller than TB wins. && eval < 15000) // 50% larger than VALUE_KNOWN_WIN, but smaller than TB wins.
return eval; return eval;
// Step 8. Null move search with verification search (~40 Elo) // Step 8. Null move search with verification search (~22 Elo)
if ( !PvNode if ( !PvNode
&& (ss-1)->currentMove != MOVE_NULL && (ss-1)->currentMove != MOVE_NULL
&& (ss-1)->statScore < 23767 && (ss-1)->statScore < 23767
@@ -925,7 +925,7 @@ namespace {
ss->ttPv = ttPv; ss->ttPv = ttPv;
} }
// Step 10. If the position is not in TT, decrease depth by 2 or 1 depending on node type // Step 10. If the position is not in TT, decrease depth by 2 or 1 depending on node type (~3 Elo)
if ( PvNode if ( PvNode
&& depth >= 6 && depth >= 6
&& !ttMove) && !ttMove)
@@ -940,7 +940,7 @@ moves_loop: // When in check, search starts here
int rangeReduction = 0; int rangeReduction = 0;
// Step 11. A small Probcut idea, when we are in check // Step 11. A small Probcut idea, when we are in check (~0 Elo)
probCutBeta = beta + 409; probCutBeta = beta + 409;
if ( ss->inCheck if ( ss->inCheck
&& !PvNode && !PvNode
@@ -1017,12 +1017,12 @@ moves_loop: // When in check, search starts here
Value delta = beta - alpha; Value delta = beta - alpha;
// Step 13. Pruning at shallow depth (~200 Elo). Depth conditions are important for mate finding. // Step 13. Pruning at shallow depth (~98 Elo). Depth conditions are important for mate finding.
if ( !rootNode if ( !rootNode
&& pos.non_pawn_material(us) && pos.non_pawn_material(us)
&& bestValue > VALUE_TB_LOSS_IN_MAX_PLY) && bestValue > VALUE_TB_LOSS_IN_MAX_PLY)
{ {
// Skip quiet moves if movecount exceeds our FutilityMoveCount threshold // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold (~7 Elo)
moveCountPruning = moveCount >= futility_move_count(improving, depth); moveCountPruning = moveCount >= futility_move_count(improving, depth);
// Reduced depth of the next LMR search // Reduced depth of the next LMR search
@@ -1031,18 +1031,18 @@ moves_loop: // When in check, search starts here
if ( captureOrPromotion if ( captureOrPromotion
|| givesCheck) || givesCheck)
{ {
// Futility pruning for captures // Futility pruning for captures (~0 Elo)
if ( !pos.empty(to_sq(move)) if ( !pos.empty(to_sq(move))
&& !givesCheck && !givesCheck
&& !PvNode && !PvNode
&& lmrDepth < 6 && lmrDepth < 6
&& !ss->inCheck && !ss->inCheck
&& ss->staticEval + 342 + 238 * lmrDepth + PieceValue[EG][pos.piece_on(to_sq(move))] && ss->staticEval + 342 + 238 * lmrDepth + PieceValue[EG][pos.piece_on(to_sq(move))]
+ captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] / 8 < alpha) + captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] / 8 < alpha)
continue; continue;
// SEE based pruning // SEE based pruning (~9 Elo)
if (!pos.see_ge(move, Value(-218) * depth)) // (~25 Elo) if (!pos.see_ge(move, Value(-218) * depth))
continue; continue;
} }
else else
@@ -1051,28 +1051,28 @@ moves_loop: // When in check, search starts here
+ (*contHist[1])[movedPiece][to_sq(move)] + (*contHist[1])[movedPiece][to_sq(move)]
+ (*contHist[3])[movedPiece][to_sq(move)]; + (*contHist[3])[movedPiece][to_sq(move)];
// Continuation history based pruning (~20 Elo) // Continuation history based pruning (~2 Elo)
if ( lmrDepth < 5 if ( lmrDepth < 5
&& history < -3000 * depth + 3000) && history < -3000 * depth + 3000)
continue; continue;
history += thisThread->mainHistory[us][from_to(move)]; history += thisThread->mainHistory[us][from_to(move)];
// Futility pruning: parent node (~5 Elo) // Futility pruning: parent node (~9 Elo)
if ( !ss->inCheck if ( !ss->inCheck
&& lmrDepth < 8 && lmrDepth < 8
&& ss->staticEval + 142 + 139 * lmrDepth + history / 64 <= alpha) && ss->staticEval + 142 + 139 * lmrDepth + history / 64 <= alpha)
continue; continue;
// Prune moves with negative SEE (~20 Elo) // Prune moves with negative SEE (~3 Elo)
if (!pos.see_ge(move, Value(-21 * lmrDepth * lmrDepth - 21 * lmrDepth))) if (!pos.see_ge(move, Value(-21 * lmrDepth * lmrDepth - 21 * lmrDepth)))
continue; continue;
} }
} }
// Step 14. Extensions (~75 Elo) // Step 14. Extensions (~66 Elo)
// Singular extension search (~70 Elo). If all moves but one fail low on a // Singular extension search (~58 Elo). If all moves but one fail low on a
// search of (alpha-s, beta-s), and just one fails high on (alpha, beta), // search of (alpha-s, beta-s), and just one fails high on (alpha, beta),
// then that move is singular and should be extended. To verify this we do // then that move is singular and should be extended. To verify this we do
// a reduced search on all the other moves but the ttMove and if the // a reduced search on all the other moves but the ttMove and if the
@@ -1117,13 +1117,13 @@ moves_loop: // When in check, search starts here
extension = -2; extension = -2;
} }
// Check extensions // Check extensions (~1 Elo)
else if ( givesCheck else if ( givesCheck
&& depth > 6 && depth > 6
&& abs(ss->staticEval) > 100) && abs(ss->staticEval) > 100)
extension = 1; extension = 1;
// Quiet ttMove extensions // Quiet ttMove extensions (~0 Elo)
else if ( PvNode else if ( PvNode
&& move == ttMove && move == ttMove
&& move == ss->killers[0] && move == ss->killers[0]
@@ -1149,7 +1149,7 @@ moves_loop: // When in check, search starts here
bool doDeeperSearch = false; bool doDeeperSearch = false;
// Step 16. Late moves reduction / extension (LMR, ~200 Elo) // Step 16. Late moves reduction / extension (LMR, ~98 Elo)
// We use various heuristics for the sons of a node after the first son has // We use various heuristics for the sons of a node after the first son has
// been searched. In general we would like to reduce them, but there are many // been searched. In general we would like to reduce them, but there are many
// cases where we extend a son if it has good chances to be "interesting". // cases where we extend a son if it has good chances to be "interesting".
@@ -1467,7 +1467,7 @@ moves_loop: // When in check, search starts here
if ((ss->staticEval = bestValue = tte->eval()) == VALUE_NONE) if ((ss->staticEval = bestValue = tte->eval()) == VALUE_NONE)
ss->staticEval = bestValue = evaluate(pos); ss->staticEval = bestValue = evaluate(pos);
// Can ttValue be used as a better position evaluation? // ttValue can be used as a better position evaluation (~7 Elo)
if ( ttValue != VALUE_NONE if ( ttValue != VALUE_NONE
&& (tte->bound() & (ttValue > bestValue ? BOUND_LOWER : BOUND_UPPER))) && (tte->bound() & (ttValue > bestValue ? BOUND_LOWER : BOUND_UPPER)))
bestValue = ttValue; bestValue = ttValue;
@@ -1522,7 +1522,7 @@ moves_loop: // When in check, search starts here
moveCount++; moveCount++;
// Futility pruning and moveCount pruning // Futility pruning and moveCount pruning (~5 Elo)
if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY
&& !givesCheck && !givesCheck
&& futilityBase > -VALUE_KNOWN_WIN && futilityBase > -VALUE_KNOWN_WIN
@@ -1547,7 +1547,7 @@ moves_loop: // When in check, search starts here
} }
} }
// Do not search moves with negative SEE values // Do not search moves with negative SEE values (~5 Elo)
if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY
&& !pos.see_ge(move)) && !pos.see_ge(move))
continue; continue;
@@ -1561,7 +1561,7 @@ moves_loop: // When in check, search starts here
[pos.moved_piece(move)] [pos.moved_piece(move)]
[to_sq(move)]; [to_sq(move)];
// Continuation history based pruning // Continuation history based pruning (~2 Elo)
if ( !captureOrPromotion if ( !captureOrPromotion
&& bestValue > VALUE_TB_LOSS_IN_MAX_PLY && bestValue > VALUE_TB_LOSS_IN_MAX_PLY
&& (*contHist[0])[pos.moved_piece(move)][to_sq(move)] < CounterMovePruneThreshold && (*contHist[0])[pos.moved_piece(move)][to_sq(move)] < CounterMovePruneThreshold