"Fossies" - the Fresh Open Source Software Archive

Member "stockfish-11-linux/src/timeman.cpp" (18 Jan 2020, 5311 Bytes) of package /linux/privat/stockfish-11-linux.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "timeman.cpp": 9-linux_vs_10-linux.

    1 /*
    2   Stockfish, a UCI chess playing engine derived from Glaurung 2.1
    3   Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
    4   Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
    5   Copyright (C) 2015-2020 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
    6 
    7   Stockfish is free software: you can redistribute it and/or modify
    8   it under the terms of the GNU General Public License as published by
    9   the Free Software Foundation, either version 3 of the License, or
   10   (at your option) any later version.
   11 
   12   Stockfish is distributed in the hope that it will be useful,
   13   but WITHOUT ANY WARRANTY; without even the implied warranty of
   14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15   GNU General Public License for more details.
   16 
   17   You should have received a copy of the GNU General Public License
   18   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   19 */
   20 
   21 #include <algorithm>
   22 #include <cfloat>
   23 #include <cmath>
   24 
   25 #include "search.h"
   26 #include "timeman.h"
   27 #include "uci.h"
   28 
   29 TimeManagement Time; // Our global time management object
   30 
   31 namespace {
   32 
   33   enum TimeType { OptimumTime, MaxTime };
   34 
   35   constexpr int MoveHorizon   = 50;   // Plan time management at most this many moves ahead
   36   constexpr double MaxRatio   = 7.3;  // When in trouble, we can step over reserved time with this ratio
   37   constexpr double StealRatio = 0.34; // However we must not steal time from remaining moves over this ratio
   38 
   39 
   40   // move_importance() is a skew-logistic function based on naive statistical
   41   // analysis of "how many games are still undecided after n half-moves". Game
   42   // is considered "undecided" as long as neither side has >275cp advantage.
   43   // Data was extracted from the CCRL game database with some simple filtering criteria.
   44 
   45   double move_importance(int ply) {
   46 
   47     constexpr double XScale = 6.85;
   48     constexpr double XShift = 64.5;
   49     constexpr double Skew   = 0.171;
   50 
   51     return pow((1 + exp((ply - XShift) / XScale)), -Skew) + DBL_MIN; // Ensure non-zero
   52   }
   53 
   54   template<TimeType T>
   55   TimePoint remaining(TimePoint myTime, int movesToGo, int ply, TimePoint slowMover) {
   56 
   57     constexpr double TMaxRatio   = (T == OptimumTime ? 1.0 : MaxRatio);
   58     constexpr double TStealRatio = (T == OptimumTime ? 0.0 : StealRatio);
   59 
   60     double moveImportance = (move_importance(ply) * slowMover) / 100.0;
   61     double otherMovesImportance = 0.0;
   62 
   63     for (int i = 1; i < movesToGo; ++i)
   64         otherMovesImportance += move_importance(ply + 2 * i);
   65 
   66     double ratio1 = (TMaxRatio * moveImportance) / (TMaxRatio * moveImportance + otherMovesImportance);
   67     double ratio2 = (moveImportance + TStealRatio * otherMovesImportance) / (moveImportance + otherMovesImportance);
   68 
   69     return TimePoint(myTime * std::min(ratio1, ratio2)); // Intel C++ asks for an explicit cast
   70   }
   71 
   72 } // namespace
   73 
   74 
   75 /// init() is called at the beginning of the search and calculates the allowed
   76 /// thinking time out of the time control and current game ply. We support four
   77 /// different kinds of time controls, passed in 'limits':
   78 ///
   79 ///  inc == 0 && movestogo == 0 means: x basetime  [sudden death!]
   80 ///  inc == 0 && movestogo != 0 means: x moves in y minutes
   81 ///  inc >  0 && movestogo == 0 means: x basetime + z increment
   82 ///  inc >  0 && movestogo != 0 means: x moves in y minutes + z increment
   83 
   84 void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) {
   85 
   86   TimePoint minThinkingTime = Options["Minimum Thinking Time"];
   87   TimePoint moveOverhead    = Options["Move Overhead"];
   88   TimePoint slowMover       = Options["Slow Mover"];
   89   TimePoint npmsec          = Options["nodestime"];
   90   TimePoint hypMyTime;
   91 
   92   // If we have to play in 'nodes as time' mode, then convert from time
   93   // to nodes, and use resulting values in time management formulas.
   94   // WARNING: to avoid time losses, the given npmsec (nodes per millisecond)
   95   // must be much lower than the real engine speed.
   96   if (npmsec)
   97   {
   98       if (!availableNodes) // Only once at game start
   99           availableNodes = npmsec * limits.time[us]; // Time is in msec
  100 
  101       // Convert from milliseconds to nodes
  102       limits.time[us] = TimePoint(availableNodes);
  103       limits.inc[us] *= npmsec;
  104       limits.npmsec = npmsec;
  105   }
  106 
  107   startTime = limits.startTime;
  108   optimumTime = maximumTime = std::max(limits.time[us], minThinkingTime);
  109 
  110   const int maxMTG = limits.movestogo ? std::min(limits.movestogo, MoveHorizon) : MoveHorizon;
  111 
  112   // We calculate optimum time usage for different hypothetical "moves to go" values
  113   // and choose the minimum of calculated search time values. Usually the greatest
  114   // hypMTG gives the minimum values.
  115   for (int hypMTG = 1; hypMTG <= maxMTG; ++hypMTG)
  116   {
  117       // Calculate thinking time for hypothetical "moves to go"-value
  118       hypMyTime =  limits.time[us]
  119                  + limits.inc[us] * (hypMTG - 1)
  120                  - moveOverhead * (2 + std::min(hypMTG, 40));
  121 
  122       hypMyTime = std::max(hypMyTime, TimePoint(0));
  123 
  124       TimePoint t1 = minThinkingTime + remaining<OptimumTime>(hypMyTime, hypMTG, ply, slowMover);
  125       TimePoint t2 = minThinkingTime + remaining<MaxTime    >(hypMyTime, hypMTG, ply, slowMover);
  126 
  127       optimumTime = std::min(t1, optimumTime);
  128       maximumTime = std::min(t2, maximumTime);
  129   }
  130 
  131   if (Options["Ponder"])
  132       optimumTime += optimumTime / 4;
  133 }