From: Marco Costalba Date: Mon, 13 Oct 2008 13:19:17 +0000 (+0200) Subject: Implement Last Seconds Noise (LSN) filtering X-Git-Url: https://git.sesse.net/?p=stockfish;a=commitdiff_plain;h=d8268024a9663727d1f183bf88639475eabca9d4;hp=4fa5dd4db55ba9fde841120fc8fbcd99f6540eb4 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 --- 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));