X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=3ba276809bd67cddd5537f455e5e9d8e9275486d;hp=f6cf7090f1e2dfd681a8d3b2bac3540a62c55228;hb=db4b8ee000912f88927757eb8dee255b8d66a4b4;hpb=8ab9c2511a36a929a17a689125c919c927aee786 diff --git a/src/search.cpp b/src/search.cpp index f6cf7090..3ba27680 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -57,7 +57,7 @@ namespace { inline Value razor_margin(Depth d) { return Value(512 + 32 * d); } // Futility lookup tables (initialized at startup) and their access functions - int FutilityMoveCounts[2][32]; // [improving][depth] + int FutilityMoveCounts[2][16]; // [improving][depth] inline Value futility_margin(Depth d) { return Value(200 * d); @@ -88,7 +88,7 @@ namespace { Value value_to_tt(Value v, int ply); Value value_from_tt(Value v, int ply); void update_stats(const Position& pos, Stack* ss, Move move, Depth depth, Move* quiets, int quietsCnt); - string uci_pv(const Position& pos, int depth, Value alpha, Value beta); + string uci_pv(const Position& pos, Depth depth, Value alpha, Value beta); struct Skill { Skill(int l, size_t rootSize) : level(l), @@ -101,7 +101,7 @@ namespace { } size_t candidates_size() const { return candidates; } - bool time_to_pick(int depth) const { return depth == 1 + level; } + bool time_to_pick(Depth depth) const { return depth == 1 + level; } Move pick_move(); int level; @@ -116,28 +116,26 @@ namespace { void Search::init() { - int d; // depth (ONE_PLY == 2) - int hd; // half depth (ONE_PLY == 1) - int mc; // moveCount - // Init reductions array - for (hd = 1; hd < 64; ++hd) for (mc = 1; mc < 64; ++mc) - { - double pvRed = 0.00 + log(double(hd)) * log(double(mc)) / 3.00; - double nonPVRed = 0.33 + log(double(hd)) * log(double(mc)) / 2.25; + for (int d = 1; d < 64; ++d) + for (int mc = 1; mc < 64; ++mc) + { + double pvRed = 0.00 + log(double(d)) * log(double(mc)) / 3.00; + double nonPVRed = 0.33 + log(double(d)) * log(double(mc)) / 2.25; - Reductions[1][1][hd][mc] = int8_t( pvRed >= 1.0 ? pvRed + 0.5: 0); - Reductions[0][1][hd][mc] = int8_t(nonPVRed >= 1.0 ? nonPVRed + 0.5: 0); + Reductions[1][1][d][mc] = int8_t( pvRed >= 1.0 ? pvRed + 0.5: 0); + Reductions[0][1][d][mc] = int8_t(nonPVRed >= 1.0 ? nonPVRed + 0.5: 0); - Reductions[1][0][hd][mc] = Reductions[1][1][hd][mc]; - Reductions[0][0][hd][mc] = Reductions[0][1][hd][mc]; + Reductions[1][0][d][mc] = Reductions[1][1][d][mc]; + Reductions[0][0][d][mc] = Reductions[0][1][d][mc]; - if (Reductions[0][0][hd][mc] >= 2) - Reductions[0][0][hd][mc] += 1; - } + // Increase reduction when eval is not improving + if (Reductions[0][0][d][mc] >= 2) + Reductions[0][0][d][mc] += 1; + } // Init futility move count array - for (d = 0; d < 32; ++d) + for (int d = 0; d < 16; ++d) { FutilityMoveCounts[0][d] = int(2.4 + 0.773 * pow(d + 0.00, 1.8)); FutilityMoveCounts[1][d] = int(2.9 + 1.045 * pow(d + 0.49, 1.8)); @@ -241,12 +239,12 @@ namespace { void id_loop(Position& pos) { Stack stack[MAX_PLY+4], *ss = stack+2; // To allow referencing (ss-2) and (ss+2) - int depth; + Depth depth; Value bestValue, alpha, beta, delta; std::memset(ss-2, 0, 5 * sizeof(Stack)); - depth = 0; + depth = DEPTH_ZERO; BestMoveChanges = 0; bestValue = delta = alpha = -VALUE_INFINITE; beta = VALUE_INFINITE; @@ -279,7 +277,7 @@ namespace { for (PVIdx = 0; PVIdx < std::min(multiPV, RootMoves.size()) && !Signals.stop; ++PVIdx) { // Reset aspiration window starting size - if (depth >= 5) + if (depth >= 5 * ONE_PLY) { delta = Value(16); alpha = std::max(RootMoves[PVIdx].prevScore - delta,-VALUE_INFINITE); @@ -291,7 +289,7 @@ namespace { // high/low anymore. while (true) { - bestValue = search(pos, ss, alpha, beta, depth * ONE_PLY, false); + bestValue = search(pos, ss, alpha, beta, depth, 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 @@ -322,18 +320,21 @@ namespace { // re-search, otherwise exit the loop. if (bestValue <= alpha) { + beta = (alpha + beta) / 2; alpha = std::max(bestValue - delta, -VALUE_INFINITE); Signals.failedLowAtRoot = true; Signals.stopOnPonderhit = false; } else if (bestValue >= beta) + { + alpha = (alpha + beta) / 2; beta = std::min(bestValue + delta, VALUE_INFINITE); - + } else break; - delta += 3 * delta / 8; + delta += delta / 2; assert(alpha >= -VALUE_INFINITE && beta <= VALUE_INFINITE); } @@ -361,7 +362,7 @@ namespace { if (Limits.use_time_management() && !Signals.stop && !Signals.stopOnPonderhit) { // Take some extra time if the best move has changed - if (depth > 4 && multiPV == 1) + if (depth > 4 * ONE_PLY && multiPV == 1) TimeMgr.pv_instability(BestMoveChanges); // Stop the search if only one legal move is available or all @@ -406,7 +407,7 @@ namespace { Move ttMove, move, excludedMove, bestMove; Depth ext, newDepth, predictedDepth; Value bestValue, value, ttValue, eval, nullValue, futilityValue; - bool inCheck, givesCheck, pvMove, singularExtensionNode, improving; + bool inCheck, givesCheck, singularExtensionNode, improving; bool captureOrPromotion, dangerous, doFullDepthSearch; int moveCount, quietCount; @@ -747,7 +748,6 @@ moves_loop: // When in check and at SpNode search starts from here && !captureOrPromotion && !inCheck && !dangerous - /* && move != ttMove Already implicit in the next condition */ && bestValue > VALUE_MATED_IN_MAX_PLY) { // Move count based pruning @@ -802,7 +802,6 @@ moves_loop: // When in check and at SpNode search starts from here continue; } - pvMove = PvNode && moveCount == 1; ss->currentMove = move; if (!SpNode && !captureOrPromotion && quietCount < 64) quietsSearched[quietCount++] = move; @@ -813,9 +812,8 @@ moves_loop: // When in check and at SpNode search starts from here // Step 15. Reduced depth search (LMR). If the move fails high it will be // re-searched at full depth. if ( depth >= 3 * ONE_PLY - && !pvMove + && moveCount > 1 && !captureOrPromotion - && move != ttMove && move != ss->killers[0] && move != ss->killers[1]) { @@ -852,7 +850,7 @@ moves_loop: // When in check and at SpNode search starts from here ss->reduction = DEPTH_ZERO; } else - doFullDepthSearch = !pvMove; + doFullDepthSearch = !PvNode || moveCount > 1; // Step 16. Full depth search, when LMR is skipped or fails high if (doFullDepthSearch) @@ -869,7 +867,7 @@ moves_loop: // When in check and at SpNode search starts from here // For PV nodes only, do a full PV search on the first move or after a fail // high (in the latter case search only if value < beta), otherwise let the // parent node fail low with value <= alpha and to try another move. - if (PvNode && (pvMove || (value > alpha && (RootNode || value < beta)))) + if (PvNode && (moveCount == 1 || (value > alpha && (RootNode || value < beta)))) value = newDepth < ONE_PLY ? givesCheck ? -qsearch(pos, ss+1, -beta, -alpha, DEPTH_ZERO) : -qsearch(pos, ss+1, -beta, -alpha, DEPTH_ZERO) @@ -898,7 +896,7 @@ moves_loop: // When in check and at SpNode search starts from here RootMove& rm = *std::find(RootMoves.begin(), RootMoves.end(), move); // PV move or new best move ? - if (pvMove || value > alpha) + if (moveCount == 1 || value > alpha) { rm.score = value; rm.extract_pv_from_tt(pos); @@ -906,7 +904,7 @@ moves_loop: // When in check and at SpNode search starts from here // We record how often the best move has been changed in each // iteration. This information is used for time management: When // the best move changes frequently, we allocate some more time. - if (!pvMove) + if (moveCount > 1) ++BestMoveChanges; } else @@ -1111,7 +1109,6 @@ moves_loop: // When in check and at SpNode search starts from here if ( !PvNode && !InCheck && !givesCheck - && move != ttMove && futilityBase > -VALUE_KNOWN_WIN && !pos.advanced_pawn_push(move)) { @@ -1141,7 +1138,6 @@ moves_loop: // When in check and at SpNode search starts from here // Don't search moves with negative SEE values if ( !PvNode && (!InCheck || evasionPrunable) - && move != ttMove && type_of(move) != PROMOTION && pos.see_sign(move) < VALUE_ZERO) continue; @@ -1307,7 +1303,7 @@ moves_loop: // When in check and at SpNode search starts from here // requires that all (if any) unsearched PV lines are sent using a previous // search score. - string uci_pv(const Position& pos, int depth, Value alpha, Value beta) { + string uci_pv(const Position& pos, Depth depth, Value alpha, Value beta) { std::stringstream ss; Time::point elapsed = Time::now() - SearchTime + 1; @@ -1325,13 +1321,13 @@ moves_loop: // When in check and at SpNode search starts from here if (depth == 1 && !updated) continue; - int d = updated ? depth : depth - 1; + Depth d = updated ? depth : depth - ONE_PLY; Value v = updated ? RootMoves[i].score : RootMoves[i].prevScore; if (ss.rdbuf()->in_avail()) // Not at first line ss << "\n"; - ss << "info depth " << d + ss << "info depth " << d / ONE_PLY << " seldepth " << selDepth << " multipv " << i + 1 << " score " << (i == PVIdx ? UCI::format_value(v, alpha, beta) : UCI::format_value(v)) @@ -1541,7 +1537,7 @@ void Thread::idle_loop() { void check_time() { static Time::point lastInfoTime = Time::now(); - int64_t nodes = 0; // Workaround silly 'uninitialized' gcc warning + Time::point elapsed = Time::now() - SearchTime; if (Time::now() - lastInfoTime >= 1000) { @@ -1549,14 +1545,24 @@ void check_time() { dbg_print(); } - if (Limits.ponder) - return; + if (Limits.use_time_management() && !Limits.ponder) + { + bool stillAtFirstMove = Signals.firstRootMove + && !Signals.failedLowAtRoot + && elapsed > TimeMgr.available_time() * 75 / 100; - if (Limits.nodes) + if ( stillAtFirstMove + || elapsed > TimeMgr.maximum_time() - 2 * TimerThread::Resolution) + Signals.stop = true; + } + else if (Limits.movetime && elapsed >= Limits.movetime) + Signals.stop = true; + + else if (Limits.nodes) { Threads.mutex.lock(); - nodes = RootPos.nodes_searched(); + int64_t nodes = RootPos.nodes_searched(); // Loop across all split points and sum accumulated SplitPoint nodes plus // all the currently active positions nodes. @@ -1577,18 +1583,8 @@ void check_time() { } Threads.mutex.unlock(); - } - Time::point elapsed = Time::now() - SearchTime; - bool stillAtFirstMove = Signals.firstRootMove - && !Signals.failedLowAtRoot - && elapsed > TimeMgr.available_time() * 75 / 100; - - bool noMoreTime = elapsed > TimeMgr.maximum_time() - 2 * TimerThread::Resolution - || stillAtFirstMove; - - if ( (Limits.use_time_management() && noMoreTime) - || (Limits.movetime && elapsed >= Limits.movetime) - || (Limits.nodes && nodes >= Limits.nodes)) - Signals.stop = true; + if (nodes >= Limits.nodes) + Signals.stop = true; + } }