Tune histories

Passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 268736 W: 70080 L: 69421 D: 129235
Ptnml(0-2): 831, 31795, 68460, 32448, 834
https://tests.stockfishchess.org/tests/view/6750778886d5ee47d9540e7c

Passed LTC:
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 505356 W: 129145 L: 127868 D: 248343
Ptnml(0-2): 307, 54901, 140959, 56230, 281
https://tests.stockfishchess.org/tests/view/675367de86d5ee47d9541536

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

Bench: 1148169
This commit is contained in:
Shawn Xu
2024-11-24 16:29:20 -08:00
committed by Disservin
parent cf10644d6e
commit b822fdf2f2
3 changed files with 46 additions and 39 deletions
+1 -1
View File
@@ -138,7 +138,7 @@ using LowPlyHistory = Stats<int16_t, 7183, LOW_PLY_HISTORY_SIZE, int(SQUARE_NB)
using CapturePieceToHistory = Stats<int16_t, 10692, PIECE_NB, SQUARE_NB, PIECE_TYPE_NB>; using CapturePieceToHistory = Stats<int16_t, 10692, PIECE_NB, SQUARE_NB, PIECE_TYPE_NB>;
// PieceToHistory is like ButterflyHistory but is addressed by a move's [piece][to] // PieceToHistory is like ButterflyHistory but is addressed by a move's [piece][to]
using PieceToHistory = Stats<int16_t, 29952, PIECE_NB, SQUARE_NB>; using PieceToHistory = Stats<int16_t, 30000, PIECE_NB, SQUARE_NB>;
// ContinuationHistory is the combined history of a given pair of moves, usually // ContinuationHistory is the combined history of a given pair of moves, usually
// the current one given a previous one. The nested history table is based on // the current one given a previous one. The nested history table is based on
+40 -38
View File
@@ -275,7 +275,7 @@ void Search::Worker::iterative_deepening() {
int searchAgainCounter = 0; int searchAgainCounter = 0;
lowPlyHistory.fill(0); lowPlyHistory.fill(106);
// Iterative deepening loop until requested to stop or the target depth is reached // Iterative deepening loop until requested to stop or the target depth is reached
while (++rootDepth < MAX_PLY && !threads.stop while (++rootDepth < MAX_PLY && !threads.stop
@@ -500,10 +500,10 @@ void Search::Worker::iterative_deepening() {
// Reset histories, usually before a new game // Reset histories, usually before a new game
void Search::Worker::clear() { void Search::Worker::clear() {
mainHistory.fill(0); mainHistory.fill(61);
lowPlyHistory.fill(0); lowPlyHistory.fill(106);
captureHistory.fill(-758); captureHistory.fill(-598);
pawnHistory.fill(-1158); pawnHistory.fill(-1181);
pawnCorrectionHistory.fill(0); pawnCorrectionHistory.fill(0);
majorPieceCorrectionHistory.fill(0); majorPieceCorrectionHistory.fill(0);
minorPieceCorrectionHistory.fill(0); minorPieceCorrectionHistory.fill(0);
@@ -518,7 +518,7 @@ void Search::Worker::clear() {
for (StatsType c : {NoCaptures, Captures}) for (StatsType c : {NoCaptures, Captures})
for (auto& to : continuationHistory[inCheck][c]) for (auto& to : continuationHistory[inCheck][c])
for (auto& h : to) for (auto& h : to)
h->fill(-645); h->fill(-427);
for (size_t i = 1; i < reductions.size(); ++i) for (size_t i = 1; i < reductions.size(); ++i)
reductions[i] = int((19.43 + std::log(size_t(options["Threads"])) / 2) * std::log(i)); reductions[i] = int((19.43 + std::log(size_t(options["Threads"])) / 2) * std::log(i));
@@ -538,7 +538,7 @@ Value Search::Worker::search(
// Dive into quiescence search when the depth reaches zero // Dive into quiescence search when the depth reaches zero
if (depth <= 0) if (depth <= 0)
return qsearch < PvNode ? PV : NonPV > (pos, ss, alpha, beta); return qsearch<PvNode ? PV : NonPV>(pos, ss, alpha, beta);
// Limit the depth if extensions made it too large // Limit the depth if extensions made it too large
depth = std::min(depth, MAX_PLY - 1); depth = std::min(depth, MAX_PLY - 1);
@@ -644,13 +644,13 @@ Value Search::Worker::search(
{ {
// Bonus for a quiet ttMove that fails high (~2 Elo) // Bonus for a quiet ttMove that fails high (~2 Elo)
if (!ttCapture) if (!ttCapture)
update_quiet_histories(pos, ss, *this, ttData.move, stat_bonus(depth)); update_quiet_histories(pos, ss, *this, ttData.move, stat_bonus(depth) * 747 / 1024);
// Extra penalty for early quiet moves of // Extra penalty for early quiet moves of
// the previous ply (~1 Elo on STC, ~2 Elo on LTC) // the previous ply (~1 Elo on STC, ~2 Elo on LTC)
if (prevSq != SQ_NONE && (ss - 1)->moveCount <= 2 && !priorCapture) if (prevSq != SQ_NONE && (ss - 1)->moveCount <= 2 && !priorCapture)
update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq,
-stat_malus(depth + 1)); -stat_malus(depth + 1) * 1091 / 1024);
} }
// Partial workaround for the graph history interaction problem // Partial workaround for the graph history interaction problem
@@ -762,10 +762,10 @@ Value Search::Worker::search(
if (((ss - 1)->currentMove).is_ok() && !(ss - 1)->inCheck && !priorCapture) if (((ss - 1)->currentMove).is_ok() && !(ss - 1)->inCheck && !priorCapture)
{ {
int bonus = std::clamp(-10 * int((ss - 1)->staticEval + ss->staticEval), -1831, 1428) + 623; int bonus = std::clamp(-10 * int((ss - 1)->staticEval + ss->staticEval), -1831, 1428) + 623;
thisThread->mainHistory[~us][((ss - 1)->currentMove).from_to()] << bonus; thisThread->mainHistory[~us][((ss - 1)->currentMove).from_to()] << bonus * 1340 / 1024;
if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION) if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION)
thisThread->pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq] thisThread->pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq]
<< bonus; << bonus * 1159 / 1024;
} }
// Set up the improving flag, which is true if current static evaluation is // Set up the improving flag, which is true if current static evaluation is
@@ -909,7 +909,7 @@ Value Search::Worker::search(
if (value >= probCutBeta) if (value >= probCutBeta)
{ {
thisThread->captureHistory[movedPiece][move.to_sq()][type_of(captured)] << 1300; thisThread->captureHistory[movedPiece][move.to_sq()][type_of(captured)] << 1226;
// Save ProbCut data into transposition table // Save ProbCut data into transposition table
ttWriter.write(posKey, value_to_tt(value, ss->ply), ss->ttPv, BOUND_LOWER, ttWriter.write(posKey, value_to_tt(value, ss->ply), ss->ttPv, BOUND_LOWER,
@@ -1216,8 +1216,8 @@ moves_loop: // When in check, search starts here
value = -search<NonPV>(pos, ss + 1, -(alpha + 1), -alpha, newDepth, !cutNode); value = -search<NonPV>(pos, ss + 1, -(alpha + 1), -alpha, newDepth, !cutNode);
// Post LMR continuation history updates (~1 Elo) // Post LMR continuation history updates (~1 Elo)
int bonus = 2 * (value >= beta) * stat_bonus(newDepth); int bonus = (value >= beta) * stat_bonus(newDepth);
update_continuation_histories(ss, movedPiece, move.to_sq(), bonus); update_continuation_histories(ss, movedPiece, move.to_sq(), bonus * 1427 / 1024);
} }
} }
@@ -1379,24 +1379,25 @@ moves_loop: // When in check, search starts here
// Bonus for prior countermove that caused the fail low // Bonus for prior countermove that caused the fail low
else if (!priorCapture && prevSq != SQ_NONE) else if (!priorCapture && prevSq != SQ_NONE)
{ {
int bonus = (117 * (depth > 5) + 39 * !allNode + 168 * ((ss - 1)->moveCount > 8) int bonusScale = (117 * (depth > 5) + 39 * !allNode + 168 * ((ss - 1)->moveCount > 8)
+ 115 * (!ss->inCheck && bestValue <= ss->staticEval - 108) + 115 * (!ss->inCheck && bestValue <= ss->staticEval - 108)
+ 119 * (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 83)); + 119 * (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 83));
// Proportional to "how much damage we have to undo" // Proportional to "how much damage we have to undo"
bonus += std::min(-(ss - 1)->statScore / 113, 300); bonusScale += std::min(-(ss - 1)->statScore / 113, 300);
bonus = std::max(bonus, 0); bonusScale = std::max(bonusScale, 0);
const int scaledBonus = stat_bonus(depth) * bonusScale / 32;
update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq,
stat_bonus(depth) * bonus / 93); scaledBonus * 416 / 1024);
thisThread->mainHistory[~us][((ss - 1)->currentMove).from_to()]
<< stat_bonus(depth) * bonus / 179;
thisThread->mainHistory[~us][((ss - 1)->currentMove).from_to()] << scaledBonus * 212 / 1024;
if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION) if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION)
thisThread->pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq] thisThread->pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq]
<< stat_bonus(depth) * bonus / 24; << scaledBonus * 1073 / 1024;
} }
else if (priorCapture && prevSq != SQ_NONE) else if (priorCapture && prevSq != SQ_NONE)
@@ -1410,7 +1411,7 @@ moves_loop: // When in check, search starts here
// Bonus when search fails low and there is a TT move // Bonus when search fails low and there is a TT move
else if (ttData.move && !allNode) else if (ttData.move && !allNode)
thisThread->mainHistory[us][ttData.move.from_to()] << stat_bonus(depth) * 23 / 100; thisThread->mainHistory[us][ttData.move.from_to()] << stat_bonus(depth) * 287 / 1024;
if (PvNode) if (PvNode)
bestValue = std::min(bestValue, maxValue); bestValue = std::min(bestValue, maxValue);
@@ -1808,30 +1809,30 @@ void update_all_stats(const Position& pos,
if (!pos.capture_stage(bestMove)) if (!pos.capture_stage(bestMove))
{ {
update_quiet_histories(pos, ss, workerThread, bestMove, bonus); update_quiet_histories(pos, ss, workerThread, bestMove, bonus * 1131 / 1024);
// Decrease stats for all non-best quiet moves // Decrease stats for all non-best quiet moves
for (Move move : quietsSearched) for (Move move : quietsSearched)
update_quiet_histories(pos, ss, workerThread, move, -malus); update_quiet_histories(pos, ss, workerThread, move, -malus * 1028 / 1024);
} }
else else
{ {
// Increase stats for the best move in case it was a capture move // Increase stats for the best move in case it was a capture move
captured = type_of(pos.piece_on(bestMove.to_sq())); captured = type_of(pos.piece_on(bestMove.to_sq()));
captureHistory[moved_piece][bestMove.to_sq()][captured] << bonus; captureHistory[moved_piece][bestMove.to_sq()][captured] << bonus * 1291 / 1024;
} }
// Extra penalty for a quiet early move that was not a TT move in // Extra penalty for a quiet early move that was not a TT move in
// previous ply when it gets refuted. // previous ply when it gets refuted.
if (prevSq != SQ_NONE && ((ss - 1)->moveCount == 1 + (ss - 1)->ttHit) && !pos.captured_piece()) 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); update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, -malus * 919 / 1024);
// Decrease stats for all non-best capture moves // Decrease stats for all non-best capture moves
for (Move move : capturesSearched) for (Move move : capturesSearched)
{ {
moved_piece = pos.moved_piece(move); moved_piece = pos.moved_piece(move);
captured = type_of(pos.piece_on(move.to_sq())); captured = type_of(pos.piece_on(move.to_sq()));
captureHistory[moved_piece][move.to_sq()][captured] << -malus; captureHistory[moved_piece][move.to_sq()][captured] << -malus * 1090 / 1024;
} }
} }
@@ -1839,16 +1840,16 @@ void update_all_stats(const Position& pos,
// Updates histories of the move pairs formed by moves // Updates histories of the move pairs formed by moves
// at ply -1, -2, -3, -4, and -6 with current move. // at ply -1, -2, -3, -4, and -6 with current move.
void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) { void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) {
static constexpr std::array<ConthistBonus, 5> conthist_bonuses = {
{{1, 1024}, {2, 571}, {3, 339}, {4, 500}, {6, 592}}};
bonus = bonus * 50 / 64; for (const auto [i, weight] : conthist_bonuses)
for (int i : {1, 2, 3, 4, 6})
{ {
// Only update the first 2 continuation histories if we are in check // Only update the first 2 continuation histories if we are in check
if (ss->inCheck && i > 2) if (ss->inCheck && i > 2)
break; break;
if (((ss - i)->currentMove).is_ok()) if (((ss - i)->currentMove).is_ok())
(*(ss - i)->continuationHistory)[pc][to] << bonus / (1 + (i == 3)); (*(ss - i)->continuationHistory)[pc][to] << bonus * weight / 1024;
} }
} }
@@ -1858,14 +1859,15 @@ void update_quiet_histories(
const Position& pos, Stack* ss, Search::Worker& workerThread, Move move, int bonus) { const Position& pos, Stack* ss, Search::Worker& workerThread, Move move, int bonus) {
Color us = pos.side_to_move(); Color us = pos.side_to_move();
workerThread.mainHistory[us][move.from_to()] << bonus; workerThread.mainHistory[us][move.from_to()] << bonus; // Untuned to prevent duplicate effort
if (ss->ply < LOW_PLY_HISTORY_SIZE)
workerThread.lowPlyHistory[ss->ply][move.from_to()] << bonus;
update_continuation_histories(ss, pos.moved_piece(move), move.to_sq(), bonus); if (ss->ply < LOW_PLY_HISTORY_SIZE)
workerThread.lowPlyHistory[ss->ply][move.from_to()] << bonus * 874 / 1024;
update_continuation_histories(ss, pos.moved_piece(move), move.to_sq(), bonus * 853 / 1024);
int pIndex = pawn_structure_index(pos); int pIndex = pawn_structure_index(pos);
workerThread.pawnHistory[pIndex][pos.moved_piece(move)][move.to_sq()] << bonus / 2; workerThread.pawnHistory[pIndex][pos.moved_piece(move)][move.to_sq()] << bonus * 628 / 1024;
} }
} }
+5
View File
@@ -351,6 +351,11 @@ class Worker {
friend class SearchManager; friend class SearchManager;
}; };
struct ConthistBonus {
int index;
int weight;
};
} // namespace Search } // namespace Search