diff --git a/src/search.cpp b/src/search.cpp index 57fc20c73..07c0c41ea 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -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; diff --git a/src/search.h b/src/search.h index 23f6a2b3d..2f30af9d8 100644 --- a/src/search.h +++ b/src/search.h @@ -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 { diff --git a/src/thread.cpp b/src/thread.cpp index 6c3c6487b..311f719ef 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -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(); diff --git a/src/types.h b/src/types.h index 918e5d86e..16acf5438 100644 --- a/src/types.h +++ b/src/types.h @@ -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.