Path: blob/master/src/nnue/nnue_accumulator.h
648 views
/*1Stockfish, a UCI chess playing engine derived from Glaurung 2.12Copyright (C) 2004-2026 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 <utility>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::array<std::array<std::int16_t, Size>, COLOR_NB> accumulation;49std::array<std::array<std::int32_t, PSQTBuckets>, COLOR_NB> psqtAccumulation;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 {71std::array<BiasType, Size> accumulation;72std::array<PSQTWeightType, PSQTBuckets> psqtAccumulation;73std::array<Piece, SQUARE_NB> pieces;74Bitboard pieceBB;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 std::array<BiasType, Size>& biases) {79accumulation = biases;80std::memset(reinterpret_cast<std::byte*>(this) + offsetof(Entry, psqtAccumulation),810, sizeof(Entry) - offsetof(Entry, psqtAccumulation));82}83};8485template<typename Network>86void clear(const Network& network) {87for (auto& entries1D : entries)88for (auto& entry : entries1D)89entry.clear(network.featureTransformer.biases);90}9192std::array<Entry, COLOR_NB>& operator[](Square sq) { return entries[sq]; }9394std::array<std::array<Entry, COLOR_NB>, SQUARE_NB> entries;95};9697template<typename Networks>98void clear(const Networks& networks) {99big.clear(networks.big);100small.clear(networks.small);101}102103Cache<TransformedFeatureDimensionsBig> big;104Cache<TransformedFeatureDimensionsSmall> small;105};106107108template<typename FeatureSet>109struct AccumulatorState {110Accumulator<TransformedFeatureDimensionsBig> accumulatorBig;111Accumulator<TransformedFeatureDimensionsSmall> accumulatorSmall;112typename FeatureSet::DiffType diff;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 typename FeatureSet::DiffType& dp) noexcept {139diff = dp;140accumulatorBig.computed.fill(false);141accumulatorSmall.computed.fill(false);142}143144typename FeatureSet::DiffType& reset() noexcept {145accumulatorBig.computed.fill(false);146accumulatorSmall.computed.fill(false);147return diff;148}149};150151class AccumulatorStack {152public:153static constexpr std::size_t MaxSize = MAX_PLY + 1;154155template<typename T>156[[nodiscard]] const AccumulatorState<T>& latest() const noexcept;157158void reset() noexcept;159std::pair<DirtyPiece&, DirtyThreats&> push() noexcept;160void pop() noexcept;161162template<IndexType Dimensions>163void evaluate(const Position& pos,164const FeatureTransformer<Dimensions>& featureTransformer,165AccumulatorCaches::Cache<Dimensions>& cache) noexcept;166167private:168template<typename T>169[[nodiscard]] AccumulatorState<T>& mut_latest() noexcept;170171template<typename T>172[[nodiscard]] const std::array<AccumulatorState<T>, MaxSize>& accumulators() const noexcept;173174template<typename T>175[[nodiscard]] std::array<AccumulatorState<T>, MaxSize>& mut_accumulators() noexcept;176177template<typename FeatureSet, IndexType Dimensions>178void evaluate_side(Color perspective,179const Position& pos,180const FeatureTransformer<Dimensions>& featureTransformer,181AccumulatorCaches::Cache<Dimensions>& cache) noexcept;182183template<typename FeatureSet, IndexType Dimensions>184[[nodiscard]] std::size_t find_last_usable_accumulator(Color perspective) const noexcept;185186template<typename FeatureSet, IndexType Dimensions>187void forward_update_incremental(Color perspective,188const Position& pos,189const FeatureTransformer<Dimensions>& featureTransformer,190const std::size_t begin) noexcept;191192template<typename FeatureSet, IndexType Dimensions>193void backward_update_incremental(Color perspective,194const Position& pos,195const FeatureTransformer<Dimensions>& featureTransformer,196const std::size_t end) noexcept;197198std::array<AccumulatorState<PSQFeatureSet>, MaxSize> psq_accumulators;199std::array<AccumulatorState<ThreatFeatureSet>, MaxSize> threat_accumulators;200std::size_t size = 1;201};202203} // namespace Stockfish::Eval::NNUE204205#endif // NNUE_ACCUMULATOR_H_INCLUDED206207208