X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=b39bc1764dbda697e8a4d19985abd435a8f3c61c;hp=218ce1aa2ec577962279cb3377429c5519968f1d;hb=5b35c149e833e365c2afb8039ca5c658abc53081;hpb=1e7c6fc76163336c3e642d33d46c802a39044bab diff --git a/src/search.cpp b/src/search.cpp index 218ce1aa..b39bc176 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -49,7 +49,7 @@ namespace { const bool FakeSplit = false; // Different node types, used as template parameter - enum NodeType { Root, PV, NonPV, SplitPointPV, SplitPointNonPV }; + enum NodeType { Root, PV, NonPV, SplitPointRoot, SplitPointPV, SplitPointNonPV }; // RootMove struct is used for moves at the root of the tree. For each root // move, we store a score, a node count, and a PV (really a refutation @@ -216,14 +216,14 @@ namespace { // MovePickerExt template class extends MovePicker and allows to choose at compile // time the proper moves source according to the type of node. In the default case // we simply create and use a standard MovePicker object. - template struct MovePickerExt : public MovePicker { + template struct MovePickerExt : public MovePicker { MovePickerExt(const Position& p, Move ttm, Depth d, const History& h, SearchStack* ss, Value b) : MovePicker(p, ttm, d, h, ss, b) {} }; // In case of a SpNode we use split point's shared MovePicker object as moves source - template<> struct MovePickerExt : public MovePicker { + template<> struct MovePickerExt : public MovePicker { MovePickerExt(const Position& p, Move ttm, Depth d, const History& h, SearchStack* ss, Value b) : MovePicker(p, ttm, d, h, ss, b), mp(ss->sp->mp) {} @@ -232,12 +232,6 @@ namespace { MovePicker* mp; }; - template<> struct MovePickerExt : public MovePickerExt { - - MovePickerExt(const Position& p, Move ttm, Depth d, const History& h, SearchStack* ss, Value b) - : MovePickerExt(p, ttm, d, h, ss, b) {} - }; - // Overload operator<<() to make it easier to print moves in a coordinate // notation compatible with UCI protocol. std::ostream& operator<<(std::ostream& os, Move m) { @@ -566,7 +560,8 @@ namespace { // Start with a small aspiration window and, in case of fail high/low, // research with bigger window until not failing high/low anymore. do { - // Search starting from ss+1 to allow calling update_gains() + // Search starting from ss+1 to allow referencing (ss-1). This is + // needed by update_gains() and ss copy when splitting at Root. value = search(pos, ss+1, alpha, beta, depth * ONE_PLY); // It is critical that sorting is done with a stable algorithm @@ -699,9 +694,9 @@ namespace { template Value search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth) { - const bool PvNode = (NT == PV || NT == Root || NT == SplitPointPV); - const bool SpNode = (NT == SplitPointPV || NT == SplitPointNonPV); - const bool RootNode = (NT == Root); + const bool PvNode = (NT == PV || NT == Root || NT == SplitPointPV || NT == SplitPointRoot); + const bool SpNode = (NT == SplitPointPV || NT == SplitPointNonPV || NT == SplitPointRoot); + const bool RootNode = (NT == Root || NT == SplitPointRoot); assert(alpha >= -VALUE_INFINITE && alpha <= VALUE_INFINITE); assert(beta > alpha && beta <= VALUE_INFINITE); @@ -946,7 +941,7 @@ namespace { split_point_start: // At split points actual search starts from here // Initialize a MovePicker object for the current position - MovePickerExt mp(pos, ttMove, depth, H, ss, PvNode ? -VALUE_INFINITE : beta); + MovePickerExt mp(pos, ttMove, depth, H, ss, PvNode ? -VALUE_INFINITE : beta); CheckInfo ci(pos); ss->bestMove = MOVE_NONE; futilityBase = ss->eval + ss->evalMargin; @@ -1002,14 +997,14 @@ split_point_start: // At split points actual search starts from here // If it's time to send nodes info, do it here where we have the // correct accumulated node counts searched by each thread. - if (SendSearchedNodes) + if (!SpNode && SendSearchedNodes) { SendSearchedNodes = false; cout << "info" << speed_to_uci(pos.nodes_searched()) << endl; } // For long searches send current move info to GUI - if (current_search_time() > 2000) + if (pos.thread() == 0 && current_search_time() > 2000) cout << "info" << depth_to_uci(depth) << " currmove " << move << " currmovenumber " << moveCount + MultiPVIteration << endl; @@ -1176,36 +1171,12 @@ split_point_start: // At split points actual search starts from here alpha = sp->alpha; } - if (value > bestValue) - { - bestValue = value; - ss->bestMove = move; - - if ( !RootNode - && PvNode - && value > alpha - && value < beta) // We want always alpha < beta - alpha = value; - - if (SpNode && !thread.cutoff_occurred()) - { - sp->bestValue = value; - sp->ss->bestMove = move; - sp->alpha = alpha; - sp->is_betaCutoff = (value >= beta); - } - } - - if (RootNode) + // Finished searching the move. If StopRequest is true, the search + // was aborted because the user interrupted the search or because we + // ran out of time. In this case, the return value of the search cannot + // be trusted, and we don't update the best move and/or PV. + if (RootNode && !StopRequest) { - // Finished searching the move. If StopRequest is true, the search - // was aborted because the user interrupted the search or because we - // ran out of time. In this case, the return value of the search cannot - // be trusted, and we break out of the loop without updating the best - // move and/or PV. - if (StopRequest) - break; - // Remember searched nodes counts for this move RootMove* rm = Rml.find(move); rm->nodes += pos.nodes_searched() - nodes; @@ -1222,10 +1193,6 @@ split_point_start: // At split points actual search starts from here // the best move changes frequently, we allocate some more time. if (!isPvMove && MultiPV == 1) Rml.bestMoveChanges++; - - // Update alpha - if (value > alpha) - alpha = value; } else // All other moves but the PV are set to the lowest value, this @@ -1235,16 +1202,34 @@ split_point_start: // At split points actual search starts from here } // RootNode + if (value > bestValue) + { + bestValue = value; + ss->bestMove = move; + + if ( PvNode + && value > alpha + && value < beta) // We want always alpha < beta + alpha = value; + + if (SpNode && !thread.cutoff_occurred()) + { + sp->bestValue = value; + sp->ss->bestMove = move; + sp->alpha = alpha; + sp->is_betaCutoff = (value >= beta); + } + } + // Step 19. Check for split - if ( !RootNode - && !SpNode + if ( !SpNode && depth >= Threads.min_split_depth() && bestValue < beta && Threads.available_slave_exists(pos.thread()) && !StopRequest && !thread.cutoff_occurred()) - Threads.split(pos, ss, &alpha, beta, &bestValue, depth, - threatMove, moveCount, &mp, PvNode); + bestValue = Threads.split(pos, ss, alpha, beta, bestValue, depth, + threatMove, moveCount, &mp, NT); } // Step 20. Check for mate and stalemate @@ -2220,10 +2205,14 @@ void ThreadsManager::idle_loop(int threadID, SplitPoint* sp) { memcpy(ss, tsp->ss - 1, 4 * sizeof(SearchStack)); (ss+1)->sp = tsp; - if (tsp->pvNode) + if (tsp->nodeType == Root) + search(pos, ss+1, tsp->alpha, tsp->beta, tsp->depth); + else if (tsp->nodeType == PV) search(pos, ss+1, tsp->alpha, tsp->beta, tsp->depth); - else + else if (tsp->nodeType == NonPV) search(pos, ss+1, tsp->alpha, tsp->beta, tsp->depth); + else + assert(false); assert(threads[threadID].state == Thread::SEARCHING); @@ -2252,8 +2241,6 @@ void ThreadsManager::idle_loop(int threadID, SplitPoint* sp) { // In helpful master concept a master can help only a sub-tree, and // because here is all finished is not possible master is booked. assert(threads[threadID].state == Thread::AVAILABLE); - - threads[threadID].state = Thread::SEARCHING; return; } }