Merge commit 'b822fdf2f2f00758c794cb61a25a044424d2bc0a' into cluster

This is the last commit before there are more conflicts.
This commit is contained in:
Steinar H. Gunderson
2025-12-25 19:50:17 +01:00
8 changed files with 83 additions and 81 deletions
+53 -49
View File
@@ -317,7 +317,7 @@ void Search::Worker::iterative_deepening() {
int searchAgainCounter = 0;
lowPlyHistory.fill(0);
lowPlyHistory.fill(106);
// Iterative deepening loop until requested to stop or the target depth is reached
while (++rootDepth < MAX_PLY && !threads.stop
@@ -548,10 +548,10 @@ void Search::Worker::iterative_deepening() {
// Reset histories, usually before a new game
void Search::Worker::clear() {
mainHistory.fill(0);
lowPlyHistory.fill(0);
captureHistory.fill(-758);
pawnHistory.fill(-1158);
mainHistory.fill(61);
lowPlyHistory.fill(106);
captureHistory.fill(-598);
pawnHistory.fill(-1181);
pawnCorrectionHistory.fill(0);
majorPieceCorrectionHistory.fill(0);
minorPieceCorrectionHistory.fill(0);
@@ -566,7 +566,7 @@ void Search::Worker::clear() {
for (StatsType c : {NoCaptures, Captures})
for (auto& to : continuationHistory[inCheck][c])
for (auto& h : to)
h->fill(-645);
h->fill(-427);
for (size_t i = 1; i < reductions.size(); ++i)
reductions[i] = int((19.43 + std::log(size_t(options["Threads"])) / 2) * std::log(i));
@@ -692,13 +692,13 @@ Value Search::Worker::search(
{
// Bonus for a quiet ttMove that fails high (~2 Elo)
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
// the previous ply (~1 Elo on STC, ~2 Elo on LTC)
if (prevSq != SQ_NONE && (ss - 1)->moveCount <= 2 && !priorCapture)
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
@@ -812,10 +812,10 @@ Value Search::Worker::search(
if (((ss - 1)->currentMove).is_ok() && !(ss - 1)->inCheck && !priorCapture)
{
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)
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
@@ -905,7 +905,7 @@ Value Search::Worker::search(
// Step 11. ProbCut (~10 Elo)
// If we have a good enough capture (or queen promotion) and a reduced search
// returns a value much above beta, we can (almost) safely prune the previous move.
probCutBeta = beta + 187 - 53 * improving - 27 * opponentWorsening;
probCutBeta = beta + 187 - 56 * improving;
if (!PvNode && depth > 3
&& !is_decisive(beta)
// If value from transposition table is lower than probCutBeta, don't attempt
@@ -938,8 +938,7 @@ Value Search::Worker::search(
// Prefetch the TT entry for the resulting position
prefetch(tt.first_entry(pos.key_after(move)));
ss->currentMove = move;
ss->capturedPiece = captured;
ss->currentMove = move;
ss->continuationHistory =
&this->continuationHistory[ss->inCheck][true][pos.moved_piece(move)][move.to_sq()];
ss->continuationCorrectionHistory =
@@ -960,7 +959,7 @@ Value Search::Worker::search(
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
Distributed::save(tt, threads, thisThread, ttWriter, posKey,
@@ -1187,8 +1186,7 @@ moves_loop: // When in check, search starts here
prefetch(tt.first_entry(pos.key_after(move)));
// Update the current move (this must be done after singular extension search)
ss->currentMove = move;
ss->capturedPiece = pos.piece_on(move.to_sq());
ss->currentMove = move;
ss->continuationHistory =
&thisThread->continuationHistory[ss->inCheck][capture][movedPiece][move.to_sq()];
ss->continuationCorrectionHistory =
@@ -1231,7 +1229,10 @@ moves_loop: // When in check, search starts here
r -= 1879;
if (capture)
ss->statScore = 0;
ss->statScore =
7 * int(PieceValue[pos.captured_piece()])
+ thisThread->captureHistory[movedPiece][move.to_sq()][type_of(pos.captured_piece())]
- 5000;
else
ss->statScore = 2 * thisThread->mainHistory[us][move.from_to()]
+ (*contHist[0])[movedPiece][move.to_sq()]
@@ -1266,8 +1267,8 @@ moves_loop: // When in check, search starts here
value = -search<NonPV>(pos, ss + 1, -(alpha + 1), -alpha, newDepth, !cutNode);
// Post LMR continuation history updates (~1 Elo)
int bonus = 2 * (value >= beta) * stat_bonus(newDepth);
update_continuation_histories(ss, movedPiece, move.to_sq(), bonus);
int bonus = (value >= beta) * stat_bonus(newDepth);
update_continuation_histories(ss, movedPiece, move.to_sq(), bonus * 1427 / 1024);
}
}
@@ -1429,37 +1430,39 @@ moves_loop: // When in check, search starts here
// Bonus for prior countermove that caused the fail low
else if (!priorCapture && prevSq != SQ_NONE)
{
int bonus = (117 * (depth > 5) + 39 * !allNode + 168 * ((ss - 1)->moveCount > 8)
+ 115 * (!ss->inCheck && bestValue <= ss->staticEval - 108)
+ 119 * (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 83));
int bonusScale = (117 * (depth > 5) + 39 * !allNode + 168 * ((ss - 1)->moveCount > 8)
+ 115 * (!ss->inCheck && bestValue <= ss->staticEval - 108)
+ 119 * (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 83));
// 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,
stat_bonus(depth) * bonus / 93);
thisThread->mainHistory[~us][((ss - 1)->currentMove).from_to()]
<< stat_bonus(depth) * bonus / 179;
scaledBonus * 416 / 1024);
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)
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)
{
// bonus for prior countermoves that caused the fail low
Piece capturedPiece = (ss - 1)->capturedPiece;
Piece capturedPiece = pos.captured_piece();
assert(capturedPiece != NO_PIECE);
thisThread->captureHistory[pos.piece_on(prevSq)][prevSq][type_of(capturedPiece)]
<< stat_bonus(depth) * 2;
}
// Bonus when search fails low and there is a TT move
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)
bestValue = std::min(bestValue, maxValue);
@@ -1484,7 +1487,8 @@ moves_loop: // When in check, search starts here
&& ((bestValue < ss->staticEval && bestValue < beta) // negative correction & no fail high
|| (bestValue > ss->staticEval && bestMove))) // positive correction & no fail low
{
const auto m = (ss - 1)->currentMove;
const auto m = (ss - 1)->currentMove;
static const int nonPawnWeight = 154;
auto bonus = std::clamp(int(bestValue - ss->staticEval) * depth / 8,
-CORRECTION_HISTORY_LIMIT / 4, CORRECTION_HISTORY_LIMIT / 4);
@@ -1493,9 +1497,9 @@ moves_loop: // When in check, search starts here
thisThread->majorPieceCorrectionHistory[us][major_piece_index(pos)] << bonus * 162 / 128;
thisThread->minorPieceCorrectionHistory[us][minor_piece_index(pos)] << bonus * 148 / 128;
thisThread->nonPawnCorrectionHistory[WHITE][us][non_pawn_index<WHITE>(pos)]
<< bonus * 122 / 128;
<< bonus * nonPawnWeight / 128;
thisThread->nonPawnCorrectionHistory[BLACK][us][non_pawn_index<BLACK>(pos)]
<< bonus * 185 / 128;
<< bonus * nonPawnWeight / 128;
if (m.is_ok())
(*(ss - 2)->continuationCorrectionHistory)[pos.piece_on(m.to_sq())][m.to_sq()] << bonus;
@@ -1704,8 +1708,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta)
prefetch(tt.first_entry(pos.key_after(move)));
// Update the current move
ss->currentMove = move;
ss->capturedPiece = pos.piece_on(move.to_sq());
ss->currentMove = move;
ss->continuationHistory =
&thisThread
->continuationHistory[ss->inCheck][capture][pos.moved_piece(move)][move.to_sq()];
@@ -1860,30 +1863,30 @@ void update_all_stats(const Position& pos,
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
for (Move move : quietsSearched)
update_quiet_histories(pos, ss, workerThread, move, -malus);
update_quiet_histories(pos, ss, workerThread, move, -malus * 1028 / 1024);
}
else
{
// Increase stats for the best move in case it was a capture move
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
// previous ply when it gets refuted.
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
for (Move move : capturesSearched)
{
moved_piece = pos.moved_piece(move);
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;
}
}
@@ -1891,16 +1894,16 @@ void update_all_stats(const Position& pos,
// Updates histories of the move pairs formed by moves
// at ply -1, -2, -3, -4, and -6 with current move.
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 (int i : {1, 2, 3, 4, 6})
for (const auto [i, weight] : conthist_bonuses)
{
// Only update the first 2 continuation histories if we are in check
if (ss->inCheck && i > 2)
break;
if (((ss - i)->currentMove).is_ok())
(*(ss - i)->continuationHistory)[pc][to] << bonus / (1 + (i == 3));
(*(ss - i)->continuationHistory)[pc][to] << bonus * weight / 1024;
}
}
@@ -1910,14 +1913,15 @@ void update_quiet_histories(
const Position& pos, Stack* ss, Search::Worker& workerThread, Move move, int bonus) {
Color us = pos.side_to_move();
workerThread.mainHistory[us][move.from_to()] << bonus;
if (ss->ply < LOW_PLY_HISTORY_SIZE)
workerThread.lowPlyHistory[ss->ply][move.from_to()] << bonus;
workerThread.mainHistory[us][move.from_to()] << bonus; // Untuned to prevent duplicate effort
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);
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;
}
}