diff --git a/src/nnue/features/full_threats.cpp b/src/nnue/features/full_threats.cpp index 6fc6b00ec..994d2160c 100644 --- a/src/nnue/features/full_threats.cpp +++ b/src/nnue/features/full_threats.cpp @@ -58,6 +58,35 @@ constexpr std::array AllPieces = { PiecePairData index_lut1[PIECE_NB][PIECE_NB]; // [attacker][attacked] uint8_t index_lut2[PIECE_NB][SQUARE_NB][SQUARE_NB]; // [attacker][from][to] +namespace { + +template +IndexType make_index_with_orientation( + Piece attacker, Square from, Square to, Piece attacked, int orientation) { + from = Square(int(from) ^ orientation); + to = Square(int(to) ^ orientation); + + if constexpr (Perspective == BLACK) + { + attacker = ~attacker; + attacked = ~attacked; + } + + const auto piecePairData = index_lut1[attacker][attacked]; + + const bool less_than = static_cast(from) < static_cast(to); + if ((piecePairData.excluded_pair_info() + less_than) & 2) + return FullThreats::Dimensions; + + const IndexType index = + piecePairData.feature_index_base() + offsets[attacker][from] + index_lut2[attacker][from][to]; + + sf_assume(index != FullThreats::Dimensions); + return index; +} + +} // namespace + static void init_index_luts() { for (Piece attacker : AllPieces) { @@ -129,32 +158,8 @@ void init_threat_offsets() { template IndexType FullThreats::make_index(Piece attacker, Square from, Square to, Piece attacked, Square ksq) { - from = (Square) (int(from) ^ OrientTBL[Perspective][ksq]); - to = (Square) (int(to) ^ OrientTBL[Perspective][ksq]); - - if (Perspective == BLACK) - { - attacker = ~attacker; - attacked = ~attacked; - } - - auto piecePairData = index_lut1[attacker][attacked]; - - // Some threats imply the existence of the corresponding ones in the opposite - // direction. We filter them here to ensure only one such threat is active. - - // In the below addition, the 2nd lsb gets set iff either the pair is always excluded, - // or the pair is semi-excluded and from < to. By using an unsigned compare, the following - // sequence can use an add-with-carry instruction. - bool less_than = static_cast(from) < static_cast(to); - if ((piecePairData.excluded_pair_info() + less_than) & 2) - return Dimensions; - - IndexType index = - piecePairData.feature_index_base() + offsets[attacker][from] + index_lut2[attacker][from][to]; - - sf_assume(index != Dimensions); - return index; + return make_index_with_orientation(attacker, from, to, attacked, + OrientTBL[Perspective][ksq]); } // Get a list of indices for active features in ascending order @@ -162,8 +167,9 @@ template void FullThreats::append_active_indices(const Position& pos, IndexList& active) { static constexpr Color order[2][2] = {{WHITE, BLACK}, {BLACK, WHITE}}; - Square ksq = pos.square(Perspective); - Bitboard occupied = pos.pieces(); + Square ksq = pos.square(Perspective); + const int orientation = OrientTBL[Perspective][ksq]; + Bitboard occupied = pos.pieces(); for (Color color : {WHITE, BLACK}) { @@ -187,7 +193,8 @@ void FullThreats::append_active_indices(const Position& pos, IndexList& active) Square to = pop_lsb(attacks_left); Square from = to - right; Piece attacked = pos.piece_on(to); - IndexType index = make_index(attacker, from, to, attacked, ksq); + IndexType index = make_index_with_orientation( + attacker, from, to, attacked, orientation); if (index < Dimensions) active.push_back(index); @@ -198,7 +205,8 @@ void FullThreats::append_active_indices(const Position& pos, IndexList& active) Square to = pop_lsb(attacks_right); Square from = to - left; Piece attacked = pos.piece_on(to); - IndexType index = make_index(attacker, from, to, attacked, ksq); + IndexType index = make_index_with_orientation( + attacker, from, to, attacked, orientation); if (index < Dimensions) active.push_back(index); @@ -215,8 +223,8 @@ void FullThreats::append_active_indices(const Position& pos, IndexList& active) { Square to = pop_lsb(attacks); Piece attacked = pos.piece_on(to); - IndexType index = - make_index(attacker, from, to, attacked, ksq); + IndexType index = make_index_with_orientation( + attacker, from, to, attacked, orientation); if (index < Dimensions) active.push_back(index); @@ -243,7 +251,9 @@ void FullThreats::append_changed_indices(Square ksq, IndexList& added, FusedUpdateData* fusedData, bool first) { - for (const auto dirty : diff.list) + const int orientation = OrientTBL[Perspective][ksq]; + + for (const auto& dirty : diff.list) { auto attacker = dirty.pc(); auto attacked = dirty.threatened_pc(); @@ -282,9 +292,10 @@ void FullThreats::append_changed_indices(Square ksq, } } - IndexType index = make_index(attacker, from, to, attacked, ksq); + const IndexType index = + make_index_with_orientation(attacker, from, to, attacked, orientation); - if (index != Dimensions) + if (index < Dimensions) (add ? added : removed).push_back(index); } } diff --git a/src/nnue/nnue_accumulator.cpp b/src/nnue/nnue_accumulator.cpp index 0444b6e40..7f723c61f 100644 --- a/src/nnue/nnue_accumulator.cpp +++ b/src/nnue/nnue_accumulator.cpp @@ -336,7 +336,8 @@ struct AccumulatorUpdateContext { to_psqt_weight_vector(indices)...); } - void apply(typename FeatureSet::IndexList added, typename FeatureSet::IndexList removed) { + void apply(const typename FeatureSet::IndexList& added, + const typename FeatureSet::IndexList& removed) { const auto fromAcc = from.template acc().accumulation[Perspective]; const auto toAcc = to.template acc().accumulation[Perspective]; @@ -573,6 +574,21 @@ void update_accumulator_incremental( FeatureSet::template append_changed_indices(ksq, computed.diff, added, removed); + if (!added.size() && !removed.size()) + { + auto& targetAcc = target_state.template acc(); + const auto& sourceAcc = computed.template acc(); + + std::memcpy(targetAcc.accumulation[Perspective], sourceAcc.accumulation[Perspective], + sizeof(targetAcc.accumulation[Perspective])); + std::memcpy(targetAcc.psqtAccumulation[Perspective], + sourceAcc.psqtAccumulation[Perspective], + sizeof(targetAcc.psqtAccumulation[Perspective])); + + targetAcc.computed[Perspective] = true; + return; + } + auto updateContext = make_accumulator_update_context(featureTransformer, computed, target_state); diff --git a/src/position.cpp b/src/position.cpp index a515876b6..58edbcc33 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1051,12 +1051,22 @@ inline void add_dirty_threat( template void Position::update_piece_threats(Piece pc, Square s, DirtyThreats* const dts) { - // Add newly threatened pieces - Bitboard occupied = pieces(); + const Bitboard occupied = pieces(); + const Bitboard rookQueens = pieces(ROOK, QUEEN); + const Bitboard bishopQueens = pieces(BISHOP, QUEEN); + const Bitboard knights = pieces(KNIGHT); + const Bitboard kings = pieces(KING); + const Bitboard whitePawns = pieces(WHITE, PAWN); + const Bitboard blackPawns = pieces(BLACK, PAWN); - Bitboard rAttacks = attacks_bb(s, occupied); - Bitboard bAttacks = attacks_bb(s, occupied); - Bitboard qAttacks = rAttacks | bAttacks; + const Bitboard rAttacks = attacks_bb(s, occupied); + const Bitboard bAttacks = attacks_bb(s, occupied); + + Bitboard qAttacks = Bitboard(0); + if constexpr (ComputeRay) + qAttacks = rAttacks | bAttacks; + else if (type_of(pc) == QUEEN) + qAttacks = rAttacks | bAttacks; Bitboard threatened; @@ -1092,35 +1102,42 @@ void Position::update_piece_threats(Piece pc, Square s, DirtyThreats* const dts) add_dirty_threat(dts, pc, threatened_pc, s, threatened_sq); } - Bitboard sliders = (pieces(ROOK, QUEEN) & rAttacks) | (pieces(BISHOP, QUEEN) & bAttacks); + Bitboard sliders = (rookQueens & rAttacks) | (bishopQueens & bAttacks); - Bitboard incoming_threats = (attacks_bb(s, occupied) & pieces(KNIGHT)) - | (attacks_bb(s, WHITE) & pieces(BLACK, PAWN)) - | (attacks_bb(s, BLACK) & pieces(WHITE, PAWN)) - | (attacks_bb(s, occupied) & pieces(KING)); - - while (sliders) + if constexpr (ComputeRay) { - Square slider_sq = pop_lsb(sliders); - Piece slider = piece_on(slider_sq); - - Bitboard ray = RayPassBB[slider_sq][s] & ~BetweenBB[slider_sq][s]; - threatened = ray & qAttacks & occupied; - - assert(!more_than_one(threatened)); - if (ComputeRay && threatened) + while (sliders) { - Square threatened_sq = lsb(threatened); + Square slider_sq = pop_lsb(sliders); + Piece slider = piece_on(slider_sq); - Piece threatened_pc = piece_on(threatened_sq); - add_dirty_threat(dts, slider, threatened_pc, slider_sq, threatened_sq); + const Bitboard ray = RayPassBB[slider_sq][s] & ~BetweenBB[slider_sq][s]; + const Bitboard discovered = ray & qAttacks & occupied; + + assert(!more_than_one(discovered)); + if (discovered) + { + const Square threatened_sq = lsb(discovered); + const Piece threatened_pc = piece_on(threatened_sq); + add_dirty_threat(dts, slider, threatened_pc, slider_sq, threatened_sq); + } + + add_dirty_threat(dts, slider, pc, slider_sq, s); + } + } + else + { + while (sliders) + { + Square slider_sq = pop_lsb(sliders); + Piece slider = piece_on(slider_sq); + add_dirty_threat(dts, slider, pc, slider_sq, s); } - - add_dirty_threat(dts, slider, pc, slider_sq, s); } - // Add threats of sliders that were already threatening s, - // sliders are already handled in the loop above + Bitboard incoming_threats = + (PseudoAttacks[KNIGHT][s] & knights) | (attacks_bb(s, WHITE) & blackPawns) + | (attacks_bb(s, BLACK) & whitePawns) | (PseudoAttacks[KING][s] & kings); while (incoming_threats) {