Refactor root history into low ply history

This patch changes root history to low ply history - butterfly history for plies < 4.
Doubles weight of this history for root, latter plies have lesser effect.

Passed STC:
https://tests.stockfishchess.org/tests/view/66f77d2386d5ee47d953b65d
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 180992 W: 47362 L: 46830 D: 86800
Ptnml(0-2): 554, 21499, 45928, 21891, 624

Passed LTC:
https://tests.stockfishchess.org/tests/view/66fb557986d5ee47d953b8e5
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 42462 W: 11013 L: 10682 D: 20767
Ptnml(0-2): 33, 4518, 11795, 4855, 30

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

Bench 1264335
This commit is contained in:
Michael Chaly
2024-10-02 10:49:23 +03:00
committed by Joost VandeVondele
parent 0186904f53
commit 7ac745a736
4 changed files with 40 additions and 48 deletions
+6 -6
View File
@@ -82,20 +82,20 @@ MovePicker::MovePicker(const Position& p,
Move ttm, Move ttm,
Depth d, Depth d,
const ButterflyHistory* mh, const ButterflyHistory* mh,
const ButterflyHistory* rh, const LowPlyHistory* lph,
const CapturePieceToHistory* cph, const CapturePieceToHistory* cph,
const PieceToHistory** ch, const PieceToHistory** ch,
const PawnHistory* ph, const PawnHistory* ph,
bool rn) : int pl) :
pos(p), pos(p),
mainHistory(mh), mainHistory(mh),
rootHistory(rh), lowPlyHistory(lph),
captureHistory(cph), captureHistory(cph),
continuationHistory(ch), continuationHistory(ch),
pawnHistory(ph), pawnHistory(ph),
ttMove(ttm), ttMove(ttm),
depth(d), depth(d),
rootNode(rn) { ply(pl) {
if (pos.checkers()) if (pos.checkers())
stage = EVASION_TT + !(ttm && pos.pseudo_legal(ttm)); stage = EVASION_TT + !(ttm && pos.pseudo_legal(ttm));
@@ -179,8 +179,8 @@ void MovePicker::score() {
: pt == ROOK && bool(to & threatenedByMinor) ? 24335 : pt == ROOK && bool(to & threatenedByMinor) ? 24335
: 0); : 0);
if (rootNode) if (ply < 4)
m.value += 4 * (*rootHistory)[pos.side_to_move()][m.from_to()]; m.value += 8 * (*lowPlyHistory)[ply][m.from_to()] / (1 + 2 * ply);
} }
else // Type == EVASIONS else // Type == EVASIONS
+8 -4
View File
@@ -135,6 +135,10 @@ enum StatsType {
// see https://www.chessprogramming.org/Butterfly_Boards (~11 elo) // see https://www.chessprogramming.org/Butterfly_Boards (~11 elo)
using ButterflyHistory = Stats<int16_t, 7183, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)>; using ButterflyHistory = Stats<int16_t, 7183, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)>;
// LowPlyHistory is adressed by play and move's from and to squares, used
// to improve move ordering near the root
using LowPlyHistory = Stats<int16_t, 7183, 4, int(SQUARE_NB) * int(SQUARE_NB)>;
// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type] // CapturePieceToHistory is addressed by a move's [piece][to][captured piece type]
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>;
@@ -195,11 +199,11 @@ class MovePicker {
Move, Move,
Depth, Depth,
const ButterflyHistory*, const ButterflyHistory*,
const ButterflyHistory*, const LowPlyHistory*,
const CapturePieceToHistory*, const CapturePieceToHistory*,
const PieceToHistory**, const PieceToHistory**,
const PawnHistory*, const PawnHistory*,
bool); int);
MovePicker(const Position&, Move, int, const CapturePieceToHistory*); MovePicker(const Position&, Move, int, const CapturePieceToHistory*);
Move next_move(bool skipQuiets = false); Move next_move(bool skipQuiets = false);
@@ -213,7 +217,7 @@ class MovePicker {
const Position& pos; const Position& pos;
const ButterflyHistory* mainHistory; const ButterflyHistory* mainHistory;
const ButterflyHistory* rootHistory; const LowPlyHistory* lowPlyHistory;
const CapturePieceToHistory* captureHistory; const CapturePieceToHistory* captureHistory;
const PieceToHistory** continuationHistory; const PieceToHistory** continuationHistory;
const PawnHistory* pawnHistory; const PawnHistory* pawnHistory;
@@ -222,7 +226,7 @@ class MovePicker {
int stage; int stage;
int threshold; int threshold;
Depth depth; Depth depth;
bool rootNode; int ply;
ExtMove moves[MAX_MOVES]; ExtMove moves[MAX_MOVES];
}; };
+25 -37
View File
@@ -105,21 +105,16 @@ Value value_to_tt(Value v, int ply);
Value value_from_tt(Value v, int ply, int r50c); Value value_from_tt(Value v, int ply, int r50c);
void update_pv(Move* pv, Move move, const Move* childPv); void update_pv(Move* pv, Move move, const Move* childPv);
void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus); void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus);
void update_quiet_histories(const Position& pos, void update_quiet_histories(
Stack* ss, const Position& pos, Stack* ss, Search::Worker& workerThread, Move move, int bonus);
Search::Worker& workerThread, void update_all_stats(const Position& pos,
Move move, Stack* ss,
int bonus, Search::Worker& workerThread,
bool rootNode); Move bestMove,
void update_all_stats(const Position& pos, Square prevSq,
Stack* ss, ValueList<Move, 32>& quietsSearched,
Search::Worker& workerThread, ValueList<Move, 32>& capturesSearched,
Move bestMove, Depth depth);
Square prevSq,
ValueList<Move, 32>& quietsSearched,
ValueList<Move, 32>& capturesSearched,
Depth depth,
bool rootNode);
} // namespace } // namespace
@@ -273,7 +268,7 @@ void Search::Worker::iterative_deepening() {
int searchAgainCounter = 0; int searchAgainCounter = 0;
rootHistory.fill(0); lowPlyHistory.fill(0);
// 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
@@ -499,7 +494,7 @@ 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(0);
rootHistory.fill(0); lowPlyHistory.fill(0);
captureHistory.fill(-753); captureHistory.fill(-753);
pawnHistory.fill(-1152); pawnHistory.fill(-1152);
pawnCorrectionHistory.fill(0); pawnCorrectionHistory.fill(0);
@@ -638,7 +633,7 @@ 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), rootNode); update_quiet_histories(pos, ss, *this, ttData.move, stat_bonus(depth));
// 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)
@@ -928,8 +923,8 @@ moves_loop: // When in check, search starts here
(ss - 6)->continuationHistory}; (ss - 6)->continuationHistory};
MovePicker mp(pos, ttData.move, depth, &thisThread->mainHistory, &thisThread->rootHistory, MovePicker mp(pos, ttData.move, depth, &thisThread->mainHistory, &thisThread->lowPlyHistory,
&thisThread->captureHistory, contHist, &thisThread->pawnHistory, rootNode); &thisThread->captureHistory, contHist, &thisThread->pawnHistory, ss->ply);
value = bestValue; value = bestValue;
@@ -1355,8 +1350,7 @@ moves_loop: // When in check, search starts here
// If there is a move that produces search value greater than alpha, // If there is a move that produces search value greater than alpha,
// we update the stats of searched moves. // we update the stats of searched moves.
else if (bestMove) else if (bestMove)
update_all_stats(pos, ss, *this, bestMove, prevSq, quietsSearched, capturesSearched, depth, update_all_stats(pos, ss, *this, bestMove, prevSq, quietsSearched, capturesSearched, depth);
rootNode);
// 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)
@@ -1557,9 +1551,8 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta)
// Initialize a MovePicker object for the current position, and prepare to search // Initialize a MovePicker object for the current position, and prepare to search
// the moves. We presently use two stages of move generator in quiescence search: // the moves. We presently use two stages of move generator in quiescence search:
// captures, or evasions only when in check. // captures, or evasions only when in check.
MovePicker mp(pos, ttData.move, DEPTH_QS, &thisThread->mainHistory, &thisThread->rootHistory, MovePicker mp(pos, ttData.move, DEPTH_QS, &thisThread->mainHistory, &thisThread->lowPlyHistory,
&thisThread->captureHistory, contHist, &thisThread->pawnHistory, &thisThread->captureHistory, contHist, &thisThread->pawnHistory, ss->ply);
nodeType == Root);
// Step 5. Loop through all pseudo-legal moves until no moves remain or a beta // Step 5. Loop through all pseudo-legal moves until no moves remain or a beta
// cutoff occurs. // cutoff occurs.
@@ -1768,8 +1761,7 @@ void update_all_stats(const Position& pos,
Square prevSq, Square prevSq,
ValueList<Move, 32>& quietsSearched, ValueList<Move, 32>& quietsSearched,
ValueList<Move, 32>& capturesSearched, ValueList<Move, 32>& capturesSearched,
Depth depth, Depth depth) {
bool rootNode) {
CapturePieceToHistory& captureHistory = workerThread.captureHistory; CapturePieceToHistory& captureHistory = workerThread.captureHistory;
Piece moved_piece = pos.moved_piece(bestMove); Piece moved_piece = pos.moved_piece(bestMove);
@@ -1780,11 +1772,11 @@ void update_all_stats(const Position& pos,
if (!pos.capture_stage(bestMove)) if (!pos.capture_stage(bestMove))
{ {
update_quiet_histories(pos, ss, workerThread, bestMove, quietMoveBonus, rootNode); update_quiet_histories(pos, ss, workerThread, bestMove, quietMoveBonus);
// 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, -quietMoveMalus, rootNode); update_quiet_histories(pos, ss, workerThread, move, -quietMoveMalus);
} }
else else
{ {
@@ -1826,17 +1818,13 @@ void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) {
// Updates move sorting heuristics // Updates move sorting heuristics
void update_quiet_histories(const Position& pos, void update_quiet_histories(
Stack* ss, const Position& pos, Stack* ss, Search::Worker& workerThread, Move move, int bonus) {
Search::Worker& workerThread,
Move move,
int bonus,
bool rootNode) {
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;
if (rootNode) if (ss->ply < 4)
workerThread.rootHistory[us][move.from_to()] << bonus; workerThread.lowPlyHistory[ss->ply][move.from_to()] << bonus;
update_continuation_histories(ss, pos.moved_piece(move), move.to_sq(), bonus); update_continuation_histories(ss, pos.moved_piece(move), move.to_sq(), bonus);
+1 -1
View File
@@ -278,7 +278,7 @@ class Worker {
// Public because they need to be updatable by the stats // Public because they need to be updatable by the stats
ButterflyHistory mainHistory; ButterflyHistory mainHistory;
ButterflyHistory rootHistory; LowPlyHistory lowPlyHistory;
CapturePieceToHistory captureHistory; CapturePieceToHistory captureHistory;
ContinuationHistory continuationHistory[2][2]; ContinuationHistory continuationHistory[2][2];