/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2024 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Stockfish is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ // Class for difference calculation of NNUE evaluation function #ifndef NNUE_ACCUMULATOR_H_INCLUDED #define NNUE_ACCUMULATOR_H_INCLUDED #include #include "nnue_architecture.h" #include "nnue_common.h" namespace Stockfish::Eval::NNUE { using BiasType = std::int16_t; using PSQTWeightType = std::int32_t; using IndexType = std::uint32_t; // Class that holds the result of affine transformation of input features template struct alignas(CacheLineSize) Accumulator { std::int16_t accumulation[COLOR_NB][Size]; std::int32_t psqtAccumulation[COLOR_NB][PSQTBuckets]; bool computed[COLOR_NB]; }; // AccumulatorCaches struct provides per-thread accumulator caches, where each // cache contains multiple entries for each of the possible king squares. // When the accumulator needs to be refreshed, the cached entry is used to more // efficiently update the accumulator, instead of rebuilding it from scratch. // This idea, was first described by Luecx (author of Koivisto) and // is commonly referred to as "Finny Tables". struct AccumulatorCaches { template AccumulatorCaches(const Networks& networks) { clear(networks); } template struct alignas(CacheLineSize) Cache { struct alignas(CacheLineSize) Entry { BiasType accumulation[Size]; PSQTWeightType psqtAccumulation[PSQTBuckets]; Bitboard byColorBB[COLOR_NB]; Bitboard byTypeBB[PIECE_TYPE_NB]; // To initialize a refresh entry, we set all its bitboards empty, // so we put the biases in the accumulation, without any weights on top void clear(const BiasType* biases) { std::memcpy(accumulation, biases, sizeof(accumulation)); std::memset((uint8_t*) this + offsetof(Entry, psqtAccumulation), 0, sizeof(Entry) - offsetof(Entry, psqtAccumulation)); } }; template void clear(const Network& network) { for (auto& entries1D : entries) for (auto& entry : entries1D) entry.clear(network.featureTransformer->biases); } std::array& operator[](Square sq) { return entries[sq]; } std::array, SQUARE_NB> entries; }; template void clear(const Networks& networks) { big.clear(networks.big); small.clear(networks.small); } Cache big; Cache small; }; } // namespace Stockfish::Eval::NNUE #endif // NNUE_ACCUMULATOR_H_INCLUDED