Path: blob/master/src/nnue/nnue_accumulator.h
375 views
/*1Stockfish, a UCI chess playing engine derived from Glaurung 2.12Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)34Stockfish is free software: you can redistribute it and/or modify5it under the terms of the GNU General Public License as published by6the Free Software Foundation, either version 3 of the License, or7(at your option) any later version.89Stockfish is distributed in the hope that it will be useful,10but WITHOUT ANY WARRANTY; without even the implied warranty of11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12GNU General Public License for more details.1314You should have received a copy of the GNU General Public License15along with this program. If not, see <http://www.gnu.org/licenses/>.16*/1718// Class for difference calculation of NNUE evaluation function1920#ifndef NNUE_ACCUMULATOR_H_INCLUDED21#define NNUE_ACCUMULATOR_H_INCLUDED2223#include <array>24#include <cstddef>25#include <cstdint>26#include <cstring>27#include <vector>2829#include "../types.h"30#include "nnue_architecture.h"31#include "nnue_common.h"3233namespace Stockfish {34class Position;35}3637namespace Stockfish::Eval::NNUE {3839template<IndexType Size>40struct alignas(CacheLineSize) Accumulator;4142template<IndexType TransformedFeatureDimensions>43class FeatureTransformer;4445// Class that holds the result of affine transformation of input features46template<IndexType Size>47struct alignas(CacheLineSize) Accumulator {48std::int16_t accumulation[COLOR_NB][Size];49std::int32_t psqtAccumulation[COLOR_NB][PSQTBuckets];50std::array<bool, COLOR_NB> computed;51};525354// AccumulatorCaches struct provides per-thread accumulator caches, where each55// cache contains multiple entries for each of the possible king squares.56// When the accumulator needs to be refreshed, the cached entry is used to more57// efficiently update the accumulator, instead of rebuilding it from scratch.58// This idea, was first described by Luecx (author of Koivisto) and59// is commonly referred to as "Finny Tables".60struct AccumulatorCaches {6162template<typename Networks>63AccumulatorCaches(const Networks& networks) {64clear(networks);65}6667template<IndexType Size>68struct alignas(CacheLineSize) Cache {6970struct alignas(CacheLineSize) Entry {71BiasType accumulation[Size];72PSQTWeightType psqtAccumulation[PSQTBuckets];73Bitboard byColorBB[COLOR_NB];74Bitboard byTypeBB[PIECE_TYPE_NB];7576// To initialize a refresh entry, we set all its bitboards empty,77// so we put the biases in the accumulation, without any weights on top78void clear(const BiasType* biases) {7980std::memcpy(accumulation, biases, sizeof(accumulation));81std::memset((uint8_t*) this + offsetof(Entry, psqtAccumulation), 0,82sizeof(Entry) - offsetof(Entry, psqtAccumulation));83}84};8586template<typename Network>87void clear(const Network& network) {88for (auto& entries1D : entries)89for (auto& entry : entries1D)90entry.clear(network.featureTransformer->biases);91}9293std::array<Entry, COLOR_NB>& operator[](Square sq) { return entries[sq]; }9495std::array<std::array<Entry, COLOR_NB>, SQUARE_NB> entries;96};9798template<typename Networks>99void clear(const Networks& networks) {100big.clear(networks.big);101small.clear(networks.small);102}103104Cache<TransformedFeatureDimensionsBig> big;105Cache<TransformedFeatureDimensionsSmall> small;106};107108109struct AccumulatorState {110Accumulator<TransformedFeatureDimensionsBig> accumulatorBig;111Accumulator<TransformedFeatureDimensionsSmall> accumulatorSmall;112DirtyPiece dirtyPiece;113114template<IndexType Size>115auto& acc() noexcept {116static_assert(Size == TransformedFeatureDimensionsBig117|| Size == TransformedFeatureDimensionsSmall,118"Invalid size for accumulator");119120if constexpr (Size == TransformedFeatureDimensionsBig)121return accumulatorBig;122else if constexpr (Size == TransformedFeatureDimensionsSmall)123return accumulatorSmall;124}125126template<IndexType Size>127const auto& acc() const noexcept {128static_assert(Size == TransformedFeatureDimensionsBig129|| Size == TransformedFeatureDimensionsSmall,130"Invalid size for accumulator");131132if constexpr (Size == TransformedFeatureDimensionsBig)133return accumulatorBig;134else if constexpr (Size == TransformedFeatureDimensionsSmall)135return accumulatorSmall;136}137138void reset(const DirtyPiece& dp) noexcept;139};140141142class AccumulatorStack {143public:144AccumulatorStack() :145accumulators(MAX_PLY + 1),146size{1} {}147148[[nodiscard]] const AccumulatorState& latest() const noexcept;149150void reset() noexcept;151void push(const DirtyPiece& dirtyPiece) noexcept;152void pop() noexcept;153154template<IndexType Dimensions>155void evaluate(const Position& pos,156const FeatureTransformer<Dimensions>& featureTransformer,157AccumulatorCaches::Cache<Dimensions>& cache) noexcept;158159private:160[[nodiscard]] AccumulatorState& mut_latest() noexcept;161162template<Color Perspective, IndexType Dimensions>163void evaluate_side(const Position& pos,164const FeatureTransformer<Dimensions>& featureTransformer,165AccumulatorCaches::Cache<Dimensions>& cache) noexcept;166167template<Color Perspective, IndexType Dimensions>168[[nodiscard]] std::size_t find_last_usable_accumulator() const noexcept;169170template<Color Perspective, IndexType Dimensions>171void forward_update_incremental(const Position& pos,172const FeatureTransformer<Dimensions>& featureTransformer,173const std::size_t begin) noexcept;174175template<Color Perspective, IndexType Dimensions>176void backward_update_incremental(const Position& pos,177const FeatureTransformer<Dimensions>& featureTransformer,178const std::size_t end) noexcept;179180std::vector<AccumulatorState> accumulators;181std::size_t size;182};183184} // namespace Stockfish::Eval::NNUE185186#endif // NNUE_ACCUMULATOR_H_INCLUDED187188189