mirror of
https://github.com/official-stockfish/Stockfish.git
synced 2026-07-22 12:47:08 +00:00
Help aborted searches remember mate scores
This patch improves mate finding results by protecting mate scores from being forgotten in a later iteration. This applies especially to aborted searches, but also to completed iterations in e.g. `go depth` scenarios. The only visible change to the user is the final UCI info line. The case of TB wins/losses was excluded from this patch on purpose. The reason is that in some corner cases related to rounding in some DTZ Syzygy EGTBs, later searches may turn a TB loss into a draw, for example. See #5175 and the example ``` info depth 5 seldepth 5 multipv 1 score cp -20000 nodes 122 nps 8714 hashfull 0 tbhits 26 time 14 pv h1b1 a7b6 f6e5 b6b1 e5f4 c8c3 f4g5 d7h7 g5f4 b1f5 f4f5 c3e5 f5g6 e5f4 g6h7 f4g5 h7h8 b8c7 h8h7 c7d6 h7h8 d6e5 h8h7 e5f6 h7h8 g5g7 info depth 6 seldepth 9 multipv 1 score cp 0 nodes 255 nps 18214 hashfull 0 tbhits 26 time 14 pv h1h2 d7d6 f6g5 a7e7 ``` from #5414. Matetrack for patch: ``` Using ./stockfish on matetrack.epd with --nodes 1000000 Engine ID: Stockfish dev-20260510-dbbc3ed1 Total FENs: 6554 Found mates: 3054 Best mates: 2224 ``` This is slightly more/equal compared to master (3040 and 2224), see https://github.com/vondele/matetrack/blob/faf7cf3be95ab7dfdcde6e035de28a30887cd8a5/matetrack1000000.csv#L4368. Passed STC non-reg: LLR: 2.96 (-2.94,2.94) <-1.75,0.25> Total: 108224 W: 27565 L: 27429 D: 53230 Ptnml(0-2): 212, 11755, 30064, 11847, 234 https://tests.stockfishchess.org/tests/view/6a00899e9392f0c31721406c closes https://github.com/official-stockfish/Stockfish/pull/6816 No functional change
This commit is contained in:
committed by
Joost VandeVondele
parent
ffffe1bdb5
commit
1cebdafc14
+24
-8
@@ -272,8 +272,9 @@ bool Search::Worker::iterative_deepening() {
|
|||||||
Depth lastBestMoveDepth = 0;
|
Depth lastBestMoveDepth = 0;
|
||||||
|
|
||||||
Value alpha, beta;
|
Value alpha, beta;
|
||||||
Value bestValue = -VALUE_INFINITE;
|
Value bestValue = -VALUE_INFINITE;
|
||||||
Color us = rootPos.side_to_move();
|
Value lastIterationScore = -VALUE_INFINITE;
|
||||||
|
Color us = rootPos.side_to_move();
|
||||||
double timeReduction = 1, totBestMoveChanges = 0;
|
double timeReduction = 1, totBestMoveChanges = 0;
|
||||||
int delta, iterIdx = 0;
|
int delta, iterIdx = 0;
|
||||||
|
|
||||||
@@ -461,33 +462,48 @@ bool Search::Worker::iterative_deepening() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool forgottenMate = lastIterationScore != -VALUE_INFINITE
|
||||||
|
&& is_mate_or_mated(lastIterationScore)
|
||||||
|
&& (std::abs(rootMoves[0].score) < std::abs(lastIterationScore)
|
||||||
|
|| rootMoves[0].score_is_bound());
|
||||||
|
|
||||||
if (!threads.stop)
|
if (!threads.stop)
|
||||||
{
|
{
|
||||||
if (lastIterationPV.empty() || rootMoves[0].pv[0] != lastIterationPV[0])
|
if (lastIterationPV.empty() || rootMoves[0].pv[0] != lastIterationPV[0])
|
||||||
lastBestMoveDepth = rootDepth;
|
lastBestMoveDepth = rootDepth;
|
||||||
|
|
||||||
lastIterationPV = rootMoves[0].pv;
|
// Do not replace (shorter) mate scores from a previous iteration.
|
||||||
|
if (!forgottenMate)
|
||||||
|
{
|
||||||
|
lastIterationPV = rootMoves[0].pv;
|
||||||
|
lastIterationScore = rootMoves[0].score;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool abortedLossSearch =
|
||||||
|
threads.stop && !pvIdx && rootMoves[0].score != -VALUE_INFINITE
|
||||||
|
&& is_loss(rootMoves[0].score) && !rootMoves[0].score_is_bound();
|
||||||
|
|
||||||
// An exact mated-in/TB-loss score from an aborted search cannot be trusted: the
|
// An exact mated-in/TB-loss score from an aborted search cannot be trusted: the
|
||||||
// loss could be delayed or refuted upon exploring the remaining root-moves.
|
// loss could be delayed or refuted upon exploring the remaining root-moves.
|
||||||
// Thus here we roll back to the score from the previous iteration.
|
// Thus here we roll back to the score from the previous iteration.
|
||||||
else if (!pvIdx && rootMoves[0].score != -VALUE_INFINITE && is_loss(rootMoves[0].score)
|
// We do the same if a search has failed to recover a mate score that was found
|
||||||
&& !rootMoves[0].score_is_bound())
|
// in a previous iteration.
|
||||||
|
if (abortedLossSearch || (rootMoves[0].score != -VALUE_INFINITE && forgottenMate))
|
||||||
{
|
{
|
||||||
// Bring the last best move to the front for best thread selection.
|
|
||||||
if (!lastIterationPV.empty())
|
if (!lastIterationPV.empty())
|
||||||
{
|
{
|
||||||
Utility::move_to_front(rootMoves, [&lastPV = std::as_const(lastIterationPV)](
|
Utility::move_to_front(rootMoves, [&lastPV = std::as_const(lastIterationPV)](
|
||||||
const auto& rm) { return rm == lastPV[0]; });
|
const auto& rm) { return rm == lastPV[0]; });
|
||||||
rootMoves[0].pv = lastIterationPV;
|
rootMoves[0].pv = lastIterationPV;
|
||||||
rootMoves[0].score = rootMoves[0].uciScore = rootMoves[0].previousScore;
|
rootMoves[0].score = rootMoves[0].uciScore = lastIterationScore;
|
||||||
|
rootMoves[0].unset_bound_flags();
|
||||||
|
|
||||||
if (mainThread)
|
if (mainThread)
|
||||||
uciPvSent = false;
|
uciPvSent = false;
|
||||||
}
|
}
|
||||||
// For an aborted d1 search we label the loss score as a lower bound.
|
// For an aborted d1 search we label the loss score as a lower bound.
|
||||||
else
|
else if (abortedLossSearch)
|
||||||
rootMoves[0].scoreLowerbound = true;
|
rootMoves[0].scoreLowerbound = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user