From 88331add0d1220068f1bc1c0e1db88598425dafc Mon Sep 17 00:00:00 2001 From: Disservin Date: Sat, 13 Jan 2024 20:19:33 +0100 Subject: [PATCH] Remove the dependency on a Worker from evaluate Also remove dead code, `rootSimpleEval` is no longer used since the introduction of dual net. `iterBestValue` is also no longer used in evaluate and can be reduced to a local variable. closes https://github.com/official-stockfish/Stockfish/pull/4979 No functional change --- src/evaluate.cpp | 15 +++------------ src/evaluate.h | 8 ++------ src/search.cpp | 38 ++++++++++++++++++++------------------ src/search.h | 6 ++---- src/thread.cpp | 4 +--- src/uci.cpp | 2 +- 6 files changed, 29 insertions(+), 44 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 3e067e4c..45658798 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -35,7 +35,6 @@ #include "nnue/evaluate_nnue.h" #include "nnue/nnue_architecture.h" #include "position.h" -#include "search.h" #include "types.h" #include "uci.h" #include "ucioption.h" @@ -196,7 +195,7 @@ int Eval::simple_eval(const Position& pos, Color c) { // Evaluate is the evaluator for the outer world. It returns a static evaluation // of the position from the point of view of the side to move. -Value Eval::evaluate(const Position& pos, const Search::Worker& workerThread) { +Value Eval::evaluate(const Position& pos, int optimism) { assert(!pos.checkers()); @@ -217,8 +216,6 @@ Value Eval::evaluate(const Position& pos, const Search::Worker& workerThread) { Value nnue = smallNet ? NNUE::evaluate(pos, true, &nnueComplexity) : NNUE::evaluate(pos, true, &nnueComplexity); - int optimism = workerThread.optimism[stm]; - // Blend optimism and eval with nnue complexity and material imbalance optimism += optimism * (nnueComplexity + std::abs(simpleEval - nnue)) / 512; nnue -= nnue * (nnueComplexity + std::abs(simpleEval - nnue)) / 32768; @@ -240,17 +237,11 @@ Value Eval::evaluate(const Position& pos, const Search::Worker& workerThread) { // a string (suitable for outputting to stdout) that contains the detailed // descriptions and values of each evaluation term. Useful for debugging. // Trace scores are from white's point of view -std::string Eval::trace(Position& pos, Search::Worker& workerThread) { +std::string Eval::trace(Position& pos) { if (pos.checkers()) return "Final evaluation: none (in check)"; - // Reset any global variable used in eval - workerThread.iterBestValue = VALUE_ZERO; - workerThread.rootSimpleEval = VALUE_ZERO; - workerThread.optimism[WHITE] = VALUE_ZERO; - workerThread.optimism[BLACK] = VALUE_ZERO; - std::stringstream ss; ss << std::showpoint << std::noshowpos << std::fixed << std::setprecision(2); ss << '\n' << NNUE::trace(pos) << '\n'; @@ -262,7 +253,7 @@ std::string Eval::trace(Position& pos, Search::Worker& workerThread) { v = pos.side_to_move() == WHITE ? v : -v; ss << "NNUE evaluation " << 0.01 * UCI::to_cp(v) << " (white side)\n"; - v = evaluate(pos, workerThread); + v = evaluate(pos, VALUE_ZERO); v = pos.side_to_move() == WHITE ? v : -v; ss << "Final evaluation " << 0.01 * UCI::to_cp(v) << " (white side)"; ss << " [with scaled NNUE, ...]"; diff --git a/src/evaluate.h b/src/evaluate.h index 8a9d6fc7..729baa6b 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -29,16 +29,12 @@ namespace Stockfish { class Position; class OptionsMap; -namespace Search { -class Worker; -} - namespace Eval { -std::string trace(Position& pos, Search::Worker& workerThread); +std::string trace(Position& pos); int simple_eval(const Position& pos, Color c); -Value evaluate(const Position& pos, const Search::Worker& workerThread); +Value evaluate(const Position& pos, int optimism); // The default net name MUST follow the format nn-[SHA256 first 12 digits].nnue // for the build process (profile-build and fishtest) to work. Do not change the diff --git a/src/search.cpp b/src/search.cpp index 5530d125..b23740d8 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -280,7 +280,7 @@ void Search::Worker::iterative_deepening() { ss->pv = pv; - iterBestValue = -VALUE_INFINITE; + Value bestValue = -VALUE_INFINITE; if (mainThread) { @@ -357,7 +357,7 @@ void Search::Worker::iterative_deepening() { // for every four searchAgain steps (see issue #2717). Depth adjustedDepth = std::max(1, rootDepth - failedHighCnt - 3 * (searchAgainCounter + 1) / 4); - iterBestValue = search(rootPos, ss, alpha, beta, adjustedDepth, false); + bestValue = search(rootPos, ss, alpha, beta, adjustedDepth, false); // Bring the best move to the front. It is critical that sorting // is done with a stable algorithm because all the values but the @@ -375,7 +375,7 @@ void Search::Worker::iterative_deepening() { // When failing high/low give some update (without cluttering // the UI) before a re-search. - if (mainThread && multiPV == 1 && (iterBestValue <= alpha || iterBestValue >= beta) + if (mainThread && multiPV == 1 && (bestValue <= alpha || bestValue >= beta) && mainThread->tm.elapsed(threads.nodes_searched()) > 3000) sync_cout << UCI::pv(*this, mainThread->tm.elapsed(threads.nodes_searched()), threads.nodes_searched(), threads.tb_hits(), tt.hashfull(), @@ -384,18 +384,18 @@ void Search::Worker::iterative_deepening() { // In case of failing low/high increase aspiration window and // re-search, otherwise exit the loop. - if (iterBestValue <= alpha) + if (bestValue <= alpha) { beta = (alpha + beta) / 2; - alpha = std::max(iterBestValue - delta, -VALUE_INFINITE); + alpha = std::max(bestValue - delta, -VALUE_INFINITE); failedHighCnt = 0; if (mainThread) mainThread->stopOnPonderhit = false; } - else if (iterBestValue >= beta) + else if (bestValue >= beta) { - beta = std::min(iterBestValue + delta, int(VALUE_INFINITE)); + beta = std::min(bestValue + delta, int(VALUE_INFINITE)); ++failedHighCnt; } else @@ -428,8 +428,8 @@ void Search::Worker::iterative_deepening() { } // Have we found a "mate in x"? - if (limits.mate && iterBestValue >= VALUE_MATE_IN_MAX_PLY - && VALUE_MATE - iterBestValue <= 2 * limits.mate) + if (limits.mate && bestValue >= VALUE_MATE_IN_MAX_PLY + && VALUE_MATE - bestValue <= 2 * limits.mate) threads.stop = true; if (!mainThread) @@ -449,8 +449,8 @@ void Search::Worker::iterative_deepening() { // Do we have time for the next iteration? Can we stop searching now? if (limits.use_time_management() && !threads.stop && !mainThread->stopOnPonderhit) { - double fallingEval = (66 + 14 * (mainThread->bestPreviousAverageScore - iterBestValue) - + 6 * (mainThread->iterValue[iterIdx] - iterBestValue)) + double fallingEval = (66 + 14 * (mainThread->bestPreviousAverageScore - bestValue) + + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 616.6; fallingEval = std::clamp(fallingEval, 0.51, 1.51); @@ -483,7 +483,7 @@ void Search::Worker::iterative_deepening() { threads.increaseDepth = true; } - mainThread->iterValue[iterIdx] = iterBestValue; + mainThread->iterValue[iterIdx] = bestValue; iterIdx = (iterIdx + 1) & 3; } @@ -580,7 +580,7 @@ Value Search::Worker::search( // Step 2. Check for aborted search and immediate draw if (threads.stop.load(std::memory_order_relaxed) || pos.is_draw(ss->ply) || ss->ply >= MAX_PLY) - return (ss->ply >= MAX_PLY && !ss->inCheck) ? evaluate(pos, *thisThread) + return (ss->ply >= MAX_PLY && !ss->inCheck) ? evaluate(pos, thisThread->optimism[us]) : value_draw(thisThread->nodes); // Step 3. Mate distance pruning. Even if we mate at the next move our score @@ -734,7 +734,7 @@ Value Search::Worker::search( // Never assume anything about values stored in TT unadjustedStaticEval = ss->staticEval = eval = tte->eval(); if (eval == VALUE_NONE) - unadjustedStaticEval = ss->staticEval = eval = evaluate(pos, *thisThread); + unadjustedStaticEval = ss->staticEval = eval = evaluate(pos, thisThread->optimism[us]); else if (PvNode) Eval::NNUE::hint_common_parent_position(pos); @@ -752,7 +752,7 @@ Value Search::Worker::search( } else { - unadjustedStaticEval = ss->staticEval = eval = evaluate(pos, *thisThread); + unadjustedStaticEval = ss->staticEval = eval = evaluate(pos, thisThread->optimism[us]); Value newEval = ss->staticEval @@ -1470,7 +1470,8 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta, // Step 2. Check for an immediate draw or maximum ply reached if (pos.is_draw(ss->ply) || ss->ply >= MAX_PLY) - return (ss->ply >= MAX_PLY && !ss->inCheck) ? evaluate(pos, *thisThread) : VALUE_DRAW; + return (ss->ply >= MAX_PLY && !ss->inCheck) ? evaluate(pos, thisThread->optimism[us]) + : VALUE_DRAW; assert(0 <= ss->ply && ss->ply < MAX_PLY); @@ -1501,7 +1502,8 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta, { // Never assume anything about values stored in TT if ((unadjustedStaticEval = ss->staticEval = bestValue = tte->eval()) == VALUE_NONE) - unadjustedStaticEval = ss->staticEval = bestValue = evaluate(pos, *thisThread); + unadjustedStaticEval = ss->staticEval = bestValue = + evaluate(pos, thisThread->optimism[us]); Value newEval = ss->staticEval @@ -1521,7 +1523,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta, { // In case of null move search, use previous static eval with a different sign unadjustedStaticEval = ss->staticEval = bestValue = - (ss - 1)->currentMove != Move::null() ? evaluate(pos, *thisThread) + (ss - 1)->currentMove != Move::null() ? evaluate(pos, thisThread->optimism[us]) : -(ss - 1)->staticEval; Value newEval = diff --git a/src/search.h b/src/search.h index 90ed82b9..68c9f2aa 100644 --- a/src/search.h +++ b/src/search.h @@ -184,10 +184,6 @@ class Worker { bool is_mainthread() const { return thread_idx == 0; } - // Public because evaluate uses this - Value iterBestValue, optimism[COLOR_NB]; - Value rootSimpleEval; - // Public because they need to be updatable by the stats CounterMoveHistory counterMoves; ButterflyHistory mainHistory; @@ -226,6 +222,8 @@ class Worker { std::atomic nodes, tbHits, bestMoveChanges; int selDepth, nmpMinPly; + Value optimism[COLOR_NB]; + Position rootPos; StateInfo rootState; RootMoves rootMoves; diff --git a/src/thread.cpp b/src/thread.cpp index a512c0a5..9dc4446f 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -27,7 +27,6 @@ #include #include -#include "evaluate.h" #include "misc.h" #include "movegen.h" #include "search.h" @@ -205,8 +204,7 @@ void ThreadPool::start_thinking(const OptionsMap& options, th->worker->rootDepth = th->worker->completedDepth = 0; th->worker->rootMoves = rootMoves; th->worker->rootPos.set(pos.fen(), pos.is_chess960(), &th->worker->rootState); - th->worker->rootState = setupStates->back(); - th->worker->rootSimpleEval = Eval::simple_eval(pos, pos.side_to_move()); + th->worker->rootState = setupStates->back(); } main_thread()->start_searching(); diff --git a/src/uci.cpp b/src/uci.cpp index aa493c63..789f3454 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -270,7 +270,7 @@ void UCI::trace_eval(Position& pos) { Eval::NNUE::verify(options, evalFiles); - sync_cout << "\n" << Eval::trace(p, *threads.main_thread()->worker.get()) << sync_endl; + sync_cout << "\n" << Eval::trace(p) << sync_endl; } void UCI::search_clear() {