From acef5d6a594900009d20524140a6f410cf1e4a0c Mon Sep 17 00:00:00 2001 From: Joona Kiiski Date: Sat, 11 Apr 2009 16:46:35 +0300 Subject: [PATCH 01/10] Dynamic aspiration search without research. Implement system where aspiration search window is calculated using values from previous iterations. And then some crazy experimental stuff: If search fails low at the root, don't widen window, but continue and hope we will find a better move with given window. If search fails high at the root, cut immediately, add some more time and start new iteration. Note: this patch is not complete implementation, but a first test for this idea. There are many FIXMEs left around. Most importantly how to deal with the situation when we don't have any move! Signed-off-by: Marco Costalba --- src/misc.h | 1 + src/search.cpp | 169 +++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 145 insertions(+), 25 deletions(-) diff --git a/src/misc.h b/src/misc.h index 0e656cb2..a496d88e 100644 --- a/src/misc.h +++ b/src/misc.h @@ -47,6 +47,7 @@ const std::string EngineVersion = ""; #define Min(x, y) (((x) < (y))? (x) : (y)) #define Max(x, y) (((x) < (y))? (y) : (x)) +#define Abs(a) (((a) < 0) ? -(a) : (a)) //// diff --git a/src/search.cpp b/src/search.cpp index 1582b7bc..b8d6a3a5 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -47,6 +47,60 @@ namespace { /// Types + //The IterationInfoType is used to store search history + //iteration by iteration. + // + //Because we use relatively small (dynamic) aspiration window, + //there happens many fail highs and fail lows in root. And + //because we don't do researches in those cases, "value" stored + //here is not necessarily exact. Instead in case of fail high/low + //we guess what the right value might be and store our guess + //as "speculated value" and then move on... + + class IterationInfoType { + private: + Value _value; + Value _speculatedValue; + bool _failHigh; + bool _failLow; + public: + IterationInfoType() { + clear(); + } + + inline void clear() { + set(Value(0)); + } + + inline void set(Value v) { + set(v, v, false, false); + } + + inline void set(Value v, Value specV, bool fHigh, bool fLow) { + _value = v; + _speculatedValue = specV; + _failHigh = fHigh; + _failLow = fLow; + } + + inline Value value() { + return _value; + } + + inline Value speculated_value() { + return _speculatedValue; + } + + inline bool fail_high() { + return _failHigh; + } + + inline bool fail_low() { + return _failLow; + } + }; + + // The BetaCounterType class is used to order moves at ply one. // Apart for the first one that has its score, following moves // normally have score -VALUE_INFINITE, so are ordered according @@ -196,7 +250,7 @@ namespace { BetaCounterType BetaCounter; // Scores and number of times the best move changed for each iteration: - Value ValueByIteration[PLY_MAX_PLUS_2]; + IterationInfoType IterationInfo[PLY_MAX_PLUS_2]; int BestMoveChangesByIteration[PLY_MAX_PLUS_2]; // MultiPV mode @@ -214,6 +268,7 @@ namespace { bool AbortSearch; bool Quit; bool FailHigh; + bool FailLow; bool Problem; bool PonderingEnabled; int ExactMaxTime; @@ -246,7 +301,8 @@ namespace { /// Functions Value id_loop(const Position &pos, Move searchMoves[]); - Value root_search(Position &pos, SearchStack ss[], RootMoveList &rml); + Value root_search(Position &pos, SearchStack ss[], RootMoveList &rml, + Value alpha, Value beta); 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, @@ -380,6 +436,7 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move, AbortSearch = false; Quit = false; FailHigh = false; + FailLow = false; Problem = false; ExactMaxTime = maxTime; @@ -654,14 +711,13 @@ namespace { ss[i].init(i); ss[i].initKillers(); } - ValueByIteration[0] = Value(0); - ValueByIteration[1] = rml.get_move_score(0); + IterationInfo[1].set(rml.get_move_score(0)); Iteration = 1; EasyMove = rml.scan_for_easy_move(); // Iterative deepening loop - while (!AbortSearch && Iteration < PLY_MAX) + while (Iteration < PLY_MAX) { // Initialize iteration rml.sort(); @@ -672,8 +728,59 @@ namespace { std::cout << "info depth " << Iteration << std::endl; + //Calculate dynamic search window based on previous iterations. + Value alpha; + Value beta; + + if (MultiPV == 1 && Iteration >= 6) { + Value prevDelta1 = IterationInfo[Iteration - 1].speculated_value() - IterationInfo[Iteration - 2].speculated_value(); + Value prevDelta2 = IterationInfo[Iteration - 2].speculated_value() - IterationInfo[Iteration - 3].speculated_value(); + + Value delta = Max((2 * Abs(prevDelta1) + Abs(prevDelta2)) , ProblemMargin); + + alpha = IterationInfo[Iteration - 1].value() - delta; + beta = IterationInfo[Iteration - 1].value() + delta; + if (alpha < - VALUE_INFINITE) alpha = - VALUE_INFINITE; + if (beta > VALUE_INFINITE) beta = VALUE_INFINITE; + + } else { + alpha = - VALUE_INFINITE; + beta = VALUE_INFINITE; + } + // Search to the current depth - ValueByIteration[Iteration] = root_search(p, ss, rml); + Value value = root_search(p, ss, rml, alpha, beta); + if (AbortSearch) + break; //Value cannot be trusted. Break out immediately! + + // Write PV to transposition table, in case the relevant entries have + // been overwritten during the search: + TT.insert_pv(p, ss[0].pv); + + //Save info about search result + Value speculated_value = value; + bool fHigh = false; + bool fLow = false; + + Value prev_value = IterationInfo[Iteration - 1].value(); + Value delta = value - prev_value; + + if (value >= beta) { + fHigh = true; + speculated_value = prev_value + 2 * delta; + BestMoveChangesByIteration[Iteration] += 2; //This is used to tell time management to allocate more time + } else if (value <= alpha) { + fLow = true; + speculated_value = prev_value + 2 * delta; + BestMoveChangesByIteration[Iteration] += 3; //This is used to tell time management to allocate more time + } else { + //nothing + } + + if (speculated_value < - VALUE_INFINITE) speculated_value = - VALUE_INFINITE; + if (speculated_value > VALUE_INFINITE) speculated_value = VALUE_INFINITE; + + IterationInfo[Iteration].set(value, speculated_value, fHigh, fLow); // Erase the easy move if it differs from the new best move if (ss[0].pv[0] != EasyMove) @@ -692,13 +799,13 @@ namespace { // Stop search early when the last two iterations returned a mate score if ( Iteration >= 6 - && abs(ValueByIteration[Iteration]) >= abs(VALUE_MATE) - 100 - && abs(ValueByIteration[Iteration-1]) >= abs(VALUE_MATE) - 100) + && abs(IterationInfo[Iteration].value()) >= abs(VALUE_MATE) - 100 + && abs(IterationInfo[Iteration-1].value()) >= abs(VALUE_MATE) - 100) stopSearch = true; // Stop search early if one move seems to be much better than the rest int64_t nodes = nodes_searched(); - if ( Iteration >= 8 + if ( Iteration >= 8 && !fLow && !fHigh && EasyMove == ss[0].pv[0] && ( ( rml.get_move_cumulative_nodes(0) > (nodes * 85) / 100 && current_search_time() > MaxSearchTime / 16) @@ -719,15 +826,13 @@ namespace { if (stopSearch) { + //FIXME: Implement fail-low emergency measures if (!PonderSearch) break; else StopOnPonderhit = true; } } - // Write PV to transposition table, in case the relevant entries have - // been overwritten during the search: - TT.insert_pv(p, ss[0].pv); if (MaxDepth && Iteration >= MaxDepth) break; @@ -784,15 +889,22 @@ namespace { // scheme (perhaps we should try to use this at internal PV nodes, too?) // and prints some information to the standard output. - Value root_search(Position &pos, SearchStack ss[], RootMoveList &rml) { + Value root_search(Position &pos, SearchStack ss[], RootMoveList &rml, Value alpha, Value beta) { - Value alpha = -VALUE_INFINITE; - Value beta = VALUE_INFINITE, value; + //FIXME: Implement bestValue + Value oldAlpha = alpha; + Value value; Bitboard dcCandidates = pos.discovered_check_candidates(pos.side_to_move()); // Loop through all the moves in the root move list for (int i = 0; i < rml.move_count() && !AbortSearch; i++) { + if (alpha >= beta) { + rml.set_move_score(i, -VALUE_INFINITE); + //Leave node-counters and beta-counters as they are. + continue; + } + int64_t nodes; Move move; StateInfo st; @@ -825,12 +937,12 @@ namespace { if (i < MultiPV) { - value = -search_pv(pos, ss, -beta, VALUE_INFINITE, newDepth, 1, 0); + value = -search_pv(pos, ss, -beta, -alpha, newDepth, 1, 0); // If the value has dropped a lot compared to the last iteration, // set the boolean variable Problem to true. This variable is used // for time managment: When Problem is true, we try to complete the // current iteration before playing a move. - Problem = (Iteration >= 2 && value <= ValueByIteration[Iteration-1] - ProblemMargin); + Problem = (Iteration >= 2 && value <= IterationInfo[Iteration-1].value() - ProblemMargin); if (Problem && StopOnPonderhit) StopOnPonderhit = false; @@ -906,11 +1018,12 @@ namespace { LogFile << pretty_pv(pos, current_search_time(), Iteration, nodes_searched(), value, ss[0].pv) << std::endl; - alpha = value; + if (value > alpha) + alpha = value; // Reset the global variable Problem to false if the value isn't too // far below the final value from the last iteration. - if (value > ValueByIteration[Iteration - 1] - NoProblemMargin) + if (value > IterationInfo[Iteration - 1].value() - NoProblemMargin) Problem = false; } else // MultiPV > 1 @@ -935,6 +1048,12 @@ namespace { alpha = rml.get_move_score(Min(i, MultiPV-1)); } } + + if (alpha <= oldAlpha) + FailLow = true; + else + FailLow = false; + } return alpha; } @@ -1083,7 +1202,7 @@ namespace { // (from the computer's point of view) since the previous iteration: if ( ply == 1 && Iteration >= 2 - && -value <= ValueByIteration[Iteration-1] - ProblemMargin) + && -value <= IterationInfo[Iteration-1].value() - ProblemMargin) Problem = true; } @@ -1796,7 +1915,7 @@ namespace { // (from the computer's point of view) since the previous iteration. if ( sp->ply == 1 && Iteration >= 2 - && -value <= ValueByIteration[Iteration-1] - ProblemMargin) + && -value <= IterationInfo[Iteration-1].value() - ProblemMargin) Problem = true; } lock_release(&(sp->lock)); @@ -2425,8 +2544,8 @@ namespace { return; bool overTime = t > AbsoluteMaxSearchTime - || (RootMoveNumber == 1 && t > MaxSearchTime + ExtraSearchTime) - || ( !FailHigh && !fail_high_ply_1() && !Problem + || (RootMoveNumber == 1 && t > MaxSearchTime + ExtraSearchTime && !FailLow) //FIXME: BUG?? + || ( !FailHigh && !FailLow && !fail_high_ply_1() && !Problem && t > 6*(MaxSearchTime + ExtraSearchTime)); if ( (Iteration >= 3 && (!InfiniteSearch && overTime)) @@ -2447,8 +2566,8 @@ namespace { (!InfiniteSearch && (StopOnPonderhit || t > AbsoluteMaxSearchTime || (RootMoveNumber == 1 && - t > MaxSearchTime + ExtraSearchTime) || - (!FailHigh && !fail_high_ply_1() && !Problem && + t > MaxSearchTime + ExtraSearchTime && !FailLow) || + (!FailHigh && !FailLow && !fail_high_ply_1() && !Problem && t > 6*(MaxSearchTime + ExtraSearchTime))))) AbortSearch = true; } From 6f28bcd483647e9ea1e7da629ed900fd254430ca Mon Sep 17 00:00:00 2001 From: Joona Kiiski Date: Sun, 12 Apr 2009 19:42:47 +0300 Subject: [PATCH 02/10] Implement bestValue in root_search. However just after finished writing this patch I realized that this is not the way to go. So this will be immediately reverted. (Just save this here in git in case I change my mind later :) ) Signed-off-by: Marco Costalba --- src/search.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index b8d6a3a5..6aa13a5e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -891,7 +891,7 @@ namespace { Value root_search(Position &pos, SearchStack ss[], RootMoveList &rml, Value alpha, Value beta) { - //FIXME: Implement bestValue + Value bestValue = -VALUE_INFINITE; Value oldAlpha = alpha; Value value; Bitboard dcCandidates = pos.discovered_check_candidates(pos.side_to_move()); @@ -899,7 +899,7 @@ namespace { // Loop through all the moves in the root move list for (int i = 0; i < rml.move_count() && !AbortSearch; i++) { - if (alpha >= beta) { + if (alpha >= beta) { //Aspiration window failed high, ignore rest of the moves! rml.set_move_score(i, -VALUE_INFINITE); //Leave node-counters and beta-counters as they are. continue; @@ -982,7 +982,7 @@ namespace { assert(value >= -VALUE_INFINITE && value <= VALUE_INFINITE); - if (value <= alpha && i >= MultiPV) + if (value <= bestValue && i >= MultiPV) rml.set_move_score(i, -VALUE_INFINITE); else { @@ -1018,8 +1018,12 @@ namespace { LogFile << pretty_pv(pos, current_search_time(), Iteration, nodes_searched(), value, ss[0].pv) << std::endl; - if (value > alpha) - alpha = value; + if (value > bestValue) + { + bestValue = value; + if (value > alpha) + alpha = value; + } // Reset the global variable Problem to false if the value isn't too // far below the final value from the last iteration. @@ -1046,16 +1050,17 @@ namespace { std::cout << std::endl; } alpha = rml.get_move_score(Min(i, MultiPV-1)); + bestValue = alpha; //In MultiPV-mode bestValue and alpha are always same thing. } } - if (alpha <= oldAlpha) + if (bestValue <= oldAlpha) FailLow = true; else FailLow = false; } - return alpha; + return bestValue; } From 6c4e36aab6382b7ff43ddab941487c622ca3f85e Mon Sep 17 00:00:00 2001 From: Joona Kiiski Date: Sun, 12 Apr 2009 19:49:09 +0300 Subject: [PATCH 03/10] Revert "Implement bestValue in root_search." This reverts commit 9a39f93f35254787b7b57980019dde276a89c48c. Revert bestValue in root_search Signed-off-by: Marco Costalba --- src/search.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 6aa13a5e..b8d6a3a5 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -891,7 +891,7 @@ namespace { Value root_search(Position &pos, SearchStack ss[], RootMoveList &rml, Value alpha, Value beta) { - Value bestValue = -VALUE_INFINITE; + //FIXME: Implement bestValue Value oldAlpha = alpha; Value value; Bitboard dcCandidates = pos.discovered_check_candidates(pos.side_to_move()); @@ -899,7 +899,7 @@ namespace { // Loop through all the moves in the root move list for (int i = 0; i < rml.move_count() && !AbortSearch; i++) { - if (alpha >= beta) { //Aspiration window failed high, ignore rest of the moves! + if (alpha >= beta) { rml.set_move_score(i, -VALUE_INFINITE); //Leave node-counters and beta-counters as they are. continue; @@ -982,7 +982,7 @@ namespace { assert(value >= -VALUE_INFINITE && value <= VALUE_INFINITE); - if (value <= bestValue && i >= MultiPV) + if (value <= alpha && i >= MultiPV) rml.set_move_score(i, -VALUE_INFINITE); else { @@ -1018,12 +1018,8 @@ namespace { LogFile << pretty_pv(pos, current_search_time(), Iteration, nodes_searched(), value, ss[0].pv) << std::endl; - if (value > bestValue) - { - bestValue = value; - if (value > alpha) - alpha = value; - } + if (value > alpha) + alpha = value; // Reset the global variable Problem to false if the value isn't too // far below the final value from the last iteration. @@ -1050,17 +1046,16 @@ namespace { std::cout << std::endl; } alpha = rml.get_move_score(Min(i, MultiPV-1)); - bestValue = alpha; //In MultiPV-mode bestValue and alpha are always same thing. } } - if (bestValue <= oldAlpha) + if (alpha <= oldAlpha) FailLow = true; else FailLow = false; } - return bestValue; + return alpha; } From 0ea716463bf2722931c160edcc9b68e9a800a93a Mon Sep 17 00:00:00 2001 From: Joona Kiiski Date: Sun, 12 Apr 2009 23:25:05 +0300 Subject: [PATCH 04/10] Implement a fallback system when aspiration search fails low and we are out of time. However also this patch is immediately reverted. For three reasons: 1) the case it affects is very rare (and then we are likely to lose anyway), so we can well live without this. 2) Because the case is so rare it's hard to test this change properly. 3) To perform fallback search, we must reset so many global variables that this patch is very likely both buggy and extremely bad style. Consider including this again if we clean-up global variables one day... Signed-off-by: Marco Costalba --- src/search.cpp | 47 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index b8d6a3a5..76b79dda 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -259,7 +259,7 @@ namespace { // Time managment variables int SearchStartTime; int MaxNodes, MaxDepth; - int MaxSearchTime, AbsoluteMaxSearchTime, ExtraSearchTime; + int MaxSearchTime, AbsoluteMaxSearchTime, EmergencyMaxSearchTime, ExtraSearchTime; Move EasyMove; int RootMoveNumber; bool InfiniteSearch; @@ -520,9 +520,11 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move, { MaxSearchTime = myTime / 30 + myIncrement; AbsoluteMaxSearchTime = Max(myTime / 4, myIncrement - 100); + EmergencyMaxSearchTime = Max(myTime / 2, myIncrement - 100); } else { // Blitz game without increment MaxSearchTime = myTime / 30; AbsoluteMaxSearchTime = myTime / 8; + EmergencyMaxSearchTime = myTime / 4; } } else // (x moves) / (y minutes) @@ -531,9 +533,11 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move, { MaxSearchTime = myTime / 2; AbsoluteMaxSearchTime = Min(myTime / 2, myTime - 500); + EmergencyMaxSearchTime = myTime - 500; } else { MaxSearchTime = myTime / Min(movesToGo, 20); AbsoluteMaxSearchTime = Min((4 * myTime) / movesToGo, myTime / 3); + EmergencyMaxSearchTime = Min((8 * myTime) / movesToGo, myTime / 2); } } @@ -700,6 +704,9 @@ namespace { Position p(pos); SearchStack ss[PLY_MAX_PLUS_2]; + Value alpha; + Value beta; + // searchMoves are verified, copied, scored and sorted RootMoveList rml(p, searchMoves); @@ -729,9 +736,6 @@ namespace { std::cout << "info depth " << Iteration << std::endl; //Calculate dynamic search window based on previous iterations. - Value alpha; - Value beta; - if (MultiPV == 1 && Iteration >= 6) { Value prevDelta1 = IterationInfo[Iteration - 1].speculated_value() - IterationInfo[Iteration - 2].speculated_value(); Value prevDelta2 = IterationInfo[Iteration - 2].speculated_value() - IterationInfo[Iteration - 3].speculated_value(); @@ -750,13 +754,14 @@ namespace { // Search to the current depth Value value = root_search(p, ss, rml, alpha, beta); - if (AbortSearch) - break; //Value cannot be trusted. Break out immediately! // Write PV to transposition table, in case the relevant entries have // been overwritten during the search: TT.insert_pv(p, ss[0].pv); + if (AbortSearch) + break; //Value cannot be trusted. Break out immediately! + //Save info about search result Value speculated_value = value; bool fHigh = false; @@ -826,7 +831,6 @@ namespace { if (stopSearch) { - //FIXME: Implement fail-low emergency measures if (!PonderSearch) break; else @@ -838,6 +842,34 @@ namespace { break; } + if (FailLow) + { + //Here we face the rare, but extremely difficult case: + //Our aspiration search has failed low and we've run out of time! + //So we have no move to play! + //Now use the emergency time and try as quickly as possible to + //find even one playable move. + + //FIXME: this is only for grepping logs purpose. Remove me when we are sure that this stuff really works!! + if (AbortSearch) + std::cout << "info depth " << 999 << std::endl; + else + std::cout << "info depth " << 998 << std::endl; + + //Prepare variables for emergency search + AbortSearch = false; + FailLow = false; + AbsoluteMaxSearchTime = EmergencyMaxSearchTime; + MaxSearchTime = EmergencyMaxSearchTime; + ExtraSearchTime = 0; + rml.sort(); + + std::cout << "info depth " << Iteration << std::endl; + + //Cause we failed low, it's _likely_ that we couldn't get over alpha anyway. + root_search(p, ss, rml, -VALUE_INFINITE, alpha); + } + rml.sort(); // If we are pondering, we shouldn't print the best move before we @@ -891,7 +923,6 @@ namespace { Value root_search(Position &pos, SearchStack ss[], RootMoveList &rml, Value alpha, Value beta) { - //FIXME: Implement bestValue Value oldAlpha = alpha; Value value; Bitboard dcCandidates = pos.discovered_check_candidates(pos.side_to_move()); From 3e7e1a7c53c251c244d8271082b602e6b9a9b208 Mon Sep 17 00:00:00 2001 From: Joona Kiiski Date: Sun, 12 Apr 2009 23:30:40 +0300 Subject: [PATCH 05/10] Revert "Implement a fallback system when aspiration search fails low and we are out of time." This reverts commit 55dd98f7c717b94a659931cd20e088334b1cf7a6. Revert fallback-system for root_search Signed-off-by: Marco Costalba --- src/search.cpp | 47 ++++++++--------------------------------------- 1 file changed, 8 insertions(+), 39 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 76b79dda..b8d6a3a5 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -259,7 +259,7 @@ namespace { // Time managment variables int SearchStartTime; int MaxNodes, MaxDepth; - int MaxSearchTime, AbsoluteMaxSearchTime, EmergencyMaxSearchTime, ExtraSearchTime; + int MaxSearchTime, AbsoluteMaxSearchTime, ExtraSearchTime; Move EasyMove; int RootMoveNumber; bool InfiniteSearch; @@ -520,11 +520,9 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move, { MaxSearchTime = myTime / 30 + myIncrement; AbsoluteMaxSearchTime = Max(myTime / 4, myIncrement - 100); - EmergencyMaxSearchTime = Max(myTime / 2, myIncrement - 100); } else { // Blitz game without increment MaxSearchTime = myTime / 30; AbsoluteMaxSearchTime = myTime / 8; - EmergencyMaxSearchTime = myTime / 4; } } else // (x moves) / (y minutes) @@ -533,11 +531,9 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move, { MaxSearchTime = myTime / 2; AbsoluteMaxSearchTime = Min(myTime / 2, myTime - 500); - EmergencyMaxSearchTime = myTime - 500; } else { MaxSearchTime = myTime / Min(movesToGo, 20); AbsoluteMaxSearchTime = Min((4 * myTime) / movesToGo, myTime / 3); - EmergencyMaxSearchTime = Min((8 * myTime) / movesToGo, myTime / 2); } } @@ -704,9 +700,6 @@ namespace { Position p(pos); SearchStack ss[PLY_MAX_PLUS_2]; - Value alpha; - Value beta; - // searchMoves are verified, copied, scored and sorted RootMoveList rml(p, searchMoves); @@ -736,6 +729,9 @@ namespace { std::cout << "info depth " << Iteration << std::endl; //Calculate dynamic search window based on previous iterations. + Value alpha; + Value beta; + if (MultiPV == 1 && Iteration >= 6) { Value prevDelta1 = IterationInfo[Iteration - 1].speculated_value() - IterationInfo[Iteration - 2].speculated_value(); Value prevDelta2 = IterationInfo[Iteration - 2].speculated_value() - IterationInfo[Iteration - 3].speculated_value(); @@ -754,14 +750,13 @@ namespace { // Search to the current depth Value value = root_search(p, ss, rml, alpha, beta); + if (AbortSearch) + break; //Value cannot be trusted. Break out immediately! // Write PV to transposition table, in case the relevant entries have // been overwritten during the search: TT.insert_pv(p, ss[0].pv); - if (AbortSearch) - break; //Value cannot be trusted. Break out immediately! - //Save info about search result Value speculated_value = value; bool fHigh = false; @@ -831,6 +826,7 @@ namespace { if (stopSearch) { + //FIXME: Implement fail-low emergency measures if (!PonderSearch) break; else @@ -842,34 +838,6 @@ namespace { break; } - if (FailLow) - { - //Here we face the rare, but extremely difficult case: - //Our aspiration search has failed low and we've run out of time! - //So we have no move to play! - //Now use the emergency time and try as quickly as possible to - //find even one playable move. - - //FIXME: this is only for grepping logs purpose. Remove me when we are sure that this stuff really works!! - if (AbortSearch) - std::cout << "info depth " << 999 << std::endl; - else - std::cout << "info depth " << 998 << std::endl; - - //Prepare variables for emergency search - AbortSearch = false; - FailLow = false; - AbsoluteMaxSearchTime = EmergencyMaxSearchTime; - MaxSearchTime = EmergencyMaxSearchTime; - ExtraSearchTime = 0; - rml.sort(); - - std::cout << "info depth " << Iteration << std::endl; - - //Cause we failed low, it's _likely_ that we couldn't get over alpha anyway. - root_search(p, ss, rml, -VALUE_INFINITE, alpha); - } - rml.sort(); // If we are pondering, we shouldn't print the best move before we @@ -923,6 +891,7 @@ namespace { Value root_search(Position &pos, SearchStack ss[], RootMoveList &rml, Value alpha, Value beta) { + //FIXME: Implement bestValue Value oldAlpha = alpha; Value value; Bitboard dcCandidates = pos.discovered_check_candidates(pos.side_to_move()); From 22f9f0cabe6f8de8051470fae3917533a411067e Mon Sep 17 00:00:00 2001 From: Joona Kiiski Date: Mon, 13 Apr 2009 00:27:07 +0300 Subject: [PATCH 06/10] Improve handling of fail-highs in assumed PV Check all fail highs in assumed PV with greater care (fruit/Toga already does this). Add a flag when aspiration search fails high at ply 1 to prevent search to be terminated prematurely. Signed-off-by: Marco Costalba --- src/search.cpp | 37 ++++++++++++++++++++++++++++++------- src/thread.h | 1 + 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index b8d6a3a5..5bb12a85 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -326,6 +326,7 @@ namespace { void update_killers(Move m, SearchStack& ss); bool fail_high_ply_1(); + bool aspiration_fail_high_ply_1(); int current_search_time(); int nps(); void poll(); @@ -428,6 +429,7 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move, { Threads[i].nodes = 0ULL; Threads[i].failHighPly1 = false; + Threads[i].aspirationFailHighPly1 = false; } NodesSincePoll = 0; InfiniteSearch = infinite; @@ -891,7 +893,6 @@ namespace { Value root_search(Position &pos, SearchStack ss[], RootMoveList &rml, Value alpha, Value beta) { - //FIXME: Implement bestValue Value oldAlpha = alpha; Value value; Bitboard dcCandidates = pos.discovered_check_candidates(pos.side_to_move()); @@ -1166,19 +1167,29 @@ namespace { { ss[ply].reduction = Depth(0); value = -search(pos, ss, -alpha, newDepth, ply+1, true, threadID); - if (value > alpha && value < beta) + if (value > alpha /*&& value < beta*/) { // When the search fails high at ply 1 while searching the first // move at the root, set the flag failHighPly1. This is used for // time managment: We don't want to stop the search early in // such cases, because resolving the fail high at ply 1 could // result in a big drop in score at the root. - if (ply == 1 && RootMoveNumber == 1) + if (ply == 1 && RootMoveNumber == 1) { Threads[threadID].failHighPly1 = true; + if (value >= beta) { + Threads[threadID].aspirationFailHighPly1 = true; + } + } // A fail high occurred. Re-search at full window (pv search) value = -search_pv(pos, ss, -beta, -alpha, newDepth, ply+1, threadID); Threads[threadID].failHighPly1 = false; + //FIXME: Current implementation of Problem code is not completely thread-safe. + //If poll is called before pv is updated, we lose this move. + //(failHighPly1 also suffers from same kind of problems though. There is also a small + //fraction of time when failHighPly1 and Problem are _both_ false, though we + //are facing bad problems. If we are very unlucky search is terminated). + Threads[threadID].aspirationFailHighPly1 = false; } } } @@ -1868,18 +1879,23 @@ namespace { ss[sp->ply].reduction = Depth(0); value = -search(pos, ss, -sp->alpha, newDepth, sp->ply+1, true, threadID); - if (value > sp->alpha && value < sp->beta) + if (value > sp->alpha /*&& value < sp->beta*/) { // When the search fails high at ply 1 while searching the first // move at the root, set the flag failHighPly1. This is used for // time managment: We don't want to stop the search early in // such cases, because resolving the fail high at ply 1 could // result in a big drop in score at the root. - if (sp->ply == 1 && RootMoveNumber == 1) + if (sp->ply == 1 && RootMoveNumber == 1) { Threads[threadID].failHighPly1 = true; + if (value >= sp->beta) { + Threads[threadID].aspirationFailHighPly1 = true; + } + } value = -search_pv(pos, ss, -sp->beta, -sp->alpha, newDepth, sp->ply+1, threadID); Threads[threadID].failHighPly1 = false; + Threads[threadID].aspirationFailHighPly1 = false; } } pos.undo_move(move); @@ -2466,6 +2482,13 @@ namespace { return false; } + bool aspiration_fail_high_ply_1() { + for(int i = 0; i < ActiveThreads; i++) + if(Threads[i].aspirationFailHighPly1) + return true; + return false; + } + // current_search_time() returns the number of milliseconds which have passed // since the beginning of the current search. @@ -2544,8 +2567,8 @@ namespace { return; bool overTime = t > AbsoluteMaxSearchTime - || (RootMoveNumber == 1 && t > MaxSearchTime + ExtraSearchTime && !FailLow) //FIXME: BUG?? - || ( !FailHigh && !FailLow && !fail_high_ply_1() && !Problem + || (RootMoveNumber == 1 && t > MaxSearchTime + ExtraSearchTime && !FailLow && !aspiration_fail_high_ply_1()) + || ( !FailHigh && !FailLow && !fail_high_ply_1() && !aspiration_fail_high_ply_1() && !Problem && t > 6*(MaxSearchTime + ExtraSearchTime)); if ( (Iteration >= 3 && (!InfiniteSearch && overTime)) diff --git a/src/thread.h b/src/thread.h index d97a25a6..1d3e9684 100644 --- a/src/thread.h +++ b/src/thread.h @@ -67,6 +67,7 @@ struct Thread { int activeSplitPoints; uint64_t nodes; bool failHighPly1; + bool aspirationFailHighPly1; volatile bool stop; volatile bool running; volatile bool idle; From 8da2153ee89dd6874cdf35bacedcc73ea8d13d2c Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Wed, 15 Apr 2009 10:20:35 +0200 Subject: [PATCH 07/10] Revert previous patch as per Joona request Joona says patch gives bad results after testing, so revert for now. Signed-off-by: Marco Costalba --- src/search.cpp | 37 +++++++------------------------------ src/thread.h | 1 - 2 files changed, 7 insertions(+), 31 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 5bb12a85..b8d6a3a5 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -326,7 +326,6 @@ namespace { void update_killers(Move m, SearchStack& ss); bool fail_high_ply_1(); - bool aspiration_fail_high_ply_1(); int current_search_time(); int nps(); void poll(); @@ -429,7 +428,6 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move, { Threads[i].nodes = 0ULL; Threads[i].failHighPly1 = false; - Threads[i].aspirationFailHighPly1 = false; } NodesSincePoll = 0; InfiniteSearch = infinite; @@ -893,6 +891,7 @@ namespace { Value root_search(Position &pos, SearchStack ss[], RootMoveList &rml, Value alpha, Value beta) { + //FIXME: Implement bestValue Value oldAlpha = alpha; Value value; Bitboard dcCandidates = pos.discovered_check_candidates(pos.side_to_move()); @@ -1167,29 +1166,19 @@ namespace { { ss[ply].reduction = Depth(0); value = -search(pos, ss, -alpha, newDepth, ply+1, true, threadID); - if (value > alpha /*&& value < beta*/) + if (value > alpha && value < beta) { // When the search fails high at ply 1 while searching the first // move at the root, set the flag failHighPly1. This is used for // time managment: We don't want to stop the search early in // such cases, because resolving the fail high at ply 1 could // result in a big drop in score at the root. - if (ply == 1 && RootMoveNumber == 1) { + if (ply == 1 && RootMoveNumber == 1) Threads[threadID].failHighPly1 = true; - if (value >= beta) { - Threads[threadID].aspirationFailHighPly1 = true; - } - } // A fail high occurred. Re-search at full window (pv search) value = -search_pv(pos, ss, -beta, -alpha, newDepth, ply+1, threadID); Threads[threadID].failHighPly1 = false; - //FIXME: Current implementation of Problem code is not completely thread-safe. - //If poll is called before pv is updated, we lose this move. - //(failHighPly1 also suffers from same kind of problems though. There is also a small - //fraction of time when failHighPly1 and Problem are _both_ false, though we - //are facing bad problems. If we are very unlucky search is terminated). - Threads[threadID].aspirationFailHighPly1 = false; } } } @@ -1879,23 +1868,18 @@ namespace { ss[sp->ply].reduction = Depth(0); value = -search(pos, ss, -sp->alpha, newDepth, sp->ply+1, true, threadID); - if (value > sp->alpha /*&& value < sp->beta*/) + if (value > sp->alpha && value < sp->beta) { // When the search fails high at ply 1 while searching the first // move at the root, set the flag failHighPly1. This is used for // time managment: We don't want to stop the search early in // such cases, because resolving the fail high at ply 1 could // result in a big drop in score at the root. - if (sp->ply == 1 && RootMoveNumber == 1) { + if (sp->ply == 1 && RootMoveNumber == 1) Threads[threadID].failHighPly1 = true; - if (value >= sp->beta) { - Threads[threadID].aspirationFailHighPly1 = true; - } - } value = -search_pv(pos, ss, -sp->beta, -sp->alpha, newDepth, sp->ply+1, threadID); Threads[threadID].failHighPly1 = false; - Threads[threadID].aspirationFailHighPly1 = false; } } pos.undo_move(move); @@ -2482,13 +2466,6 @@ namespace { return false; } - bool aspiration_fail_high_ply_1() { - for(int i = 0; i < ActiveThreads; i++) - if(Threads[i].aspirationFailHighPly1) - return true; - return false; - } - // current_search_time() returns the number of milliseconds which have passed // since the beginning of the current search. @@ -2567,8 +2544,8 @@ namespace { return; bool overTime = t > AbsoluteMaxSearchTime - || (RootMoveNumber == 1 && t > MaxSearchTime + ExtraSearchTime && !FailLow && !aspiration_fail_high_ply_1()) - || ( !FailHigh && !FailLow && !fail_high_ply_1() && !aspiration_fail_high_ply_1() && !Problem + || (RootMoveNumber == 1 && t > MaxSearchTime + ExtraSearchTime && !FailLow) //FIXME: BUG?? + || ( !FailHigh && !FailLow && !fail_high_ply_1() && !Problem && t > 6*(MaxSearchTime + ExtraSearchTime)); if ( (Iteration >= 3 && (!InfiniteSearch && overTime)) diff --git a/src/thread.h b/src/thread.h index 1d3e9684..d97a25a6 100644 --- a/src/thread.h +++ b/src/thread.h @@ -67,7 +67,6 @@ struct Thread { int activeSplitPoints; uint64_t nodes; bool failHighPly1; - bool aspirationFailHighPly1; volatile bool stop; volatile bool running; volatile bool idle; From ecec7dbf894ae76fb44750ffe429496fb05fcceb Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Wed, 15 Apr 2009 12:44:55 +0200 Subject: [PATCH 08/10] Little code style tweaks Let the code be more conformant to current style. No functional change. Signed-off-by: Marco Costalba --- src/misc.h | 1 - src/search.cpp | 179 ++++++++++++++++++++----------------------------- 2 files changed, 71 insertions(+), 109 deletions(-) diff --git a/src/misc.h b/src/misc.h index a496d88e..0e656cb2 100644 --- a/src/misc.h +++ b/src/misc.h @@ -47,7 +47,6 @@ const std::string EngineVersion = ""; #define Min(x, y) (((x) < (y))? (x) : (y)) #define Max(x, y) (((x) < (y))? (y) : (x)) -#define Abs(a) (((a) < 0) ? -(a) : (a)) //// diff --git a/src/search.cpp b/src/search.cpp index b8d6a3a5..8414e329 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -47,57 +47,24 @@ namespace { /// Types - //The IterationInfoType is used to store search history - //iteration by iteration. + // IterationInfoType stores search results for each iteration // - //Because we use relatively small (dynamic) aspiration window, - //there happens many fail highs and fail lows in root. And - //because we don't do researches in those cases, "value" stored - //here is not necessarily exact. Instead in case of fail high/low - //we guess what the right value might be and store our guess - //as "speculated value" and then move on... + // Because we use relatively small (dynamic) aspiration window, + // there happens many fail highs and fail lows in root. And + // because we don't do researches in those cases, "value" stored + // here is not necessarily exact. Instead in case of fail high/low + // we guess what the right value might be and store our guess + // as a "speculated value" and then move on. Speculated values are + // used just to calculate aspiration window width, so also if are + // not exact is not big a problem. - class IterationInfoType { - private: - Value _value; - Value _speculatedValue; - bool _failHigh; - bool _failLow; - public: - IterationInfoType() { - clear(); - } + struct IterationInfoType { - inline void clear() { - set(Value(0)); - } + IterationInfoType(Value v = Value(0), Value sv = Value(0), bool fh = false, bool fl = false) + : value(v), speculatedValue(sv), failHigh(fh), failLow(fl) {} - inline void set(Value v) { - set(v, v, false, false); - } - - inline void set(Value v, Value specV, bool fHigh, bool fLow) { - _value = v; - _speculatedValue = specV; - _failHigh = fHigh; - _failLow = fLow; - } - - inline Value value() { - return _value; - } - - inline Value speculated_value() { - return _speculatedValue; - } - - inline bool fail_high() { - return _failHigh; - } - - inline bool fail_low() { - return _failLow; - } + Value value, speculatedValue; + bool failHigh, failLow; }; @@ -301,14 +268,10 @@ namespace { /// Functions Value id_loop(const Position &pos, Move searchMoves[]); - Value root_search(Position &pos, SearchStack ss[], RootMoveList &rml, - Value alpha, Value beta); - 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); - Value qsearch(Position &pos, SearchStack ss[], Value alpha, Value beta, - Depth depth, int ply, int threadID); + Value root_search(Position &pos, SearchStack ss[], RootMoveList &rml, Value alpha, Value beta); + 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); + 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); void init_node(SearchStack ss[], int ply, int threadID); @@ -711,7 +674,7 @@ namespace { ss[i].init(i); ss[i].initKillers(); } - IterationInfo[1].set(rml.get_move_score(0)); + IterationInfo[1] = IterationInfoType(rml.get_move_score(0), rml.get_move_score(0)); Iteration = 1; EasyMove = rml.scan_for_easy_move(); @@ -728,59 +691,60 @@ namespace { std::cout << "info depth " << Iteration << std::endl; - //Calculate dynamic search window based on previous iterations. - Value alpha; - Value beta; + // Calculate dynamic search window based on previous iterations + Value alpha, beta; - if (MultiPV == 1 && Iteration >= 6) { - Value prevDelta1 = IterationInfo[Iteration - 1].speculated_value() - IterationInfo[Iteration - 2].speculated_value(); - Value prevDelta2 = IterationInfo[Iteration - 2].speculated_value() - IterationInfo[Iteration - 3].speculated_value(); + if (MultiPV == 1 && Iteration >= 6) + { + int prevDelta1 = IterationInfo[Iteration - 1].speculatedValue - IterationInfo[Iteration - 2].speculatedValue; + int prevDelta2 = IterationInfo[Iteration - 2].speculatedValue - IterationInfo[Iteration - 3].speculatedValue; - Value delta = Max((2 * Abs(prevDelta1) + Abs(prevDelta2)) , ProblemMargin); + int delta = Max(2 * abs(prevDelta1) + abs(prevDelta2), ProblemMargin); - alpha = IterationInfo[Iteration - 1].value() - delta; - beta = IterationInfo[Iteration - 1].value() + delta; - if (alpha < - VALUE_INFINITE) alpha = - VALUE_INFINITE; - if (beta > VALUE_INFINITE) beta = VALUE_INFINITE; - - } else { - alpha = - VALUE_INFINITE; - beta = VALUE_INFINITE; + alpha = Max(IterationInfo[Iteration - 1].value - delta, -VALUE_INFINITE); + beta = Min(IterationInfo[Iteration - 1].value + delta, VALUE_INFINITE); + } + else + { + alpha = - VALUE_INFINITE; + beta = VALUE_INFINITE; } // Search to the current depth Value value = root_search(p, ss, rml, alpha, beta); if (AbortSearch) - break; //Value cannot be trusted. Break out immediately! + break; // Value cannot be trusted. Break out immediately! // Write PV to transposition table, in case the relevant entries have - // been overwritten during the search: + // been overwritten during the search. TT.insert_pv(p, ss[0].pv); //Save info about search result - Value speculated_value = value; + Value speculatedValue; bool fHigh = false; bool fLow = false; + Value delta = value - IterationInfo[Iteration - 1].value; - Value prev_value = IterationInfo[Iteration - 1].value(); - Value delta = value - prev_value; + if (value >= beta) + { + assert(delta > 0); - if (value >= beta) { - fHigh = true; - speculated_value = prev_value + 2 * delta; - BestMoveChangesByIteration[Iteration] += 2; //This is used to tell time management to allocate more time - } else if (value <= alpha) { - fLow = true; - speculated_value = prev_value + 2 * delta; - BestMoveChangesByIteration[Iteration] += 3; //This is used to tell time management to allocate more time - } else { - //nothing + fHigh = true; + speculatedValue = value + delta; + BestMoveChangesByIteration[Iteration] += 2; // Allocate more time } + else if (value <= alpha) + { + assert(delta < 0); - if (speculated_value < - VALUE_INFINITE) speculated_value = - VALUE_INFINITE; - if (speculated_value > VALUE_INFINITE) speculated_value = VALUE_INFINITE; + fLow = true; + speculatedValue = value + delta; + BestMoveChangesByIteration[Iteration] += 3; // Allocate more time + } else + speculatedValue = value; - IterationInfo[Iteration].set(value, speculated_value, fHigh, fLow); + speculatedValue = Min(Max(speculatedValue, -VALUE_INFINITE), VALUE_INFINITE); + IterationInfo[Iteration] = IterationInfoType(value, speculatedValue, fHigh, fLow); // Erase the easy move if it differs from the new best move if (ss[0].pv[0] != EasyMove) @@ -799,13 +763,15 @@ namespace { // Stop search early when the last two iterations returned a mate score if ( Iteration >= 6 - && abs(IterationInfo[Iteration].value()) >= abs(VALUE_MATE) - 100 - && abs(IterationInfo[Iteration-1].value()) >= abs(VALUE_MATE) - 100) + && abs(IterationInfo[Iteration].value) >= abs(VALUE_MATE) - 100 + && abs(IterationInfo[Iteration-1].value) >= abs(VALUE_MATE) - 100) stopSearch = true; // Stop search early if one move seems to be much better than the rest int64_t nodes = nodes_searched(); - if ( Iteration >= 8 && !fLow && !fHigh + if ( Iteration >= 8 + && !fLow + && !fHigh && EasyMove == ss[0].pv[0] && ( ( rml.get_move_cumulative_nodes(0) > (nodes * 85) / 100 && current_search_time() > MaxSearchTime / 16) @@ -899,12 +865,11 @@ namespace { // Loop through all the moves in the root move list for (int i = 0; i < rml.move_count() && !AbortSearch; i++) { - if (alpha >= beta) { - rml.set_move_score(i, -VALUE_INFINITE); - //Leave node-counters and beta-counters as they are. - continue; + if (alpha >= beta) + { + rml.set_move_score(i, -VALUE_INFINITE); + continue; // Leave node-counters and beta-counters as they are } - int64_t nodes; Move move; StateInfo st; @@ -942,7 +907,7 @@ namespace { // set the boolean variable Problem to true. This variable is used // for time managment: When Problem is true, we try to complete the // current iteration before playing a move. - Problem = (Iteration >= 2 && value <= IterationInfo[Iteration-1].value() - ProblemMargin); + Problem = (Iteration >= 2 && value <= IterationInfo[Iteration-1].value - ProblemMargin); if (Problem && StopOnPonderhit) StopOnPonderhit = false; @@ -967,7 +932,7 @@ namespace { // was aborted because the user interrupted the search or because we // ran out of time. In this case, the return value of the search cannot // be trusted, and we break out of the loop without updating the best - // move and/or PV: + // move and/or PV. if (AbortSearch) break; @@ -1019,11 +984,11 @@ namespace { << std::endl; if (value > alpha) - alpha = value; + alpha = value; // Reset the global variable Problem to false if the value isn't too // far below the final value from the last iteration. - if (value > IterationInfo[Iteration - 1].value() - NoProblemMargin) + if (value > IterationInfo[Iteration - 1].value - NoProblemMargin) Problem = false; } else // MultiPV > 1 @@ -1047,13 +1012,11 @@ namespace { } alpha = rml.get_move_score(Min(i, MultiPV-1)); } - } + } // New best move case - if (alpha <= oldAlpha) - FailLow = true; - else - FailLow = false; + assert(alpha >= oldAlpha); + FailLow = (alpha == oldAlpha); } return alpha; } @@ -1202,7 +1165,7 @@ namespace { // (from the computer's point of view) since the previous iteration: if ( ply == 1 && Iteration >= 2 - && -value <= IterationInfo[Iteration-1].value() - ProblemMargin) + && -value <= IterationInfo[Iteration-1].value - ProblemMargin) Problem = true; } @@ -1915,7 +1878,7 @@ namespace { // (from the computer's point of view) since the previous iteration. if ( sp->ply == 1 && Iteration >= 2 - && -value <= IterationInfo[Iteration-1].value() - ProblemMargin) + && -value <= IterationInfo[Iteration-1].value - ProblemMargin) Problem = true; } lock_release(&(sp->lock)); From 7af1b40b4e560da33a35825d61eedf1775cc7110 Mon Sep 17 00:00:00 2001 From: Joona Kiiski Date: Wed, 15 Apr 2009 18:14:06 +0300 Subject: [PATCH 09/10] Restore calling insert_pv after search is aborted + small clean-up Restore old behaviour that after search is aborted we call insert_pv, before breaking out from the iterative deepening loop. Remove one useless FIXME and document other better. Signed-off-by: Marco Costalba --- src/search.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 8414e329..d769619d 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -712,13 +712,14 @@ namespace { // Search to the current depth Value value = root_search(p, ss, rml, alpha, beta); - if (AbortSearch) - break; // Value cannot be trusted. Break out immediately! // Write PV to transposition table, in case the relevant entries have // been overwritten during the search. TT.insert_pv(p, ss[0].pv); + if (AbortSearch) + break; // Value cannot be trusted. Break out immediately! + //Save info about search result Value speculatedValue; bool fHigh = false; @@ -857,7 +858,6 @@ namespace { Value root_search(Position &pos, SearchStack ss[], RootMoveList &rml, Value alpha, Value beta) { - //FIXME: Implement bestValue Value oldAlpha = alpha; Value value; Bitboard dcCandidates = pos.discovered_check_candidates(pos.side_to_move()); @@ -2507,7 +2507,7 @@ namespace { return; bool overTime = t > AbsoluteMaxSearchTime - || (RootMoveNumber == 1 && t > MaxSearchTime + ExtraSearchTime && !FailLow) //FIXME: BUG?? + || (RootMoveNumber == 1 && t > MaxSearchTime + ExtraSearchTime && !FailLow) //FIXME: We are not checking any problem flags, BUG? || ( !FailHigh && !FailLow && !fail_high_ply_1() && !Problem && t > 6*(MaxSearchTime + ExtraSearchTime)); From e30720b0bf10a91c04fcd5d881a728a3d97e850f Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Thu, 16 Apr 2009 10:02:01 +0200 Subject: [PATCH 10/10] Remove failHigh/Low bits from IterationInfoType We don't use that info anyway. Also document a little more new aspiration window code. Signed-off-by: Marco Costalba --- src/search.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index d769619d..21aa4f92 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -60,11 +60,10 @@ namespace { struct IterationInfoType { - IterationInfoType(Value v = Value(0), Value sv = Value(0), bool fh = false, bool fl = false) - : value(v), speculatedValue(sv), failHigh(fh), failLow(fl) {} + IterationInfoType(Value v = Value(0), Value sv = Value(0)) + : value(v), speculatedValue(sv) {} Value value, speculatedValue; - bool failHigh, failLow; }; @@ -736,6 +735,7 @@ namespace { } else if (value <= alpha) { + assert(value == alpha); assert(delta < 0); fLow = true; @@ -745,7 +745,7 @@ namespace { speculatedValue = value; speculatedValue = Min(Max(speculatedValue, -VALUE_INFINITE), VALUE_INFINITE); - IterationInfo[Iteration] = IterationInfoType(value, speculatedValue, fHigh, fLow); + IterationInfo[Iteration] = IterationInfoType(value, speculatedValue); // Erase the easy move if it differs from the new best move if (ss[0].pv[0] != EasyMove) @@ -867,8 +867,11 @@ namespace { { if (alpha >= beta) { + // We failed high, invalidate and skip next moves, leave node-counters + // and beta-counters as they are and quickly return, we will try to do + // a research at the next iteration with a bigger aspiration window. rml.set_move_score(i, -VALUE_INFINITE); - continue; // Leave node-counters and beta-counters as they are + continue; } int64_t nodes; Move move; @@ -951,7 +954,7 @@ namespace { rml.set_move_score(i, -VALUE_INFINITE); else { - // New best move! + // PV move or new best move! // Update PV rml.set_move_score(i, value);