mirror of
https://github.com/official-stockfish/Stockfish.git
synced 2026-07-22 12:47:08 +00:00
Compare commits
4
Commits
ebcea3efe9
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4bcd40409 | ||
|
|
4d75fd4f70 | ||
|
|
d70dec7d6f | ||
|
|
b4ea9205a6 |
+22
-26
@@ -80,17 +80,17 @@ SRCS = attacks.cpp benchmark.cpp bitboard.cpp evaluate.cpp main.cpp \
|
|||||||
misc.cpp movegen.cpp movepick.cpp position.cpp \
|
misc.cpp movegen.cpp movepick.cpp position.cpp \
|
||||||
search.cpp thread.cpp timeman.cpp tt.cpp uci.cpp ucioption.cpp tune.cpp syzygy/tbprobe.cpp \
|
search.cpp thread.cpp timeman.cpp tt.cpp uci.cpp ucioption.cpp tune.cpp syzygy/tbprobe.cpp \
|
||||||
nnue/nnue_accumulator.cpp nnue/nnue_misc.cpp nnue/network.cpp \
|
nnue/nnue_accumulator.cpp nnue/nnue_misc.cpp nnue/network.cpp \
|
||||||
nnue/features/half_ka_v2_hm.cpp nnue/features/full_threats.cpp \
|
nnue/features/half_ka_v2_hm.cpp nnue/features/full_threats.cpp nnue/features/pp_3wide.cpp \
|
||||||
engine.cpp score.cpp memory.cpp
|
engine.cpp score.cpp memory.cpp
|
||||||
|
|
||||||
OTHER_SRCS = universal/entry_x86.cpp universal/entry_arm64.cpp universal/entry_riscv64.cpp universal/nnue_embed.cpp
|
OTHER_SRCS = universal/entry_x86.cpp universal/entry_arm64.cpp universal/entry_riscv64.cpp universal/nnue_embed.cpp
|
||||||
|
|
||||||
HEADERS = attacks.h benchmark.h bitboard.h evaluate.h misc.h movegen.h movepick.h history.h \
|
HEADERS = attacks.h 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/features/full_threats.h \
|
nnue/nnue_misc.h nnue/features/half_ka_v2_hm.h nnue/features/full_threats.h \
|
||||||
nnue/layers/affine_transform.h nnue/layers/affine_transform_sparse_input.h \
|
nnue/features/pp_3wide.h nnue/layers/affine_transform.h nnue/layers/affine_transform_sparse_input.h \
|
||||||
nnue/layers/clipped_relu.h nnue/layers/sqr_clipped_relu.h nnue/nnue_accumulator.h \
|
nnue/layers/clipped_relu.h nnue/layers/sqr_clipped_relu.h nnue/nnue_accumulator.h \
|
||||||
nnue/nnue_architecture.h nnue/nnue_common.h nnue/nnue_feature_transformer.h nnue/simd.h \
|
nnue/nnue_architecture.h nnue/nnue_common.h nnue/nnue_feature_transformer.h nnue/simd.h \
|
||||||
nnue/nnz_helper.h position.h search.h syzygy/tbprobe.h thread.h thread_win32_osx.h timeman.h \
|
nnue/nnz_helper.h position.h search.h syzygy/tbprobe.h thread.h thread_native.h timeman.h \
|
||||||
tt.h tune.h types.h uci.h ucioption.h perft.h nnue/network.h engine.h score.h numa.h memory.h shm.h shm_linux.h
|
tt.h tune.h types.h uci.h ucioption.h perft.h nnue/network.h engine.h score.h numa.h memory.h shm.h shm_linux.h
|
||||||
|
|
||||||
OBJS = $(notdir $(SRCS:.cpp=.o))
|
OBJS = $(notdir $(SRCS:.cpp=.o))
|
||||||
@@ -685,31 +685,27 @@ else ifeq ($(COMP),mingw)
|
|||||||
CXXFLAGS += -fno-ipa-cp-clone
|
CXXFLAGS += -fno-ipa-cp-clone
|
||||||
endif
|
endif
|
||||||
|
|
||||||
### On mingw use Windows threads, otherwise POSIX
|
# On Android Bionic's C library comes with its own pthread implementation bundled in
|
||||||
ifneq ($(comp),mingw)
|
ifneq ($(OS),Android)
|
||||||
CXXFLAGS += -DUSE_PTHREADS
|
# Haiku has pthreads in its libroot, so only link it in on other platforms
|
||||||
# On Android Bionic's C library comes with its own pthread implementation bundled in
|
ifneq ($(KERNEL),Haiku)
|
||||||
ifneq ($(OS),Android)
|
ifneq ($(COMP),ndk)
|
||||||
# Haiku has pthreads in its libroot, so only link it in on other platforms
|
ifneq ($(arch),wasm32)
|
||||||
ifneq ($(KERNEL),Haiku)
|
LDFLAGS += -lpthread
|
||||||
ifneq ($(COMP),ndk)
|
|
||||||
ifneq ($(arch),wasm32)
|
|
||||||
LDFLAGS += -lpthread
|
|
||||||
|
|
||||||
add_lrt = yes
|
add_lrt = yes
|
||||||
ifeq ($(target_windows),yes)
|
ifeq ($(target_windows),yes)
|
||||||
add_lrt = no
|
add_lrt = no
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(TARGET_KERNEL),Darwin)
|
|
||||||
add_lrt = no
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(add_lrt),yes)
|
|
||||||
LDFLAGS += -lrt
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(TARGET_KERNEL),Darwin)
|
||||||
|
add_lrt = no
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(add_lrt),yes)
|
||||||
|
LDFLAGS += -lrt
|
||||||
|
endif
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
@@ -903,7 +899,7 @@ endif
|
|||||||
ifeq ($(pext),yes)
|
ifeq ($(pext),yes)
|
||||||
CXXFLAGS += -DUSE_PEXT
|
CXXFLAGS += -DUSE_PEXT
|
||||||
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
|
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
|
||||||
CXXFLAGS += -mbmi2 -DUSE_COMPTIME_ATTACKS
|
CXXFLAGS += -mbmi2
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|||||||
+7
-22
@@ -24,15 +24,17 @@
|
|||||||
|
|
||||||
namespace Stockfish::Attacks {
|
namespace Stockfish::Attacks {
|
||||||
|
|
||||||
namespace {
|
#ifdef USE_DUAL_HYPERBOLA_QUINT
|
||||||
|
alignas(64) DualMagic DualMagics[SQUARE_NB];
|
||||||
|
#endif
|
||||||
|
|
||||||
Bitboard LineBB[SQUARE_NB][SQUARE_NB];
|
Bitboard LineBB[SQUARE_NB][SQUARE_NB];
|
||||||
Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
|
Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
|
||||||
Bitboard RayPassBB[SQUARE_NB][SQUARE_NB];
|
Bitboard RayPassBB[SQUARE_NB][SQUARE_NB];
|
||||||
|
|
||||||
#ifdef USE_DUAL_HYPERBOLA_QUINT
|
namespace {
|
||||||
alignas(64) DualMagic DualMagics[SQUARE_NB];
|
|
||||||
#else
|
#ifndef USE_DUAL_HYPERBOLA_QUINT
|
||||||
alignas(64) Magic Magics[SQUARE_NB][2];
|
alignas(64) Magic Magics[SQUARE_NB][2];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -187,28 +189,11 @@ void init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_DUAL_HYPERBOLA_QUINT
|
#ifndef USE_DUAL_HYPERBOLA_QUINT
|
||||||
const DualMagic& dual_magic(Square s) { return DualMagics[s]; }
|
|
||||||
#else
|
|
||||||
const Magic& magic(Square s, PieceType pt) {
|
const Magic& magic(Square s, PieceType pt) {
|
||||||
assert((pt == BISHOP || pt == ROOK) && is_ok(s));
|
assert((pt == BISHOP || pt == ROOK) && is_ok(s));
|
||||||
return Magics[s][pt - BISHOP];
|
return Magics[s][pt - BISHOP];
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Bitboard line_bb(Square s1, Square s2) {
|
|
||||||
assert(is_ok(s1) && is_ok(s2));
|
|
||||||
return LineBB[s1][s2];
|
|
||||||
}
|
|
||||||
|
|
||||||
Bitboard between_bb(Square s1, Square s2) {
|
|
||||||
assert(is_ok(s1) && is_ok(s2));
|
|
||||||
return BetweenBB[s1][s2];
|
|
||||||
}
|
|
||||||
|
|
||||||
Bitboard ray_pass_bb(Square s1, Square s2) {
|
|
||||||
assert(is_ok(s1) && is_ok(s2));
|
|
||||||
return RayPassBB[s1][s2];
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Stockfish::Attacks
|
} // namespace Stockfish::Attacks
|
||||||
|
|||||||
+30
-4
@@ -22,6 +22,7 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "bitboard.h"
|
#include "bitboard.h"
|
||||||
@@ -135,7 +136,9 @@ struct alignas(32) DualMagic {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const DualMagic& dual_magic(Square s);
|
extern DualMagic DualMagics[SQUARE_NB];
|
||||||
|
|
||||||
|
inline const DualMagic& dual_magic(Square s) { return DualMagics[s]; }
|
||||||
|
|
||||||
#else
|
#else
|
||||||
// Magic holds all magic bitboards relevant data for a single square
|
// Magic holds all magic bitboards relevant data for a single square
|
||||||
@@ -164,9 +167,24 @@ const Magic& magic(Square s, PieceType pt);
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Bitboard line_bb(Square s1, Square s2);
|
extern Bitboard LineBB[SQUARE_NB][SQUARE_NB];
|
||||||
Bitboard between_bb(Square s1, Square s2);
|
extern Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
|
||||||
Bitboard ray_pass_bb(Square s1, Square s2);
|
extern Bitboard RayPassBB[SQUARE_NB][SQUARE_NB];
|
||||||
|
|
||||||
|
inline Bitboard line_bb(Square s1, Square s2) {
|
||||||
|
assert(is_ok(s1) && is_ok(s2));
|
||||||
|
return LineBB[s1][s2];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Bitboard between_bb(Square s1, Square s2) {
|
||||||
|
assert(is_ok(s1) && is_ok(s2));
|
||||||
|
return BetweenBB[s1][s2];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Bitboard ray_pass_bb(Square s1, Square s2) {
|
||||||
|
assert(is_ok(s1) && is_ok(s2));
|
||||||
|
return RayPassBB[s1][s2];
|
||||||
|
}
|
||||||
|
|
||||||
// Returns the bitboard of target square for the given step
|
// Returns the bitboard of target square for the given step
|
||||||
// from the given square. If the step is off the board, returns empty bitboard.
|
// from the given square. If the step is off the board, returns empty bitboard.
|
||||||
@@ -304,6 +322,14 @@ inline Bitboard attacks_bb(Square s, Bitboard occupied) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::pair<Bitboard, Bitboard> both_attacks_bb(Square s, Bitboard occupied) {
|
||||||
|
#ifdef USE_DUAL_HYPERBOLA_QUINT
|
||||||
|
return dual_magic(s).both_attacks_bb(occupied);
|
||||||
|
#else
|
||||||
|
return {attacks_bb<BISHOP>(s, occupied), attacks_bb<ROOK>(s, occupied)};
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// Returns the attacks by the given piece
|
// Returns the attacks by the given piece
|
||||||
// assuming the board is occupied according to the passed Bitboard.
|
// assuming the board is occupied according to the passed Bitboard.
|
||||||
// Sliding piece attacks do not continue past an occupied square.
|
// Sliding piece attacks do not continue past an occupied square.
|
||||||
|
|||||||
+17
-1
@@ -20,6 +20,7 @@
|
|||||||
#define BITBOARD_H_INCLUDED
|
#define BITBOARD_H_INCLUDED
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
@@ -127,8 +128,23 @@ constexpr Bitboard pawn_single_push_bb(Color c, Bitboard b) {
|
|||||||
return c == WHITE ? shift<NORTH>(b) : shift<SOUTH>(b);
|
return c == WHITE ? shift<NORTH>(b) : shift<SOUTH>(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr int edge_distance(File f) { return std::min(f, File(FILE_H - f)); }
|
inline constexpr auto PawnPairBB = []() {
|
||||||
|
std::array<Bitboard, SQUARE_NB> result{};
|
||||||
|
for (Square s = SQ_A1; s <= SQ_H8; ++s)
|
||||||
|
{
|
||||||
|
Bitboard file = file_bb(s);
|
||||||
|
Bitboard files = file | shift<EAST>(file) | shift<WEST>(file);
|
||||||
|
result[s] = files & ~(Rank1BB | Rank8BB) & ~square_bb(s);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}();
|
||||||
|
|
||||||
|
// Returns the squares that can host a pawn forming a "pawn pair" with a pawn
|
||||||
|
// on s: own file plus adjacent files, restricted to ranks 2-7, excluding s.
|
||||||
|
// The geometry is color-independent.
|
||||||
|
constexpr Bitboard pawn_pair_bb(Square s) { return PawnPairBB[s]; }
|
||||||
|
|
||||||
|
constexpr int edge_distance(File f) { return std::min(f, File(FILE_H - f)); }
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr int constexpr_popcount(T v) {
|
constexpr int constexpr_popcount(T v) {
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@ namespace Eval {
|
|||||||
// for the build process (profile-build and fishtest) to work. Do not change the
|
// for the build process (profile-build and fishtest) to work. Do not change the
|
||||||
// name of the macro or the location where this macro is defined, as it is used
|
// name of the macro or the location where this macro is defined, as it is used
|
||||||
// in the Makefile/Fishtest.
|
// in the Makefile/Fishtest.
|
||||||
#define EvalFileDefaultName "nn-0ee0657fb25e.nnue"
|
#define EvalFileDefaultName "nn-89cb98a217f7.nnue"
|
||||||
|
|
||||||
namespace NNUE {
|
namespace NNUE {
|
||||||
class Network;
|
class Network;
|
||||||
|
|||||||
+2
-1
@@ -554,7 +554,8 @@ std::optional<usize> str_to_size_t(const std::string& s) {
|
|||||||
errno = 0;
|
errno = 0;
|
||||||
char* endptr = nullptr;
|
char* endptr = nullptr;
|
||||||
const unsigned long long value = std::strtoull(s.c_str(), &endptr, 10);
|
const unsigned long long value = std::strtoull(s.c_str(), &endptr, 10);
|
||||||
if (errno == ERANGE || *endptr != '\0' || value > std::numeric_limits<usize>::max())
|
if (errno == ERANGE || (*endptr != '\0' && !std::isspace(*endptr))
|
||||||
|
|| value > std::numeric_limits<usize>::max())
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
return static_cast<usize>(value);
|
return static_cast<usize>(value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
#include "full_threats.h"
|
#include "full_threats.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cassert>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -73,7 +72,7 @@ constexpr auto make_piece_indices_piece() {
|
|||||||
|
|
||||||
for (Square from = SQ_A1; from <= SQ_H8; ++from)
|
for (Square from = SQ_A1; from <= SQ_H8; ++from)
|
||||||
{
|
{
|
||||||
Bitboard attacks = Attacks::PawnPushOrAttacks[C][from];
|
Bitboard attacks = Attacks::PseudoAttacks[C][from];
|
||||||
|
|
||||||
for (Square to = SQ_A1; to <= SQ_H8; ++to)
|
for (Square to = SQ_A1; to <= SQ_H8; ++to)
|
||||||
{
|
{
|
||||||
@@ -136,8 +135,8 @@ constexpr auto init_threat_offsets() {
|
|||||||
|
|
||||||
else if (from >= SQ_A2 && from <= SQ_H7)
|
else if (from >= SQ_A2 && from <= SQ_H7)
|
||||||
{
|
{
|
||||||
Bitboard attacks = (pieceIdx < 8) ? Attacks::PawnPushOrAttacks[WHITE][from]
|
Bitboard attacks = (pieceIdx < 8) ? Attacks::PseudoAttacks[WHITE][from]
|
||||||
: Attacks::PawnPushOrAttacks[BLACK][from];
|
: Attacks::PseudoAttacks[BLACK][from];
|
||||||
cumulativePieceOffset += constexpr_popcount(attacks);
|
cumulativePieceOffset += constexpr_popcount(attacks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -208,11 +207,9 @@ inline sf_always_inline IndexType FullThreats::make_index(
|
|||||||
// Get a list of indices for active features in ascending order
|
// Get a list of indices for active features in ascending order
|
||||||
|
|
||||||
void FullThreats::append_active_indices(Color perspective, const Position& pos, IndexList& active) {
|
void FullThreats::append_active_indices(Color perspective, const Position& pos, IndexList& active) {
|
||||||
const Square ksq = pos.square<KING>(perspective);
|
const Square ksq = pos.square<KING>(perspective);
|
||||||
const Bitboard occupied = pos.pieces();
|
const Bitboard occupied = pos.pieces();
|
||||||
const Bitboard pawns = pos.pieces(PAWN);
|
const Bitboard pawnTargets = pos.pieces(KNIGHT, ROOK);
|
||||||
|
|
||||||
const Bitboard pawnTargets = pos.pieces(PAWN, KNIGHT, ROOK);
|
|
||||||
const Bitboard minorSliderTargets = pos.pieces(PAWN, KNIGHT, BISHOP, ROOK);
|
const Bitboard minorSliderTargets = pos.pieces(PAWN, KNIGHT, BISHOP, ROOK);
|
||||||
const Bitboard queenTargets = pos.pieces(PAWN, KNIGHT, BISHOP, ROOK, QUEEN);
|
const Bitboard queenTargets = pos.pieces(PAWN, KNIGHT, BISHOP, ROOK, QUEEN);
|
||||||
|
|
||||||
@@ -221,18 +218,14 @@ void FullThreats::append_active_indices(Color perspective, const Position& pos,
|
|||||||
const Color c = Color(perspective ^ color);
|
const Color c = Color(perspective ^ color);
|
||||||
|
|
||||||
{
|
{
|
||||||
const Piece attacker = make_piece(c, PAWN);
|
const Piece attacker = make_piece(c, PAWN);
|
||||||
const Bitboard cPawns = pos.pieces(c, PAWN);
|
const Bitboard cPawns = pos.pieces(c, PAWN);
|
||||||
// Set of pawns which are prevented from movement by a pawn in front of them
|
auto process_pawn_attacks = [&](Bitboard attacks, Direction attkDir) {
|
||||||
const Bitboard pushers = pawn_single_push_bb(~c, pawns) & cPawns;
|
|
||||||
|
|
||||||
auto process_pawn_attacks = [&](Bitboard attacks, Direction attkDir) {
|
|
||||||
while (attacks)
|
while (attacks)
|
||||||
{
|
{
|
||||||
Square to = pop_lsb(attacks);
|
Square to = pop_lsb(attacks);
|
||||||
Square from = to - attkDir;
|
Square from = to - attkDir;
|
||||||
Piece attacked = pos.piece_on(to);
|
Piece attacked = pos.piece_on(to);
|
||||||
assert(file_of(from) != file_of(to) || type_of(attacked) == PAWN);
|
|
||||||
IndexType index = make_index(perspective, attacker, from, to, attacked, ksq);
|
IndexType index = make_index(perspective, attacker, from, to, attacked, ksq);
|
||||||
active.push_back_if_lt(index, Dimensions);
|
active.push_back_if_lt(index, Dimensions);
|
||||||
}
|
}
|
||||||
@@ -242,13 +235,11 @@ void FullThreats::append_active_indices(Color perspective, const Position& pos,
|
|||||||
{
|
{
|
||||||
process_pawn_attacks(shift<NORTH_EAST>(cPawns) & pawnTargets, NORTH_EAST);
|
process_pawn_attacks(shift<NORTH_EAST>(cPawns) & pawnTargets, NORTH_EAST);
|
||||||
process_pawn_attacks(shift<NORTH_WEST>(cPawns) & pawnTargets, NORTH_WEST);
|
process_pawn_attacks(shift<NORTH_WEST>(cPawns) & pawnTargets, NORTH_WEST);
|
||||||
process_pawn_attacks(shift<NORTH>(pushers), NORTH);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
process_pawn_attacks(shift<SOUTH_WEST>(cPawns) & pawnTargets, SOUTH_WEST);
|
process_pawn_attacks(shift<SOUTH_WEST>(cPawns) & pawnTargets, SOUTH_WEST);
|
||||||
process_pawn_attacks(shift<SOUTH_EAST>(cPawns) & pawnTargets, SOUTH_EAST);
|
process_pawn_attacks(shift<SOUTH_EAST>(cPawns) & pawnTargets, SOUTH_EAST);
|
||||||
process_pawn_attacks(shift<SOUTH>(pushers), SOUTH);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,16 +29,18 @@ class Position;
|
|||||||
|
|
||||||
namespace Stockfish::Eval::NNUE::Features {
|
namespace Stockfish::Eval::NNUE::Features {
|
||||||
|
|
||||||
static constexpr int numValidTargets[PIECE_NB] = {0, 6, 10, 8, 8, 10, 0, 0,
|
// Pawn diagonal threats only target knights and rooks (pawn-pawn relationships
|
||||||
0, 6, 10, 8, 8, 10, 0, 0};
|
// are handled by the PP_3Wide feature set), so pawns have 4 valid targets.
|
||||||
|
static constexpr int numValidTargets[PIECE_NB] = {0, 4, 10, 8, 8, 10, 0, 0,
|
||||||
|
0, 4, 10, 8, 8, 10, 0, 0};
|
||||||
|
|
||||||
class FullThreats {
|
class FullThreats {
|
||||||
public:
|
public:
|
||||||
// Hash value embedded in the evaluation file
|
// Hash value embedded in the evaluation file
|
||||||
static constexpr u32 HashValue = 0x8f234cb8u;
|
static constexpr u32 HashValue = 0x2e6b9d04u;
|
||||||
|
|
||||||
// Number of feature dimensions
|
// Number of feature dimensions
|
||||||
static constexpr IndexType Dimensions = 60720;
|
static constexpr IndexType Dimensions = 59808;
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
// Orient a square according to perspective (rotates by 180 for black)
|
// Orient a square according to perspective (rotates by 180 for black)
|
||||||
@@ -54,7 +56,7 @@ class FullThreats {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static constexpr int map[PIECE_TYPE_NB-2][PIECE_TYPE_NB-2] = {
|
static constexpr int map[PIECE_TYPE_NB-2][PIECE_TYPE_NB-2] = {
|
||||||
{ 0, 1, -1, 2, -1, -1},
|
{-1, 0, -1, 1, -1, -1},
|
||||||
{ 0, 1, 2, 3, 4, -1},
|
{ 0, 1, 2, 3, 4, -1},
|
||||||
{ 0, 1, 2, 3, -1, -1},
|
{ 0, 1, 2, 3, -1, -1},
|
||||||
{ 0, 1, 2, 3, -1, -1},
|
{ 0, 1, 2, 3, -1, -1},
|
||||||
@@ -64,9 +66,8 @@ class FullThreats {
|
|||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
// Maximum number of simultaneously active features.
|
// Maximum number of simultaneously active features.
|
||||||
static constexpr IndexType MaxActiveDimensions = 128;
|
using IndexList = ValueList<u16, 256>;
|
||||||
using IndexList = ValueList<IndexType, MaxActiveDimensions>;
|
using DiffType = DirtyThreats;
|
||||||
using DiffType = DirtyThreats;
|
|
||||||
|
|
||||||
static IndexType
|
static IndexType
|
||||||
make_index(Color perspective, Piece attkr, Square from, Square to, Piece attkd, Square ksq);
|
make_index(Color perspective, Piece attkr, Square from, Square to, Piece attkd, Square ksq);
|
||||||
|
|||||||
@@ -0,0 +1,171 @@
|
|||||||
|
/*
|
||||||
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
|
Copyright (C) 2004-2026 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pp_3wide.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "full_threats.h"
|
||||||
|
#include "../../bitboard.h"
|
||||||
|
#include "../../misc.h"
|
||||||
|
#include "../../position.h"
|
||||||
|
#include "../../types.h"
|
||||||
|
#include "../nnue_common.h"
|
||||||
|
|
||||||
|
namespace Stockfish::Eval::NNUE::Features {
|
||||||
|
|
||||||
|
constexpr IndexType make_pawn_id(Color color, Square square) {
|
||||||
|
assert(square >= SQ_A2 && square <= SQ_H7);
|
||||||
|
return 48 * int(color) + square - SQ_A2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_AVX512ICL
|
||||||
|
static inline __m256i pp_idx_epi16(__m256i a, __m256i b) {
|
||||||
|
const __m256i hi = _mm256_max_epu16(a, b);
|
||||||
|
const __m256i lo = _mm256_min_epu16(a, b);
|
||||||
|
const __m256i prod = _mm256_mullo_epi16(hi, _mm256_sub_epi16(hi, _mm256_set1_epi16(1)));
|
||||||
|
return _mm256_add_epi16(_mm256_add_epi16(_mm256_srli_epi16(prod, 1), lo),
|
||||||
|
_mm256_set1_epi16(i16(PP_3Wide::IndexBase)));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline sf_always_inline IndexType PP_3Wide::make_index(
|
||||||
|
Color perspective, Color color, Square from, Square to, Color pairedColor, Square ksq) {
|
||||||
|
const i8 orientation = FullThreats::OrientTBL[ksq] ^ (56 * perspective);
|
||||||
|
unsigned from_oriented = u8(from) ^ orientation;
|
||||||
|
unsigned to_oriented = u8(to) ^ orientation;
|
||||||
|
|
||||||
|
Color color_oriented = Color(color ^ perspective);
|
||||||
|
Color pairedColor_oriented = Color(pairedColor ^ perspective);
|
||||||
|
|
||||||
|
assert(from_oriented >= SQ_A2 && from_oriented <= SQ_H7);
|
||||||
|
assert(to_oriented >= SQ_A2 && to_oriented <= SQ_H7);
|
||||||
|
|
||||||
|
const IndexType idA = make_pawn_id(color_oriented, Square(from_oriented));
|
||||||
|
const IndexType idB = make_pawn_id(pairedColor_oriented, Square(to_oriented));
|
||||||
|
const IndexType hi = std::max(idA, idB);
|
||||||
|
const IndexType lo = std::min(idA, idB);
|
||||||
|
|
||||||
|
return hi * (hi - 1) / 2 + lo + IndexBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PP_3Wide::append_active_indices(Color perspective, const Position& pos, IndexList& active) {
|
||||||
|
const Square ksq = pos.square<KING>(perspective);
|
||||||
|
const Bitboard white = pos.pieces(WHITE, PAWN);
|
||||||
|
const Bitboard black = pos.pieces(BLACK, PAWN);
|
||||||
|
|
||||||
|
Bitboard bb = white;
|
||||||
|
while (bb)
|
||||||
|
{
|
||||||
|
Square from = pop_lsb(bb);
|
||||||
|
const Bitboard band = pawn_pair_bb(from);
|
||||||
|
for (Bitboard ww = band & bb; ww;)
|
||||||
|
active.push_back(make_index(perspective, WHITE, from, pop_lsb(ww), WHITE, ksq));
|
||||||
|
for (Bitboard wb = band & black; wb;)
|
||||||
|
active.push_back(make_index(perspective, WHITE, from, pop_lsb(wb), BLACK, ksq));
|
||||||
|
}
|
||||||
|
|
||||||
|
bb = black;
|
||||||
|
while (bb)
|
||||||
|
{
|
||||||
|
Square from = pop_lsb(bb);
|
||||||
|
const Bitboard band = pawn_pair_bb(from);
|
||||||
|
for (Bitboard bbk = band & bb; bbk;)
|
||||||
|
active.push_back(make_index(perspective, BLACK, from, pop_lsb(bbk), BLACK, ksq));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PP_3Wide::append_changed_indices(Color perspective,
|
||||||
|
Square ksq,
|
||||||
|
const DiffType& diff,
|
||||||
|
IndexList& removed,
|
||||||
|
IndexList& added,
|
||||||
|
[[maybe_unused]] const ThreatWeightType* prefetchBase,
|
||||||
|
[[maybe_unused]] IndexType prefetchStride) {
|
||||||
|
|
||||||
|
const Bitboard whiteBefore = diff.before[WHITE];
|
||||||
|
const Bitboard blackBefore = diff.before[BLACK];
|
||||||
|
const Bitboard whiteAfter = diff.after[WHITE];
|
||||||
|
const Bitboard blackAfter = diff.after[BLACK];
|
||||||
|
|
||||||
|
if (whiteBefore == whiteAfter && blackBefore == blackAfter)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#ifdef USE_AVX512ICL
|
||||||
|
const u8 orientation = u8(FullThreats::OrientTBL[ksq]) ^ u8(56 * perspective);
|
||||||
|
const __m512i iota = AllSquares;
|
||||||
|
const __m512i adjusted =
|
||||||
|
_mm512_sub_epi8(_mm512_xor_si512(iota, _mm512_set1_epi8(orientation)), _mm512_set1_epi8(8));
|
||||||
|
|
||||||
|
auto generate = [&](Bitboard updatedW, Bitboard updatedB, Bitboard pawnsW, Bitboard pawnsB,
|
||||||
|
IndexList& out) {
|
||||||
|
const Bitboard friendly = perspective == WHITE ? pawnsW : pawnsB;
|
||||||
|
const Bitboard enemy = perspective == WHITE ? pawnsB : pawnsW;
|
||||||
|
const __m512i ids = _mm512_mask_blend_epi8(
|
||||||
|
friendly, _mm512_add_epi8(adjusted, _mm512_set1_epi8(48)), adjusted);
|
||||||
|
|
||||||
|
const Bitboard unchanged = (pawnsW | pawnsB) & ~(updatedW | updatedB);
|
||||||
|
for (Bitboard u = updatedW | updatedB; u;)
|
||||||
|
{
|
||||||
|
const Square a = pop_lsb(u);
|
||||||
|
const Bitboard partners = pawn_pair_bb(a) & (unchanged | u);
|
||||||
|
const int n = popcount(partners);
|
||||||
|
if (!n)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const u16 colorOff = (enemy & a) ? 48 : 0;
|
||||||
|
const u16 aId = u16(((u8(a) ^ orientation) - 8) + colorOff);
|
||||||
|
const __m256i pids = _mm256_cvtepu8_epi16(
|
||||||
|
_mm512_castsi512_si128(_mm512_maskz_compress_epi8(partners, ids)));
|
||||||
|
const __m256i feats = pp_idx_epi16(_mm256_set1_epi16(aId), pids);
|
||||||
|
|
||||||
|
u16* w = out.make_space(n);
|
||||||
|
_mm256_storeu_epi16(w, feats);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
auto generate = [&](Bitboard updatedW, Bitboard updatedB, Bitboard pawnsW, Bitboard pawnsB,
|
||||||
|
IndexList& out) {
|
||||||
|
auto push = [&](IndexType index) {
|
||||||
|
if (prefetchBase)
|
||||||
|
prefetch<PrefetchRw::READ, PrefetchLoc::LOW>(reinterpret_cast<const void*>(
|
||||||
|
reinterpret_cast<uintptr_t>(prefetchBase) + index * prefetchStride));
|
||||||
|
out.push_back(index);
|
||||||
|
};
|
||||||
|
const Bitboard unchanged = (pawnsW | pawnsB) & ~(updatedW | updatedB);
|
||||||
|
for (Bitboard u = updatedW | updatedB; u;)
|
||||||
|
{
|
||||||
|
const Square a = pop_lsb(u);
|
||||||
|
const Bitboard mask = pawn_pair_bb(a) & (unchanged | u);
|
||||||
|
const Color aCol = (pawnsB & a) ? BLACK : WHITE;
|
||||||
|
for (Bitboard pb = pawnsB & mask; pb;)
|
||||||
|
push(make_index(perspective, aCol, a, pop_lsb(pb), BLACK, ksq));
|
||||||
|
for (Bitboard pw = pawnsW & mask; pw;)
|
||||||
|
push(make_index(perspective, aCol, a, pop_lsb(pw), WHITE, ksq));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
generate(whiteAfter & ~whiteBefore, blackAfter & ~blackBefore, whiteAfter, blackAfter, added);
|
||||||
|
generate(whiteBefore & ~whiteAfter, blackBefore & ~blackAfter, whiteBefore, blackBefore,
|
||||||
|
removed);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Stockfish::Eval::NNUE::Features
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
||||||
|
Copyright (C) 2004-2026 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NNUE_FEATURES_PP_3WIDE_INCLUDED
|
||||||
|
#define NNUE_FEATURES_PP_3WIDE_INCLUDED
|
||||||
|
|
||||||
|
#include "../../misc.h"
|
||||||
|
#include "../../types.h"
|
||||||
|
#include "../nnue_common.h"
|
||||||
|
|
||||||
|
namespace Stockfish {
|
||||||
|
class Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Stockfish::Eval::NNUE::Features {
|
||||||
|
|
||||||
|
class PP_3Wide {
|
||||||
|
public:
|
||||||
|
static constexpr u32 HashValue = 0x86f2b1ddu;
|
||||||
|
|
||||||
|
static constexpr IndexType PawnIds = COLOR_NB * 48;
|
||||||
|
static constexpr IndexType Dimensions = PawnIds * (PawnIds - 1) / 2;
|
||||||
|
|
||||||
|
// Pawn pair feature indices are concatenated to threats, so this must equal ThreatFeatureSet::Dimensions;
|
||||||
|
// see nnue_feature_transformer.h
|
||||||
|
static constexpr IndexType IndexBase = 59808;
|
||||||
|
using IndexList = ValueList<u16, 256>;
|
||||||
|
using DiffType = DirtyPawnPairs;
|
||||||
|
|
||||||
|
static IndexType make_index(
|
||||||
|
Color perspective, Color color, Square from, Square to, Color pairedColor, Square ksq);
|
||||||
|
|
||||||
|
static void append_active_indices(Color perspective, const Position& pos, IndexList& active);
|
||||||
|
|
||||||
|
static void append_changed_indices(Color perspective,
|
||||||
|
Square ksq,
|
||||||
|
const DiffType& diff,
|
||||||
|
IndexList& removed,
|
||||||
|
IndexList& added,
|
||||||
|
const ThreatWeightType* prefetchBase = nullptr,
|
||||||
|
IndexType prefetchStride = 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Stockfish::Eval::NNUE::Features
|
||||||
|
|
||||||
|
#endif // #ifndef NNUE_FEATURES_PP_3WIDE_INCLUDED
|
||||||
@@ -57,17 +57,19 @@ AccumulatorState& AccumulatorStack::mut_latest() noexcept { return accumulators[
|
|||||||
void AccumulatorStack::reset() noexcept {
|
void AccumulatorStack::reset() noexcept {
|
||||||
accumulators[0].dirtyPiece = {};
|
accumulators[0].dirtyPiece = {};
|
||||||
new (&accumulators[0].dirtyThreats) DirtyThreats;
|
new (&accumulators[0].dirtyThreats) DirtyThreats;
|
||||||
|
new (&accumulators[0].dirtyPawnPairs) DirtyPawnPairs;
|
||||||
accumulators[0].computed.fill(false);
|
accumulators[0].computed.fill(false);
|
||||||
size = 1;
|
size = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<DirtyPiece&, DirtyThreats&> AccumulatorStack::push() noexcept {
|
Dirties& AccumulatorStack::push() noexcept {
|
||||||
assert(size < MaxSize);
|
assert(size < MaxSize);
|
||||||
auto& st = accumulators[size];
|
auto& st = accumulators[size];
|
||||||
st.computed.fill(false);
|
st.computed.fill(false);
|
||||||
new (&st.dirtyThreats) DirtyThreats;
|
new (&st.dirtyThreats) DirtyThreats;
|
||||||
|
new (&st.dirtyPawnPairs) DirtyPawnPairs;
|
||||||
size++;
|
size++;
|
||||||
return {st.dirtyPiece, st.dirtyThreats};
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccumulatorStack::pop() noexcept {
|
void AccumulatorStack::pop() noexcept {
|
||||||
@@ -177,8 +179,8 @@ void apply_combined(Color perspective,
|
|||||||
vec_t acc[Tiling::NumRegs];
|
vec_t acc[Tiling::NumRegs];
|
||||||
psqt_vec_t psqt[Tiling::NumPsqtRegs];
|
psqt_vec_t psqt[Tiling::NumPsqtRegs];
|
||||||
|
|
||||||
const auto* psqWeights = &featureTransformer.weights[0];
|
const auto* psqWeights = &featureTransformer.weights[0];
|
||||||
const auto* threatWeights = &featureTransformer.threatWeights[0];
|
const auto* threatAndPpWeights = &featureTransformer.threatAndPpWeights[0];
|
||||||
|
|
||||||
for (IndexType j = 0; j < Dimensions / Tiling::TileHeight; ++j)
|
for (IndexType j = 0; j < Dimensions / Tiling::TileHeight; ++j)
|
||||||
{
|
{
|
||||||
@@ -208,7 +210,7 @@ void apply_combined(Color perspective,
|
|||||||
for (int i = 0; i < thrRemoved.ssize(); ++i)
|
for (int i = 0; i < thrRemoved.ssize(); ++i)
|
||||||
{
|
{
|
||||||
auto* column = reinterpret_cast<const vec_i8_t*>(
|
auto* column = reinterpret_cast<const vec_i8_t*>(
|
||||||
&threatWeights[thrRemoved[i] * Dimensions + tileOff]);
|
&threatAndPpWeights[thrRemoved[i] * Dimensions + tileOff]);
|
||||||
|
|
||||||
#ifdef USE_NEON
|
#ifdef USE_NEON
|
||||||
for (IndexType k = 0; k < Tiling::NumRegs; k += 2)
|
for (IndexType k = 0; k < Tiling::NumRegs; k += 2)
|
||||||
@@ -224,8 +226,8 @@ void apply_combined(Color perspective,
|
|||||||
|
|
||||||
for (int i = 0; i < thrAdded.ssize(); ++i)
|
for (int i = 0; i < thrAdded.ssize(); ++i)
|
||||||
{
|
{
|
||||||
auto* column =
|
auto* column = reinterpret_cast<const vec_i8_t*>(
|
||||||
reinterpret_cast<const vec_i8_t*>(&threatWeights[thrAdded[i] * Dimensions + tileOff]);
|
&threatAndPpWeights[thrAdded[i] * Dimensions + tileOff]);
|
||||||
|
|
||||||
#ifdef USE_NEON
|
#ifdef USE_NEON
|
||||||
for (IndexType k = 0; k < Tiling::NumRegs; k += 2)
|
for (IndexType k = 0; k < Tiling::NumRegs; k += 2)
|
||||||
@@ -271,7 +273,8 @@ void apply_combined(Color perspective,
|
|||||||
for (int i = 0; i < thrRemoved.ssize(); ++i)
|
for (int i = 0; i < thrRemoved.ssize(); ++i)
|
||||||
{
|
{
|
||||||
auto* columnPsqt = reinterpret_cast<const psqt_vec_t*>(
|
auto* columnPsqt = reinterpret_cast<const psqt_vec_t*>(
|
||||||
&featureTransformer.threatPsqtWeights[thrRemoved[i] * PSQTBuckets + psqtTileOff]);
|
&featureTransformer
|
||||||
|
.threatAndPpPsqtWeights[thrRemoved[i] * PSQTBuckets + psqtTileOff]);
|
||||||
for (usize k = 0; k < Tiling::NumPsqtRegs; ++k)
|
for (usize k = 0; k < Tiling::NumPsqtRegs; ++k)
|
||||||
psqt[k] = vec_sub_psqt_32(psqt[k], columnPsqt[k]);
|
psqt[k] = vec_sub_psqt_32(psqt[k], columnPsqt[k]);
|
||||||
}
|
}
|
||||||
@@ -279,7 +282,7 @@ void apply_combined(Color perspective,
|
|||||||
for (int i = 0; i < thrAdded.ssize(); ++i)
|
for (int i = 0; i < thrAdded.ssize(); ++i)
|
||||||
{
|
{
|
||||||
auto* columnPsqt = reinterpret_cast<const psqt_vec_t*>(
|
auto* columnPsqt = reinterpret_cast<const psqt_vec_t*>(
|
||||||
&featureTransformer.threatPsqtWeights[thrAdded[i] * PSQTBuckets + psqtTileOff]);
|
&featureTransformer.threatAndPpPsqtWeights[thrAdded[i] * PSQTBuckets + psqtTileOff]);
|
||||||
for (usize k = 0; k < Tiling::NumPsqtRegs; ++k)
|
for (usize k = 0; k < Tiling::NumPsqtRegs; ++k)
|
||||||
psqt[k] = vec_add_psqt_32(psqt[k], columnPsqt[k]);
|
psqt[k] = vec_add_psqt_32(psqt[k], columnPsqt[k]);
|
||||||
}
|
}
|
||||||
@@ -293,9 +296,9 @@ void apply_combined(Color perspective,
|
|||||||
usize tileOffset = 0;
|
usize tileOffset = 0;
|
||||||
|
|
||||||
const auto* psqWeights = &featureTransformer.weights[0];
|
const auto* psqWeights = &featureTransformer.weights[0];
|
||||||
const auto* threatWeights = &featureTransformer.threatWeights[0];
|
const auto* threatWeights = &featureTransformer.threatAndPpWeights[0];
|
||||||
const auto* psqtWeights = &featureTransformer.psqtWeights[0];
|
const auto* psqtWeights = &featureTransformer.psqtWeights[0];
|
||||||
const auto* threatPsqtWeights = &featureTransformer.threatPsqtWeights[0];
|
const auto* threatPsqtWeights = &featureTransformer.threatAndPpPsqtWeights[0];
|
||||||
|
|
||||||
while (tileOffset < Dimensions)
|
while (tileOffset < Dimensions)
|
||||||
{
|
{
|
||||||
@@ -373,18 +376,18 @@ void apply_combined(Color perspective,
|
|||||||
{
|
{
|
||||||
const IndexType offset = Dimensions * index;
|
const IndexType offset = Dimensions * index;
|
||||||
for (IndexType j = 0; j < Dimensions; ++j)
|
for (IndexType j = 0; j < Dimensions; ++j)
|
||||||
toAcc[j] -= featureTransformer.threatWeights[offset + j];
|
toAcc[j] -= featureTransformer.threatAndPpWeights[offset + j];
|
||||||
for (usize k = 0; k < PSQTBuckets; ++k)
|
for (usize k = 0; k < PSQTBuckets; ++k)
|
||||||
toPsqtAcc[k] -= featureTransformer.threatPsqtWeights[index * PSQTBuckets + k];
|
toPsqtAcc[k] -= featureTransformer.threatAndPpPsqtWeights[index * PSQTBuckets + k];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto index : thrAdded)
|
for (const auto index : thrAdded)
|
||||||
{
|
{
|
||||||
const IndexType offset = Dimensions * index;
|
const IndexType offset = Dimensions * index;
|
||||||
for (IndexType j = 0; j < Dimensions; ++j)
|
for (IndexType j = 0; j < Dimensions; ++j)
|
||||||
toAcc[j] += featureTransformer.threatWeights[offset + j];
|
toAcc[j] += featureTransformer.threatAndPpWeights[offset + j];
|
||||||
for (usize k = 0; k < PSQTBuckets; ++k)
|
for (usize k = 0; k < PSQTBuckets; ++k)
|
||||||
toPsqtAcc[k] += featureTransformer.threatPsqtWeights[index * PSQTBuckets + k];
|
toPsqtAcc[k] += featureTransformer.threatAndPpPsqtWeights[index * PSQTBuckets + k];
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -407,22 +410,28 @@ void update_accumulator_incremental(Color perspective,
|
|||||||
PSQFeatureSet::IndexList psqRemoved, psqAdded;
|
PSQFeatureSet::IndexList psqRemoved, psqAdded;
|
||||||
ThreatFeatureSet::IndexList thrRemoved, thrAdded;
|
ThreatFeatureSet::IndexList thrRemoved, thrAdded;
|
||||||
|
|
||||||
const auto& dirtyPiece = Forward ? target_state.dirtyPiece : computed.dirtyPiece;
|
const auto& dirtyPiece = Forward ? target_state.dirtyPiece : computed.dirtyPiece;
|
||||||
const auto& dirtyThreats = Forward ? target_state.dirtyThreats : computed.dirtyThreats;
|
const auto& dirtyThreats = Forward ? target_state.dirtyThreats : computed.dirtyThreats;
|
||||||
|
const auto& dirtyPawnPairs = Forward ? target_state.dirtyPawnPairs : computed.dirtyPawnPairs;
|
||||||
|
|
||||||
const auto* pfBase = &featureTransformer.threatWeights[0];
|
// Used solely for prefetching
|
||||||
IndexType pfStride = FeatureTransformer::OutputDimensions;
|
const auto* threatPpBase = &featureTransformer.threatAndPpWeights[0];
|
||||||
|
IndexType pfStride = FeatureTransformer::OutputDimensions;
|
||||||
|
|
||||||
if constexpr (Forward)
|
if constexpr (Forward)
|
||||||
{
|
{
|
||||||
ThreatFeatureSet::append_changed_indices(perspective, ksq, dirtyThreats, thrRemoved,
|
ThreatFeatureSet::append_changed_indices(perspective, ksq, dirtyThreats, thrRemoved,
|
||||||
thrAdded, pfBase, pfStride);
|
thrAdded, threatPpBase, pfStride);
|
||||||
|
PairFeatureSet::append_changed_indices(perspective, ksq, dirtyPawnPairs, thrRemoved,
|
||||||
|
thrAdded, threatPpBase, pfStride);
|
||||||
PSQFeatureSet::append_changed_indices(perspective, ksq, dirtyPiece, psqRemoved, psqAdded);
|
PSQFeatureSet::append_changed_indices(perspective, ksq, dirtyPiece, psqRemoved, psqAdded);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ThreatFeatureSet::append_changed_indices(perspective, ksq, dirtyThreats, thrAdded,
|
ThreatFeatureSet::append_changed_indices(perspective, ksq, dirtyThreats, thrAdded,
|
||||||
thrRemoved, pfBase, pfStride);
|
thrRemoved, threatPpBase, pfStride);
|
||||||
|
PairFeatureSet::append_changed_indices(perspective, ksq, dirtyPawnPairs, thrAdded,
|
||||||
|
thrRemoved, threatPpBase, pfStride);
|
||||||
PSQFeatureSet::append_changed_indices(perspective, ksq, dirtyPiece, psqAdded, psqRemoved);
|
PSQFeatureSet::append_changed_indices(perspective, ksq, dirtyPiece, psqAdded, psqRemoved);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -575,6 +584,7 @@ void update_accumulator_refresh_cache(Color perspective,
|
|||||||
|
|
||||||
ThreatFeatureSet::IndexList active;
|
ThreatFeatureSet::IndexList active;
|
||||||
ThreatFeatureSet::append_active_indices(perspective, pos, active);
|
ThreatFeatureSet::append_active_indices(perspective, pos, active);
|
||||||
|
PairFeatureSet::append_active_indices(perspective, pos, active);
|
||||||
|
|
||||||
accumulator.computed[perspective] = true;
|
accumulator.computed[perspective] = true;
|
||||||
|
|
||||||
@@ -582,8 +592,8 @@ void update_accumulator_refresh_cache(Color perspective,
|
|||||||
vec_t acc[Tiling::NumRegs];
|
vec_t acc[Tiling::NumRegs];
|
||||||
psqt_vec_t psqt[Tiling::NumPsqtRegs];
|
psqt_vec_t psqt[Tiling::NumPsqtRegs];
|
||||||
|
|
||||||
const auto* weights = &featureTransformer.weights[0];
|
const auto* weights = &featureTransformer.weights[0];
|
||||||
const auto* threatWeights = &featureTransformer.threatWeights[0];
|
const auto* threatAndPpWeights = &featureTransformer.threatAndPpWeights[0];
|
||||||
|
|
||||||
for (IndexType j = 0; j < Dimensions / Tiling::TileHeight; ++j)
|
for (IndexType j = 0; j < Dimensions / Tiling::TileHeight; ++j)
|
||||||
{
|
{
|
||||||
@@ -614,8 +624,8 @@ void update_accumulator_refresh_cache(Color perspective,
|
|||||||
|
|
||||||
for (int i = 0; i < active.ssize(); ++i)
|
for (int i = 0; i < active.ssize(); ++i)
|
||||||
{
|
{
|
||||||
auto* column =
|
auto* column = reinterpret_cast<const vec_i8_t*>(
|
||||||
reinterpret_cast<const vec_i8_t*>(&threatWeights[active[i] * Dimensions + tileOff]);
|
&threatAndPpWeights[active[i] * Dimensions + tileOff]);
|
||||||
|
|
||||||
#ifdef USE_NEON
|
#ifdef USE_NEON
|
||||||
for (IndexType k = 0; k < Tiling::NumRegs; k += 2)
|
for (IndexType k = 0; k < Tiling::NumRegs; k += 2)
|
||||||
@@ -664,7 +674,7 @@ void update_accumulator_refresh_cache(Color perspective,
|
|||||||
for (int i = 0; i < active.ssize(); ++i)
|
for (int i = 0; i < active.ssize(); ++i)
|
||||||
{
|
{
|
||||||
auto* columnPsqt = reinterpret_cast<const psqt_vec_t*>(
|
auto* columnPsqt = reinterpret_cast<const psqt_vec_t*>(
|
||||||
&featureTransformer.threatPsqtWeights[active[i] * PSQTBuckets + psqtTileOff]);
|
&featureTransformer.threatAndPpPsqtWeights[active[i] * PSQTBuckets + psqtTileOff]);
|
||||||
for (usize k = 0; k < Tiling::NumPsqtRegs; ++k)
|
for (usize k = 0; k < Tiling::NumPsqtRegs; ++k)
|
||||||
psqt[k] = vec_add_psqt_32(psqt[k], columnPsqt[k]);
|
psqt[k] = vec_add_psqt_32(psqt[k], columnPsqt[k]);
|
||||||
}
|
}
|
||||||
@@ -676,9 +686,9 @@ void update_accumulator_refresh_cache(Color perspective,
|
|||||||
#elif defined(USE_RVV)
|
#elif defined(USE_RVV)
|
||||||
|
|
||||||
const auto* weights = &featureTransformer.weights[0];
|
const auto* weights = &featureTransformer.weights[0];
|
||||||
const auto* threatWeights = &featureTransformer.threatWeights[0];
|
const auto* threatWeights = &featureTransformer.threatAndPpWeights[0];
|
||||||
const auto* psqtWeights = &featureTransformer.psqtWeights[0];
|
const auto* psqtWeights = &featureTransformer.psqtWeights[0];
|
||||||
const auto* threatPsqtWeights = &featureTransformer.threatPsqtWeights[0];
|
const auto* threatPsqtWeights = &featureTransformer.threatAndPpPsqtWeights[0];
|
||||||
|
|
||||||
usize tileOffset = 0;
|
usize tileOffset = 0;
|
||||||
|
|
||||||
@@ -763,11 +773,11 @@ void update_accumulator_refresh_cache(Color perspective,
|
|||||||
|
|
||||||
for (IndexType j = 0; j < Dimensions; ++j)
|
for (IndexType j = 0; j < Dimensions; ++j)
|
||||||
accumulator.accumulation[perspective][j] +=
|
accumulator.accumulation[perspective][j] +=
|
||||||
featureTransformer.threatWeights[offset + j];
|
featureTransformer.threatAndPpWeights[offset + j];
|
||||||
|
|
||||||
for (usize k = 0; k < PSQTBuckets; ++k)
|
for (usize k = 0; k < PSQTBuckets; ++k)
|
||||||
accumulator.psqtAccumulation[perspective][k] +=
|
accumulator.psqtAccumulation[perspective][k] +=
|
||||||
featureTransformer.threatPsqtWeights[index * PSQTBuckets + k];
|
featureTransformer.threatAndPpPsqtWeights[index * PSQTBuckets + k];
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "../types.h"
|
#include "../types.h"
|
||||||
#include "../misc.h"
|
#include "../misc.h"
|
||||||
@@ -90,10 +89,7 @@ struct AccumulatorCaches {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct AccumulatorState: public Accumulator {
|
struct AccumulatorState: public Accumulator, Dirties {};
|
||||||
DirtyPiece dirtyPiece;
|
|
||||||
DirtyThreats dirtyThreats;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AccumulatorStack {
|
class AccumulatorStack {
|
||||||
public:
|
public:
|
||||||
@@ -101,9 +97,9 @@ class AccumulatorStack {
|
|||||||
|
|
||||||
[[nodiscard]] const AccumulatorState& latest() const noexcept;
|
[[nodiscard]] const AccumulatorState& latest() const noexcept;
|
||||||
|
|
||||||
void reset() noexcept;
|
void reset() noexcept;
|
||||||
std::pair<DirtyPiece&, DirtyThreats&> push() noexcept;
|
Dirties& push() noexcept;
|
||||||
void pop() noexcept;
|
void pop() noexcept;
|
||||||
|
|
||||||
void evaluate(const Position& pos,
|
void evaluate(const Position& pos,
|
||||||
const FeatureTransformer& featureTransformer,
|
const FeatureTransformer& featureTransformer,
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include "features/half_ka_v2_hm.h"
|
#include "features/half_ka_v2_hm.h"
|
||||||
#include "features/full_threats.h"
|
#include "features/full_threats.h"
|
||||||
|
#include "features/pp_3wide.h"
|
||||||
#include "layers/affine_transform.h"
|
#include "layers/affine_transform.h"
|
||||||
#include "layers/affine_transform_sparse_input.h"
|
#include "layers/affine_transform_sparse_input.h"
|
||||||
#include "layers/clipped_relu.h"
|
#include "layers/clipped_relu.h"
|
||||||
@@ -37,6 +38,7 @@ namespace Stockfish::Eval::NNUE {
|
|||||||
|
|
||||||
// Input features used in evaluation function
|
// Input features used in evaluation function
|
||||||
using ThreatFeatureSet = Features::FullThreats;
|
using ThreatFeatureSet = Features::FullThreats;
|
||||||
|
using PairFeatureSet = Features::PP_3Wide;
|
||||||
using PSQFeatureSet = Features::HalfKAv2_hm;
|
using PSQFeatureSet = Features::HalfKAv2_hm;
|
||||||
|
|
||||||
// Number of input feature dimensions after conversion
|
// Number of input feature dimensions after conversion
|
||||||
|
|||||||
+28
-9
@@ -187,12 +187,9 @@ inline void write_little_endian(std::ostream& stream, const IntType* values, usi
|
|||||||
// Read N signed integers from the stream s, putting them in the array out.
|
// Read N signed integers from the stream s, putting them in the array out.
|
||||||
// The stream is assumed to be compressed using the signed LEB128 format.
|
// The stream is assumed to be compressed using the signed LEB128 format.
|
||||||
// See https://en.wikipedia.org/wiki/LEB128 for a description of the compression scheme.
|
// See https://en.wikipedia.org/wiki/LEB128 for a description of the compression scheme.
|
||||||
template<typename BufType, typename IntType, usize Count>
|
template<typename BufType, typename IntType>
|
||||||
inline void read_leb_128_detail(std::istream& stream,
|
inline void read_leb_128_detail(
|
||||||
std::array<IntType, Count>& out,
|
std::istream& stream, IntType* out, usize Count, u32& bytes_left, BufType& buf, u32& buf_pos) {
|
||||||
u32& bytes_left,
|
|
||||||
BufType& buf,
|
|
||||||
u32& buf_pos) {
|
|
||||||
|
|
||||||
static_assert(std::is_signed_v<IntType>, "Not implemented for unsigned types");
|
static_assert(std::is_signed_v<IntType>, "Not implemented for unsigned types");
|
||||||
static_assert(sizeof(IntType) <= 4, "Not implemented for types larger than 32 bit");
|
static_assert(sizeof(IntType) <= 4, "Not implemented for types larger than 32 bit");
|
||||||
@@ -233,7 +230,24 @@ inline void read_leb_128(std::istream& stream, Arrays&... outs) {
|
|||||||
std::array<u8, 8192> buf;
|
std::array<u8, 8192> buf;
|
||||||
u32 buf_pos = u32(buf.size());
|
u32 buf_pos = u32(buf.size());
|
||||||
|
|
||||||
(read_leb_128_detail(stream, outs, bytes_left, buf, buf_pos), ...);
|
(read_leb_128_detail(stream, outs.data(), outs.size(), bytes_left, buf, buf_pos), ...);
|
||||||
|
|
||||||
|
assert(bytes_left == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename IntType>
|
||||||
|
inline void read_leb_128(std::istream& stream, IntType* out, usize expected) {
|
||||||
|
// Check the presence of our LEB128 magic string
|
||||||
|
char leb128MagicString[Leb128MagicStringSize];
|
||||||
|
stream.read(leb128MagicString, Leb128MagicStringSize);
|
||||||
|
assert(strncmp(Leb128MagicString, leb128MagicString, Leb128MagicStringSize) == 0);
|
||||||
|
|
||||||
|
auto bytes_left = read_little_endian<u32>(stream);
|
||||||
|
std::array<u8, 8192> buf;
|
||||||
|
u32 buf_pos = u32(buf.size());
|
||||||
|
|
||||||
|
read_leb_128_detail(stream, out, expected, bytes_left, buf, buf_pos);
|
||||||
|
|
||||||
assert(bytes_left == 0);
|
assert(bytes_left == 0);
|
||||||
}
|
}
|
||||||
@@ -243,8 +257,8 @@ inline void read_leb_128(std::istream& stream, Arrays&... outs) {
|
|||||||
// This takes N integers from array values, compresses them with
|
// This takes N integers from array values, compresses them with
|
||||||
// the LEB128 algorithm and writes the result on the stream s.
|
// the LEB128 algorithm and writes the result on the stream s.
|
||||||
// See https://en.wikipedia.org/wiki/LEB128 for a description of the compression scheme.
|
// See https://en.wikipedia.org/wiki/LEB128 for a description of the compression scheme.
|
||||||
template<typename IntType, usize Count>
|
template<typename IntType>
|
||||||
inline void write_leb_128(std::ostream& stream, const std::array<IntType, Count>& values) {
|
inline void write_leb_128(std::ostream& stream, const IntType* values, usize Count) {
|
||||||
|
|
||||||
// Write our LEB128 magic string
|
// Write our LEB128 magic string
|
||||||
stream.write(Leb128MagicString, Leb128MagicStringSize);
|
stream.write(Leb128MagicString, Leb128MagicStringSize);
|
||||||
@@ -303,6 +317,11 @@ inline void write_leb_128(std::ostream& stream, const std::array<IntType, Count>
|
|||||||
flush();
|
flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename IntType, usize Count>
|
||||||
|
inline void write_leb_128(std::ostream& stream, const std::array<IntType, Count>& values) {
|
||||||
|
write_leb_128(stream, values.data(), Count);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Stockfish::Eval::NNUE
|
} // namespace Stockfish::Eval::NNUE
|
||||||
|
|
||||||
#endif // #ifndef NNUE_COMMON_H_INCLUDED
|
#endif // #ifndef NNUE_COMMON_H_INCLUDED
|
||||||
|
|||||||
@@ -87,7 +87,9 @@ class FeatureTransformer {
|
|||||||
|
|
||||||
// Number of input/output dimensions
|
// Number of input/output dimensions
|
||||||
static constexpr IndexType ThreatInputDimensions = ThreatFeatureSet::Dimensions;
|
static constexpr IndexType ThreatInputDimensions = ThreatFeatureSet::Dimensions;
|
||||||
static constexpr IndexType InputDimensions = PSQFeatureSet::Dimensions + ThreatInputDimensions;
|
static constexpr IndexType PairInputDimensions = PairFeatureSet::Dimensions;
|
||||||
|
static constexpr IndexType InputDimensions =
|
||||||
|
PSQFeatureSet::Dimensions + ThreatInputDimensions + PairInputDimensions;
|
||||||
static constexpr IndexType OutputDimensions = HalfDimensions;
|
static constexpr IndexType OutputDimensions = HalfDimensions;
|
||||||
|
|
||||||
// Size of forward propagation buffer
|
// Size of forward propagation buffer
|
||||||
@@ -128,7 +130,8 @@ class FeatureTransformer {
|
|||||||
|
|
||||||
// Hash value embedded in the evaluation file
|
// Hash value embedded in the evaluation file
|
||||||
static constexpr u32 get_hash_value() {
|
static constexpr u32 get_hash_value() {
|
||||||
return combine_hash({ThreatFeatureSet::HashValue, PSQFeatureSet::HashValue})
|
return combine_hash(
|
||||||
|
{ThreatFeatureSet::HashValue, PairFeatureSet::HashValue, PSQFeatureSet::HashValue})
|
||||||
^ (OutputDimensions * 2);
|
^ (OutputDimensions * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,22 +139,42 @@ class FeatureTransformer {
|
|||||||
permute<16>(biases, PackusEpi16Order);
|
permute<16>(biases, PackusEpi16Order);
|
||||||
permute<16>(weights, PackusEpi16Order);
|
permute<16>(weights, PackusEpi16Order);
|
||||||
|
|
||||||
permute<8>(threatWeights, PackusEpi16Order);
|
permute<8>(threatAndPpWeights, PackusEpi16Order);
|
||||||
}
|
}
|
||||||
|
|
||||||
void unpermute_weights() {
|
void unpermute_weights() {
|
||||||
permute<16>(biases, InversePackusEpi16Order);
|
permute<16>(biases, InversePackusEpi16Order);
|
||||||
permute<16>(weights, InversePackusEpi16Order);
|
permute<16>(weights, InversePackusEpi16Order);
|
||||||
permute<8>(threatWeights, InversePackusEpi16Order);
|
permute<8>(threatAndPpWeights, InversePackusEpi16Order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto threatWeights() { return threatAndPpWeights.data(); }
|
||||||
|
auto threatWeights() const { return threatAndPpWeights.data(); }
|
||||||
|
auto ppWeights() { return &threatAndPpWeights[ThreatFeatureSet::Dimensions * HalfDimensions]; }
|
||||||
|
auto ppWeights() const {
|
||||||
|
return &threatAndPpWeights[ThreatFeatureSet::Dimensions * HalfDimensions];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto threatPsqtWeights() { return threatAndPpPsqtWeights.data(); }
|
||||||
|
auto threatPsqtWeights() const { return threatAndPpPsqtWeights.data(); }
|
||||||
|
auto ppPsqtWeights() {
|
||||||
|
return &threatAndPpPsqtWeights[ThreatFeatureSet::Dimensions * PSQTBuckets];
|
||||||
|
}
|
||||||
|
auto ppPsqtWeights() const {
|
||||||
|
return &threatAndPpPsqtWeights[ThreatFeatureSet::Dimensions * PSQTBuckets];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Read network parameters
|
// Read network parameters
|
||||||
bool read_parameters(std::istream& stream) {
|
bool read_parameters(std::istream& stream) {
|
||||||
read_leb_128(stream, biases);
|
read_leb_128(stream, biases);
|
||||||
|
|
||||||
read_little_endian<ThreatWeightType>(stream, threatWeights.data(),
|
read_little_endian<ThreatWeightType>(stream, threatWeights(),
|
||||||
ThreatInputDimensions * HalfDimensions);
|
ThreatInputDimensions * HalfDimensions);
|
||||||
read_leb_128(stream, threatPsqtWeights);
|
read_leb_128(stream, threatPsqtWeights(), ThreatFeatureSet::Dimensions * PSQTBuckets);
|
||||||
|
read_little_endian<ThreatWeightType>(stream, ppWeights(),
|
||||||
|
PairInputDimensions * HalfDimensions);
|
||||||
|
read_leb_128(stream, ppPsqtWeights(), PairFeatureSet::Dimensions * PSQTBuckets);
|
||||||
|
|
||||||
read_leb_128(stream, weights);
|
read_leb_128(stream, weights);
|
||||||
read_leb_128(stream, psqtWeights);
|
read_leb_128(stream, psqtWeights);
|
||||||
@@ -170,9 +193,14 @@ class FeatureTransformer {
|
|||||||
write_leb_128<BiasType>(stream, copy->biases);
|
write_leb_128<BiasType>(stream, copy->biases);
|
||||||
|
|
||||||
|
|
||||||
write_little_endian<ThreatWeightType>(stream, copy->threatWeights.data(),
|
write_little_endian<ThreatWeightType>(stream, copy->threatWeights(),
|
||||||
ThreatInputDimensions * HalfDimensions);
|
ThreatInputDimensions * HalfDimensions);
|
||||||
write_leb_128<PSQTWeightType>(stream, copy->threatPsqtWeights);
|
write_leb_128<PSQTWeightType>(stream, copy->threatPsqtWeights(),
|
||||||
|
ThreatFeatureSet::Dimensions * PSQTBuckets);
|
||||||
|
write_little_endian<ThreatWeightType>(stream, copy->ppWeights(),
|
||||||
|
PairInputDimensions * HalfDimensions);
|
||||||
|
write_leb_128<PSQTWeightType>(stream, copy->ppPsqtWeights(),
|
||||||
|
PairFeatureSet::Dimensions * PSQTBuckets);
|
||||||
|
|
||||||
write_leb_128<WeightType>(stream, copy->weights);
|
write_leb_128<WeightType>(stream, copy->weights);
|
||||||
write_leb_128<PSQTWeightType>(stream, copy->psqtWeights);
|
write_leb_128<PSQTWeightType>(stream, copy->psqtWeights);
|
||||||
@@ -187,8 +215,8 @@ class FeatureTransformer {
|
|||||||
hash_combine(h, get_raw_data_hash(weights));
|
hash_combine(h, get_raw_data_hash(weights));
|
||||||
hash_combine(h, get_raw_data_hash(psqtWeights));
|
hash_combine(h, get_raw_data_hash(psqtWeights));
|
||||||
|
|
||||||
hash_combine(h, get_raw_data_hash(threatWeights));
|
hash_combine(h, get_raw_data_hash(threatAndPpWeights));
|
||||||
hash_combine(h, get_raw_data_hash(threatPsqtWeights));
|
hash_combine(h, get_raw_data_hash(threatAndPpPsqtWeights));
|
||||||
|
|
||||||
hash_combine(h, get_hash_value());
|
hash_combine(h, get_hash_value());
|
||||||
|
|
||||||
@@ -399,12 +427,20 @@ class FeatureTransformer {
|
|||||||
alignas(CacheLineSize) std::array<BiasType, HalfDimensions> biases;
|
alignas(CacheLineSize) std::array<BiasType, HalfDimensions> biases;
|
||||||
alignas(
|
alignas(
|
||||||
CacheLineSize) std::array<WeightType, HalfDimensions * PSQFeatureSet::Dimensions> weights;
|
CacheLineSize) std::array<WeightType, HalfDimensions * PSQFeatureSet::Dimensions> weights;
|
||||||
|
|
||||||
|
// Threats and pawn-pair features are concatenated into one array to allow for a single index to address either.
|
||||||
|
// The first pawn-pair feature is at index ThreatFeatureSet::Dimensions.
|
||||||
|
static_assert(PairFeatureSet::IndexBase == ThreatFeatureSet::Dimensions);
|
||||||
|
|
||||||
|
alignas(CacheLineSize) std::array<ThreatWeightType,
|
||||||
|
(ThreatFeatureSet::Dimensions + PairFeatureSet::Dimensions)
|
||||||
|
* HalfDimensions> threatAndPpWeights;
|
||||||
alignas(CacheLineSize)
|
alignas(CacheLineSize)
|
||||||
std::array<ThreatWeightType, HalfDimensions * ThreatFeatureSet::Dimensions> threatWeights;
|
std::array<PSQTWeightType, PSQTBuckets * PSQFeatureSet::Dimensions> psqtWeights;
|
||||||
alignas(CacheLineSize)
|
// As above
|
||||||
std::array<PSQTWeightType, PSQFeatureSet::Dimensions * PSQTBuckets> psqtWeights;
|
alignas(CacheLineSize) std::array<PSQTWeightType,
|
||||||
alignas(CacheLineSize)
|
(ThreatFeatureSet::Dimensions + PairFeatureSet::Dimensions)
|
||||||
std::array<PSQTWeightType, ThreatFeatureSet::Dimensions * PSQTBuckets> threatPsqtWeights;
|
* PSQTBuckets> threatAndPpPsqtWeights;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Stockfish::Eval::NNUE
|
} // namespace Stockfish::Eval::NNUE
|
||||||
|
|||||||
+32
-37
@@ -469,12 +469,13 @@ void Position::set_check_info() const {
|
|||||||
update_slider_blockers(WHITE);
|
update_slider_blockers(WHITE);
|
||||||
update_slider_blockers(BLACK);
|
update_slider_blockers(BLACK);
|
||||||
|
|
||||||
Square ksq = square<KING>(~sideToMove);
|
Square ksq = square<KING>(~sideToMove);
|
||||||
|
const auto [bishopAttacks, rookAttacks] = both_attacks_bb(ksq, pieces());
|
||||||
|
|
||||||
st->checkSquares[PAWN] = attacks_bb<PAWN>(ksq, ~sideToMove);
|
st->checkSquares[PAWN] = attacks_bb<PAWN>(ksq, ~sideToMove);
|
||||||
st->checkSquares[KNIGHT] = attacks_bb<KNIGHT>(ksq);
|
st->checkSquares[KNIGHT] = attacks_bb<KNIGHT>(ksq);
|
||||||
st->checkSquares[BISHOP] = attacks_bb<BISHOP>(ksq, pieces());
|
st->checkSquares[BISHOP] = bishopAttacks;
|
||||||
st->checkSquares[ROOK] = attacks_bb<ROOK>(ksq, pieces());
|
st->checkSquares[ROOK] = rookAttacks;
|
||||||
st->checkSquares[QUEEN] = st->checkSquares[BISHOP] | st->checkSquares[ROOK];
|
st->checkSquares[QUEEN] = st->checkSquares[BISHOP] | st->checkSquares[ROOK];
|
||||||
st->checkSquares[KING] = 0;
|
st->checkSquares[KING] = 0;
|
||||||
}
|
}
|
||||||
@@ -641,8 +642,9 @@ void Position::update_slider_blockers(Color c) const {
|
|||||||
// Slider attacks use the occupied bitboard to indicate occupancy.
|
// Slider attacks use the occupied bitboard to indicate occupancy.
|
||||||
Bitboard Position::attackers_to(Square s, Bitboard occupied) const {
|
Bitboard Position::attackers_to(Square s, Bitboard occupied) const {
|
||||||
|
|
||||||
return (attacks_bb<ROOK>(s, occupied) & pieces(ROOK, QUEEN))
|
const auto [bishopAttacks, rookAttacks] = both_attacks_bb(s, occupied);
|
||||||
| (attacks_bb<BISHOP>(s, occupied) & pieces(BISHOP, QUEEN))
|
|
||||||
|
return (rookAttacks & pieces(ROOK, QUEEN)) | (bishopAttacks & pieces(BISHOP, QUEEN))
|
||||||
| (attacks_bb<PAWN>(s, BLACK) & pieces(WHITE, PAWN))
|
| (attacks_bb<PAWN>(s, BLACK) & pieces(WHITE, PAWN))
|
||||||
| (attacks_bb<PAWN>(s, WHITE) & pieces(BLACK, PAWN))
|
| (attacks_bb<PAWN>(s, WHITE) & pieces(BLACK, PAWN))
|
||||||
| (attacks_bb<KNIGHT>(s) & pieces(KNIGHT)) | (attacks_bb<KING>(s) & pieces(KING));
|
| (attacks_bb<KNIGHT>(s) & pieces(KNIGHT)) | (attacks_bb<KING>(s) & pieces(KING));
|
||||||
@@ -789,12 +791,12 @@ bool Position::gives_check(Move m) const {
|
|||||||
// checks and ordinary discovered check, so the only case we need to handle
|
// checks and ordinary discovered check, so the only case we need to handle
|
||||||
// is the unusual case of a discovered check through the captured pawn.
|
// is the unusual case of a discovered check through the captured pawn.
|
||||||
case EN_PASSANT : {
|
case EN_PASSANT : {
|
||||||
Square capsq = make_square(file_of(to), rank_of(from));
|
Square capsq = make_square(file_of(to), rank_of(from));
|
||||||
Bitboard b = (pieces() ^ from ^ capsq) | to;
|
Bitboard b = (pieces() ^ from ^ capsq) | to;
|
||||||
|
const auto [bishopAttacks, rookAttacks] = both_attacks_bb(square<KING>(~sideToMove), b);
|
||||||
|
|
||||||
return (attacks_bb<ROOK>(square<KING>(~sideToMove), b) & pieces(sideToMove, QUEEN, ROOK))
|
return (rookAttacks & pieces(sideToMove, QUEEN, ROOK))
|
||||||
| (attacks_bb<BISHOP>(square<KING>(~sideToMove), b)
|
| (bishopAttacks & pieces(sideToMove, QUEEN, BISHOP));
|
||||||
& pieces(sideToMove, QUEEN, BISHOP));
|
|
||||||
}
|
}
|
||||||
default : //CASTLING
|
default : //CASTLING
|
||||||
{
|
{
|
||||||
@@ -815,8 +817,7 @@ bool Position::gives_check(Move m) const {
|
|||||||
void Position::do_move(Move m,
|
void Position::do_move(Move m,
|
||||||
StateInfo& newSt,
|
StateInfo& newSt,
|
||||||
bool givesCheck,
|
bool givesCheck,
|
||||||
DirtyPiece& dp,
|
Dirties& dirties,
|
||||||
DirtyThreats& dts,
|
|
||||||
const TranspositionTable* tt = nullptr,
|
const TranspositionTable* tt = nullptr,
|
||||||
const SharedHistories* history = nullptr) {
|
const SharedHistories* history = nullptr) {
|
||||||
|
|
||||||
@@ -838,6 +839,13 @@ void Position::do_move(Move m,
|
|||||||
++st->rule50;
|
++st->rule50;
|
||||||
++st->pliesFromNull;
|
++st->pliesFromNull;
|
||||||
|
|
||||||
|
auto& dpps = dirties.dirtyPawnPairs;
|
||||||
|
auto& dts = dirties.dirtyThreats;
|
||||||
|
auto& dp = dirties.dirtyPiece;
|
||||||
|
|
||||||
|
dpps.before[WHITE] = pieces(WHITE, PAWN);
|
||||||
|
dpps.before[BLACK] = pieces(BLACK, PAWN);
|
||||||
|
|
||||||
Color us = sideToMove;
|
Color us = sideToMove;
|
||||||
Color them = ~us;
|
Color them = ~us;
|
||||||
Square from = m.from_sq();
|
Square from = m.from_sq();
|
||||||
@@ -1063,6 +1071,9 @@ void Position::do_move(Move m,
|
|||||||
|
|
||||||
assert(pos_is_ok());
|
assert(pos_is_ok());
|
||||||
|
|
||||||
|
dpps.after[WHITE] = pieces(WHITE, PAWN);
|
||||||
|
dpps.after[BLACK] = pieces(BLACK, PAWN);
|
||||||
|
|
||||||
assert(dp.pc != NO_PIECE);
|
assert(dp.pc != NO_PIECE);
|
||||||
assert(!(bool(captured) || m.type_of() == CASTLING) ^ (dp.remove_sq != SQ_NONE));
|
assert(!(bool(captured) || m.type_of() == CASTLING) ^ (dp.remove_sq != SQ_NONE));
|
||||||
assert(dp.from != SQ_NONE);
|
assert(dp.from != SQ_NONE);
|
||||||
@@ -1189,8 +1200,9 @@ void Position::update_piece_threats(Piece pc,
|
|||||||
const Bitboard occupied = pieces();
|
const Bitboard occupied = pieces();
|
||||||
const Bitboard rookQueens = pieces(ROOK, QUEEN);
|
const Bitboard rookQueens = pieces(ROOK, QUEEN);
|
||||||
const Bitboard bishopQueens = pieces(BISHOP, QUEEN);
|
const Bitboard bishopQueens = pieces(BISHOP, QUEEN);
|
||||||
const Bitboard rAttacks = attacks_bb<ROOK>(s, occupied);
|
const auto attacks = both_attacks_bb(s, occupied);
|
||||||
const Bitboard bAttacks = attacks_bb<BISHOP>(s, occupied);
|
const Bitboard bAttacks = attacks.first;
|
||||||
|
const Bitboard rAttacks = attacks.second;
|
||||||
const Bitboard occupiedNoK = occupied ^ pieces(KING);
|
const Bitboard occupiedNoK = occupied ^ pieces(KING);
|
||||||
|
|
||||||
Bitboard sliders = (rookQueens & rAttacks) | (bishopQueens & bAttacks);
|
Bitboard sliders = (rookQueens & rAttacks) | (bishopQueens & bAttacks);
|
||||||
@@ -1235,32 +1247,14 @@ void Position::update_piece_threats(Piece pc,
|
|||||||
Bitboard threatened = attacks_bb(pc, s, occupied) & occupiedNoK;
|
Bitboard threatened = attacks_bb(pc, s, occupied) & occupiedNoK;
|
||||||
Bitboard incoming_threats = PseudoAttacks[KNIGHT][s] & knights;
|
Bitboard incoming_threats = PseudoAttacks[KNIGHT][s] & knights;
|
||||||
|
|
||||||
// Compute both incoming and outgoing pawn threats. Incoming pawn pushers are only
|
if (type_of(pc) == KNIGHT || type_of(pc) == ROOK)
|
||||||
// added if 'pc' is a pawn.
|
incoming_threats |=
|
||||||
Bitboard pawnThreats = 0;
|
|
||||||
if (type_of(pc) == PAWN)
|
|
||||||
{
|
|
||||||
Bitboard whiteAttacks = PawnPushOrAttacks[WHITE][s];
|
|
||||||
Bitboard blackAttacks = PawnPushOrAttacks[BLACK][s];
|
|
||||||
|
|
||||||
threatened |= (color_of(pc) == WHITE ? whiteAttacks : blackAttacks) & pieces(PAWN);
|
|
||||||
|
|
||||||
pawnThreats = whiteAttacks & blackPawns;
|
|
||||||
pawnThreats |= blackAttacks & whitePawns;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pawnThreats =
|
|
||||||
(attacks_bb<PAWN>(s, WHITE) & blackPawns) | (attacks_bb<PAWN>(s, BLACK) & whitePawns);
|
(attacks_bb<PAWN>(s, WHITE) & blackPawns) | (attacks_bb<PAWN>(s, BLACK) & whitePawns);
|
||||||
}
|
|
||||||
|
|
||||||
if (type_of(pc) == PAWN || type_of(pc) == KNIGHT || type_of(pc) == ROOK)
|
|
||||||
incoming_threats |= pawnThreats;
|
|
||||||
|
|
||||||
switch (type_of(pc))
|
switch (type_of(pc))
|
||||||
{
|
{
|
||||||
case PAWN :
|
case PAWN :
|
||||||
threatened &= pieces(PAWN, KNIGHT, ROOK);
|
threatened &= pieces(KNIGHT, ROOK);
|
||||||
break;
|
break;
|
||||||
case BISHOP :
|
case BISHOP :
|
||||||
case ROOK :
|
case ROOK :
|
||||||
@@ -1508,8 +1502,9 @@ bool Position::see_ge(Move m, int threshold) const {
|
|||||||
assert(swap >= res);
|
assert(swap >= res);
|
||||||
occupied ^= least_significant_square_bb(bb);
|
occupied ^= least_significant_square_bb(bb);
|
||||||
|
|
||||||
attackers |= (attacks_bb<BISHOP>(to, occupied) & pieces(BISHOP, QUEEN))
|
const auto [bishopAttacks, rookAttacks] = both_attacks_bb(to, occupied);
|
||||||
| (attacks_bb<ROOK>(to, occupied) & pieces(ROOK, QUEEN));
|
attackers |=
|
||||||
|
(bishopAttacks & pieces(BISHOP, QUEEN)) | (rookAttacks & pieces(ROOK, QUEEN));
|
||||||
}
|
}
|
||||||
|
|
||||||
else // KING
|
else // KING
|
||||||
|
|||||||
+13
-14
@@ -147,8 +147,7 @@ class Position {
|
|||||||
void do_move(Move m,
|
void do_move(Move m,
|
||||||
StateInfo& newSt,
|
StateInfo& newSt,
|
||||||
bool givesCheck,
|
bool givesCheck,
|
||||||
DirtyPiece& dp,
|
Dirties& dirties,
|
||||||
DirtyThreats& dts,
|
|
||||||
const TranspositionTable* tt,
|
const TranspositionTable* tt,
|
||||||
const SharedHistories* worker);
|
const SharedHistories* worker);
|
||||||
void undo_move(Move m);
|
void undo_move(Move m);
|
||||||
@@ -221,16 +220,15 @@ class Position {
|
|||||||
std::array<Bitboard, PIECE_TYPE_NB> byTypeBB;
|
std::array<Bitboard, PIECE_TYPE_NB> byTypeBB;
|
||||||
std::array<Bitboard, COLOR_NB> byColorBB;
|
std::array<Bitboard, COLOR_NB> byColorBB;
|
||||||
|
|
||||||
int pieceCount[PIECE_NB];
|
int pieceCount[PIECE_NB];
|
||||||
int castlingRightsMask[SQUARE_NB];
|
int castlingRightsMask[SQUARE_NB];
|
||||||
Square castlingRookSquare[CASTLING_RIGHT_NB];
|
Square castlingRookSquare[CASTLING_RIGHT_NB];
|
||||||
Bitboard castlingPath[CASTLING_RIGHT_NB];
|
Bitboard castlingPath[CASTLING_RIGHT_NB];
|
||||||
StateInfo* st;
|
StateInfo* st;
|
||||||
int gamePly;
|
int gamePly;
|
||||||
Color sideToMove;
|
Color sideToMove;
|
||||||
bool chess960;
|
bool chess960;
|
||||||
DirtyPiece scratch_dp;
|
Dirties scratchDirties;
|
||||||
DirtyThreats scratch_dts;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const Position& pos);
|
std::ostream& operator<<(std::ostream& os, const Position& pos);
|
||||||
@@ -437,8 +435,9 @@ inline void Position::swap_piece(Square s, Piece pc, DirtyThreats* const dts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void Position::do_move(Move m, StateInfo& newSt, const TranspositionTable* tt = nullptr) {
|
inline void Position::do_move(Move m, StateInfo& newSt, const TranspositionTable* tt = nullptr) {
|
||||||
new (&scratch_dts) DirtyThreats;
|
new (&scratchDirties.dirtyThreats) DirtyThreats;
|
||||||
do_move(m, newSt, gives_check(m), scratch_dp, scratch_dts, tt, nullptr);
|
new (&scratchDirties.dirtyPawnPairs) DirtyPawnPairs;
|
||||||
|
do_move(m, newSt, gives_check(m), scratchDirties, tt, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline StateInfo* Position::state() const { return st; }
|
inline StateInfo* Position::state() const { return st; }
|
||||||
|
|||||||
+4
-3
@@ -644,12 +644,13 @@ void Search::Worker::do_move(
|
|||||||
bool capture = pos.capture_stage(move);
|
bool capture = pos.capture_stage(move);
|
||||||
++nodes;
|
++nodes;
|
||||||
|
|
||||||
auto [dirtyPiece, dirtyThreats] = accumulatorStack.push();
|
Dirties& dirties = accumulatorStack.push();
|
||||||
pos.do_move(move, st, givesCheck, dirtyPiece, dirtyThreats, &tt, &sharedHistory);
|
pos.do_move(move, st, givesCheck, dirties, &tt, &sharedHistory);
|
||||||
|
|
||||||
if (ss != nullptr)
|
if (ss != nullptr)
|
||||||
{
|
{
|
||||||
ss->currentMove = move;
|
auto& dirtyPiece = dirties.dirtyPiece;
|
||||||
|
ss->currentMove = move;
|
||||||
ss->continuationHistory =
|
ss->continuationHistory =
|
||||||
&continuationHistory[ss->inCheck][capture][dirtyPiece.pc][move.to_sq()];
|
&continuationHistory[ss->inCheck][capture][dirtyPiece.pc][move.to_sq()];
|
||||||
ss->continuationCorrectionHistory =
|
ss->continuationCorrectionHistory =
|
||||||
|
|||||||
+1
-1
@@ -31,7 +31,7 @@
|
|||||||
#include "numa.h"
|
#include "numa.h"
|
||||||
#include "position.h"
|
#include "position.h"
|
||||||
#include "search.h"
|
#include "search.h"
|
||||||
#include "thread_win32_osx.h"
|
#include "thread_native.h"
|
||||||
|
|
||||||
namespace Stockfish {
|
namespace Stockfish {
|
||||||
|
|
||||||
|
|||||||
@@ -16,10 +16,29 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef THREAD_WIN32_OSX_H_INCLUDED
|
#ifndef THREAD_NATIVE_H_INCLUDED
|
||||||
#define THREAD_WIN32_OSX_H_INCLUDED
|
#define THREAD_NATIVE_H_INCLUDED
|
||||||
|
|
||||||
#include <thread>
|
#ifdef _MSC_VER
|
||||||
|
#include <thread>
|
||||||
|
#else
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <functional>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "misc.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Stockfish {
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
// MSVC-compatible toolchains use std::thread because they do not provide
|
||||||
|
// pthreads by default. On all other platforms, pthreads is required and used.
|
||||||
|
|
||||||
|
using NativeThread = std::thread;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
// On OSX threads other than the main thread are created with a reduced stack
|
// On OSX threads other than the main thread are created with a reduced stack
|
||||||
// size of 512KB by default, this is too low for deep searches, which require
|
// size of 512KB by default, this is too low for deep searches, which require
|
||||||
@@ -27,13 +46,6 @@
|
|||||||
// The implementation calls pthread_create() with the stack size parameter
|
// The implementation calls pthread_create() with the stack size parameter
|
||||||
// equal to the Linux 8MB default, on platforms that support it.
|
// equal to the Linux 8MB default, on platforms that support it.
|
||||||
|
|
||||||
#if defined(__APPLE__) || defined(__MINGW32__) || defined(__MINGW64__) || defined(USE_PTHREADS)
|
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
namespace Stockfish {
|
|
||||||
|
|
||||||
class NativeThread {
|
class NativeThread {
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
|
|
||||||
@@ -63,16 +75,8 @@ class NativeThread {
|
|||||||
void join() { pthread_join(thread, nullptr); }
|
void join() { pthread_join(thread, nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Stockfish
|
#endif // _MSC_VER
|
||||||
|
|
||||||
#else // Default case: use STL classes
|
|
||||||
|
|
||||||
namespace Stockfish {
|
|
||||||
|
|
||||||
using NativeThread = std::thread;
|
|
||||||
|
|
||||||
} // namespace Stockfish
|
} // namespace Stockfish
|
||||||
|
|
||||||
#endif
|
#endif // #ifndef THREAD_NATIVE_H_INCLUDED
|
||||||
|
|
||||||
#endif // #ifndef THREAD_WIN32_OSX_H_INCLUDED
|
|
||||||
+11
@@ -344,6 +344,17 @@ struct DirtyThreats {
|
|||||||
DirtyThreatList list;
|
DirtyThreatList list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DirtyPawnPairs {
|
||||||
|
Bitboard before[COLOR_NB];
|
||||||
|
Bitboard after[COLOR_NB];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Dirties {
|
||||||
|
DirtyPiece dirtyPiece;
|
||||||
|
DirtyThreats dirtyThreats;
|
||||||
|
DirtyPawnPairs dirtyPawnPairs;
|
||||||
|
};
|
||||||
|
|
||||||
#define ENABLE_INCR_OPERATORS_ON(T) \
|
#define ENABLE_INCR_OPERATORS_ON(T) \
|
||||||
constexpr T& operator++(T& d) { return d = T(int(d) + 1); } \
|
constexpr T& operator++(T& d) { return d = T(int(d) + 1); } \
|
||||||
constexpr T& operator--(T& d) { return d = T(int(d) - 1); }
|
constexpr T& operator--(T& d) { return d = T(int(d) - 1); }
|
||||||
|
|||||||
Reference in New Issue
Block a user