mirror of
https://github.com/official-stockfish/Stockfish.git
synced 2026-07-22 20:57:10 +00:00
Add PVMoves Struct
Use a dedicated struct for keeping track of the pv moves. anematode pointed out that we can use the ValueList for this as well, left that open for a future patch. Passed Non Regression https://tests.stockfishchess.org/tests/view/69d399cfec2dc6794cf18376 LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 267264 W: 68895 L: 68927 D: 129442 Ptnml(0-2): 790, 29238, 73566, 29290, 748 closes https://github.com/official-stockfish/Stockfish/pull/6726 No functional change
This commit is contained in:
committed by
Joost VandeVondele
parent
4bdeb6352c
commit
45711fceb4
+14
-25
@@ -128,7 +128,6 @@ void update_correction_history(const Position& pos,
|
||||
Value value_draw(size_t nodes) { return VALUE_DRAW - 1 + Value(nodes & 0x2); }
|
||||
Value value_to_tt(Value v, int ply);
|
||||
Value value_from_tt(Value v, int ply, int r50c);
|
||||
void update_pv(Move* pv, Move move, const Move* childPv);
|
||||
void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus);
|
||||
void update_quiet_histories(
|
||||
const Position& pos, Stack* ss, Search::Worker& workerThread, Move move, int bonus);
|
||||
@@ -263,7 +262,7 @@ bool Search::Worker::iterative_deepening() {
|
||||
|
||||
SearchManager* mainThread = (is_mainthread() ? main_manager() : nullptr);
|
||||
|
||||
Move pv[MAX_PLY + 1];
|
||||
PVMoves pv;
|
||||
|
||||
Depth lastBestMoveDepth = 0;
|
||||
|
||||
@@ -290,7 +289,7 @@ bool Search::Worker::iterative_deepening() {
|
||||
for (int i = 0; i <= MAX_PLY + 2; ++i)
|
||||
(ss + i)->ply = i;
|
||||
|
||||
ss->pv = pv;
|
||||
ss->pv = &pv;
|
||||
|
||||
if (mainThread)
|
||||
{
|
||||
@@ -652,7 +651,7 @@ Value Search::Worker::search(
|
||||
assert(0 < depth && depth < MAX_PLY);
|
||||
assert(!(PvNode && cutNode));
|
||||
|
||||
Move pv[MAX_PLY + 1];
|
||||
PVMoves pv;
|
||||
StateInfo st;
|
||||
|
||||
Key posKey;
|
||||
@@ -1293,8 +1292,8 @@ moves_loop: // When in check, search starts here
|
||||
// otherwise let the parent node fail low with value <= alpha and try another move.
|
||||
if (PvNode && (moveCount == 1 || value > alpha))
|
||||
{
|
||||
(ss + 1)->pv = pv;
|
||||
(ss + 1)->pv[0] = Move::none();
|
||||
(ss + 1)->pv = &pv;
|
||||
(ss + 1)->pv->clear();
|
||||
|
||||
// Extend move from transposition table if we are about to dive into qsearch.
|
||||
// decisive score handling improves mate finding and retrograde analysis.
|
||||
@@ -1353,8 +1352,8 @@ moves_loop: // When in check, search starts here
|
||||
|
||||
assert((ss + 1)->pv);
|
||||
|
||||
for (Move* m = (ss + 1)->pv; *m != Move::none(); ++m)
|
||||
rm.pv.push_back(*m);
|
||||
for (Move pvMove : *(ss + 1)->pv)
|
||||
rm.pv.push_back(pvMove);
|
||||
|
||||
// We record how often the best move has been changed in each iteration.
|
||||
// This information is used for time management. In MultiPV mode,
|
||||
@@ -1383,7 +1382,7 @@ moves_loop: // When in check, search starts here
|
||||
bestMove = move;
|
||||
|
||||
if (PvNode && !rootNode) // Update pv even in fail-high case
|
||||
update_pv(ss->pv, move, (ss + 1)->pv);
|
||||
ss->pv->update(move, (ss + 1)->pv);
|
||||
|
||||
if (value >= beta)
|
||||
{
|
||||
@@ -1527,7 +1526,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta)
|
||||
return alpha;
|
||||
}
|
||||
|
||||
Move pv[MAX_PLY + 1];
|
||||
PVMoves pv;
|
||||
StateInfo st;
|
||||
|
||||
Key posKey;
|
||||
@@ -1539,8 +1538,8 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta)
|
||||
// Step 1. Initialize node
|
||||
if (PvNode)
|
||||
{
|
||||
(ss + 1)->pv = pv;
|
||||
ss->pv[0] = Move::none();
|
||||
(ss + 1)->pv = &pv;
|
||||
ss->pv->clear();
|
||||
}
|
||||
|
||||
bestMove = Move::none();
|
||||
@@ -1701,7 +1700,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta)
|
||||
bestMove = move;
|
||||
|
||||
if (PvNode) // Update pv even in fail-high case
|
||||
update_pv(ss->pv, move, (ss + 1)->pv);
|
||||
ss->pv->update(move, (ss + 1)->pv);
|
||||
|
||||
if (value < beta) // Update alpha here!
|
||||
alpha = value;
|
||||
@@ -1817,15 +1816,6 @@ Value value_from_tt(Value v, int ply, int r50c) {
|
||||
}
|
||||
|
||||
|
||||
// Adds current move and appends child pv[]
|
||||
void update_pv(Move* pv, Move move, const Move* childPv) {
|
||||
|
||||
for (*pv++ = move; childPv && *childPv != Move::none();)
|
||||
*pv++ = *childPv++;
|
||||
*pv = Move::none();
|
||||
}
|
||||
|
||||
|
||||
// Updates stats at the end of search() when a bestMove is found
|
||||
void update_all_stats(const Position& pos,
|
||||
Stack* ss,
|
||||
@@ -1923,7 +1913,6 @@ void update_quiet_histories(
|
||||
workerThread.sharedHistory.pawn_entry(pos)[pos.moved_piece(move)][move.to_sq()]
|
||||
<< bonus * (bonus > 0 ? 974 : 543) / 1024;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// When playing with strength handicap, choose the best move among a set of
|
||||
@@ -2113,8 +2102,8 @@ void syzygy_extend_pv(const OptionsMap& options,
|
||||
v = VALUE_DRAW;
|
||||
|
||||
// Undo the PV moves
|
||||
for (auto it = rootMove.pv.rbegin(); it != rootMove.pv.rend(); ++it)
|
||||
pos.undo_move(*it);
|
||||
for (size_t i = rootMove.pv.size(); i > 0; --i)
|
||||
pos.undo_move(rootMove.pv[i - 1]);
|
||||
|
||||
// Inform if we couldn't get a full extension in time
|
||||
if (time_abort())
|
||||
|
||||
+57
-17
@@ -23,7 +23,6 @@
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
@@ -31,6 +30,7 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
#include "history.h"
|
||||
#include "misc.h"
|
||||
@@ -58,11 +58,52 @@ class OptionsMap;
|
||||
|
||||
namespace Search {
|
||||
|
||||
struct PVMoves {
|
||||
Move moves[MAX_PLY + 1];
|
||||
std::size_t length = 0;
|
||||
|
||||
Move* begin() { return moves; }
|
||||
const Move* begin() const { return moves; }
|
||||
Move* end() { return moves + length; }
|
||||
const Move* end() const { return moves + length; }
|
||||
|
||||
Move& operator[](std::size_t index) { return moves[index]; }
|
||||
const Move& operator[](std::size_t index) const { return moves[index]; }
|
||||
|
||||
bool empty() const { return length == 0; }
|
||||
std::size_t size() const { return length; }
|
||||
|
||||
void clear() { length = 0; }
|
||||
|
||||
void push_back(Move move) {
|
||||
assert(length < MAX_PLY + 1);
|
||||
moves[length++] = move;
|
||||
}
|
||||
|
||||
void resize(std::size_t newSize) {
|
||||
assert(newSize <= length);
|
||||
length = newSize;
|
||||
}
|
||||
|
||||
void update(Move move, const PVMoves* childPv) {
|
||||
assert(childPv == nullptr || childPv->size() <= MAX_PLY);
|
||||
length = childPv ? childPv->length : 0;
|
||||
|
||||
if (childPv)
|
||||
{
|
||||
std::memcpy(moves + 1, childPv->moves, length * sizeof(Move));
|
||||
}
|
||||
|
||||
moves[0] = move;
|
||||
++length;
|
||||
}
|
||||
};
|
||||
|
||||
// Stack struct keeps track of the information we need to remember from nodes
|
||||
// shallower and deeper in the tree during the search. Each search thread has
|
||||
// its own array of Stack objects, indexed by the current ply.
|
||||
struct Stack {
|
||||
Move* pv;
|
||||
PVMoves* pv;
|
||||
PieceToHistory* continuationHistory;
|
||||
CorrectionHistory<PieceTo>* continuationCorrectionHistory;
|
||||
int ply;
|
||||
@@ -85,8 +126,7 @@ struct Stack {
|
||||
// fail low). Score is normally set at -VALUE_INFINITE for all non-pv moves.
|
||||
struct RootMove {
|
||||
|
||||
explicit RootMove(Move m) :
|
||||
pv(1, m) {}
|
||||
explicit RootMove(Move m) { pv.push_back(m); }
|
||||
bool extract_ponder_from_tt(const TranspositionTable& tt, Position& pos);
|
||||
bool operator==(const Move& m) const { return pv[0] == m; }
|
||||
// Sort in descending order
|
||||
@@ -94,18 +134,18 @@ struct RootMove {
|
||||
return m.score != score ? m.score < score : m.previousScore < previousScore;
|
||||
}
|
||||
|
||||
uint64_t effort = 0;
|
||||
Value score = -VALUE_INFINITE;
|
||||
Value previousScore = -VALUE_INFINITE;
|
||||
Value averageScore = -VALUE_INFINITE;
|
||||
Value meanSquaredScore = -VALUE_INFINITE * VALUE_INFINITE;
|
||||
Value uciScore = -VALUE_INFINITE;
|
||||
bool scoreLowerbound = false;
|
||||
bool scoreUpperbound = false;
|
||||
int selDepth = 0;
|
||||
int tbRank = 0;
|
||||
Value tbScore;
|
||||
std::vector<Move> pv;
|
||||
uint64_t effort = 0;
|
||||
Value score = -VALUE_INFINITE;
|
||||
Value previousScore = -VALUE_INFINITE;
|
||||
Value averageScore = -VALUE_INFINITE;
|
||||
Value meanSquaredScore = -VALUE_INFINITE * VALUE_INFINITE;
|
||||
Value uciScore = -VALUE_INFINITE;
|
||||
bool scoreLowerbound = false;
|
||||
bool scoreUpperbound = false;
|
||||
int selDepth = 0;
|
||||
int tbRank = 0;
|
||||
Value tbScore;
|
||||
PVMoves pv;
|
||||
};
|
||||
|
||||
using RootMoves = std::vector<RootMove>;
|
||||
@@ -343,7 +383,7 @@ class Worker {
|
||||
Depth rootDepth, completedDepth;
|
||||
Value rootDelta;
|
||||
|
||||
std::vector<Move> lastIterationPV;
|
||||
PVMoves lastIterationPV;
|
||||
|
||||
size_t threadIdx, numaThreadIdx, numaTotal;
|
||||
NumaReplicatedAccessToken numaAccessToken;
|
||||
|
||||
Reference in New Issue
Block a user