X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=ab37e480fc5d50bdb10f79b6e3f08b8e2d0d1e5a;hp=515787c1042da05329220c2737b866be0f3d2da2;hb=7618ee2df1e4e5a3fa6cd511cc42545a255eb9d2;hpb=55f0d6377f7828fb43428ed643a99780053dd589 diff --git a/src/search.cpp b/src/search.cpp index 515787c1..ab37e480 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-2009 Marco Costalba + Copyright (C) 2008-2010 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 @@ -215,12 +215,14 @@ namespace { // Step 14. Reduced search + int ReductionLevel = 2; // 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 @@ -254,10 +256,10 @@ namespace { int MultiPV; // Time managment variables - int RootMoveNumber, SearchStartTime, MaxNodes, MaxDepth; - int MaxSearchTime, AbsoluteMaxSearchTime, ExtraSearchTime, ExactMaxTime; + int SearchStartTime, MaxNodes, MaxDepth, MaxSearchTime; + int AbsoluteMaxSearchTime, ExtraSearchTime, ExactMaxTime; bool UseTimeManagement, InfiniteSearch, PonderSearch, StopOnPonderhit; - bool AbortSearch, Quit, AspirationFailLow; + bool FirstRootMove, AbortSearch, Quit, AspirationFailLow; // Show current line? bool ShowCurrentLine; @@ -282,7 +284,7 @@ namespace { /// Local functions Value id_loop(const Position& pos, Move searchMoves[]); - Value root_search(Position& pos, SearchStack ss[], RootMoveList& rml, Value& oldAlpha, Value& beta); + Value root_search(Position& pos, SearchStack ss[], RootMoveList& rml, Value* alphaPtr, Value* betaPtr); Value search_pv(Position& pos, SearchStack ss[], Value alpha, Value beta, Depth depth, int ply, int threadID); Value search(Position& pos, SearchStack ss[], Value beta, Depth depth, int ply, bool allowNullmove, int threadID, Move excludedMove = MOVE_NONE); Value qsearch(Position& pos, SearchStack ss[], Value alpha, Value beta, Depth depth, int ply, int threadID); @@ -373,6 +375,7 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move, // Initialize global search variables StopOnPonderhit = AbortSearch = Quit = AspirationFailLow = false; + MaxSearchTime = AbsoluteMaxSearchTime = ExtraSearchTime = 0; NodesSincePoll = 0; TM.resetNodeCounters(); SearchStartTime = get_system_time(); @@ -440,10 +443,6 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move, { TM.set_active_threads(newActiveThreads); init_eval(TM.active_threads()); - // HACK: init_eval() destroys the static castleRightsMask[] array in the - // Position class. The below line repairs the damage. - Position p(pos.to_fen()); - assert(pos.is_ok()); } // Wake up sleeping threads @@ -547,20 +546,31 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move, return !Quit; } +// init_reduction_tables() -/// init_search() is called during startup. It initializes various lookup tables - -void init_search() { +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 our reduction lookup tables + // Init 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() { + + for (int i = 0; i < 8; i++) + init_reduction_tables(PVReductionMatrix[i], NonPVReductionMatrix[i], 4.0 * pow(1.3, i), 2.0 * pow(1.3, i)); // Init futility margins array for (int i = 0; i < 16; i++) // i == depth (OnePly = 2) @@ -647,8 +657,6 @@ namespace { // Initialize iteration Iteration++; BestMoveChangesByIteration[Iteration] = 0; - if (Iteration <= 5) - ExtraSearchTime = 0; cout << "info depth " << Iteration << endl; @@ -665,8 +673,21 @@ namespace { beta = Min(ValueByIteration[Iteration - 1] + AspirationDelta, VALUE_INFINITE); } - // Search to the current depth, rml is updated and sorted - value = root_search(p, ss, rml, alpha, beta); + // 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); // Write PV to transposition table, in case the relevant entries have // been overwritten during the search. @@ -786,18 +807,21 @@ namespace { // scheme, prints some information to the standard output and handles // the fail low/high loops. - Value root_search(Position& pos, SearchStack ss[], RootMoveList& rml, Value& oldAlpha, Value& beta) { + Value root_search(Position& pos, SearchStack ss[], RootMoveList& rml, Value* alphaPtr, Value* betaPtr) { EvalInfo ei; StateInfo st; + CheckInfo ci(pos); int64_t nodes; Move move; Depth depth, ext, newDepth; - Value value, alpha; + Value value, alpha, beta; bool isCheck, moveIsCheck, captureOrPromotion, dangerous; - int researchCount = 0; - CheckInfo ci(pos); - alpha = oldAlpha; + int researchCountFH, researchCountFL; + + researchCountFH = researchCountFL = 0; + alpha = *alphaPtr; + beta = *betaPtr; isCheck = pos.is_check(); // Step 1. Initialize node and poll (omitted at root, but I can see no good reason for this, FIXME) @@ -828,8 +852,8 @@ namespace { // Step 10. Loop through all moves in the root move list for (int i = 0; i < rml.move_count() && !AbortSearch; i++) { - // This is used by time management and starts from 1 - RootMoveNumber = i + 1; + // This is used by time management + FirstRootMove = (i == 0); // Save the current node count before the move is searched nodes = TM.nodes_searched(); @@ -843,7 +867,7 @@ namespace { if (current_search_time() >= 1000) cout << "info currmove " << move - << " currmovenumber " << RootMoveNumber << endl; + << " currmovenumber " << i + 1 << endl; moveIsCheck = pos.move_is_check(move); captureOrPromotion = pos.move_is_capture_or_promotion(move); @@ -929,8 +953,8 @@ namespace { print_pv_info(pos, ss, alpha, beta, value); // Prepare for a research after a fail high, each time with a wider window - researchCount++; - beta = Min(beta + AspirationDelta * (1 << researchCount), VALUE_INFINITE); + *betaPtr = beta = Min(beta + AspirationDelta * (1 << researchCountFH), VALUE_INFINITE); + researchCountFH++; } // End of fail high loop @@ -950,6 +974,7 @@ namespace { rml.set_move_nodes(i, TM.nodes_searched() - nodes); assert(value >= -VALUE_INFINITE && value <= VALUE_INFINITE); + assert(value < beta); // Step 17. Check for new best move if (value <= alpha && i >= MultiPV) @@ -975,8 +1000,7 @@ namespace { // Print information to the standard output print_pv_info(pos, ss, alpha, beta, value); - // Raise alpha to setup proper non-pv search upper bound, note - // that we can end up with alpha >= beta and so get a fail high. + // Raise alpha to setup proper non-pv search upper bound if (value > alpha) alpha = value; } @@ -1002,22 +1026,21 @@ namespace { } } // PV move or new best move - assert(alpha >= oldAlpha); + assert(alpha >= *alphaPtr); - AspirationFailLow = (alpha == oldAlpha); + AspirationFailLow = (alpha == *alphaPtr); if (AspirationFailLow && StopOnPonderhit) StopOnPonderhit = false; } // Can we exit fail low loop ? - if (AbortSearch || alpha > oldAlpha) + if (AbortSearch || !AspirationFailLow) break; // Prepare for a research after a fail low, each time with a wider window - researchCount++; - alpha = Max(alpha - AspirationDelta * (1 << researchCount), -VALUE_INFINITE); - oldAlpha = alpha; + *alphaPtr = alpha = Max(alpha - AspirationDelta * (1 << researchCountFL), -VALUE_INFINITE); + researchCountFL++; } // Fail low loop @@ -1381,13 +1404,17 @@ namespace { 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 @@ -2480,7 +2507,7 @@ namespace { if (PonderSearch) return; - bool stillAtFirstMove = RootMoveNumber == 1 + bool stillAtFirstMove = FirstRootMove && !AspirationFailLow && t > MaxSearchTime + ExtraSearchTime; @@ -2503,7 +2530,7 @@ namespace { int t = current_search_time(); PonderSearch = false; - bool stillAtFirstMove = RootMoveNumber == 1 + bool stillAtFirstMove = FirstRootMove && !AspirationFailLow && t > MaxSearchTime + ExtraSearchTime;