Skip to content

Commit

Permalink
Refactor final stats updates.
Browse files Browse the repository at this point in the history
This PR refactors update_quiet_stats, update_capture_stats and search to more clearly reflect what is actually done.

Effectively, all stat updates that need to be done after search is finished and a bestmove is found,
are collected in a new function ```final_stats_update()```. This shortens our main search routine, and simplifies ```update_quiet_stats```.
The latter function is now more easily reusable with fewer arguments, as the handling of ```quietsSearched``` is only needed in ```final_stats_update```.
```update_capture_stats```, which was only called once is now integrated in ```final_stats_update```, which allows for removing a branch and reusing some ```stat_bonus``` calls. The need for refactoring was also suggested by the fact that the comments of ```update_quiet_stats``` and ```update_capture_stats``` were incorrect (e.g. ```update_capture_stats``` was called, correctly, also when the bestmove was a quiet and not a capture).

passed non-regression STC:
LLR: 2.96 (-2.94,2.94) [-3.00,1.00]
Total: 75196 W: 16364 L: 16347 D: 42485
http://tests.stockfishchess.org/tests/view/5db004ec0ebc5902c06db9e1

The diff is most easily readable as ```git diff master --patience```

No functional change
  • Loading branch information
vondele authored and snicolet committed Oct 25, 2019
1 parent 90c0385 commit 648c7ec
Showing 1 changed file with 54 additions and 48 deletions.
102 changes: 54 additions & 48 deletions src/search.cpp
Expand Up @@ -153,8 +153,9 @@ namespace {
Value value_from_tt(Value v, int ply);
void update_pv(Move* pv, Move move, Move* childPv);
void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus);
void update_quiet_stats(const Position& pos, Stack* ss, Move move, Move* quiets, int quietCount, int bonus);
void update_capture_stats(const Position& pos, Move move, Move* captures, int captureCount, int bonus);
void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus);
void update_all_stats(const Position& pos, Stack* ss, Move bestMove, Value bestValue, Value beta, Square prevSq,
Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth);

// perft() is our utility to verify move generation. All the leaf nodes up
// to the given depth are generated and counted, and the sum is returned.
Expand Down Expand Up @@ -679,7 +680,7 @@ namespace {
if (ttValue >= beta)
{
if (!pos.capture_or_promotion(ttMove))
update_quiet_stats(pos, ss, ttMove, nullptr, 0, stat_bonus(depth));
update_quiet_stats(pos, ss, ttMove, stat_bonus(depth));

// Extra penalty for early quiet moves of the previous ply
if ((ss-1)->moveCount <= 2 && !priorCapture)
Expand Down Expand Up @@ -1276,21 +1277,11 @@ namespace {
if (!moveCount)
bestValue = excludedMove ? alpha
: inCheck ? mated_in(ss->ply) : VALUE_DRAW;
else if (bestMove)
{
// Quiet best move: update move sorting heuristics
if (!pos.capture_or_promotion(bestMove))
update_quiet_stats(pos, ss, bestMove, quietsSearched, quietCount,
stat_bonus(depth + (bestValue > beta + PawnValueMg)));

update_capture_stats(pos, bestMove, capturesSearched, captureCount, stat_bonus(depth + 1));

// Extra penalty for a quiet TT or main killer move in previous ply when it gets refuted
if ( ((ss-1)->moveCount == 1 || ((ss-1)->currentMove == (ss-1)->killers[0]))
&& !priorCapture)
update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + 1));
else if (bestMove)
update_all_stats(pos, ss, bestMove, bestValue, beta, prevSq,
quietsSearched, quietCount, capturesSearched, captureCount, depth);

}
// Bonus for prior countermove that caused the fail low
else if ( (depth >= 3 || PvNode)
&& !priorCapture)
Expand Down Expand Up @@ -1564,43 +1555,65 @@ namespace {
}


// update_continuation_histories() updates histories of the move pairs formed
// by moves at ply -1, -2, and -4 with current move.
// update_all_stats() updates stats at the end of search() when a bestMove is found

void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) {
void update_all_stats(const Position& pos, Stack* ss, Move bestMove, Value bestValue, Value beta, Square prevSq,
Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth) {

for (int i : {1, 2, 4, 6})
if (is_ok((ss-i)->currentMove))
(*(ss-i)->continuationHistory)[pc][to] << bonus;
}
int bonus1, bonus2;
Color us = pos.side_to_move();
Thread* thisThread = pos.this_thread();
CapturePieceToHistory& captureHistory = thisThread->captureHistory;
Piece moved_piece = pos.moved_piece(bestMove);
PieceType captured = type_of(pos.piece_on(to_sq(bestMove)));

bonus1 = stat_bonus(depth + 1);
bonus2 = bestValue > beta + PawnValueMg ? bonus1 // larger bonus
: stat_bonus(depth); // smaller bonus

if (!pos.capture_or_promotion(bestMove))
{
update_quiet_stats(pos, ss, bestMove, bonus2);

// Decrease all the non-best quiet moves
for (int i = 0; i < quietCount; ++i)
{
thisThread->mainHistory[us][from_to(quietsSearched[i])] << -bonus2;
update_continuation_histories(ss, pos.moved_piece(quietsSearched[i]), to_sq(quietsSearched[i]), -bonus2);
}
}
else
captureHistory[moved_piece][to_sq(bestMove)][captured] << bonus1;

// Extra penalty for a quiet TT or main killer move in previous ply when it gets refuted
if ( ((ss-1)->moveCount == 1 || ((ss-1)->currentMove == (ss-1)->killers[0]))
&& !pos.captured_piece())
update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -bonus1);

