X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=7029ae032ef8ba2703a7fa5080f4f319628fcf46;hp=b31ed0c21c9cbfe080f96197c21c2695cfd0106f;hb=30c583204f97da2c67b5042c30327013e70ae209;hpb=c3d2e6aba981ecc0caf82f81a1d44e8c4954e151 diff --git a/src/search.cpp b/src/search.cpp index b31ed0c2..7029ae03 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -63,6 +63,10 @@ namespace { // Different node types, used as a template parameter enum NodeType { NonPV, PV }; + // Sizes and phases of the skip-blocks, used for distributing search depths across the threads + const int skipSize[] = { 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4 }; + const int skipPhase[] = { 0, 1, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 7 }; + // Razoring and futility margin based on depth const int razor_margin[4] = { 483, 570, 603, 554 }; Value futility_margin(Depth d) { return Value(150 * d / ONE_PLY); } @@ -78,7 +82,7 @@ namespace { // History and stats update bonus, based on depth Value stat_bonus(Depth depth) { int d = depth / ONE_PLY ; - return Value(d * d + 2 * d - 2); + return d > 17 ? VALUE_ZERO : Value(d * d + 2 * d - 2); } // Skill structure is used to implement strength limit @@ -159,7 +163,7 @@ void Search::init() { for (int d = 1; d < 64; ++d) for (int mc = 1; mc < 64; ++mc) { - double r = log(d) * log(mc) / 2; + double r = log(d) * log(mc) / 1.95; Reductions[NonPV][imp][d][mc] = int(std::round(r)); Reductions[PV][imp][d][mc] = std::max(Reductions[NonPV][imp][d][mc] - 1, 0); @@ -308,13 +312,10 @@ void MainThread::search() { std::cout << sync_endl; } -// Sizes and phases of the skip-blocks, used for distributing search depths across the threads. -static int skipsize[20] = {1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4}; -static int phase [20] = {0, 1, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 7}; -// Thread::search() is the main iterative deepening loop. It calls search() -// repeatedly with increasing depth until the allocated thinking time has been -// consumed, the user stops the search, or the maximum search depth is reached. +/// Thread::search() is the main iterative deepening loop. It calls search() +/// repeatedly with increasing depth until the allocated thinking time has been +/// consumed, the user stops the search, or the maximum search depth is reached. void Thread::search() { @@ -324,8 +325,8 @@ void Thread::search() { MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr); std::memset(ss-4, 0, 7 * sizeof(Stack)); - for(int i = -4; i < 0; i++) - (ss+i)->counterMoves = &this->counterMoveHistory[NO_PIECE][0]; // use as sentinel. + for(int i = 4; i > 0; i--) + (ss-i)->counterMoves = &this->counterMoveHistory[NO_PIECE][0]; // Use as sentinel bestValue = delta = alpha = -VALUE_INFINITE; beta = VALUE_INFINITE; @@ -350,16 +351,18 @@ void Thread::search() { multiPV = std::min(multiPV, rootMoves.size()); - int hIdx = (idx - 1) % 20; // helper index, cycle after 20 threads - // Iterative deepening loop until requested to stop or the target depth is reached while ( (rootDepth += ONE_PLY) < DEPTH_MAX && !Signals.stop && (!Limits.depth || Threads.main()->rootDepth / ONE_PLY <= Limits.depth)) { - // skip half of the plies in blocks depending on game ply and helper index. - if (idx && ((rootDepth / ONE_PLY + rootPos.game_ply() + phase[hIdx]) / skipsize[hIdx]) % 2) - continue; + // Distribute search depths across the threads + if (idx) + { + int i = (idx - 1) % 20; + if (((rootDepth / ONE_PLY + rootPos.game_ply() + skipPhase[i]) / skipSize[i]) % 2) + continue; + } // Age out PV variability metric if (mainThread) @@ -539,7 +542,7 @@ namespace { Depth extension, newDepth; Value bestValue, value, ttValue, eval; bool ttHit, inCheck, givesCheck, singularExtensionNode, improving; - bool captureOrPromotion, doFullDepthSearch, moveCountPruning; + bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets; Piece moved_piece; int moveCount, quietCount; @@ -806,12 +809,12 @@ namespace { moves_loop: // When in check search starts from here - const CounterMoveStats* cmh = (ss-1)->counterMoves; - const CounterMoveStats* fmh = (ss-2)->counterMoves; - const CounterMoveStats* fmh2 = (ss-4)->counterMoves; + const CounterMoveStats& cmh = *(ss-1)->counterMoves; + const CounterMoveStats& fmh = *(ss-2)->counterMoves; + const CounterMoveStats& fm2 = *(ss-4)->counterMoves; const bool cm_ok = is_ok((ss-1)->currentMove); const bool fm_ok = is_ok((ss-2)->currentMove); - const bool fm2_ok = is_ok((ss-4)->currentMove); + const bool f2_ok = is_ok((ss-4)->currentMove); MovePicker mp(pos, ttMove, depth, ss); value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc @@ -826,10 +829,11 @@ moves_loop: // When in check search starts from here && !excludedMove // Recursive singular search is not allowed && (tte->bound() & BOUND_LOWER) && tte->depth() >= depth - 3 * ONE_PLY; + skipQuiets = false; // Step 11. Loop through moves // Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs - while ((move = mp.next_move()) != MOVE_NONE) + while ((move = mp.next_move(skipQuiets)) != MOVE_NONE) { assert(is_ok(move)); @@ -864,12 +868,7 @@ moves_loop: // When in check search starts from here moveCountPruning = depth < 16 * ONE_PLY && moveCount >= FutilityMoveCounts[improving][depth / ONE_PLY]; - // Step 12. Extensions - // Extend checks - if ( givesCheck - && !moveCountPruning - && pos.see_ge(move, VALUE_ZERO)) - extension = ONE_PLY; + // Step 12. Singular and Gives Check Extensions // Singular extension search. If all moves but one fail low on a search of // (alpha-s, beta-s), and just one fails high on (alpha, beta), then that move @@ -878,7 +877,6 @@ moves_loop: // When in check search starts from here // ttValue minus a margin then we extend the ttMove. if ( singularExtensionNode && move == ttMove - && !extension && pos.legal(move)) { Value rBeta = std::max(ttValue - 2 * depth / ONE_PLY, -VALUE_MATE); @@ -890,6 +888,10 @@ moves_loop: // When in check search starts from here if (value < rBeta) extension = ONE_PLY; } + else if ( givesCheck + && !moveCountPruning + && pos.see_ge(move, VALUE_ZERO)) + extension = ONE_PLY; // Calculate new depth for this move newDepth = depth - ONE_PLY + extension; @@ -903,17 +905,19 @@ moves_loop: // When in check search starts from here && (!pos.advanced_pawn_push(move) || pos.non_pawn_material() >= 5000)) { // Move count based pruning - if (moveCountPruning) + if (moveCountPruning) { + skipQuiets = true; continue; + } // Reduced depth of the next LMR search int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), DEPTH_ZERO) / ONE_PLY; // Countermoves based pruning if ( lmrDepth < 3 - && (((*cmh )[moved_piece][to_sq(move)] < VALUE_ZERO) || !cm_ok) - && (((*fmh )[moved_piece][to_sq(move)] < VALUE_ZERO) || !fm_ok) - && (((*fmh2)[moved_piece][to_sq(move)] < VALUE_ZERO) || !fm2_ok || (cm_ok && fm_ok))) + && ((cmh[moved_piece][to_sq(move)] < VALUE_ZERO) || !cm_ok) + && ((fmh[moved_piece][to_sq(move)] < VALUE_ZERO) || !fm_ok) + && ((fm2[moved_piece][to_sq(move)] < VALUE_ZERO) || !f2_ok || (cm_ok && fm_ok))) continue; // Futility pruning: parent node @@ -973,9 +977,9 @@ moves_loop: // When in check search starts from here && !pos.see_ge(make_move(to_sq(move), from_sq(move)), VALUE_ZERO)) r -= 2 * ONE_PLY; - ss->history = (*cmh )[moved_piece][to_sq(move)] - + (*fmh )[moved_piece][to_sq(move)] - + (*fmh2)[moved_piece][to_sq(move)] + ss->history = cmh[moved_piece][to_sq(move)] + + fmh[moved_piece][to_sq(move)] + + fm2[moved_piece][to_sq(move)] + thisThread->history.get(~pos.side_to_move(), move) - 4000; // Correction factor @@ -1379,8 +1383,8 @@ moves_loop: // When in check search starts from here void update_cm_stats(Stack* ss, Piece pc, Square s, Value bonus) { for (int i : {1, 2, 4}) - if (is_ok((ss-i)->currentMove)) - (ss-i)->counterMoves->update(pc, s, bonus); + if (is_ok((ss-i)->currentMove)) + (ss-i)->counterMoves->update(pc, s, bonus); }