diff --git a/src/history.h b/src/history.h index 8d14a7a7cb1..17ab3481c3e 100644 --- a/src/history.h +++ b/src/history.h @@ -138,7 +138,7 @@ using LowPlyHistory = Stats; // PieceToHistory is like ButterflyHistory but is addressed by a move's [piece][to] -using PieceToHistory = Stats; +using PieceToHistory = Stats; // 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 diff --git a/src/search.cpp b/src/search.cpp index e352c96e33e..9a0a9d04606 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -275,7 +275,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 @@ -500,10 +500,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); @@ -518,7 +518,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)); @@ -538,7 +538,7 @@ Value Search::Worker::search( // Dive into quiescence search when the depth reaches zero if (depth <= 0) - return qsearch < PvNode ? PV : NonPV > (pos, ss, alpha, beta); + return qsearch(pos, ss, alpha, beta); // Limit the depth if extensions made it too large 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) 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 @@ -762,10 +762,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 @@ -909,7 +909,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 ttWriter.write(posKey, value_to_tt(value, ss->ply), ss->ttPv, BOUND_LOWER, @@ -1216,8 +1216,8 @@ Value Search::Worker::search( value = -search(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); } } @@ -1379,24 +1379,25 @@ Value Search::Worker::search( // 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) @@ -1410,7 +1411,7 @@ Value Search::Worker::search( // 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); @@ -1808,30 +1809,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; } } @@ -1839,16 +1840,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 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; } } @@ -1858,14 +1859,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; + 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; + workerThread.lowPlyHistory[ss->ply][move.from_to()] << bonus * 874 / 1024; - update_continuation_histories(ss, pos.moved_piece(move), move.to_sq(), bonus); + 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; } } diff --git a/src/search.h b/src/search.h index b618855b9fc..e9a7943d128 100644 --- a/src/search.h +++ b/src/search.h @@ -351,6 +351,11 @@ class Worker { friend class SearchManager; }; +struct ConthistBonus { + int index; + int weight; +}; + } // namespace Search