// update_capture_stats() updates move sorting heuristics when a new capture best move is found
// Decrease all the non-best capture moves
for (int i = 0; i < captureCount; ++i)
{
moved_piece = pos.moved_piece(capturesSearched[i]);
captured = type_of(pos.piece_on(to_sq(capturesSearched[i])));
captureHistory[moved_piece][to_sq(capturesSearched[i])][captured] << -bonus1;
}
}

void update_capture_stats(const Position& pos, Move move,
Move* captures, int captureCount, int bonus) {

CapturePieceToHistory& captureHistory = pos.this_thread()->captureHistory;
Piece moved_piece = pos.moved_piece(move);
PieceType captured = type_of(pos.piece_on(to_sq(move)));
// update_continuation_histories() updates histories of the move pairs formed
// by moves at ply -1, -2, and -4 with current move.

if (pos.capture_or_promotion(move))
captureHistory[moved_piece][to_sq(move)][captured] << bonus;
void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) {

// Decrease all the other played capture moves
for (int i = 0; i < captureCount; ++i)
{
moved_piece = pos.moved_piece(captures[i]);
captured = type_of(pos.piece_on(to_sq(captures[i])));
captureHistory[moved_piece][to_sq(captures[i])][captured] << -bonus;
}
for (int i : {1, 2, 4, 6})
if (is_ok((ss-i)->currentMove))
(*(ss-i)->continuationHistory)[pc][to] << bonus;
}


// update_quiet_stats() updates move sorting heuristics when a new quiet best move is found
// update_quiet_stats() updates move sorting heuristics

void update_quiet_stats(const Position& pos, Stack* ss, Move move,
Move* quiets, int quietCount, int bonus) {
void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus) {

if (ss->killers[0] != move)
{
Expand All @@ -1621,13 +1634,6 @@ namespace {
Square prevSq = to_sq((ss-1)->currentMove);
thisThread->counterMoves[pos.piece_on(prevSq)][prevSq] = move;
}

// Decrease all the other played quiet moves
for (int i = 0; i < quietCount; ++i)
{
thisThread->mainHistory[us][from_to(quiets[i])] << -bonus;
update_continuation_histories(ss, pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus);
}
}

// When playing with strength handicap, choose best move among a set of RootMoves
Expand Down

0 comments on commit 648c7ec

Please sign in to comment.