]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Sync static null conditions with real one
[stockfish] / src / search.cpp
index 4592ac084ebc56d60a59b83415167bd2f75af146..92d2eda61d188b007a9cc4f42e7cbb41c196bbee 100644 (file)
@@ -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
 
@@ -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);
 
@@ -1343,11 +1368,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 +1390,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 +1397,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