From d8268024a9663727d1f183bf88639475eabca9d4 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Mon, 13 Oct 2008 15:19:17 +0200 Subject: [PATCH] Implement Last Seconds Noise (LSN) filtering 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 --- src/search.cpp | 31 ++++++++++++++++++++++++++++--- src/ucioption.cpp | 3 +++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 10aa196a..ee7d906e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -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); } diff --git a/src/ucioption.cpp b/src/ucioption.cpp index fe30334a..14579054 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -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)); -- 2.39.2