Skip to content

Commit 486c817

Browse files
vondelemcostalba
authored andcommitted
Replace easyMove with simple scheme
Reduces time for a stable bestMove, giving some of the won time for the next move. the version before the pvDraw passed both STC and LTC passed STC: http://tests.stockfishchess.org/tests/view/59e98d5a0ebc590ccbb896ec LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 78561 W: 13945 L: 13921 D: 50695 elo = 0.106 +- 1.445 LOS: 55.716% passed LTC: http://tests.stockfishchess.org/tests/view/59eb9df90ebc590ccbb897ae LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 29056 W: 3640 L: 3530 D: 21886 elo = 1.315 +- 1.982 LOS: 90.314% This version, rebased on pvDrawPR with the obvious change, was verified again on STC: http://tests.stockfishchess.org/tests/view/59ee104e0ebc590ccbb89899 LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 19890 W: 3648 L: 3525 D: 12717 elo = 2.149 +- 2.895 LOS: 92.692% and LTC: http://tests.stockfishchess.org/tests/view/59f9673a0ebc590ccbb89ea0 Total : 17966 Win : 2273 ( 12.652%) Loss : 2149 ( 11.961%) Draw : 13544 ( 75.387%) Score : 50.345% Sensitivity : 0.014% 2*(W-L)/(W+L) : 5.608% LLR [-3.0, 1.0] : 2.95 BayesElo range : [ -1.161, 4.876, 10.830] (DrawElo: 341.132) LogisticElo range : [ -0.501, 2.105, 4.677] LOS : 94.369 % LTC again: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 17966 W: 2273 L: 2149 D: 13544 LogisticElo range : [ -0.501, 2.105, 4.677] LOS : 94.369 % unchanged bench: 5234652
1 parent e0d2fdc commit 486c817

File tree

2 files changed

+24
-65
lines changed

2 files changed

+24
-65
lines changed

src/search.cpp

Lines changed: 22 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -96,46 +96,6 @@ namespace {
9696
Move best = MOVE_NONE;
9797
};
9898

99-
// EasyMoveManager structure is used to detect an 'easy move'. When the PV is stable
100-
// across multiple search iterations, we can quickly return the best move.
101-
struct EasyMoveManager {
102-
103-
void clear() {
104-
stableCnt = 0;
105-
expectedPosKey = 0;
106-
pv[0] = pv[1] = pv[2] = MOVE_NONE;
107-
}
108-
109-
Move get(Key key) const {
110-
return expectedPosKey == key ? pv[2] : MOVE_NONE;
111-
}
112-
113-
void update(Position& pos, const std::vector<Move>& newPv) {
114-
115-
assert(newPv.size() >= 3);
116-
117-
// Keep track of how many times in a row the 3rd ply remains stable
118-
stableCnt = (newPv[2] == pv[2]) ? stableCnt + 1 : 0;
119-
120-
if (!std::equal(newPv.begin(), newPv.begin() + 3, pv))
121-
{
122-
std::copy(newPv.begin(), newPv.begin() + 3, pv);
123-
124-
StateInfo st[2];
125-
pos.do_move(newPv[0], st[0]);
126-
pos.do_move(newPv[1], st[1]);
127-
expectedPosKey = pos.key();
128-
pos.undo_move(newPv[1]);
129-
pos.undo_move(newPv[0]);
130-
}
131-
}
132-
133-
Key expectedPosKey;
134-
int stableCnt;
135-
Move pv[3];
136-
};
137-
138-
EasyMoveManager EasyMove;
13999
Value DrawValue[COLOR_NB];
140100

141101
template <NodeType NT>
@@ -220,6 +180,7 @@ void Search::clear() {
220180

221181
Threads.main()->callsCnt = 0;
222182
Threads.main()->previousScore = VALUE_INFINITE;
183+
Threads.main()->previousTimeReduction = 1;
223184
}
224185

225186

