Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
official-stockfish
GitHub Repository: official-stockfish/Stockfish
Path: blob/master/src/nnue/nnue_accumulator.h
375 views
1
/*
2
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
3
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
4
5
Stockfish is free software: you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation, either version 3 of the License, or
8
(at your option) any later version.
9
10
Stockfish is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
14
15
You should have received a copy of the GNU General Public License
16
along with this program. If not, see <http://www.gnu.org/licenses/>.
17
*/
18
19
// Class for difference calculation of NNUE evaluation function
20
21
#ifndef NNUE_ACCUMULATOR_H_INCLUDED
22
#define NNUE_ACCUMULATOR_H_INCLUDED
23
24
#include <array>
25
#include <cstddef>
26
#include <cstdint>
27
#include <cstring>
28
#include <vector>
29
30
#include "../types.h"
31
#include "nnue_architecture.h"
32
#include "nnue_common.h"
33
34
namespace Stockfish {
35
class Position;
36
}
37
38
namespace Stockfish::Eval::NNUE {
39
40
template<IndexType Size>
41
struct alignas(CacheLineSize) Accumulator;
42
43
template<IndexType TransformedFeatureDimensions>
44
class FeatureTransformer;
45
46
// Class that holds the result of affine transformation of input features
47
template<IndexType Size>
48
struct alignas(CacheLineSize) Accumulator {
49
std::int16_t accumulation[COLOR_NB][Size];
50
std::int32_t psqtAccumulation[COLOR_NB][PSQTBuckets];
51
std::array<bool, COLOR_NB> computed;
52
};
53
54
55
// AccumulatorCaches struct provides per-thread accumulator caches, where each
56
// cache contains multiple entries for each of the possible king squares.
57
// When the accumulator needs to be refreshed, the cached entry is used to more
58
// efficiently update the accumulator, instead of rebuilding it from scratch.
59
// This idea, was first described by Luecx (author of Koivisto) and
60
// is commonly referred to as "Finny Tables".
61
struct AccumulatorCaches {
62
63
template<typename Networks>
64
AccumulatorCaches(const Networks& networks) {
65
clear(networks);
66
}
67
68
template<IndexType Size>
69
struct alignas(CacheLineSize) Cache {
70
71
struct alignas(CacheLineSize) Entry {
72
BiasType accumulation[Size];
73
PSQTWeightType psqtAccumulation[PSQTBuckets];
74
Bitboard byColorBB[COLOR_NB];
75
Bitboard byTypeBB[PIECE_TYPE_NB];
76
77
// To initialize a refresh entry, we set all its bitboards empty,
78
// so we put the biases in the accumulation, without any weights on top
79
void clear(const BiasType* biases) {
80
81
std::memcpy(accumulation, biases, sizeof(accumulation));
82
std::memset((uint8_t*) this + offsetof(Entry, psqtAccumulation), 0,
83
sizeof(Entry) - offsetof(Entry, psqtAccumulation));
84
}
85
};
86
87
template<typename Network>
88
void clear(const Network& network) {
89
for (auto& entries1D : entries)
90
for (auto& entry : entries1D)
91
entry.clear(network.featureTransformer->biases);
92
}
93
94
std::array<Entry, COLOR_NB>& operator[](Square sq) { return entries[sq]; }
95
96
std::array<std::array<Entry, COLOR_NB>, SQUARE_NB> entries;
97
};
98
99
template<typename Networks>
100
void clear(const Networks& networks) {
101
big.clear(networks.big);
102
small.clear(networks.small);
103
}
104
105
Cache<TransformedFeatureDimensionsBig> big;
106
Cache<TransformedFeatureDimensionsSmall> small;
107
};
108
109
110
struct AccumulatorState {
111
Accumulator<TransformedFeatureDimensionsBig> accumulatorBig;
112
Accumulator<TransformedFeatureDimensionsSmall> accumulatorSmall;
113
DirtyPiece dirtyPiece;
114
115
template<IndexType Size>
116
auto& acc() noexcept {
117
static_assert(Size == TransformedFeatureDimensionsBig
118
|| Size == TransformedFeatureDimensionsSmall,
119
"Invalid size for accumulator");
120
121
if constexpr (Size == TransformedFeatureDimensionsBig)
122
return accumulatorBig;
123
else if constexpr (Size == TransformedFeatureDimensionsSmall)
124
return accumulatorSmall;
125
}
126
127
template<IndexType Size>
128
const auto& acc() const noexcept {
129
static_assert(Size == TransformedFeatureDimensionsBig
130
|| Size == TransformedFeatureDimensionsSmall,
131
"Invalid size for accumulator");
132
133
if constexpr (Size == TransformedFeatureDimensionsBig)
134
return accumulatorBig;
135
else if constexpr (Size == TransformedFeatureDimensionsSmall)
136
return accumulatorSmall;
137
}
138
139
void reset(const DirtyPiece& dp) noexcept;
140
};
141
142
143
class AccumulatorStack {
144
public:
145
AccumulatorStack() :
146
accumulators(MAX_PLY + 1),
147
size{1} {}
148
149
[[nodiscard]] const AccumulatorState& latest() const noexcept;
150
151
void reset() noexcept;
152
void push(const DirtyPiece& dirtyPiece) noexcept;
153
void pop() noexcept;
154
155
template<IndexType Dimensions>
156
void evaluate(const Position& pos,
157
const FeatureTransformer<Dimensions>& featureTransformer,
158
AccumulatorCaches::Cache<Dimensions>& cache) noexcept;
159
160
private:
161
[[nodiscard]] AccumulatorState& mut_latest() noexcept;
162
163
template<Color Perspective, IndexType Dimensions>
164
void evaluate_side(const Position& pos,
165
const FeatureTransformer<Dimensions>& featureTransformer,
166
AccumulatorCaches::Cache<Dimensions>& cache) noexcept;
167
168
template<Color Perspective, IndexType Dimensions>
169
[[nodiscard]] std::size_t find_last_usable_accumulator() const noexcept;
170
171
template<Color Perspective, IndexType Dimensions>
172
void forward_update_incremental(const Position& pos,
173
const FeatureTransformer<Dimensions>& featureTransformer,
174
const std::size_t begin) noexcept;
175
176
template<Color Perspective, IndexType Dimensions>
177
void backward_update_incremental(const Position& pos,
178
const FeatureTransformer<Dimensions>& featureTransformer,
179
const std::size_t end) noexcept;
180
181
std::vector<AccumulatorState> accumulators;
182
std::size_t size;
183
};
184
185
} // namespace Stockfish::Eval::NNUE
186
187
#endif // NNUE_ACCUMULATOR_H_INCLUDED
188
189