]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Reintroduce depth 2 razoring (with additional margin)
[stockfish] / src / search.cpp
index a5b07d2f18c30185d2da0192076dd612578a0480..2acca99c25c72f901cbe6bbcfeac681def339d49 100644 (file)
@@ -66,8 +66,9 @@ namespace {
   const int SkipSize[]  = { 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4 };
   const int SkipPhase[] = { 0, 1, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 7 };
 
-  // Razoring and futility margins
-  const int RazorMargin = 590;
+  // Razor and futility margins
+  const int RazorMargin1 = 590;
+  const int RazorMargin2 = 604;
   Value futility_margin(Depth d) { return Value(150 * d / ONE_PLY); }
 
   // Futility and reductions lookup tables, initialized at startup
@@ -325,7 +326,7 @@ void Thread::search() {
 
       // Age out PV variability metric
       if (mainThread)
-          mainThread->bestMoveChanges *= 0.505, mainThread->failedLow = false;
+          mainThread->bestMoveChanges *= 0.517, mainThread->failedLow = false;
 
       // Save the last iteration's scores before first PV line is searched and
       // all the move scores except the (new) PV are set to -VALUE_INFINITE.
@@ -444,21 +445,21 @@ void Thread::search() {
               const int F[] = { mainThread->failedLow,
                                 bestValue - mainThread->previousScore };
 
-              int improvingFactor = std::max(229, std::min(715, 357 + 119 * F[0] - 6 * F[1]));
+              int improvingFactor = std::max(246, std::min(832, 306 + 119 * F[0] - 6 * F[1]));
 
               // If the bestMove is stable over several iterations, reduce time accordingly
               timeReduction = 1.0;
               for (int i : {3, 4, 5})
                   if (lastBestMoveDepth * i < completedDepth)
-                     timeReduction *= 1.3;
+                     timeReduction *= 1.25;
 
               // Use part of the gained time from a previous stable move for the current move
               double unstablePvFactor = 1.0 + mainThread->bestMoveChanges;
-              unstablePvFactor *= std::pow(mainThread->previousTimeReduction, 0.51) / timeReduction;
+              unstablePvFactor *= std::pow(mainThread->previousTimeReduction, 0.528) / timeReduction;
 
               // Stop the search if we have only one legal move, or if available time elapsed
               if (   rootMoves.size() == 1
-                  || Time.elapsed() > Time.optimum() * unstablePvFactor * improvingFactor / 605)
+                  || Time.elapsed() > Time.optimum() * unstablePvFactor * improvingFactor / 581)
               {
                   // If we are allowed to ponder do not stop the search now but
                   // keep pondering until the GUI sends "ponderhit" or "stop".
@@ -517,13 +518,6 @@ namespace {
     bestValue = -VALUE_INFINITE;
     maxValue = VALUE_INFINITE;
 
-    // Initialize statScore to zero for the childs of the current position.
-    // So statScore is shared between sibling positions and only the first sibling
-    // starts with statScore = 0. Later siblings start with the last calculated
-    // statScore of the previous sibling. This influences in LMR the reduction rules
-    // which based on the statScore of parent position.
-    (ss+1)->statScore = 0;
-
     // Check for the available remaining time
     if (thisThread == Threads.main())
         static_cast<MainThread*>(thisThread)->check_time();
@@ -560,6 +554,13 @@ namespace {
     (ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE;
     Square prevSq = to_sq((ss-1)->currentMove);
 
+    // Initialize statScore to zero for the grandchildren of the current position.
+    // So statScore is shared between all grandchildren and only the first grandchild
+    // starts with statScore = 0. Later grandchildren start with the last calculated
+    // statScore of the previous grandchild. This influences the reduction rules in
+    // LMR which are based on the statScore of parent position.
+    (ss+2)->statScore = 0;
+
     // Step 4. Transposition table lookup. We don't want the score of a partial
     // search to overwrite a previous full search TT value, so we use a different
     // position key in case of an excluded move.
@@ -680,9 +681,20 @@ namespace {
 
     // Step 7. Razoring (skipped when in check)
     if (   !PvNode
-        &&  depth <= ONE_PLY
-        &&  eval + RazorMargin <= alpha)
-        return qsearch<NonPV, false>(pos, ss, alpha, alpha+1);
+        &&  depth <= ONE_PLY)
+    {
+        if (eval + RazorMargin1 <= alpha)
+            return qsearch<NonPV, false>(pos, ss, alpha, alpha+1);
+    }
+    else if (   !PvNode
+             &&  depth <= 2 * ONE_PLY
+             &&  eval + RazorMargin2 <= alpha)
+    {
+        Value ralpha = alpha - RazorMargin2;
+        Value v = qsearch<NonPV, false>(pos, ss, ralpha, ralpha+1);
+        if (v <= ralpha)
+            return v;
+    }
 
     // Step 8. Futility pruning: child node (skipped when in check)
     if (   !rootNode