X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=692754b11f36bd262764380281e3b847049d7c5e;hp=4592ac084ebc56d60a59b83415167bd2f75af146;hb=8fabd69d4a70380daa547362ed83be1091b86414;hpb=b638f6b0354ea124dc80e5e38189474d34141e2d diff --git a/src/search.cpp b/src/search.cpp index 4592ac08..692754b1 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -215,12 +215,14 @@ namespace { // Step 14. Reduced search + int ReductionLevel; // 0 = most aggressive reductions, 7 = minimum reductions + // 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 PVReductionMatrix[8][64][64]; // [depth][moveNumber] + int8_t NonPVReductionMatrix[8][64][64]; // [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)]; } + inline Depth pv_reduction(Depth d, int mn) { return (Depth) PVReductionMatrix[ReductionLevel][Min(d / 2, 63)][Min(mn, 63)]; } + inline Depth nonpv_reduction(Depth d, int mn) { return (Depth) NonPVReductionMatrix[ReductionLevel][Min(d / 2, 63)][Min(mn, 63)]; } // Common adjustments @@ -544,20 +546,30 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move, return !Quit; } +// init_reduction_tables() is called by init_search() and initializes +// the tables used by LMR. +static void init_reduction_tables(int8_t pvTable[64][64], int8_t nonPvTable[64][64], int pvInhib, int nonPvInhib) +{ + double pvBase = 1.001 - log(3.0) * log(16.0) / pvInhib; + double nonPvBase = 1.001 - log(3.0) * log(4.0) / nonPvInhib; -/// init_search() is called during startup. It initializes various lookup tables - -void init_search() { - - // Init our reduction lookup tables for (int i = 1; i < 64; i++) // i == depth (OnePly = 1) for (int j = 1; j < 64; j++) // j == moveNumber { - double pvRed = 0.5 + log(double(i)) * log(double(j)) / 6.0; - double nonPVRed = 0.5 + log(double(i)) * log(double(j)) / 3.0; - 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); + double pvRed = pvBase + log(double(i)) * log(double(j)) / pvInhib; + double nonPVRed = nonPvBase + log(double(i)) * log(double(j)) / nonPvInhib; + + pvTable[i][j] = (int8_t) ( pvRed >= 1.0 ? floor( pvRed * int(OnePly)) : 0); + nonPvTable[i][j] = (int8_t) (nonPVRed >= 1.0 ? floor(nonPVRed * int(OnePly)) : 0); } +} + +// init_search() is called during startup. It initializes various lookup tables +void init_search() { + + // Init reduction lookup tables + for (int i = 0; i < 8; i++) + init_reduction_tables(PVReductionMatrix[i], NonPVReductionMatrix[i], int(4 * pow(1.3, i)), int(2 * pow(1.3, i))); // Init futility margins array for (int i = 0; i < 16; i++) // i == depth (OnePly = 2) @@ -660,6 +672,19 @@ namespace { beta = Min(ValueByIteration[Iteration - 1] + AspirationDelta, VALUE_INFINITE); } + // Choose optimum reduction level + ReductionLevel = 2; + + if (UseTimeManagement) + { + int level = int(floor(log(float(MaxSearchTime) / current_search_time()) / log(2.0) + 1.0)); + ReductionLevel = Min(Max(level, 0), 7); + } + else + { + //FIXME + } + // Search to the current depth, rml is updated and sorted, alpha and beta could change value = root_search(p, ss, rml, &alpha, &beta); @@ -1101,14 +1126,13 @@ namespace { tte = TT.retrieve(pos.get_key()); } - // Step 10. Loop through moves - // Loop through all legal moves until no moves remain or a beta cutoff occurs - // Initialize a MovePicker object for the current position mateThreat = pos.has_mate_threat(opposite_color(pos.side_to_move())); MovePicker mp = MovePicker(pos, ttMove, depth, H, &ss[ply]); CheckInfo ci(pos); + // Step 10. Loop through moves + // Loop through all legal moves until no moves remain or a beta cutoff occurs while ( alpha < beta && (move = mp.get_next_move()) != MOVE_NONE && !TM.thread_should_stop(threadID)) @@ -1325,12 +1349,12 @@ namespace { } // Step 6. Razoring - if ( !value_is_mate(beta) + if ( refinedValue < beta - razor_margin(depth) + && ttMove == MOVE_NONE + && ss[ply - 1].currentMove != MOVE_NULL + && depth < RazorDepth && !isCheck - && depth < RazorDepth - && refinedValue < beta - razor_margin(depth) - && ss[ply - 1].currentMove != MOVE_NULL - && ttMove == MOVE_NONE + && !value_is_mate(beta) && !pos.has_pawn_on_7th(pos.side_to_move())) { Value rbeta = beta - razor_margin(depth); @@ -1343,11 +1367,13 @@ namespace { // Step 7. Static null move pruning // We're betting that the opponent doesn't have a move that will reduce - // the score by more than fuility_margin(depth) if we do a null move. - if ( !isCheck - && allowNullmove - && depth < RazorDepth - && refinedValue - futility_margin(depth, 0) >= beta) + // the score by more than futility_margin(depth) if we do a null move. + if ( allowNullmove + && depth < RazorDepth + && !isCheck + && !value_is_mate(beta) + && ok_to_do_nullmove(pos) + && refinedValue >= beta + futility_margin(depth, 0)) return refinedValue - futility_margin(depth, 0); // Step 8. Null move search with verification search @@ -1363,8 +1389,6 @@ namespace { { ss[ply].currentMove = MOVE_NULL; - pos.do_null_move(st); - // Null move dynamic reduction based on depth int R = 3 + (depth >= 5 * OnePly ? depth / 8 : 0); @@ -1372,19 +1396,25 @@ namespace { if (refinedValue - beta > PawnValueMidgame) R++; + pos.do_null_move(st); + nullValue = -search(pos, ss, -(beta-1), depth-R*OnePly, ply+1, false, threadID); pos.undo_null_move(); if (nullValue >= beta) { + // Do not return unproven mate scores + if (nullValue >= value_mate_in(PLY_MAX)) + nullValue = beta; + if (depth < 6 * OnePly) - return beta; + return nullValue; // Do zugzwang verification search Value v = search(pos, ss, beta, depth-5*OnePly, ply, false, threadID); if (v >= beta) - return beta; + return nullValue; } else { // The null move failed low, which means that we may be faced with // some kind of threat. If the previous move was reduced, check if @@ -1414,13 +1444,12 @@ namespace { tte = TT.retrieve(posKey); } - // Step 10. Loop through moves - // Loop through all legal moves until no moves remain or a beta cutoff occurs - // Initialize a MovePicker object for the current position MovePicker mp = MovePicker(pos, ttMove, depth, H, &ss[ply], beta); CheckInfo ci(pos); + // Step 10. Loop through moves + // Loop through all legal moves until no moves remain or a beta cutoff occurs while ( bestValue < beta && (move = mp.get_next_move()) != MOVE_NONE && !TM.thread_should_stop(threadID)) @@ -1443,7 +1472,7 @@ namespace { if ( depth >= SingularExtensionDepthAtNonPVNodes && tte && move == tte->move() - && !excludedMove // Do not allow recursive single-reply search + && !excludedMove // Do not allow recursive singular extension search && ext < OnePly && is_lower_bound(tte->type()) && tte->depth() >= depth - 3 * OnePly) @@ -1493,8 +1522,8 @@ namespace { // Step 13. Make the move pos.do_move(move, st, ci, moveIsCheck); - // Step 14. Reduced search - // if the move fails high will be re-searched at full depth. + // Step 14. Reduced search, if the move fails high + // will be re-searched at full depth. bool doFullDepthSearch = true; if ( depth >= 3*OnePly @@ -1548,11 +1577,11 @@ namespace { } // Step 19. Check for mate and stalemate - // All legal moves have been searched and if there were + // All legal moves have been searched and if there are // no legal moves, it must be mate or stalemate. - // If one move was excluded return fail low. + // If one move was excluded return fail low score. if (!moveCount) - return excludedMove ? beta - 1 : (pos.is_check() ? value_mated_in(ply) : VALUE_DRAW); + return excludedMove ? beta - 1 : (isCheck ? value_mated_in(ply) : VALUE_DRAW); // Step 20. Update tables // If the search is not aborted, update the transposition table, @@ -1672,8 +1701,7 @@ namespace { enoughMaterial = pos.non_pawn_material(pos.side_to_move()) > RookValueMidgame; futilityBase = staticValue + FutilityMarginQS + ei.futilityMargin[pos.side_to_move()]; - // Loop through the moves until no moves remain or a beta cutoff - // occurs. + // Loop through the moves until no moves remain or a beta cutoff occurs while ( alpha < beta && (move = mp.get_next_move()) != MOVE_NONE) { @@ -1742,7 +1770,7 @@ namespace { // All legal moves have been searched. A special case: If we're in check // and no legal moves were found, it is checkmate. - if (!moveCount && pos.is_check()) // Mate! + if (!moveCount && isCheck) // Mate! return value_mated_in(ply); // Update transposition table