Skip to content

Commit

Permalink
Replace easyMove with simple scheme
Browse files Browse the repository at this point in the history
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
  • Loading branch information
vondele authored and mcostalba committed Nov 3, 2017
1 parent e0d2fdc commit 486c817
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 65 deletions.
85 changes: 22 additions & 63 deletions src/search.cpp
Expand Up @@ -96,46 +96,6 @@ namespace {
Move best = MOVE_NONE;
};

// EasyMoveManager structure is used to detect an 'easy move'. When the PV is stable
// across multiple search iterations, we can quickly return the best move.
struct EasyMoveManager {

void clear() {
stableCnt = 0;
expectedPosKey = 0;
pv[0] = pv[1] = pv[2] = MOVE_NONE;
}

Move get(Key key) const {
return expectedPosKey == key ? pv[2] : MOVE_NONE;
}

void update(Position& pos, const std::vector<Move>& newPv) {

assert(newPv.size() >= 3);

// Keep track of how many times in a row the 3rd ply remains stable
stableCnt = (newPv[2] == pv[2]) ? stableCnt + 1 : 0;

if (!std::equal(newPv.begin(), newPv.begin() + 3, pv))
{
std::copy(newPv.begin(), newPv.begin() + 3, pv);

StateInfo st[2];
pos.do_move(newPv[0], st[0]);
pos.do_move(newPv[1], st[1]);
expectedPosKey = pos.key();
pos.undo_move(newPv[1]);
pos.undo_move(newPv[0]);
}
}

Key expectedPosKey;
int stableCnt;
Move pv[3];
};

EasyMoveManager EasyMove;
Value DrawValue[COLOR_NB];

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

Threads.main()->callsCnt = 0;
Threads.main()->previousScore = VALUE_INFINITE;
Threads.main()->previousTimeReduction = 1;
}


Expand Down Expand Up @@ -285,8 +246,7 @@ void MainThread::search() {

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

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

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

if (mainThread)
{
easyMove = EasyMove.get(rootPos.key());
EasyMove.clear();
mainThread->easyMovePlayed = mainThread->failedLow = false;
mainThread->failedLow = false;
mainThread->bestMoveChanges = 0;
}

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

if (rootMoves[0].pv[0] != lastBestMove) {
lastBestMove = rootMoves[0].pv[0];
lastBestMoveDepth = rootDepth;
}

// Have we found a "mate in x"?
if ( Limits.mate
&& bestValue >= VALUE_MATE_IN_MAX_PLY
Expand All @@ -472,8 +437,7 @@ void Thread::search() {
if (!Threads.stop && !Threads.stopOnPonderhit)
{
// Stop the search if only one legal move is available, or if all
// of the available time has been used, or if we matched an easyMove
// from the previous search and just did a fast verification.
// of the available time has been used
const int F[] = { mainThread->failedLow,
bestValue - mainThread->previousScore };
int improvingFactor = std::max(229, std::min(715, 357 + 119 * F[0] - 6 * F[1]));
Expand All @@ -485,14 +449,17 @@ void Thread::search() {

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

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

if ( rootMoves.size() == 1
|| Time.elapsed() > Time.optimum() * unstablePvFactor * improvingFactor / 628
|| (mainThread->easyMovePlayed = doEasyMove, doEasyMove))
|| Time.elapsed() > Time.optimum() * unstablePvFactor * improvingFactor / 628)
{
// If we are allowed to ponder do not stop the search now but
// keep pondering until the GUI sends "ponderhit" or "stop".
Expand All @@ -502,21 +469,13 @@ void Thread::search() {
Threads.stop = true;
}
}

if (rootMoves[0].pv.size() >= 3)
EasyMove.update(rootPos, rootMoves[0].pv);
else
EasyMove.clear();
}
}

if (!mainThread)
return;

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

// If skill level is enabled, swap best PV line with the sub-optimal one
if (skill.enabled())
Expand Down
4 changes: 2 additions & 2 deletions src/thread.h
Expand Up @@ -82,8 +82,8 @@ struct MainThread : public Thread {
void search() override;
void check_time();

bool easyMovePlayed, failedLow;
double bestMoveChanges;
bool failedLow;
double bestMoveChanges, previousTimeReduction;
Value previousScore;
int callsCnt;
};
Expand Down

0 comments on commit 486c817

Please sign in to comment.