Implement Last Seconds Noise (LSN) filtering
authorMarco Costalba <mcostalba@gmail.com>
Mon, 13 Oct 2008 13:19:17 +0000 (15:19 +0200)
committerMarco Costalba <mcostalba@gmail.com>
Mon, 13 Oct 2008 18:40:48 +0000 (20:40 +0200)
When an engine is in deep trouble at few
seconds from time limit then giveup without
fighting anymore.

This is used to reduce "lucky draws" and time pressure
blunders noises that can obfuscate results during tests
blitz games (typical one minute games).

Goal of this technique is to reduce number of matches
needed to reliably prove then an engine A is stronger
then an opponent B.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
src/search.cpp
src/ucioption.cpp

index 10aa196add95d87944db24863eb1cbd5c764010e..ee7d906e61698010afd4b7e64336c44505493b2e 100644 (file)
@@ -152,6 +152,12 @@ namespace {
   Depth RazorDepth = 4*OnePly;
   Value RazorMargin = Value(0x300);
 
+  // Last seconds noise filtering (LSN)
+  bool UseLSNFiltering = false;
+  bool looseOnTime = false;
+  int LSNTime = 4 * 1000; // In milliseconds
+  Value LSNValue = Value(0x200);
+
   // Extensions.  Array index 0 is used at non-PV nodes, index 1 at PV nodes.
   Depth CheckExtension[2] = {OnePly, OnePly};
   Depth SingleReplyExtension[2] = {OnePly / 2, OnePly / 2};
@@ -220,7 +226,7 @@ namespace {
 
   /// Functions
 
-  void id_loop(const Position &pos, Move searchMoves[]);
+  Value id_loop(const Position &pos, Move searchMoves[]);
   Value root_search(Position &pos, SearchStack ss[], RootMoveList &rml);
   Value search_pv(Position &pos, SearchStack ss[], Value alpha, Value beta,
                   Depth depth, int ply, int threadID);
@@ -394,6 +400,10 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move,
   RazorDepth = (get_option_value_int("Maximum Razoring Depth") + 1) * OnePly;
   RazorMargin = value_from_centipawns(get_option_value_int("Razoring Margin"));
 
+  UseLSNFiltering = get_option_value_bool("LSN filtering");
+  LSNTime = get_option_value_int("LSN Time Margin (sec)") * 1000;
+  LSNValue = value_from_centipawns(get_option_value_int("LSN Value Margin"));
+
   MinimumSplitDepth = get_option_value_int("Minimum Split Depth") * OnePly;
   MaxThreadsPerSplitPoint =
     get_option_value_int("Maximum Number of Threads per Split Point");
@@ -468,7 +478,21 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move,
 
   // We're ready to start thinking.  Call the iterative deepening loop
   // function:
-  id_loop(pos, searchMoves);
+  if (!looseOnTime)
+  {
+      Value v = id_loop(pos, searchMoves);
+      looseOnTime = (   UseLSNFiltering
+                     && myTime < LSNTime
+                     && myIncrement == 0
+                     && v < -LSNValue);
+  }
+  else
+  {
+      looseOnTime = false; // reset for next match
+      while (SearchStartTime + myTime + 1000 > get_system_time())
+          ; // wait here
+      id_loop(pos, searchMoves); // to fail gracefully
+  }
 
   if(UseLogFile)
     LogFile.close();
@@ -570,7 +594,7 @@ namespace {
   // been consumed, the user stops the search, or the maximum search depth is
   // reached.
 
-  void id_loop(const Position &pos, Move searchMoves[]) {
+  Value id_loop(const Position &pos, Move searchMoves[]) {
     Position p(pos);
     SearchStack ss[PLY_MAX_PLUS_2];
 
@@ -694,6 +718,7 @@ namespace {
       LogFile << "Ponder move: " << move_to_san(p, ss[0].pv[1]) << '\n';
       LogFile << std::endl;
     }
+    return rml.get_move_score(0);
   }
 
 
index fe30334a6b2edcdf5fda616ee4d232d215cbaf83..145790546308f6024301bb7ac686b93ec5c20097 100644 (file)
@@ -126,6 +126,9 @@ namespace {
     o.push_back(Option("Futility Margin 2", 300, 0, 1000));
     o.push_back(Option("Maximum Razoring Depth", 3, 0, 4));
     o.push_back(Option("Razoring Margin", 300, 150, 600));
+    o.push_back(Option("LSN filtering", true));
+    o.push_back(Option("LSN Time Margin (sec)", 4, 1, 10));
+    o.push_back(Option("LSN Value Margin", 200, 100, 600));
     o.push_back(Option("Randomness", 0, 0, 10));
     o.push_back(Option("Minimum Split Depth", 4, 4, 7));
     o.push_back(Option("Maximum Number of Threads per Split Point", 5, 4, 8));