mirror of
https://github.com/official-stockfish/Stockfish.git
synced 2026-07-22 12:47:08 +00:00
Update nnue architecture to SFNNv16 and net nn-89cb98a217f7.nnue
Failed STC (https://tests.stockfishchess.org/tests/view/6a4f36355529b8472df7ff7e): LLR: -2.94 (-2.94,2.94) <0.00,2.00> Total: 144768 W: 38003 L: 38051 D: 68714 Ptnml(0-2): 521, 17154, 37050, 17170, 489 Passed LTC (https://tests.stockfishchess.org/tests/view/6a501dad5529b8472df80103): LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 189888 W: 49613 L: 48984 D: 91291 Ptnml(0-2): 122, 20406, 53256, 21041, 119 Passed VLTC (https://tests.stockfishchess.org/tests/view/6a52892c5529b8472df80481): LLR: 2.94 (-2.94,2.94) <0.00,2.00> Total: 46124 W: 12156 L: 11865 D: 22103 Ptnml(0-2): 12, 4523, 13696, 4824, 7 Passed VVLTC (https://tests.stockfishchess.org/tests/view/6a566a285529b8472df80b84): LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 44698 W: 11805 L: 11507 D: 21386 Ptnml(0-2): 9, 3819, 14395, 4117, 9 This PR adds pawn pair features, a new set of features that is indexed by pairs of pawns occupying the same or adjacent files (hence "3-wide"). Because these are a superset of pawn–pawn interactions in threat inputs (including the recently added pawn-pusher inputs), those are removed. HalfKA features remain unchanged. Pawn-pair features were invented by Jonathan for Pawnocchio, based on his observation that in a net trained on *all* pairs of pawns, the most important pawn pairs were those differing by at most one file. sscg13 made the necessary changes to the trainer (https://github.com/official-stockfish/nnue-pytorch/pull/502) and initial changes to inference. The slowdown was originally far too large (some 10%); following major optimizations from Jonathan and a bit from me, the slowdown is small enough for a comfortable LTC pass; on my machine I get a 3.5% slowdown overall. I expect there are further "easy" speedups in the new code, so this gap should narrow a bit. Nettest PR: https://github.com/vondele/nettest/pull/359 closes https://github.com/official-stockfish/Stockfish/pull/6982 Bench: 2718396 Co-Authored-By: anematode <timothy.herchen@gmail.com> Co-Authored-By: Jonathan Hallström <lmj.hallstrom@gmail.com>
This commit is contained in:
committed by
Joost VandeVondele
co-authored by
anematode
Jonathan Hallström
parent
4d75fd4f70
commit
f4bcd40409
+2
-2
@@ -80,14 +80,14 @@ 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_native.h timeman.h \
|
nnue/nnz_helper.h position.h search.h syzygy/tbprobe.h thread.h thread_native.h timeman.h \
|
||||||
|
|||||||
+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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
+14
-23
@@ -817,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) {
|
||||||
|
|
||||||
@@ -840,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();
|
||||||
@@ -1065,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);
|
||||||
@@ -1238,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 :
|
||||||
|
|||||||
+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 =
|
||||||
|
|||||||
+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