X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=669302fcfa22997feaae32bf4f196fc077f64195;hp=f8dd1361dea615e1f84cccb5a7ad347b10a80e4e;hb=9643d7524ee905e09491b1bc558ee3d0f6e1d16f;hpb=91ce930b28440e05f4c4b75e0ed7bcc2c58fa07c diff --git a/src/search.cpp b/src/search.cpp index f8dd1361..669302fc 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -52,7 +52,7 @@ using std::endl; namespace { /// Types - enum NodeType { NonPV, PV}; + enum NodeType { NonPV, PV }; // ThreadsManager class is used to handle all the threads related stuff in search, // init, starting, parking and, the most important, launching a slave thread at a @@ -179,8 +179,7 @@ namespace { // Step 9. Internal iterative deepening // Minimum depth for use of internal iterative deepening - const Depth IIDDepthAtPVNodes = 5 * OnePly; - const Depth IIDDepthAtNonPVNodes = 8 * OnePly; + const Depth IIDDepth[2] = { 8 * OnePly /* non-PV */, 5 * OnePly /* PV */}; // At Non-PV nodes we do an internal iterative deepening search // when the static evaluation is at most IIDMargin below beta. @@ -215,11 +214,10 @@ namespace { // Step 14. Reduced search // Reduction lookup tables (initialized at startup) and their getter functions - int8_t PVReductionMatrix[64][64]; // [depth][moveNumber] - int8_t NonPVReductionMatrix[64][64]; // [depth][moveNumber] + int8_t ReductionMatrix[2][64][64]; // [pv][depth][moveNumber] - inline Depth pv_reduction(Depth d, int mn) { return (Depth) PVReductionMatrix[Min(d / 2, 63)][Min(mn, 63)]; } - inline Depth nonpv_reduction(Depth d, int mn) { return (Depth) NonPVReductionMatrix[Min(d / 2, 63)][Min(mn, 63)]; } + template + inline Depth reduction(Depth d, int mn) { return (Depth) ReductionMatrix[PV][Min(d / 2, 63)][Min(mn, 63)]; } // Common adjustments @@ -283,6 +281,9 @@ namespace { template Value search(Position& pos, SearchStack ss[], Value alpha, Value beta, Depth depth, int ply, bool allowNullmove, int threadID, Move excludedMove = MOVE_NONE); + template + Depth extension(const Position& pos, Move m, bool captureOrPromotion, bool moveIsCheck, bool singleEvasion, bool mateThreat, bool* dangerous); + Value qsearch(Position& pos, SearchStack ss[], Value alpha, Value beta, Depth depth, int ply, int threadID); void sp_search(SplitPoint* sp, int threadID); void sp_search_pv(SplitPoint* sp, int threadID); @@ -292,7 +293,6 @@ namespace { bool connected_moves(const Position& pos, Move m1, Move m2); bool value_is_mate(Value value); bool move_is_killer(Move m, const SearchStack& ss); - Depth extension(const Position&, Move, bool, bool, bool, bool, bool, bool*); bool ok_to_do_nullmove(const Position& pos); bool ok_to_prune(const Position& pos, Move m, Move threat); bool ok_to_use_TT(const TTEntry* tte, Depth depth, Value beta, int ply); @@ -552,8 +552,8 @@ void init_search() { { double pvRed = log(double(i)) * log(double(j)) / 3.0; double nonPVRed = log(double(i)) * log(double(j)) / 1.5; - PVReductionMatrix[i][j] = (int8_t) ( pvRed >= 1.0 ? floor( pvRed * int(OnePly)) : 0); - NonPVReductionMatrix[i][j] = (int8_t) (nonPVRed >= 1.0 ? floor(nonPVRed * int(OnePly)) : 0); + ReductionMatrix[PV][i][j] = (int8_t) ( pvRed >= 1.0 ? floor( pvRed * int(OnePly)) : 0); + ReductionMatrix[NonPV][i][j] = (int8_t) (nonPVRed >= 1.0 ? floor(nonPVRed * int(OnePly)) : 0); } // Init futility margins array @@ -845,7 +845,7 @@ namespace { // Step 11. Decide the new search depth depth = (Iteration - 2) * OnePly + InitialDepth; - ext = extension(pos, move, true, captureOrPromotion, moveIsCheck, false, false, &dangerous); + ext = extension(pos, move, captureOrPromotion, moveIsCheck, false, false, &dangerous); newDepth = depth + ext; // Step 12. Futility pruning (omitted at root) @@ -883,7 +883,7 @@ namespace { && !captureOrPromotion && !move_is_castle(move)) { - ss[0].reduction = pv_reduction(depth, i - MultiPV + 2); + ss[0].reduction = reduction(depth, i - MultiPV + 2); if (ss[0].reduction) { // Reduced depth non-pv search using alpha as upperbound @@ -1022,7 +1022,7 @@ namespace { } - // search_pv() is the main search function for PV nodes. + // search<>() is the main search function for both PV and non-PV nodes template Value search(Position& pos, SearchStack ss[], Value alpha, Value beta, @@ -1196,23 +1196,12 @@ namespace { } // Step 9. Internal iterative deepening - // We have different rules for PV nodes and non-pv nodes - if ( PvNode - && depth >= IIDDepthAtPVNodes - && ttMove == MOVE_NONE) - { - search(pos, ss, alpha, beta, depth-2*OnePly, ply, false, threadID); - ttMove = ss[ply].pv[ply]; - tte = TT.retrieve(posKey); - } - - if ( !PvNode - && depth >= IIDDepthAtNonPVNodes + if ( depth >= IIDDepth[PvNode] && ttMove == MOVE_NONE - && !isCheck - && ss[ply].eval >= beta - IIDMargin) + && (PvNode || (!isCheck && ss[ply].eval >= beta - IIDMargin))) { - search(pos, ss, alpha, beta, depth/2, ply, false, threadID); + Depth d = (PvNode ? depth - 2 * OnePly : depth / 2); + search(pos, ss, alpha, beta, d, ply, false, threadID); ttMove = ss[ply].pv[ply]; tte = TT.retrieve(posKey); } @@ -1241,7 +1230,7 @@ namespace { captureOrPromotion = pos.move_is_capture_or_promotion(move); // Step 11. Decide the new search depth - ext = extension(pos, move, PvNode, captureOrPromotion, moveIsCheck, singleEvasion, mateThreat, &dangerous); + ext = extension(pos, move, captureOrPromotion, moveIsCheck, singleEvasion, mateThreat, &dangerous); // Singular extension search. We extend the TT move if its value is much better than // its siblings. To verify this we do a reduced search on all the other moves but the @@ -1285,7 +1274,7 @@ namespace { continue; // Value based pruning - Depth predictedDepth = newDepth - nonpv_reduction(depth, moveCount); // We illogically ignore reduction condition depth >= 3*OnePly + Depth predictedDepth = newDepth - reduction(depth, moveCount); // We illogically ignore reduction condition depth >= 3*OnePly futilityValueScaled = ss[ply].eval + futility_margin(predictedDepth, moveCount) + H.gain(pos.piece_on(move_from(move)), move_to(move)); @@ -1316,7 +1305,7 @@ namespace { && !move_is_castle(move) && !move_is_killer(move, ss[ply])) { - ss[ply].reduction = (PvNode ? pv_reduction(depth, moveCount) : nonpv_reduction(depth, moveCount)); + ss[ply].reduction = reduction(depth, moveCount); if (ss[ply].reduction) { value = -search(pos, ss, -(alpha+1), -alpha, newDepth-ss[ply].reduction, ply+1, true, threadID); @@ -1636,7 +1625,7 @@ namespace { captureOrPromotion = pos.move_is_capture_or_promotion(move); // Step 11. Decide the new search depth - ext = extension(pos, move, false, captureOrPromotion, moveIsCheck, false, sp->mateThreat, &dangerous); + ext = extension(pos, move, captureOrPromotion, moveIsCheck, false, sp->mateThreat, &dangerous); newDepth = sp->depth - OnePly + ext; // Update current move @@ -1658,7 +1647,7 @@ namespace { } // Value based pruning - Depth predictedDepth = newDepth - nonpv_reduction(sp->depth, moveCount); + Depth predictedDepth = newDepth - reduction(sp->depth, moveCount); futilityValueScaled = ss[sp->ply].eval + futility_margin(predictedDepth, moveCount) + H.gain(pos.piece_on(move_from(move)), move_to(move)); @@ -1684,7 +1673,7 @@ namespace { && !move_is_castle(move) && !move_is_killer(move, ss[sp->ply])) { - ss[sp->ply].reduction = nonpv_reduction(sp->depth, moveCount); + ss[sp->ply].reduction = reduction(sp->depth, moveCount); if (ss[sp->ply].reduction) { value = -search(pos, ss, -(sp->alpha+1), -(sp->alpha), newDepth-ss[sp->ply].reduction, sp->ply+1, true, threadID); @@ -1769,7 +1758,7 @@ namespace { captureOrPromotion = pos.move_is_capture_or_promotion(move); // Step 11. Decide the new search depth - ext = extension(pos, move, true, captureOrPromotion, moveIsCheck, false, sp->mateThreat, &dangerous); + ext = extension(pos, move, captureOrPromotion, moveIsCheck, false, sp->mateThreat, &dangerous); newDepth = sp->depth - OnePly + ext; // Update current move @@ -1789,7 +1778,7 @@ namespace { && !move_is_castle(move) && !move_is_killer(move, ss[sp->ply])) { - ss[sp->ply].reduction = pv_reduction(sp->depth, moveCount); + ss[sp->ply].reduction = reduction(sp->depth, moveCount); if (ss[sp->ply].reduction) { Value localAlpha = sp->alpha; @@ -2003,9 +1992,9 @@ namespace { // any case are marked as 'dangerous'. Note that also if a move is not // extended, as example because the corresponding UCI option is set to zero, // the move is marked as 'dangerous' so, at least, we avoid to prune it. - - Depth extension(const Position& pos, Move m, bool pvNode, bool captureOrPromotion, - bool moveIsCheck, bool singleEvasion, bool mateThreat, bool* dangerous) { + template + Depth extension(const Position& pos, Move m, bool captureOrPromotion, bool moveIsCheck, + bool singleEvasion, bool mateThreat, bool* dangerous) { assert(m != MOVE_NONE); @@ -2015,13 +2004,13 @@ namespace { if (*dangerous) { if (moveIsCheck) - result += CheckExtension[pvNode]; + result += CheckExtension[PvNode]; if (singleEvasion) - result += SingleEvasionExtension[pvNode]; + result += SingleEvasionExtension[PvNode]; if (mateThreat) - result += MateThreatExtension[pvNode]; + result += MateThreatExtension[PvNode]; } if (pos.type_of_piece_on(move_from(m)) == PAWN) @@ -2029,12 +2018,12 @@ namespace { Color c = pos.side_to_move(); if (relative_rank(c, move_to(m)) == RANK_7) { - result += PawnPushTo7thExtension[pvNode]; + result += PawnPushTo7thExtension[PvNode]; *dangerous = true; } if (pos.pawn_is_passed(c, move_to(m))) { - result += PassedPawnExtension[pvNode]; + result += PassedPawnExtension[PvNode]; *dangerous = true; } } @@ -2046,11 +2035,11 @@ namespace { && !move_is_promotion(m) && !move_is_ep(m)) { - result += PawnEndgameExtension[pvNode]; + result += PawnEndgameExtension[PvNode]; *dangerous = true; } - if ( pvNode + if ( PvNode && captureOrPromotion && pos.type_of_piece_on(move_to(m)) != PAWN && pos.see_sign(m) >= 0)