Remove code unneeded for playing, refactor, update to latest master dev

This commit is contained in:
Dariusz Orzechowski
2020-07-20 05:45:24 +02:00
parent 961047ed6e
commit 4cceeb7380
90 changed files with 2007 additions and 12428 deletions
+8 -324
View File
@@ -925,9 +925,12 @@ namespace {
if (value >= probcutBeta)
{
tte->save(posKey, value_to_tt(value, ss->ply), ttPv,
BOUND_LOWER,
depth - 3, move, ss->staticEval);
if ( !(ttHit
&& tte->depth() >= depth - 3
&& ttValue != VALUE_NONE))
tte->save(posKey, value_to_tt(value, ss->ply), ttPv,
BOUND_LOWER,
depth - 3, move, ss->staticEval);
return value;
}
}
@@ -985,7 +988,7 @@ moves_loop: // When in check, search starts from here
ss->moveCount = ++moveCount;
if (rootNode && thisThread == Threads.main() && Time.elapsed() > 3000 && !Limits.silent)
if (rootNode && thisThread == Threads.main() && Time.elapsed() > 3000)
sync_cout << "info depth " << depth
<< " currmove " << UCI::move(move, pos.is_chess960())
<< " currmovenumber " << moveCount + thisThread->pvIdx << sync_endl;
@@ -1553,13 +1556,7 @@ moves_loop: // When in check, search starts from here
prefetch(TT.first_entry(pos.key_after(move)));
// Check for legality just before making the move
if (
#if defined(EVAL_LEARN)
// HACK: pos.piece_on(from_sq(m)) sometimes will be NO_PIECE during machine learning.
!pos.pseudo_legal(move) ||
#endif // EVAL_LEARN
!pos.legal(move)
)
if (!pos.legal(move))
{
moveCount--;
continue;
@@ -1959,316 +1956,3 @@ void Tablebases::rank_root_moves(Position& pos, Search::RootMoves& rootMoves) {
m.tbRank = 0;
}
}
// --- expose the functions such as fixed depth search used for learning to the outside
#if defined (EVAL_LEARN)
namespace Learner
{
// For learning, prepare a stub that can call search,qsearch() from one thread.
// From now on, it is better to have a Searcher and prepare a substitution table for each thread like Apery.
// It might have been good.
// Initialization for learning.
// Called from Learner::search(),Learner::qsearch().
void init_for_search(Position& pos, Stack* ss)
{
// RootNode requires ss->ply == 0.
// Because it clears to zero, ss->ply == 0, so it's okay...
std::memset(ss - 7, 0, 10 * sizeof(Stack));
// About Search::Limits
// Be careful because this member variable is global and affects other threads.
{
auto& limits = Search::Limits;
// Make the search equivalent to the "go infinite" command. (Because it is troublesome if time management is done)
limits.infinite = true;
// Since PV is an obstacle when displayed, erase it.
limits.silent = true;
// If you use this, it will be compared with the accumulated nodes of each thread. Therefore, do not use it.
limits.nodes = 0;
// depth is also processed by the one passed as an argument of Learner::search().
limits.depth = 0;
// Set a large value to prevent the draw value from being returned due to the number of moves near the draw.
//limits.max_game_ply = 1 << 16;
// If you do not include the ball entry rule, it will be a draw and it will be difficult to settle.
//limits.enteringKingRule = EnteringKingRule::EKR_27_POINT;
}
// Set DrawValue
{
// Because it is not prepared for each thread
// May be overwritten by another thread. There is no help for it.
// If that happens, I think it should be 0.
//drawValueTable[REPETITION_DRAW][BLACK] = VALUE_ZERO;
//drawValueTable[REPETITION_DRAW][WHITE] = VALUE_ZERO;
}
// Regarding this_thread.
{
auto th = pos.this_thread();
th->completedDepth = 0;
th->selDepth = 0;
th->rootDepth = 0;
// Zero initialization of the number of search nodes
th->nodes = 0;
// Clear all history types. This initialization takes a little time, and the accuracy of the search is rather low, so the good and bad are not well understood.
// th->clear();
int ct = int(Options["Contempt"]) * PawnValueEg / 100; // From centipawns
Color us = pos.side_to_move();
// In analysis mode, adjust contempt in accordance with user preference
if (Limits.infinite || Options["UCI_AnalyseMode"])
ct = Options["Analysis Contempt"] == "Off" ? 0
: Options["Analysis Contempt"] == "Both" ? ct
: Options["Analysis Contempt"] == "White" && us == BLACK ? -ct
: Options["Analysis Contempt"] == "Black" && us == WHITE ? -ct
: ct;
// Evaluation score is from the white point of view
th->contempt = (us == WHITE ? make_score(ct, ct / 2)
: -make_score(ct, ct / 2));
for (int i = 7; i > 0; i--)
(ss - i)->continuationHistory = &th->continuationHistory[0][0][NO_PIECE][0]; // Use as a sentinel
// set rootMoves
auto& rootMoves = th->rootMoves;
rootMoves.clear();
for (auto m: MoveList<LEGAL>(pos))
rootMoves.push_back(Search::RootMove(m));
assert(!rootMoves.empty());
//#if defined(USE_GLOBAL_OPTIONS)
// Since the generation of the substitution table for each search thread should be managed,
// Increase the generation of the substitution table for this thread because it is a new search.
//TT.new_search(th->thread_id());
// ↑ If you call new_search here, it may be a loss because you can't use the previous search result.
// Do not do this here, but caller should do TT.new_search(th->thread_id()) for each station ...
// →Because we want to avoid reaching the same final diagram, use the substitution table commonly for all threads when generating teachers.
//#endif
}
}
// A pair of reader and evaluation value. Returned by Learner::search(),Learner::qsearch().
typedef std::pair<Value, std::vector<Move> > ValueAndPV;
// Stationary search.
//
// Precondition) Search thread is set by pos.set_this_thread(Threads[thread_id]).
// Also, when Threads.stop arrives, the search is interrupted, so the PV at that time is not correct.
// After returning from search(), if Threads.stop == true, do not use the search result.
// Also, note that before calling, if you do not call it with Threads.stop == false, the search will be interrupted and it will return.
//
// If it is clogged, MOVE_RESIGN is returned in the PV array.
//
//Although it was possible to specify alpha and beta with arguments, this will show the result when searching in that window
// Because it writes to the substitution table, the value that can be pruned is written to that window when learning
// As it has a bad effect, I decided to stop allowing the window range to be specified.
ValueAndPV qsearch(Position& pos)
{
Stack stack[MAX_PLY + 10], * ss = stack + 7;
Move pv[MAX_PLY + 1];
init_for_search(pos, ss);
ss->pv = pv; // For the time being, it must be a dummy and somewhere with a buffer.
if (pos.is_draw(0)) {
// Return draw value if draw.
return { VALUE_DRAW, {} };
}
// Is it stuck?
if (MoveList<LEGAL>(pos).size() == 0)
{
// Return the mated value if checkmated.
return { mated_in(/*ss->ply*/ 0 + 1), {} };
}
auto bestValue = ::qsearch<PV>(pos, ss, -VALUE_INFINITE, VALUE_INFINITE, 0);
// Returns the PV obtained.
std::vector<Move> pvs;
for (Move* p = &ss->pv[0]; is_ok(*p); ++p)
pvs.push_back(*p);
return ValueAndPV(bestValue, pvs);
}
// Normal search. Depth depth (specified as an integer).
// 3 If you want a score for hand reading,
// auto v = search(pos,3);
// Do something like
// Evaluation value is obtained in v.first and PV is obtained in v.second.
// When multi pv is enabled, you can get the PV (reading line) array in pos.this_thread()->rootMoves[N].pv.
// Specify multi pv with the argument multiPV of this function. (The value of Options["MultiPV"] is ignored)
//
// Declaration win judgment is not done as root (because it is troublesome to handle), so it is not done here.
// Handle it by the caller.
//
// Precondition) Search thread is set by pos.set_this_thread(Threads[thread_id]).
// Also, when Threads.stop arrives, the search is interrupted, so the PV at that time is not correct.
// After returning from search(), if Threads.stop == true, do not use the search result.
// Also, note that before calling, if you do not call it with Threads.stop == false, the search will be interrupted and it will return.
ValueAndPV search(Position& pos, int depth_, size_t multiPV /* = 1 */, uint64_t nodesLimit /* = 0 */)
{
std::vector<Move> pvs;
Depth depth = depth_;
if (depth < 0)
return std::pair<Value, std::vector<Move>>(Eval::evaluate(pos), std::vector<Move>());
if (depth == 0)
return qsearch(pos);
Stack stack[MAX_PLY + 10], * ss = stack + 7;
Move pv[MAX_PLY + 1];
init_for_search(pos, ss);
ss->pv = pv; // For the time being, it must be a dummy and somewhere with a buffer.
// Initialize the variables related to this_thread
auto th = pos.this_thread();
auto& rootDepth = th->rootDepth;
auto& pvIdx = th->pvIdx;
auto& pvLast = th->pvLast;
auto& rootMoves = th->rootMoves;
auto& completedDepth = th->completedDepth;
auto& selDepth = th->selDepth;
// A function to search the top N of this stage as best move
//size_t multiPV = Options["MultiPV"];
// Do not exceed the number of moves in this situation
multiPV = std::min(multiPV, rootMoves.size());
// If you do not multiply the node limit by the value of MultiPV, you will not be thinking about the same node for one candidate hand when you fix the depth and have MultiPV.
nodesLimit *= multiPV;
Value alpha = -VALUE_INFINITE;
Value beta = VALUE_INFINITE;
Value delta = -VALUE_INFINITE;
Value bestValue = -VALUE_INFINITE;
while ((rootDepth += 1) <= depth
// exit this loop even if the node limit is exceeded
// The number of search nodes is passed in the argument of this function.
&& !(nodesLimit /* limited nodes */ && th->nodes.load(std::memory_order_relaxed) >= nodesLimit)
)
{
for (RootMove& rm : rootMoves)
rm.previousScore = rm.score;
size_t pvFirst = 0;
pvLast = 0;
// MultiPV loop. We perform a full root search for each PV line
for (pvIdx = 0; pvIdx < multiPV && !Threads.stop; ++pvIdx)
{
if (pvIdx == pvLast)
{
pvFirst = pvLast;
for (pvLast++; pvLast < rootMoves.size(); pvLast++)
if (rootMoves[pvLast].tbRank != rootMoves[pvFirst].tbRank)
break;
}
// selDepth output with USI info for each depth and PV line
selDepth = 0;
// Switch to aspiration search for depth 5 and above.
if (rootDepth >= 5 * 1)
{
delta = Value(20);
Value p = rootMoves[pvIdx].previousScore;
alpha = std::max(p - delta, -VALUE_INFINITE);
beta = std::min(p + delta, VALUE_INFINITE);
}
// aspiration search
int failedHighCnt = 0;
while (true)
{
Depth adjustedDepth = std::max(1, rootDepth - failedHighCnt * 1);
bestValue = ::search<PV>(pos, ss, alpha, beta, adjustedDepth, false);
stable_sort(rootMoves.begin() + pvIdx, rootMoves.end());
//my_stable_sort(pos.this_thread()->thread_id(),&rootMoves[0] + pvIdx, rootMoves.size() - pvIdx);
// Expand aspiration window for fail low/high.
// However, if it is the value specified by the argument, it will be treated as fail low/high and break.
if (bestValue <= alpha)
{
beta = (alpha + beta) / 2;
alpha = std::max(bestValue - delta, -VALUE_INFINITE);
failedHighCnt = 0;
//if (mainThread)
// mainThread->stopOnPonderhit = false;
}
else if (bestValue >= beta)
{
beta = std::min(bestValue + delta, VALUE_INFINITE);
++failedHighCnt;
}
else
break;
delta += delta / 4 + 5;
assert(-VALUE_INFINITE <= alpha && beta <= VALUE_INFINITE);
// runaway check
//assert(th->nodes.load(std::memory_order_relaxed) <= 1000000 );
}
stable_sort(rootMoves.begin(), rootMoves.begin() + pvIdx + 1);
//my_stable_sort(pos.this_thread()->thread_id() , &rootMoves[0] , pvIdx + 1);
} // multi PV
completedDepth = rootDepth;
}
// Pass PV_is(ok) to eliminate this PV, there may be NULL_MOVE in the middle.
// → PV should not be NULL_MOVE because it is PV
// MOVE_WIN has never been thrust. (For now)
for (Move move : rootMoves[0].pv)
{
if (!is_ok(move))
break;
pvs.push_back(move);
}
//sync_cout << rootDepth << sync_endl;
// Considering multiPV, the score of rootMoves[0] is returned as bestValue.
bestValue = rootMoves[0].score;
return ValueAndPV(bestValue, pvs);
}
}
#endif