From 3da33eff0afdd2ae02e2c8b942ec95d31f723f75 Mon Sep 17 00:00:00 2001 From: Alexander Lyashuk Date: Wed, 5 Feb 2025 23:24:54 +0100 Subject: [PATCH] Make ValueHead a separate search algorithm. --- src/chess/callbacks.h | 14 +++--- src/chess/position.h | 2 + src/engine_classic.cc | 78 ------------------------------- src/search/instamove/instamove.cc | 77 ++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 85 deletions(-) diff --git a/src/chess/callbacks.h b/src/chess/callbacks.h index 7e28d271b1..6c9d724a81 100644 --- a/src/chess/callbacks.h +++ b/src/chess/callbacks.h @@ -68,24 +68,24 @@ struct ThinkingInfo { // Hash fullness * 1000 int hashfull = -1; // Moves to mate. - std::optional mate; + std::optional mate = std::nullopt; // Win in centipawns. - std::optional score; + std::optional score = std::nullopt; // Win/Draw/Lose probability * 1000. struct WDL { int w; int d; int l; }; - std::optional wdl; + std::optional wdl = std::nullopt; // Number of successful TB probes (not the same as playouts ending in TB hit). int tb_hits = -1; // Best line found. Moves are from perspective of white player. - std::vector pv; + std::vector pv = {}; // Multipv index. int multipv = -1; // Freeform comment. - std::string comment; + std::string comment = ""; // Those are extensions and not really UCI protocol. // 1 if it's "player1", 2 if it's "player2" @@ -93,9 +93,9 @@ struct ThinkingInfo { // Index of the game in the tournament (0-based). int game_id = -1; // The color of the player, if known. - std::optional is_black; + std::optional is_black = std::nullopt; // Moves left - std::optional moves_left; + std::optional moves_left = std::nullopt; }; // Is sent when a single game is finished. diff --git a/src/chess/position.h b/src/chess/position.h index dc679606fd..638314232e 100644 --- a/src/chess/position.h +++ b/src/chess/position.h @@ -98,6 +98,8 @@ class PositionHistory { PositionHistory() = default; PositionHistory(const PositionHistory& other) = default; PositionHistory(PositionHistory&& other) = default; + PositionHistory(std::span positions) + : positions_(positions.begin(), positions.end()) {} PositionHistory& operator=(const PositionHistory& other) = default; PositionHistory& operator=(PositionHistory&& other) = default; diff --git a/src/engine_classic.cc b/src/engine_classic.cc index 28dc99a980..f48fe4a04f 100644 --- a/src/engine_classic.cc +++ b/src/engine_classic.cc @@ -61,11 +61,6 @@ const OptionId kStrictUciTiming{"strict-uci-timing", "StrictTiming", "The UCI host compensates for lag, waits for " "the 'readyok' reply before sending 'go' and " "only then starts timing."}; -const OptionId kValueOnly{ - "value-only", "ValueOnly", - "In value only mode all search parameters are ignored and the position is " - "evaluated by getting the valuation of every child position and choosing " - "the worst for the opponent."}; const OptionId kClearTree{"", "ClearTree", "Clear the tree before the next search."}; @@ -123,7 +118,6 @@ void EngineClassic::PopulateOptions(OptionsParser* options) { options->Add(kStrictUciTiming) = false; options->HideOption(kStrictUciTiming); - options->Add(kValueOnly) = false; options->Add(kClearTree); options->HideOption(kClearTree); } @@ -265,74 +259,6 @@ class PonderResponseTransformer : public TransformingUciResponder { std::string ponder_move_; }; -void ValueOnlyGo(classic::NodeTree* tree, Network* network, - const OptionsDict& options, - std::unique_ptr responder) { - auto input_format = network->GetCapabilities().input_format; - - const auto& board = tree->GetPositionHistory().Last().GetBoard(); - auto legal_moves = board.GenerateLegalMoves(); - tree->GetCurrentHead()->CreateEdges(legal_moves); - PositionHistory history = tree->GetPositionHistory(); - std::vector planes; - for (auto edge : tree->GetCurrentHead()->Edges()) { - history.Append(edge.GetMove()); - if (history.ComputeGameResult() == GameResult::UNDECIDED) { - planes.emplace_back(EncodePositionForNN( - input_format, history, 8, FillEmptyHistory::FEN_ONLY, nullptr)); - } - history.Pop(); - } - - std::vector comp_q; - int batch_size = options.Get(classic::SearchParams::kMiniBatchSizeId); - if (batch_size == 0) batch_size = network->GetMiniBatchSize(); - - for (size_t i = 0; i < planes.size(); i += batch_size) { - auto comp = network->NewComputation(); - for (int j = 0; j < batch_size; j++) { - comp->AddInput(std::move(planes[i + j])); - if (i + j + 1 == planes.size()) break; - } - comp->ComputeBlocking(); - - for (int j = 0; j < batch_size; j++) comp_q.push_back(comp->GetQVal(j)); - } - - Move best; - int comp_idx = 0; - float max_q = std::numeric_limits::lowest(); - for (auto edge : tree->GetCurrentHead()->Edges()) { - history.Append(edge.GetMove()); - auto result = history.ComputeGameResult(); - float q = -1; - if (result == GameResult::UNDECIDED) { - // NN eval is for side to move perspective - so if its good, its bad for - // us. - q = -comp_q[comp_idx]; - comp_idx++; - } else if (result == GameResult::DRAW) { - q = 0; - } else { - // A legal move to a non-drawn terminal without tablebases must be a - // win. - q = 1; - } - if (q >= max_q) { - max_q = q; - best = edge.GetMove(tree->GetPositionHistory().IsBlackToMove()); - } - history.Pop(); - } - std::vector infos; - ThinkingInfo thinking; - thinking.depth = 1; - infos.push_back(thinking); - responder->OutputThinkingInfo(&infos); - BestMoveInfo info(best); - responder->OutputBestMove(&info); -} - } // namespace void EngineClassic::Go(const GoParams& params) { @@ -374,10 +300,6 @@ void EngineClassic::Go(const GoParams& params) { // Strip movesleft information from the response. responder = std::make_unique(std::move(responder)); } - if (options_.Get(kValueOnly)) { - ValueOnlyGo(tree_.get(), network_.get(), options_, std::move(responder)); - return; - } if (options_.Get