mirror of
https://github.com/official-stockfish/Stockfish.git
synced 2026-07-22 12:47:08 +00:00
[refactor] Add helper functions and simplify thread selection
I found these changes useful and natural when working on a patch to improve mate reporting. I can revert some of the changes if maintainers would prefer that. E.g. I am not sure whether `unset_bound_flags()` is worth defining. closes https://github.com/official-stockfish/Stockfish/pull/6785 No functional change
This commit is contained in:
committed by
Joost VandeVondele
parent
6127bf711e
commit
fcbd160d26
+10
-12
@@ -441,8 +441,8 @@ bool Search::Worker::iterative_deepening() {
|
||||
&& rootMoves[pvIdx].previousScore < rootMoves[pvIdx - 1].score)
|
||||
? rootMoves[pvIdx].previousScore
|
||||
: rootMoves[pvIdx - 1].score;
|
||||
rootMoves[pvIdx].previousScore = -VALUE_INFINITE;
|
||||
rootMoves[pvIdx].scoreLowerbound = rootMoves[pvIdx].scoreUpperbound = false;
|
||||
rootMoves[pvIdx].previousScore = -VALUE_INFINITE;
|
||||
rootMoves[pvIdx].unset_bound_flags();
|
||||
rootMoves[pvIdx].pv.resize(1);
|
||||
}
|
||||
|
||||
@@ -471,7 +471,7 @@ bool Search::Worker::iterative_deepening() {
|
||||
// loss could be delayed or refuted upon exploring the remaining root-moves.
|
||||
// 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)
|
||||
&& !rootMoves[0].scoreLowerbound && !rootMoves[0].scoreUpperbound)
|
||||
&& !rootMoves[0].score_is_bound())
|
||||
{
|
||||
// Bring the last best move to the front for best thread selection.
|
||||
if (!lastIterationPV.empty())
|
||||
@@ -491,9 +491,8 @@ bool Search::Worker::iterative_deepening() {
|
||||
|
||||
// Have we found a "mate in x" after a completed iteration?
|
||||
if (limits.mate && !threads.stop
|
||||
&& ((rootMoves[0].score >= VALUE_MATE_IN_MAX_PLY
|
||||
&& VALUE_MATE - rootMoves[0].score <= 2 * limits.mate)
|
||||
|| (rootMoves[0].score <= VALUE_MATED_IN_MAX_PLY
|
||||
&& ((is_mate(rootMoves[0].score) && VALUE_MATE - rootMoves[0].score <= 2 * limits.mate)
|
||||
|| (is_mated(rootMoves[0].score)
|
||||
&& VALUE_MATE + rootMoves[0].score <= 2 * limits.mate)))
|
||||
threads.stop = true;
|
||||
|
||||
@@ -1357,7 +1356,7 @@ moves_loop: // When in check, search starts here
|
||||
{
|
||||
rm.score = rm.uciScore = value;
|
||||
rm.selDepth = selDepth;
|
||||
rm.scoreLowerbound = rm.scoreUpperbound = false;
|
||||
rm.unset_bound_flags();
|
||||
|
||||
if (value >= beta)
|
||||
{
|
||||
@@ -1810,7 +1809,7 @@ Value value_from_tt(Value v, int ply, int r50c) {
|
||||
if (is_win(v))
|
||||
{
|
||||
// Downgrade a potentially false mate score
|
||||
if (v >= VALUE_MATE_IN_MAX_PLY && VALUE_MATE - v > 100 - r50c)
|
||||
if (is_mate(v) && VALUE_MATE - v > 100 - r50c)
|
||||
return VALUE_TB_WIN_IN_MAX_PLY - 1;
|
||||
|
||||
// Downgrade a potentially false TB score.
|
||||
@@ -1824,7 +1823,7 @@ Value value_from_tt(Value v, int ply, int r50c) {
|
||||
if (is_loss(v))
|
||||
{
|
||||
// Downgrade a potentially false mate score.
|
||||
if (v <= VALUE_MATED_IN_MAX_PLY && VALUE_MATE + v > 100 - r50c)
|
||||
if (is_mated(v) && VALUE_MATE + v > 100 - r50c)
|
||||
return VALUE_TB_LOSS_IN_MAX_PLY + 1;
|
||||
|
||||
// Downgrade a potentially false TB score.
|
||||
@@ -2158,13 +2157,12 @@ void SearchManager::pv(Search::Worker& worker,
|
||||
if (v == -VALUE_INFINITE)
|
||||
v = VALUE_ZERO;
|
||||
|
||||
bool isTBScore = worker.tbConfig.rootInTB && std::abs(v) <= VALUE_TB;
|
||||
bool isTBScore = worker.tbConfig.rootInTB && !is_mate_or_mated(v);
|
||||
v = isTBScore ? rootMoves[i].tbScore : v;
|
||||
|
||||
// Potentially correct and extend the PV, and in exceptional cases v.
|
||||
// Bound flags indicate an unreliable PV, also when we usePreviousScore.
|
||||
if (is_decisive(v) && std::abs(v) < VALUE_MATE_IN_MAX_PLY
|
||||
&& ((!rootMoves[i].scoreLowerbound && !rootMoves[i].scoreUpperbound) || isTBScore))
|
||||
if (is_decisive(v) && !is_mate_or_mated(v) && (!rootMoves[i].score_is_bound() || isTBScore))
|
||||
syzygy_extend_pv(worker.options, worker.limits, pos, rootMoves[i], v);
|
||||
|
||||
std::string pv;
|
||||
|
||||
@@ -128,6 +128,8 @@ struct RootMove {
|
||||
|
||||
explicit RootMove(Move m) { pv.push_back(m); }
|
||||
bool extract_ponder_from_tt(const TranspositionTable& tt, Position& pos);
|
||||
bool score_is_bound() const { return scoreLowerbound || scoreUpperbound; }
|
||||
void unset_bound_flags() { scoreLowerbound = scoreUpperbound = false; }
|
||||
bool operator==(const Move& m) const { return pv[0] == m; }
|
||||
// Sort in descending order
|
||||
bool operator<(const RootMove& m) const {
|
||||
|
||||
+16
-21
@@ -366,45 +366,40 @@ Thread* ThreadPool::get_best_thread() const {
|
||||
for (auto&& th : threads)
|
||||
votes[th->worker->rootMoves[0].pv[0]] += thread_voting_value(th.get());
|
||||
|
||||
auto has_bound = [](const Thread* th) {
|
||||
return th->worker->rootMoves[0].scoreLowerbound || th->worker->rootMoves[0].scoreUpperbound;
|
||||
};
|
||||
|
||||
for (auto&& th : threads)
|
||||
{
|
||||
const auto bestThreadScore = bestThread->worker->rootMoves[0].score;
|
||||
const auto newThreadScore = th->worker->rootMoves[0].score;
|
||||
const auto& bestThreadMove = bestThread->worker->rootMoves[0];
|
||||
const auto& newThreadMove = th->worker->rootMoves[0];
|
||||
|
||||
const auto& bestThreadPV = bestThread->worker->rootMoves[0].pv;
|
||||
const auto& newThreadPV = th->worker->rootMoves[0].pv;
|
||||
|
||||
const auto bestThreadMoveVote = votes[bestThreadPV[0]];
|
||||
const auto newThreadMoveVote = votes[newThreadPV[0]];
|
||||
const auto bestThreadMoveVote = votes[bestThreadMove.pv[0]];
|
||||
const auto newThreadMoveVote = votes[newThreadMove.pv[0]];
|
||||
|
||||
// Aborted (d1) searches may lead to inexact win (or loss) scores.
|
||||
const bool bestThreadDecisive = bestThreadScore != -VALUE_INFINITE
|
||||
&& is_decisive(bestThreadScore) && !has_bound(bestThread);
|
||||
const bool newThreadDecisive =
|
||||
newThreadScore != -VALUE_INFINITE && is_decisive(newThreadScore) && !has_bound(th.get());
|
||||
const bool bestThreadDecisive = bestThreadMove.score != -VALUE_INFINITE
|
||||
&& is_decisive(bestThreadMove.score)
|
||||
&& !bestThreadMove.score_is_bound();
|
||||
const bool newThreadDecisive = newThreadMove.score != -VALUE_INFINITE
|
||||
&& is_decisive(newThreadMove.score)
|
||||
&& !newThreadMove.score_is_bound();
|
||||
|
||||
// We make sure not to pick a thread with a truncated principal variation.
|
||||
const bool betterVotingValue =
|
||||
thread_voting_value(th.get()) * int(newThreadPV.size() > 2)
|
||||
> thread_voting_value(bestThread) * int(bestThreadPV.size() > 2);
|
||||
thread_voting_value(th.get()) * int(newThreadMove.pv.size() > 2)
|
||||
> thread_voting_value(bestThread) * int(bestThreadMove.pv.size() > 2);
|
||||
|
||||
if (bestThreadDecisive)
|
||||
{
|
||||
// Make sure we pick the shortest mate / TB conversion.
|
||||
if (newThreadDecisive && std::abs(newThreadScore) > std::abs(bestThreadScore))
|
||||
if (newThreadDecisive && std::abs(newThreadMove.score) > std::abs(bestThreadMove.score))
|
||||
{
|
||||
assert((is_win(bestThreadScore) && is_win(newThreadScore))
|
||||
|| (is_loss(bestThreadScore) && is_loss(newThreadScore)));
|
||||
assert((is_win(bestThreadMove.score) && is_win(newThreadMove.score))
|
||||
|| (is_loss(bestThreadMove.score) && is_loss(newThreadMove.score)));
|
||||
|
||||
bestThread = th.get();
|
||||
}
|
||||
}
|
||||
else if (newThreadDecisive
|
||||
|| (!is_loss(newThreadScore)
|
||||
|| (!is_loss(newThreadMove.score)
|
||||
&& (newThreadMoveVote > bestThreadMoveVote
|
||||
|| (newThreadMoveVote == bestThreadMoveVote && betterVotingValue))))
|
||||
bestThread = th.get();
|
||||
|
||||
+12
@@ -178,6 +178,18 @@ constexpr bool is_loss(Value value) {
|
||||
|
||||
constexpr bool is_decisive(Value value) { return is_win(value) || is_loss(value); }
|
||||
|
||||
constexpr bool is_mate(Value value) {
|
||||
assert(is_valid(value));
|
||||
return value >= VALUE_MATE_IN_MAX_PLY;
|
||||
}
|
||||
|
||||
constexpr bool is_mated(Value value) {
|
||||
assert(is_valid(value));
|
||||
return value <= VALUE_MATED_IN_MAX_PLY;
|
||||
}
|
||||
|
||||
constexpr bool is_mate_or_mated(Value value) { return is_mate(value) || is_mated(value); }
|
||||
|
||||
// In the code, we make the assumption that these values
|
||||
// are such that non_pawn_material() can be used to uniquely
|
||||
// identify the material on the board.
|
||||
|
||||
Reference in New Issue
Block a user