@@ -285,8 +246,7 @@ void MainThread::search() {
285246

286247
// Check if there are threads with a better score than main thread
287248
Thread* bestThread = this;
288-
if ( !this->easyMovePlayed
289-
&& Options["MultiPV"] == 1
249+
if ( Options["MultiPV"] == 1
290250
&& !Limits.depth
291251
&& !Skill(Options["Skill Level"]).enabled()
292252
&& rootMoves[0].pv[0] != MOVE_NONE)
@@ -326,8 +286,10 @@ void Thread::search() {
326286

327287
Stack stack[MAX_PLY+7], *ss = stack+4; // To reference from (ss-4) to (ss+2)
328288
Value bestValue, alpha, beta, delta;
329-
Move easyMove = MOVE_NONE;
289+
Move lastBestMove = MOVE_NONE;
290+
Depth lastBestMoveDepth = DEPTH_ZERO;
330291
MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr);
292+
double timeReduction = 1.0;
331293

332294
std::memset(ss-4, 0, 7 * sizeof(Stack));
333295
for (int i = 4; i > 0; i--)
@@ -338,9 +300,7 @@ void Thread::search() {
338300

339301
if (mainThread)
340302
{
341-
easyMove = EasyMove.get(rootPos.key());
342-
EasyMove.clear();
343-
mainThread->easyMovePlayed = mainThread->failedLow = false;
303+
mainThread->failedLow = false;
344304
mainThread->bestMoveChanges = 0;
345305
}
346306

@@ -453,6 +413,11 @@ void Thread::search() {
453413
if (!Threads.stop)
454414
completedDepth = rootDepth;
455415

416+
if (rootMoves[0].pv[0] != lastBestMove) {
417+
lastBestMove = rootMoves[0].pv[0];
418+
lastBestMoveDepth = rootDepth;
419+
}
420+
456421
// Have we found a "mate in x"?
457422
if ( Limits.mate
458423
&& bestValue >= VALUE_MATE_IN_MAX_PLY
@@ -472,8 +437,7 @@ void Thread::search() {
472437
if (!Threads.stop && !Threads.stopOnPonderhit)
473438
{
474439
// Stop the search if only one legal move is available, or if all
475-
// of the available time has been used, or if we matched an easyMove
476-
// from the previous search and just did a fast verification.
440+
// of the available time has been used
477441
const int F[] = { mainThread->failedLow,
478442
bestValue - mainThread->previousScore };
479443
int improvingFactor = std::max(229, std::min(715, 357 + 119 * F[0] - 6 * F[1]));
@@ -485,14 +449,17 @@ void Thread::search() {
485449

486450
double unstablePvFactor = 1 + mainThread->bestMoveChanges + thinkHard;
487451

488-
bool doEasyMove = rootMoves[0].pv[0] == easyMove
489-
&& !thinkHard
490-
&& mainThread->bestMoveChanges < 0.03
491-
&& Time.elapsed() > Time.optimum() * 5 / 44;
452+
// if the bestMove is stable over several iterations, reduce time for this move,
453+
// the longer the move has been stable, the more.
454+
// Use part of the gained time from a previous stable move for the current move.
455+
timeReduction = 1;
456+
for (int i : {3, 4, 5})
457+
if (lastBestMoveDepth * i < completedDepth && !thinkHard)
458+
timeReduction *= 1.3;
459+
unstablePvFactor *= std::pow(mainThread->previousTimeReduction, 0.51) / timeReduction;
492460

493461
if ( rootMoves.size() == 1
494-
|| Time.elapsed() > Time.optimum() * unstablePvFactor * improvingFactor / 628
495-
|| (mainThread->easyMovePlayed = doEasyMove, doEasyMove))
462+
|| Time.elapsed() > Time.optimum() * unstablePvFactor * improvingFactor / 628)
496463
{
497464
// If we are allowed to ponder do not stop the search now but
498465
// keep pondering until the GUI sends "ponderhit" or "stop".
@@ -502,21 +469,13 @@ void Thread::search() {
502469
Threads.stop = true;
503470
}
504471
}
505-
506-
if (rootMoves[0].pv.size() >= 3)
507-
EasyMove.update(rootPos, rootMoves[0].pv);
508-
else
509-
EasyMove.clear();
510472
}
511473
}
512474

513475
if (!mainThread)
514476
return;
515477

516-
// Clear any candidate easy move that wasn't stable for the last search
517-
// iterations; the second condition prevents consecutive fast moves.
518-
if (EasyMove.stableCnt < 6 || mainThread->easyMovePlayed)
519-
EasyMove.clear();
478+
mainThread->previousTimeReduction = timeReduction;
520479

521480
// If skill level is enabled, swap best PV line with the sub-optimal one
522481
if (skill.enabled())

src/thread.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ struct MainThread : public Thread {
8282
void search() override;
8383
void check_time();
8484

85-
bool easyMovePlayed, failedLow;
86-
double bestMoveChanges;
85+
bool failedLow;
86+
double bestMoveChanges, previousTimeReduction;
8787
Value previousScore;
8888
int callsCnt;
8989
};

0 commit comments

Comments
 (0)