From 5dec3e547e35798f1b47c42f32f5c052aea24644 Mon Sep 17 00:00:00 2001 From: tttak Date: Fri, 3 Jul 2020 23:01:37 +0900 Subject: [PATCH] merge "Provide WDL statistics" https://github.com/official-stockfish/Stockfish/commit/110068808b51344ac59f8c6a0846f5dfdf670392 https://github.com/official-stockfish/Stockfish/pull/2778 https://github.com/official-stockfish/Stockfish/pull/2788 --- Readme.md | 5 +++++ src/search.cpp | 3 +++ src/uci.cpp | 39 +++++++++++++++++++++++++++++++++++++++ src/uci.h | 1 + src/ucioption.cpp | 1 + 5 files changed, 49 insertions(+) diff --git a/Readme.md b/Readme.md index 2b1de86b..e60ac718 100644 --- a/Readme.md +++ b/Readme.md @@ -66,6 +66,11 @@ Currently, Stockfish has the following UCI options: If enabled by UCI_LimitStrength, aim for an engine strength of the given Elo. This Elo rating has been calibrated at a time control of 60s+0.6s and anchored to CCRL 40/4. + * #### UCI_ShowWDL + If enabled, show approximate WDL statistics as part of the engine output. + These WDL numbers model expected game outcomes for a given evaluation and + game ply for engine self-play at fishtest LTC conditions (60+0.6s per game). + * #### Move Overhead Assume a time delay of x ms due to network and GUI overheads. This is useful to avoid losses on time in those cases. diff --git a/src/search.cpp b/src/search.cpp index 68f97fca..5990905f 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1841,6 +1841,9 @@ string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) { << " multipv " << i + 1 << " score " << UCI::value(v); + if (Options["UCI_ShowWDL"]) + ss << UCI::wdl(v, pos.game_ply()); + if (!tb && i == pvIdx) ss << (v >= beta ? " lowerbound" : v <= alpha ? " upperbound" : ""); diff --git a/src/uci.cpp b/src/uci.cpp index 13888d1a..a95a629d 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -19,6 +19,7 @@ */ #include +#include #include #include #include @@ -221,6 +222,28 @@ namespace { << "\nNodes/second : " << 1000 * nodes / elapsed << endl; } + // The win rate model returns the probability (per mille) of winning given an eval + // and a game-ply. The model fits rather accurately the LTC fishtest statistics. + int win_rate_model(Value v, int ply) { + + // The model captures only up to 240 plies, so limit input (and rescale) + double m = std::min(240, ply) / 64.0; + + // Coefficients of a 3rd order polynomial fit based on fishtest data + // for two parameters needed to transform eval to the argument of a + // logistic function. + double as[] = {-8.24404295, 64.23892342, -95.73056462, 153.86478679}; + double bs[] = {-3.37154371, 28.44489198, -56.67657741, 72.05858751}; + double a = (((as[0] * m + as[1]) * m + as[2]) * m) + as[3]; + double b = (((bs[0] * m + bs[1]) * m + bs[2]) * m) + bs[3]; + + // Transform eval to centipawns with limited range + double x = Utility::clamp(double(100 * v) / PawnValueEg, -1000.0, 1000.0); + + // Return win rate in per mille (rounded to nearest) + return int(0.5 + 1000 / (1 + std::exp((a - x) / b))); + } + // When you calculate check sum, save it and check the consistency later. uint64_t eval_sum; } // namespace @@ -437,6 +460,22 @@ string UCI::value(Value v) { } +/// UCI::wdl() report WDL statistics given an evaluation and a game ply, based on +/// data gathered for fishtest LTC games. + +string UCI::wdl(Value v, int ply) { + + stringstream ss; + + int wdl_w = win_rate_model( v, ply); + int wdl_l = win_rate_model(-v, ply); + int wdl_d = 1000 - wdl_w - wdl_l; + ss << " wdl " << wdl_w << " " << wdl_d << " " << wdl_l; + + return ss.str(); +} + + /// UCI::square() converts a Square to a string in algebraic notation (g1, a7, etc.) std::string UCI::square(Square s) { diff --git a/src/uci.h b/src/uci.h index d255db76..5073262e 100644 --- a/src/uci.h +++ b/src/uci.h @@ -73,6 +73,7 @@ std::string value(Value v); std::string square(Square s); std::string move(Move m, bool chess960); std::string pv(const Position& pos, Depth depth, Value alpha, Value beta); +std::string wdl(Value v, int ply); Move to_move(const Position& pos, std::string& str); // Flag that read the evaluation function. This is set to false when evaldir is changed. diff --git a/src/ucioption.cpp b/src/ucioption.cpp index c24884ce..d63caa9f 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -75,6 +75,7 @@ void init(OptionsMap& o) { o["UCI_AnalyseMode"] << Option(false); o["UCI_LimitStrength"] << Option(false); o["UCI_Elo"] << Option(1350, 1350, 2850); + o["UCI_ShowWDL"] << Option(false); o["SyzygyPath"] << Option("", on_tb_path); o["SyzygyProbeDepth"] << Option(1, 1, 100); o["Syzygy50MoveRule"] << Option(true);