Skip to content

Commit

Permalink
Add functions to check for decisive scores
Browse files Browse the repository at this point in the history
No functional change.
Bench 840721
  • Loading branch information
Nonlinear2 committed Nov 22, 2024
1 parent 82b092c commit 5a25794
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 36 deletions.
2 changes: 1 addition & 1 deletion src/score.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ namespace Stockfish {
Score::Score(Value v, const Position& pos) {
assert(-VALUE_INFINITE < v && v < VALUE_INFINITE);

if (std::abs(v) < VALUE_TB_WIN_IN_MAX_PLY)
if (!is_decisive(v))
{
score = InternalUnits{UCIEngine::to_cp(v, pos)};
}
Expand Down
56 changes: 26 additions & 30 deletions src/search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ void Search::Worker::iterative_deepening() {
// if we would have had time to fully search other root-moves. Thus
// we suppress this output and below pick a proven score/PV for this
// thread (from the previous iteration).
&& !(threads.abortedSearch && rootMoves[0].uciScore <= VALUE_TB_LOSS_IN_MAX_PLY))
&& !(threads.abortedSearch && is_loss(rootMoves[0].uciScore)))
main_manager()->pv(*this, threads, tt, rootDepth);

if (threads.stop)
Expand All @@ -401,7 +401,7 @@ void Search::Worker::iterative_deepening() {
// We make sure not to pick an unproven mated-in score,
// in case this thread prematurely stopped search (aborted-search).
if (threads.abortedSearch && rootMoves[0].score != -VALUE_INFINITE
&& rootMoves[0].score <= VALUE_TB_LOSS_IN_MAX_PLY)
&& is_loss(rootMoves[0].score))
{
// Bring the last best move to the front for best thread selection.
Utility::move_to_front(rootMoves, [&lastBestPV = std::as_const(lastBestPV)](
Expand Down Expand Up @@ -782,7 +782,7 @@ Value Search::Worker::search(
if (eval < alpha - 469 - 307 * depth * depth)
{
value = qsearch<NonPV>(pos, ss, alpha - 1, alpha);
if (value < alpha && std::abs(value) < VALUE_TB_WIN_IN_MAX_PLY)
if (value < alpha && !is_decisive(value))
return value;
}

Expand All @@ -792,16 +792,15 @@ Value Search::Worker::search(
&& eval - futility_margin(depth, cutNode && !ss->ttHit, improving, opponentWorsening)
- (ss - 1)->statScore / 290
>= beta
&& eval >= beta && (!ttData.move || ttCapture) && beta > VALUE_TB_LOSS_IN_MAX_PLY
&& eval < VALUE_TB_WIN_IN_MAX_PLY)
&& eval >= beta && (!ttData.move || ttCapture) && !is_loss(beta) && !is_win(eval))
return beta + (eval - beta) / 3;

improving |= ss->staticEval >= beta + 100;

// Step 9. Null move search with verification search (~35 Elo)
if (cutNode && (ss - 1)->currentMove != Move::null() && eval >= beta
&& ss->staticEval >= beta - 21 * depth + 421 && !excludedMove && pos.non_pawn_material(us)
&& ss->ply >= thisThread->nmpMinPly && beta > VALUE_TB_LOSS_IN_MAX_PLY)
&& ss->ply >= thisThread->nmpMinPly && !is_loss(beta))
{
assert(eval - beta >= 0);

Expand All @@ -819,7 +818,7 @@ Value Search::Worker::search(
pos.undo_null_move();

// Do not return unproven mate or TB scores
if (nullValue >= beta && nullValue < VALUE_TB_WIN_IN_MAX_PLY)
if (nullValue >= beta && !is_win(nullValue))
{
if (thisThread->nmpMinPly || depth < 16)
return nullValue;
Expand Down Expand Up @@ -858,7 +857,7 @@ Value Search::Worker::search(
// returns a value much above beta, we can (almost) safely prune the previous move.
probCutBeta = beta + 187 - 53 * improving - 27 * opponentWorsening;
if (!PvNode && depth > 3
&& std::abs(beta) < VALUE_TB_WIN_IN_MAX_PLY
&& !is_decisive(beta)
// If value from transposition table is lower than probCutBeta, don't attempt
// probCut there and in further interactions with transposition table cutoff
// depth is set to depth - 3 because probCut search has depth set to depth - 4
Expand Down Expand Up @@ -916,8 +915,7 @@ Value Search::Worker::search(
// Save ProbCut data into transposition table
ttWriter.write(posKey, value_to_tt(value, ss->ply), ss->ttPv, BOUND_LOWER,
depth - 3, move, unadjustedStaticEval, tt.generation());
return std::abs(value) < VALUE_TB_WIN_IN_MAX_PLY ? value - (probCutBeta - beta)
: value;
return is_decisive(value) ? value : value - (probCutBeta - beta);
}
}

Expand All @@ -929,8 +927,7 @@ Value Search::Worker::search(
// Step 12. A small Probcut idea (~4 Elo)
probCutBeta = beta + 417;
if ((ttData.bound & BOUND_LOWER) && ttData.depth >= depth - 4 && ttData.value >= probCutBeta
&& std::abs(beta) < VALUE_TB_WIN_IN_MAX_PLY
&& std::abs(ttData.value) < VALUE_TB_WIN_IN_MAX_PLY)
&& !is_decisive(beta) && !is_decisive(ttData.value))
return probCutBeta;

const PieceToHistory* contHist[] = {(ss - 1)->continuationHistory,
Expand Down Expand Up @@ -993,7 +990,7 @@ Value Search::Worker::search(

// Step 14. Pruning at shallow depth (~120 Elo).
// Depth conditions are important for mate finding.
if (!rootNode && pos.non_pawn_material(us) && bestValue > VALUE_TB_LOSS_IN_MAX_PLY)
if (!rootNode && pos.non_pawn_material(us) && !is_loss(bestValue))
{
// Skip quiet moves if movecount exceeds our FutilityMoveCount threshold (~8 Elo)
if (moveCount >= futility_move_count(improving, depth))
Expand Down Expand Up @@ -1043,8 +1040,7 @@ Value Search::Worker::search(
// Futility pruning: parent node (~13 Elo)
if (!ss->inCheck && lmrDepth < 12 && futilityValue <= alpha)
{
if (bestValue <= futilityValue && std::abs(bestValue) < VALUE_TB_WIN_IN_MAX_PLY
&& futilityValue < VALUE_TB_WIN_IN_MAX_PLY)
if (bestValue <= futilityValue && !is_decisive(bestValue) && !is_win(futilityValue))
bestValue = futilityValue;
continue;
}
Expand Down Expand Up @@ -1076,7 +1072,7 @@ Value Search::Worker::search(

if (!rootNode && move == ttData.move && !excludedMove
&& depth >= 4 - (thisThread->completedDepth > 33) + ss->ttPv
&& std::abs(ttData.value) < VALUE_TB_WIN_IN_MAX_PLY && (ttData.bound & BOUND_LOWER)
&& !is_decisive(ttData.value) && (ttData.bound & BOUND_LOWER)
&& ttData.depth >= depth - 3)
{
Value singularBeta = ttData.value - (56 + 79 * (ss->ttPv && !PvNode)) * depth / 64;
Expand Down Expand Up @@ -1104,7 +1100,7 @@ Value Search::Worker::search(
// over the original beta, we assume this expected cut-node is not
// singular (multiple moves fail high), and we can prune the whole
// subtree by returning a softbound.
else if (value >= beta && std::abs(value) < VALUE_TB_WIN_IN_MAX_PLY)
else if (value >= beta && !is_decisive(value))
return value;

// Negative extensions
Expand Down Expand Up @@ -1318,7 +1314,7 @@ Value Search::Worker::search(
// promote it to bestmove by pretending it just exceeds alpha (but not beta).
int inc =
(value == bestValue && (int(nodes) & 15) == 0 && ss->ply + 2 >= thisThread->rootDepth
&& std::abs(value) + 1 < VALUE_TB_WIN_IN_MAX_PLY);
&& !is_win(std::abs(value) + 1));

if (value + inc > bestValue)
{
Expand All @@ -1340,7 +1336,7 @@ Value Search::Worker::search(
else
{
// Reduce other moves if we have found at least one score improvement (~2 Elo)
if (depth > 2 && depth < 14 && std::abs(value) < VALUE_TB_WIN_IN_MAX_PLY)
if (depth > 2 && depth < 14 && !is_decisive(value))
depth -= 2;

assert(depth > 0);
Expand Down Expand Up @@ -1368,8 +1364,8 @@ Value Search::Worker::search(
assert(moveCount || !ss->inCheck || excludedMove || !MoveList<LEGAL>(pos).size());

// Adjust best value for fail high cases at non-pv nodes
if (!PvNode && bestValue >= beta && std::abs(bestValue) < VALUE_TB_WIN_IN_MAX_PLY
&& std::abs(beta) < VALUE_TB_WIN_IN_MAX_PLY && std::abs(alpha) < VALUE_TB_WIN_IN_MAX_PLY)
if (!PvNode && bestValue >= beta && !is_decisive(bestValue)
&& !is_decisive(beta) && !is_decisive(alpha))
bestValue = (bestValue * depth + beta) / (depth + 1);

if (!moveCount)
Expand Down Expand Up @@ -1542,7 +1538,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta)
to_corrected_static_eval(unadjustedStaticEval, *thisThread, pos, ss);

// ttValue can be used as a better position evaluation (~13 Elo)
if (std::abs(ttData.value) < VALUE_TB_WIN_IN_MAX_PLY
if (!is_decisive(ttData.value)
&& (ttData.bound & (ttData.value > bestValue ? BOUND_LOWER : BOUND_UPPER)))
bestValue = ttData.value;
}
Expand All @@ -1560,7 +1556,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta)
// Stand pat. Return immediately if static value is at least beta
if (bestValue >= beta)
{
if (std::abs(bestValue) < VALUE_TB_WIN_IN_MAX_PLY)
if (!is_decisive(bestValue))
bestValue = (bestValue + beta) / 2;
if (!ss->ttHit)
ttWriter.write(posKey, value_to_tt(bestValue, ss->ply), false, BOUND_LOWER,
Expand Down Expand Up @@ -1601,10 +1597,10 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta)
moveCount++;

// Step 6. Pruning
if (bestValue > VALUE_TB_LOSS_IN_MAX_PLY && pos.non_pawn_material(us))
if (!is_loss(bestValue) && pos.non_pawn_material(us))
{
// Futility pruning and moveCount pruning (~10 Elo)
if (!givesCheck && move.to_sq() != prevSq && futilityBase > VALUE_TB_LOSS_IN_MAX_PLY
if (!givesCheck && move.to_sq() != prevSq && !is_loss(futilityBase)
&& move.type_of() != PROMOTION)
{
if (moveCount > 2)
Expand Down Expand Up @@ -1691,7 +1687,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta)
return mated_in(ss->ply); // Plies to mate from the root
}

if (std::abs(bestValue) < VALUE_TB_WIN_IN_MAX_PLY && bestValue >= beta)
if (!is_decisive(bestValue) && bestValue >= beta)
bestValue = (3 * bestValue + beta) / 4;

// Save gathered info in transposition table. The static evaluation
Expand Down Expand Up @@ -1732,7 +1728,7 @@ namespace {
Value value_to_tt(Value v, int ply) {

assert(v != VALUE_NONE);
return v >= VALUE_TB_WIN_IN_MAX_PLY ? v + ply : v <= VALUE_TB_LOSS_IN_MAX_PLY ? v - ply : v;
return is_win(v) ? v + ply : is_loss(v) ? v - ply : v;
}


Expand All @@ -1747,7 +1743,7 @@ Value value_from_tt(Value v, int ply, int r50c) {
return VALUE_NONE;

// handle TB win or better
if (v >= VALUE_TB_WIN_IN_MAX_PLY)
if (is_win(v))
{
// Downgrade a potentially false mate score
if (v >= VALUE_MATE_IN_MAX_PLY && VALUE_MATE - v > 100 - r50c)
Expand All @@ -1761,7 +1757,7 @@ Value value_from_tt(Value v, int ply, int r50c) {
}

// handle TB loss or worse
if (v <= VALUE_TB_LOSS_IN_MAX_PLY)
if (is_loss(v))
{
// Downgrade a potentially false mate score.
if (v <= VALUE_MATED_IN_MAX_PLY && VALUE_MATE + v > 100 - r50c)
Expand Down Expand Up @@ -2100,7 +2096,7 @@ void SearchManager::pv(Search::Worker& worker,
bool isExact = i != pvIdx || tb || !updated; // tablebase- and previous-scores are exact

// Potentially correct and extend the PV, and in exceptional cases v
if (std::abs(v) >= VALUE_TB_WIN_IN_MAX_PLY && std::abs(v) < VALUE_MATE_IN_MAX_PLY
if (is_decisive(v) && std::abs(v) < VALUE_MATE_IN_MAX_PLY
&& ((!rootMoves[i].scoreLowerbound && !rootMoves[i].scoreUpperbound) || isExact))
syzygy_extend_pv(worker.options, worker.limits, pos, rootMoves[i], v);

Expand Down
10 changes: 5 additions & 5 deletions src/thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,13 +329,13 @@ Thread* ThreadPool::get_best_thread() const {
const auto bestThreadMoveVote = votes[bestThreadPV[0]];
const auto newThreadMoveVote = votes[newThreadPV[0]];

const bool bestThreadInProvenWin = bestThreadScore >= VALUE_TB_WIN_IN_MAX_PLY;
const bool newThreadInProvenWin = newThreadScore >= VALUE_TB_WIN_IN_MAX_PLY;
const bool bestThreadInProvenWin = is_win(bestThreadScore);
const bool newThreadInProvenWin = is_win(newThreadScore);

const bool bestThreadInProvenLoss =
bestThreadScore != -VALUE_INFINITE && bestThreadScore <= VALUE_TB_LOSS_IN_MAX_PLY;
bestThreadScore != -VALUE_INFINITE && is_loss(bestThreadScore);
const bool newThreadInProvenLoss =
newThreadScore != -VALUE_INFINITE && newThreadScore <= VALUE_TB_LOSS_IN_MAX_PLY;
newThreadScore != -VALUE_INFINITE && is_loss(newThreadScore);

// We make sure not to pick a thread with truncated principal variation
const bool betterVotingValue =
Expand All @@ -355,7 +355,7 @@ Thread* ThreadPool::get_best_thread() const {
bestThread = th.get();
}
else if (newThreadInProvenWin || newThreadInProvenLoss
|| (newThreadScore > VALUE_TB_LOSS_IN_MAX_PLY
|| (!is_loss(newThreadScore)
&& (newThreadMoveVote > bestThreadMoveVote
|| (newThreadMoveVote == bestThreadMoveVote && betterVotingValue))))
bestThread = th.get();
Expand Down
14 changes: 14 additions & 0 deletions src/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,20 @@ constexpr Value VALUE_TB = VALUE_MATE_IN_MAX_PLY - 1;
constexpr Value VALUE_TB_WIN_IN_MAX_PLY = VALUE_TB - MAX_PLY;
constexpr Value VALUE_TB_LOSS_IN_MAX_PLY = -VALUE_TB_WIN_IN_MAX_PLY;


constexpr bool is_win(Value value) {
assert(value != VALUE_NONE);
return value >= VALUE_TB_WIN_IN_MAX_PLY;
}

constexpr bool is_loss(Value value) {
assert(value != VALUE_NONE);
return value <= VALUE_TB_LOSS_IN_MAX_PLY;
}

// mates, TB scores, infinite values and VALUE_NONE are considered decisive
constexpr bool is_decisive(Value value) { return value == VALUE_NONE || is_win(value) || is_loss(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.
Expand Down

0 comments on commit 5a25794

Please sign in to comment.