]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Improve handling of fail-highs in assumed PV
[stockfish] / src / search.cpp
index 76b79dda74cb189693857247157ac21600e2fb1f..5bb12a856ce19dcb3085727960cc7dc9f5ba1fc6 100644 (file)
@@ -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;
@@ -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;
@@ -520,11 +522,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 +533,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 +702,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 +731,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 +752,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 +828,7 @@ namespace {
 
             if (stopSearch)
             {
+                //FIXME: Implement fail-low emergency measures
                 if (!PonderSearch)
                     break;
                 else
@@ -842,34 +840,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
@@ -1197,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;
           }
         }
       }
@@ -1899,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);
@@ -2497,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.
@@ -2575,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))