mirror of
https://github.com/opelly27/Stockfish.git
synced 2026-05-20 02:47:45 +00:00
754fc8a8b5
The Tempo variable was introduced 10 years ago in our search because the
classical evaluation function was antisymmetrical in White and Black by design
to gain speed:
Eval(White to play) = -Eval(Black to play)
Nowadays our neural networks know which side is to play in a position when
they evaluate a position and are trained on real games, so the neural network
encodes the advantage of moving as an output of search. This patch shows that
the Tempo variable is not necessary anymore.
STC:
LLR: 2.94 (-2.94,2.94) <-2.50,0.50>
Total: 33512 W: 2805 L: 2709 D: 27998
Ptnml(0-2): 80, 2209, 12095, 2279, 93
https://tests.stockfishchess.org/tests/view/60a44ceace8ea25a3ef03d30
LTC:
LLR: 2.95 (-2.94,2.94) <-2.50,0.50>
Total: 53920 W: 1807 L: 1760 D: 50353
Ptnml(0-2): 16, 1617, 23650, 1658, 19
https://tests.stockfishchess.org/tests/view/60a477f0ce8ea25a3ef03d49
We also tried a match (20000 games) at STC using purely classical, result was neutral:
https://tests.stockfishchess.org/tests/view/60a4eebcce8ea25a3ef03db5
Note: there are two locations left in search.cpp where we assume antisymmetry
of evaluation (in relation with a speed optimization for null moves in lines
770 and 1439), but as the values are just used for heuristic pruning this
approximation should not hurt too much because the order of magnitude is still
true most of the time.
closes https://github.com/official-stockfish/Stockfish/pull/3481
Bench: 4015864
102 lines
3.6 KiB
C++
102 lines
3.6 KiB
C++
/*
|
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
|
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
|
|
|
Stockfish is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Stockfish is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <algorithm>
|
|
#include <cfloat>
|
|
#include <cmath>
|
|
|
|
#include "search.h"
|
|
#include "timeman.h"
|
|
#include "uci.h"
|
|
|
|
namespace Stockfish {
|
|
|
|
TimeManagement Time; // Our global time management object
|
|
|
|
|
|
/// TimeManagement::init() is called at the beginning of the search and calculates
|
|
/// the bounds of time allowed for the current game ply. We currently support:
|
|
// 1) x basetime (+ z increment)
|
|
// 2) x moves in y seconds (+ z increment)
|
|
|
|
void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) {
|
|
|
|
TimePoint moveOverhead = TimePoint(Options["Move Overhead"]);
|
|
TimePoint slowMover = TimePoint(Options["Slow Mover"]);
|
|
TimePoint npmsec = TimePoint(Options["nodestime"]);
|
|
|
|
// optScale is a percentage of available time to use for the current move.
|
|
// maxScale is a multiplier applied to optimumTime.
|
|
double optScale, maxScale;
|
|
|
|
// If we have to play in 'nodes as time' mode, then convert from time
|
|
// to nodes, and use resulting values in time management formulas.
|
|
// WARNING: to avoid time losses, the given npmsec (nodes per millisecond)
|
|
// must be much lower than the real engine speed.
|
|
if (npmsec)
|
|
{
|
|
if (!availableNodes) // Only once at game start
|
|
availableNodes = npmsec * limits.time[us]; // Time is in msec
|
|
|
|
// Convert from milliseconds to nodes
|
|
limits.time[us] = TimePoint(availableNodes);
|
|
limits.inc[us] *= npmsec;
|
|
limits.npmsec = npmsec;
|
|
}
|
|
|
|
startTime = limits.startTime;
|
|
|
|
// Maximum move horizon of 50 moves
|
|
int mtg = limits.movestogo ? std::min(limits.movestogo, 50) : 50;
|
|
|
|
// Make sure timeLeft is > 0 since we may use it as a divisor
|
|
TimePoint timeLeft = std::max(TimePoint(1),
|
|
limits.time[us] + limits.inc[us] * (mtg - 1) - moveOverhead * (2 + mtg));
|
|
|
|
// A user may scale time usage by setting UCI option "Slow Mover"
|
|
// Default is 100 and changing this value will probably lose elo.
|
|
timeLeft = slowMover * timeLeft / 100;
|
|
|
|
// x basetime (+ z increment)
|
|
// If there is a healthy increment, timeLeft can exceed actual available
|
|
// game time for the current move, so also cap to 20% of available game time.
|
|
if (limits.movestogo == 0)
|
|
{
|
|
optScale = std::min(0.0084 + std::pow(ply + 3.0, 0.5) * 0.0042,
|
|
0.2 * limits.time[us] / double(timeLeft));
|
|
maxScale = std::min(7.0, 4.0 + ply / 12.0);
|
|
}
|
|
|
|
// x moves in y seconds (+ z increment)
|
|
else
|
|
{
|
|
optScale = std::min((0.8 + ply / 128.0) / mtg,
|
|
0.8 * limits.time[us] / double(timeLeft));
|
|
maxScale = std::min(6.3, 1.5 + 0.11 * mtg);
|
|
}
|
|
|
|
// Never use more than 80% of the available time for this move
|
|
optimumTime = TimePoint(optScale * timeLeft);
|
|
maximumTime = TimePoint(std::min(0.8 * limits.time[us] - moveOverhead, maxScale * optimumTime));
|
|
|
|
if (Options["Ponder"])
|
|
optimumTime += optimumTime / 4;
|
|
}
|
|
|
|
} // namespace Stockfish
|