diff --git a/src/Makefile b/src/Makefile index 4307b7c7473..e7f8ce556bb 100644 --- a/src/Makefile +++ b/src/Makefile @@ -57,7 +57,7 @@ SRCS = benchmark.cpp bitboard.cpp evaluate.cpp main.cpp \ search.cpp thread.cpp timeman.cpp tt.cpp uci.cpp ucioption.cpp tune.cpp syzygy/tbprobe.cpp \ nnue/nnue_misc.cpp nnue/features/half_ka_v2_hm.cpp nnue/network.cpp engine.cpp score.cpp memory.cpp -HEADERS = benchmark.h bitboard.h evaluate.h misc.h movegen.h movepick.h \ +HEADERS = benchmark.h bitboard.h evaluate.h misc.h movegen.h movepick.h history.h \ nnue/nnue_misc.h nnue/features/half_ka_v2_hm.h nnue/layers/affine_transform.h \ nnue/layers/affine_transform_sparse_input.h nnue/layers/clipped_relu.h nnue/layers/simd.h \ nnue/layers/sqr_clipped_relu.h nnue/nnue_accumulator.h nnue/nnue_architecture.h \ diff --git a/src/history.h b/src/history.h new file mode 100644 index 00000000000..8d14a7a7cb1 --- /dev/null +++ b/src/history.h @@ -0,0 +1,185 @@ +/* + Stockfish, a UCI chess playing engine derived from Glaurung 2.1 + Copyright (C) 2004-2024 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 . +*/ + +#ifndef HISTORY_H_INCLUDED +#define HISTORY_H_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include // IWYU pragma: keep + +#include "position.h" + +namespace Stockfish { + +constexpr int PAWN_HISTORY_SIZE = 512; // has to be a power of 2 +constexpr int CORRECTION_HISTORY_SIZE = 32768; // has to be a power of 2 +constexpr int CORRECTION_HISTORY_LIMIT = 1024; +constexpr int LOW_PLY_HISTORY_SIZE = 4; + +static_assert((PAWN_HISTORY_SIZE & (PAWN_HISTORY_SIZE - 1)) == 0, + "PAWN_HISTORY_SIZE has to be a power of 2"); + +static_assert((CORRECTION_HISTORY_SIZE & (CORRECTION_HISTORY_SIZE - 1)) == 0, + "CORRECTION_HISTORY_SIZE has to be a power of 2"); + +enum PawnHistoryType { + Normal, + Correction +}; + +template +inline int pawn_structure_index(const Position& pos) { + return pos.pawn_key() & ((T == Normal ? PAWN_HISTORY_SIZE : CORRECTION_HISTORY_SIZE) - 1); +} + +inline int major_piece_index(const Position& pos) { + return pos.major_piece_key() & (CORRECTION_HISTORY_SIZE - 1); +} + +inline int minor_piece_index(const Position& pos) { + return pos.minor_piece_key() & (CORRECTION_HISTORY_SIZE - 1); +} + +template +inline int non_pawn_index(const Position& pos) { + return pos.non_pawn_key(c) & (CORRECTION_HISTORY_SIZE - 1); +} + +// StatsEntry stores the stat table value. It is usually a number but could +// be a move or even a nested history. We use a class instead of a naked value +// to directly call history update operator<<() on the entry so to use stats +// tables at caller sites as simple multi-dim arrays. +template +class StatsEntry { + + T entry; + + public: + void operator=(const T& v) { entry = v; } + T* operator&() { return &entry; } + T* operator->() { return &entry; } + operator const T&() const { return entry; } + + void operator<<(int bonus) { + static_assert(D <= std::numeric_limits::max(), "D overflows T"); + + // Make sure that bonus is in range [-D, D] + int clampedBonus = std::clamp(bonus, -D, D); + entry += clampedBonus - entry * std::abs(clampedBonus) / D; + + assert(std::abs(entry) <= D); + } +}; + +// Stats is a generic N-dimensional array used to store various statistics. +// The first template parameter T is the base type of the array, and the second +// template parameter D limits the range of updates in [-D, D] when we update +// values with the << operator, while the last parameters (Size and Sizes) +// encode the dimensions of the array. +template +struct Stats: public std::array, Size> { + using stats = Stats; + + void fill(const T& v) { + + // For standard-layout 'this' points to the first struct member + assert(std::is_standard_layout_v); + + using entry = StatsEntry; + entry* p = reinterpret_cast(this); + std::fill(p, p + sizeof(*this) / sizeof(entry), v); + } +}; + +template +struct Stats: public std::array, Size> {}; + +// In stats table, D=0 means that the template parameter is not used +enum StatsParams { + NOT_USED = 0 +}; +enum StatsType { + NoCaptures, + Captures +}; + +// ButterflyHistory records how often quiet moves have been successful or unsuccessful +// during the current search, and is used for reduction and move ordering decisions. +// It uses 2 tables (one for each color) indexed by the move's from and to squares, +// see https://www.chessprogramming.org/Butterfly_Boards (~11 elo) +using ButterflyHistory = Stats; + +// LowPlyHistory is adressed by play and move's from and to squares, used +// to improve move ordering near the root +using LowPlyHistory = Stats; + +// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type] +using CapturePieceToHistory = Stats; + +// PieceToHistory is like ButterflyHistory but is addressed by a move's [piece][to] +using PieceToHistory = Stats; + +// ContinuationHistory is the combined history of a given pair of moves, usually +// the current one given a previous one. The nested history table is based on +// PieceToHistory instead of ButterflyBoards. +// (~63 elo) +using ContinuationHistory = Stats; + +// PawnHistory is addressed by the pawn structure and a move's [piece][to] +using PawnHistory = Stats; + +// Correction histories record differences between the static evaluation of +// positions and their search score. It is used to improve the static evaluation +// used by some search heuristics. +// see https://www.chessprogramming.org/Static_Evaluation_Correction_History +enum CorrHistType { + Pawn, // By color and pawn structure + Major, // By color and positions of major pieces (Queen, Rook) and King + Minor, // By color and positions of minor pieces (Knight, Bishop) and King + NonPawn, // By color and non-pawn material positions + PieceTo, // By [piece][to] move + Continuation, // Combined history of move pairs +}; + +template +struct CorrHistTypedef { + using type = Stats; +}; + +template<> +struct CorrHistTypedef { + using type = Stats; +}; + +template<> +struct CorrHistTypedef { + using type = Stats::type, NOT_USED, PIECE_NB, SQUARE_NB>; +}; + +template +using CorrectionHistory = typename CorrHistTypedef::type; + +} // namespace Stockfish + +#endif // #ifndef HISTORY_H_INCLUDED diff --git a/src/movepick.cpp b/src/movepick.cpp index 2a1fb837348..720f2e031ea 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -19,7 +19,9 @@ #include "movepick.h" #include +#include #include +#include #include #include "bitboard.h" diff --git a/src/movepick.h b/src/movepick.h index f8f84d02474..0278b70ec82 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -19,172 +19,13 @@ #ifndef MOVEPICK_H_INCLUDED #define MOVEPICK_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include // IWYU pragma: keep - +#include "history.h" #include "movegen.h" -#include "position.h" #include "types.h" namespace Stockfish { -constexpr int PAWN_HISTORY_SIZE = 512; // has to be a power of 2 -constexpr int CORRECTION_HISTORY_SIZE = 32768; // has to be a power of 2 -constexpr int CORRECTION_HISTORY_LIMIT = 1024; -constexpr int LOW_PLY_HISTORY_SIZE = 4; - -static_assert((PAWN_HISTORY_SIZE & (PAWN_HISTORY_SIZE - 1)) == 0, - "PAWN_HISTORY_SIZE has to be a power of 2"); - -static_assert((CORRECTION_HISTORY_SIZE & (CORRECTION_HISTORY_SIZE - 1)) == 0, - "CORRECTION_HISTORY_SIZE has to be a power of 2"); - -enum PawnHistoryType { - Normal, - Correction -}; - -template -inline int pawn_structure_index(const Position& pos) { - return pos.pawn_key() & ((T == Normal ? PAWN_HISTORY_SIZE : CORRECTION_HISTORY_SIZE) - 1); -} - -inline int material_index(const Position& pos) { - return pos.material_key() & (CORRECTION_HISTORY_SIZE - 1); -} - -inline int major_piece_index(const Position& pos) { - return pos.major_piece_key() & (CORRECTION_HISTORY_SIZE - 1); -} - -inline int minor_piece_index(const Position& pos) { - return pos.minor_piece_key() & (CORRECTION_HISTORY_SIZE - 1); -} - -template -inline int non_pawn_index(const Position& pos) { - return pos.non_pawn_key(c) & (CORRECTION_HISTORY_SIZE - 1); -} - -// StatsEntry stores the stat table value. It is usually a number but could -// be a move or even a nested history. We use a class instead of a naked value -// to directly call history update operator<<() on the entry so to use stats -// tables at caller sites as simple multi-dim arrays. -template -class StatsEntry { - - T entry; - - public: - void operator=(const T& v) { entry = v; } - T* operator&() { return &entry; } - T* operator->() { return &entry; } - operator const T&() const { return entry; } - - void operator<<(int bonus) { - static_assert(D <= std::numeric_limits::max(), "D overflows T"); - - // Make sure that bonus is in range [-D, D] - int clampedBonus = std::clamp(bonus, -D, D); - entry += clampedBonus - entry * std::abs(clampedBonus) / D; - - assert(std::abs(entry) <= D); - } -}; - -// Stats is a generic N-dimensional array used to store various statistics. -// The first template parameter T is the base type of the array, and the second -// template parameter D limits the range of updates in [-D, D] when we update -// values with the << operator, while the last parameters (Size and Sizes) -// encode the dimensions of the array. -template -struct Stats: public std::array, Size> { - using stats = Stats; - - void fill(const T& v) { - - // For standard-layout 'this' points to the first struct member - assert(std::is_standard_layout_v); - - using entry = StatsEntry; - entry* p = reinterpret_cast(this); - std::fill(p, p + sizeof(*this) / sizeof(entry), v); - } -}; - -template -struct Stats: public std::array, Size> {}; - -// In stats table, D=0 means that the template parameter is not used -enum StatsParams { - NOT_USED = 0 -}; -enum StatsType { - NoCaptures, - Captures -}; - -// ButterflyHistory records how often quiet moves have been successful or unsuccessful -// during the current search, and is used for reduction and move ordering decisions. -// It uses 2 tables (one for each color) indexed by the move's from and to squares, -// see https://www.chessprogramming.org/Butterfly_Boards (~11 elo) -using ButterflyHistory = Stats; - -// LowPlyHistory is adressed by play and move's from and to squares, used -// to improve move ordering near the root -using LowPlyHistory = Stats; - -// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type] -using CapturePieceToHistory = Stats; - -// PieceToHistory is like ButterflyHistory but is addressed by a move's [piece][to] -using PieceToHistory = Stats; - -// ContinuationHistory is the combined history of a given pair of moves, usually -// the current one given a previous one. The nested history table is based on -// PieceToHistory instead of ButterflyBoards. -// (~63 elo) -using ContinuationHistory = Stats; - -// PawnHistory is addressed by the pawn structure and a move's [piece][to] -using PawnHistory = Stats; - -// Correction histories record differences between the static evaluation of -// positions and their search score. It is used to improve the static evaluation -// used by some search heuristics. -// see https://www.chessprogramming.org/Static_Evaluation_Correction_History -enum CorrHistType { - Pawn, // By color and pawn structure - Major, // By color and positions of major pieces (Queen, Rook) and King - Minor, // By color and positions of minor pieces (Knight, Bishop) and King - NonPawn, // By color and non-pawn material positions - PieceTo, // By [piece][to] move - Continuation, // Combined history of move pairs -}; - -template -struct CorrHistTypedef { - using type = Stats; -}; - -template<> -struct CorrHistTypedef { - using type = Stats; -}; - -template<> -struct CorrHistTypedef { - using type = Stats::type, NOT_USED, PIECE_NB, SQUARE_NB>; -}; - -template -using CorrectionHistory = typename CorrHistTypedef::type; +class Position; // The MovePicker class is used to pick one pseudo-legal move at a time from the // current position. The most important method is next_move(), which emits one diff --git a/src/search.cpp b/src/search.cpp index 4864057c1b1..d6914da0b67 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -34,6 +34,7 @@ #include #include "evaluate.h" +#include "history.h" #include "misc.h" #include "movegen.h" #include "movepick.h" diff --git a/src/search.h b/src/search.h index 751a398483f..b618855b9fc 100644 --- a/src/search.h +++ b/src/search.h @@ -31,8 +31,8 @@ #include #include +#include "history.h" #include "misc.h" -#include "movepick.h" #include "nnue/network.h" #include "nnue/nnue_accumulator.h" #include "numa.h"