X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=40561544ab00a872947d6fef00db1364de71dfaf;hp=091c00fe2e06a9e8b6c194bdc460440d9f3d957c;hb=19dd0de4ff83e682bafa56d27f302d8f00d3040d;hpb=fe3352665b2dfc6c339136856c782057a5c5476e diff --git a/src/search.cpp b/src/search.cpp index 091c00fe..40561544 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1,7 +1,7 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) - Copyright (C) 2008-2012 Marco Costalba, Joona Kiiski, Tord Romstad + Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -88,6 +88,7 @@ namespace { Value DrawValue[COLOR_NB]; History Hist; Gains Gain; + Refutations Refutation; template Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth); @@ -145,7 +146,7 @@ void Search::init() { // Init futility move count array for (d = 0; d < 32; d++) - FutilityMoveCounts[d] = int(3.001 + 0.25 * pow(double(d), 2.0)); + FutilityMoveCounts[d] = int(3.001 + 0.3 * pow(double(d), 1.8)); } @@ -182,7 +183,7 @@ void Search::think() { static PolyglotBook book; // Defined static to initialize the PRNG only once RootColor = RootPos.side_to_move(); - TimeMgr.init(Limits, RootPos.startpos_ply_counter(), RootColor); + TimeMgr.init(Limits, RootPos.game_ply(), RootColor); if (RootMoves.empty()) { @@ -264,6 +265,10 @@ void Search::think() { finalize: + // When search is stopped this info is not printed + sync_cout << "info nodes " << RootPos.nodes_searched() + << " time " << Time::now() - SearchTime + 1 << sync_endl; + // When we reach max depth we arrive here even without Signals.stop is raised, // but if we are pondering or in infinite search, according to UCI protocol, // we shouldn't print the best move before the GUI sends a "stop" or "ponderhit" @@ -293,7 +298,6 @@ namespace { Stack ss[MAX_PLY_PLUS_2]; int depth, prevBestMoveChanges; Value bestValue, alpha, beta, delta; - bool bestMoveNeverChanged = true; memset(ss, 0, 4 * sizeof(Stack)); depth = BestMoveChanges = 0; @@ -302,6 +306,7 @@ namespace { TT.new_search(); Hist.clear(); Gain.clear(); + Refutation.clear(); PVSize = Options["MultiPV"]; Skill skill(Options["Skill Level"]); @@ -354,7 +359,7 @@ namespace { // we want to keep the same order for all the moves but the new // PV that goes to the front. Note that in case of MultiPV search // the already searched PV lines are preserved. - sort(RootMoves.begin() + PVIdx, RootMoves.end()); + std::stable_sort(RootMoves.begin() + PVIdx, RootMoves.end()); // Write PV back to transposition table in case the relevant // entries have been overwritten during the search. @@ -399,7 +404,7 @@ namespace { } // Sort the PV lines searched so far and update the GUI - sort(RootMoves.begin(), RootMoves.begin() + PVIdx + 1); + std::stable_sort(RootMoves.begin(), RootMoves.begin() + PVIdx + 1); if (PVIdx + 1 == PVSize || Time::now() - SearchTime > 3000) sync_cout << uci_pv(pos, depth, alpha, beta) << sync_endl; @@ -416,10 +421,6 @@ namespace { << std::endl; } - // Filter out startup noise when monitoring best move stability - if (depth > 2 && BestMoveChanges) - bestMoveNeverChanged = false; - // Do we have found a "mate in x"? if ( Limits.mate && bestValue >= VALUE_MATE_IN_MAX_PLY @@ -445,8 +446,9 @@ namespace { if ( depth >= 12 && !stop && PVSize == 1 - && ( (bestMoveNeverChanged && pos.captured_piece_type()) - || Time::now() - SearchTime > (TimeMgr.available_time() * 40) / 100)) + && bestValue > VALUE_MATED_IN_MAX_PLY + && ( RootMoves.size() == 1 + || Time::now() - SearchTime > (TimeMgr.available_time() * 20) / 100)) { Value rBeta = bestValue - 2 * PawnValueMg; (ss+1)->excludedMove = RootMoves[0].pv[0]; @@ -494,7 +496,7 @@ namespace { Move movesSearched[64]; StateInfo st; const TTEntry *tte; - SplitPoint* sp; + SplitPoint* splitPoint; Key posKey; Move ttMove, move, excludedMove, bestMove, threatMove; Depth ext, newDepth; @@ -511,15 +513,15 @@ namespace { if (SpNode) { - sp = ss->sp; - bestMove = sp->bestMove; - threatMove = sp->threatMove; - bestValue = sp->bestValue; + splitPoint = ss->splitPoint; + bestMove = splitPoint->bestMove; + threatMove = splitPoint->threatMove; + bestValue = splitPoint->bestValue; tte = NULL; ttMove = excludedMove = MOVE_NONE; ttValue = VALUE_NONE; - assert(sp->bestValue > -VALUE_INFINITE && sp->moveCount > 0); + assert(splitPoint->bestValue > -VALUE_INFINITE && splitPoint->moveCount > 0); goto split_point_start; } @@ -527,6 +529,7 @@ namespace { bestValue = -VALUE_INFINITE; ss->currentMove = threatMove = (ss+1)->excludedMove = bestMove = MOVE_NONE; ss->ply = (ss-1)->ply + 1; + ss->futilityMoveCount = 0; (ss+1)->skipNullMove = false; (ss+1)->reduction = DEPTH_ZERO; (ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE; @@ -537,7 +540,7 @@ namespace { if (!RootNode) { // Step 2. Check for aborted search and immediate draw - if (Signals.stop || pos.is_draw() || ss->ply > MAX_PLY) + if (Signals.stop || pos.is_draw() || ss->ply > MAX_PLY) return DrawValue[pos.side_to_move()]; // Step 3. Mate distance pruning. Even if we mate at the next move our score @@ -647,10 +650,11 @@ namespace { && !ss->skipNullMove && depth < 4 * ONE_PLY && !inCheck - && eval - FutilityMargins[depth][0] >= beta + && eval - futility_margin(depth, (ss-1)->futilityMoveCount) >= beta && abs(beta) < VALUE_MATE_IN_MAX_PLY + && abs(eval) < VALUE_KNOWN_WIN && pos.non_pawn_material(pos.side_to_move())) - return eval - FutilityMargins[depth][0]; + return eval - futility_margin(depth, (ss-1)->futilityMoveCount); // Step 8. Null move search with verification search (is omitted in PV nodes) if ( !PvNode @@ -683,7 +687,7 @@ namespace { if (nullValue >= VALUE_MATE_IN_MAX_PLY) nullValue = beta; - if (depth < 6 * ONE_PLY) + if (depth < 12 * ONE_PLY) return nullValue; // Do verification search at high depths @@ -750,7 +754,7 @@ namespace { && ttMove == MOVE_NONE && (PvNode || (!inCheck && ss->staticEval + Value(256) >= beta))) { - Depth d = (PvNode ? depth - 2 * ONE_PLY : depth / 2); + Depth d = depth - 2 * ONE_PLY - (PvNode ? DEPTH_ZERO : depth / 4); ss->skipNullMove = true; search(pos, ss, alpha, beta, d); @@ -762,7 +766,7 @@ namespace { split_point_start: // At split points actual search starts from here - MovePicker mp(pos, ttMove, depth, Hist, ss, PvNode ? -VALUE_INFINITE : beta); + MovePicker mp(pos, ttMove, depth, Hist, Refutation, ss, PvNode ? -VALUE_INFINITE : beta); CheckInfo ci(pos); value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc singularExtensionNode = !RootNode @@ -794,8 +798,8 @@ split_point_start: // At split points actual search starts from here if (!pos.pl_move_is_legal(move, ci.pinned)) continue; - moveCount = ++sp->moveCount; - sp->mutex.unlock(); + moveCount = ++splitPoint->moveCount; + splitPoint->mutex.unlock(); } else moveCount++; @@ -861,9 +865,8 @@ split_point_start: // At split points actual search starts from here && !captureOrPromotion && !inCheck && !dangerous - && move != ttMove - && (bestValue > VALUE_MATED_IN_MAX_PLY || ( bestValue == -VALUE_INFINITE - && alpha > VALUE_MATED_IN_MAX_PLY))) + /* && move != ttMove Already implicit in the next condition */ + && bestValue > VALUE_MATED_IN_MAX_PLY) { // Move count based pruning if ( depth < 16 * ONE_PLY @@ -871,7 +874,7 @@ split_point_start: // At split points actual search starts from here && (!threatMove || !refutes(pos, move, threatMove))) { if (SpNode) - sp->mutex.lock(); + splitPoint->mutex.lock(); continue; } @@ -885,22 +888,33 @@ split_point_start: // At split points actual search starts from here if (futilityValue < beta) { - if (SpNode) - sp->mutex.lock(); + bestValue = std::max(bestValue, futilityValue); + if (SpNode) + { + splitPoint->mutex.lock(); + if (bestValue > splitPoint->bestValue) + splitPoint->bestValue = bestValue; + } continue; } // Prune moves with negative SEE at low depths - if ( predictedDepth < 2 * ONE_PLY + if ( predictedDepth < 4 * ONE_PLY && pos.see_sign(move) < 0) { if (SpNode) - sp->mutex.lock(); + splitPoint->mutex.lock(); continue; } + + // We have not pruned the move that will be searched, but remember how + // far in the move list we are to be more aggressive in the child node. + ss->futilityMoveCount = moveCount; } + else + ss->futilityMoveCount = 0; // Check for legality only before to do the move if (!RootNode && !SpNode && !pos.pl_move_is_legal(move, ci.pinned)) @@ -929,7 +943,8 @@ split_point_start: // At split points actual search starts from here { ss->reduction = reduction(depth, moveCount); Depth d = std::max(newDepth - ss->reduction, ONE_PLY); - alpha = SpNode ? sp->alpha : alpha; + if (SpNode) + alpha = splitPoint->alpha; value = -search(pos, ss+1, -(alpha+1), -alpha, d); @@ -942,7 +957,9 @@ split_point_start: // At split points actual search starts from here // Step 16. Full depth search, when LMR is skipped or fails high if (doFullDepthSearch) { - alpha = SpNode ? sp->alpha : alpha; + if (SpNode) + alpha = splitPoint->alpha; + value = newDepth < ONE_PLY ? givesCheck ? -qsearch(pos, ss+1, -(alpha+1), -alpha, DEPTH_ZERO) : -qsearch(pos, ss+1, -(alpha+1), -alpha, DEPTH_ZERO) @@ -965,9 +982,9 @@ split_point_start: // At split points actual search starts from here // Step 18. Check for new best move if (SpNode) { - sp->mutex.lock(); - bestValue = sp->bestValue; - alpha = sp->alpha; + splitPoint->mutex.lock(); + bestValue = splitPoint->bestValue; + alpha = splitPoint->alpha; } // Finished searching the move. If Signals.stop is true, the search @@ -1002,20 +1019,20 @@ split_point_start: // At split points actual search starts from here if (value > bestValue) { - bestValue = SpNode ? sp->bestValue = value : value; + bestValue = SpNode ? splitPoint->bestValue = value : value; if (value > alpha) { - bestMove = SpNode ? sp->bestMove = move : move; + bestMove = SpNode ? splitPoint->bestMove = move : move; if (PvNode && value < beta) // Update alpha! Always alpha < beta - alpha = SpNode ? sp->alpha = value : value; + alpha = SpNode ? splitPoint->alpha = value : value; else { assert(value >= beta); // Fail high if (SpNode) - sp->cutoff = true; + splitPoint->cutoff = true; break; } @@ -1075,6 +1092,8 @@ split_point_start: // At split points actual search starts from here // Increase history value of the cut-off move Value bonus = Value(int(depth) * int(depth)); Hist.update(pos.piece_moved(bestMove), to_sq(bestMove), bonus); + Square prevSq = to_sq((ss-1)->currentMove); + Refutation.update(pos.piece_on(prevSq), prevSq, bestMove); // Decrease history of all the other played non-capture moves for (int i = 0; i < playedMoveCount - 1; i++) @@ -1126,9 +1145,15 @@ split_point_start: // At split points actual search starts from here ss->ply = (ss-1)->ply + 1; // Check for an instant draw or maximum ply reached - if (pos.is_draw() || ss->ply > MAX_PLY) + if (pos.is_draw() || ss->ply > MAX_PLY) return DrawValue[pos.side_to_move()]; + // Decide whether or not to include checks, this fixes also the type of + // TT entry depth that we are going to use. Note that in qsearch we use + // only two types of depth in TT: DEPTH_QS_CHECKS or DEPTH_QS_NO_CHECKS. + ttDepth = InCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS + : DEPTH_QS_NO_CHECKS; + // Transposition table lookup. At PV nodes, we don't use the TT for // pruning, but only for move ordering. posKey = pos.key(); @@ -1136,11 +1161,6 @@ split_point_start: // At split points actual search starts from here ttMove = tte ? tte->move() : MOVE_NONE; ttValue = tte ? value_from_tt(tte->value(),ss->ply) : VALUE_NONE; - // Decide whether or not to include checks, this fixes also the type of - // TT entry depth that we are going to use. Note that in qsearch we use - // only two types of depth in TT: DEPTH_QS_CHECKS or DEPTH_QS_NO_CHECKS. - ttDepth = InCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS - : DEPTH_QS_NO_CHECKS; if ( tte && tte->depth() >= ttDepth && ttValue != VALUE_NONE // Only in case of TT access race @@ -1221,10 +1241,11 @@ split_point_start: // At split points actual search starts from here continue; } - // Prune moves with negative or equal SEE + // Prune moves with negative or equal SEE and also moves with positive + // SEE where capturing piece loses a tempo and SEE < beta - futilityBase. if ( futilityBase < beta && depth < DEPTH_ZERO - && pos.see(move) <= 0) + && pos.see(move, beta - futilityBase) <= 0) { bestValue = std::max(bestValue, futilityBase); continue; @@ -1574,7 +1595,7 @@ void RootMove::extract_pv_from_tt(Position& pos) { && pos.is_pseudo_legal(m = tte->move()) // Local copy, TT could change && pos.pl_move_is_legal(m, pos.pinned_pieces()) && ply < MAX_PLY - && (!pos.is_draw() || ply < 2)); + && (!pos.is_draw() || ply < 2)); pv.push_back(MOVE_NONE); // Must be zero-terminating @@ -1614,13 +1635,11 @@ void Thread::idle_loop() { // Pointer 'this_sp' is not null only if we are called from split(), and not // at the thread creation. So it means we are the split point's master. - const SplitPoint* this_sp = splitPointsSize ? activeSplitPoint : NULL; + SplitPoint* this_sp = splitPointsSize ? activeSplitPoint : NULL; assert(!this_sp || (this_sp->masterThread == this && searching)); - // If this thread is the master of a split point and all slaves have finished - // their work at this split point, return from the idle loop. - while (!this_sp || this_sp->slavesMask) + while (true) { // If we are not searching, wait for a condition to be signaled instead of // wasting CPU time polling for work. @@ -1668,7 +1687,7 @@ void Thread::idle_loop() { Position pos(*sp->pos, this); memcpy(ss, sp->ss - 1, 4 * sizeof(Stack)); - (ss+1)->sp = sp; + (ss+1)->splitPoint = sp; sp->mutex.lock(); @@ -1713,6 +1732,17 @@ void Thread::idle_loop() { // unsafe because if we are exiting there is a chance are already freed. sp->mutex.unlock(); } + + // If this thread is the master of a split point and all slaves have finished + // their work at this split point, return from the idle loop. + if (this_sp && !this_sp->slavesMask) + { + this_sp->mutex.lock(); + bool finished = !this_sp->slavesMask; // Retest under lock protection + this_sp->mutex.unlock(); + if (finished) + return; + } } }