- accumulator.computed_accumulation = true;
- accumulator.computed_score = false;
- }
-
- // Calculate cumulative value using difference calculation
- void UpdateAccumulator(const Position& pos) const {
- const auto prev_accumulator = pos.state()->previous->accumulator;
- auto& accumulator = pos.state()->accumulator;
- IndexType i = 0;
- Features::IndexList removed_indices[2], added_indices[2];
- bool reset[2];
- RawFeatures::AppendChangedIndices(pos, kRefreshTriggers[i],
- removed_indices, added_indices, reset);
- for (Color perspective : { WHITE, BLACK }) {
-
- #if defined(USE_AVX2)
- constexpr IndexType kNumChunks = kHalfDimensions / (kSimdWidth / 2);
- auto accumulation = reinterpret_cast<__m256i*>(
- &accumulator.accumulation[perspective][i][0]);
-
- #elif defined(USE_SSE2)
- constexpr IndexType kNumChunks = kHalfDimensions / (kSimdWidth / 2);
- auto accumulation = reinterpret_cast<__m128i*>(
- &accumulator.accumulation[perspective][i][0]);
-
- #elif defined(USE_MMX)
- constexpr IndexType kNumChunks = kHalfDimensions / (kSimdWidth / 2);
- auto accumulation = reinterpret_cast<__m64*>(
- &accumulator.accumulation[perspective][i][0]);
-
- #elif defined(USE_NEON)
- constexpr IndexType kNumChunks = kHalfDimensions / (kSimdWidth / 2);
- auto accumulation = reinterpret_cast<int16x8_t*>(
- &accumulator.accumulation[perspective][i][0]);
- #endif
-
- if (reset[perspective]) {
- std::memcpy(accumulator.accumulation[perspective][i], biases_,
- kHalfDimensions * sizeof(BiasType));
- } else {
- std::memcpy(accumulator.accumulation[perspective][i],
- prev_accumulator.accumulation[perspective][i],
- kHalfDimensions * sizeof(BiasType));
- // Difference calculation for the deactivated features
- for (const auto index : removed_indices[perspective]) {
- const IndexType offset = kHalfDimensions * index;
-
- #if defined(USE_AVX2)
- auto column = reinterpret_cast<const __m256i*>(&weights_[offset]);
- for (IndexType j = 0; j < kNumChunks; ++j) {
- accumulation[j] = _mm256_sub_epi16(accumulation[j], column[j]);
+ if (st->accumulator.state[c] == COMPUTED)
+ {
+ if (next == nullptr)
+ return;
+
+ // Update incrementally in two steps. First, we update the "next"
+ // accumulator. Then, we update the current accumulator (pos.state()).
+
+ // Gather all features to be updated. This code assumes HalfKP features
+ // only and doesn't support refresh triggers.
+ static_assert(std::is_same_v<Features::FeatureSet<Features::HalfKP<Features::Side::kFriend>>,
+ RawFeatures>);
+ Features::IndexList removed[2], added[2];
+ Features::HalfKP<Features::Side::kFriend>::AppendChangedIndices(pos,
+ next->dirtyPiece, c, &removed[0], &added[0]);
+ for (StateInfo *st2 = pos.state(); st2 != next; st2 = st2->previous)
+ Features::HalfKP<Features::Side::kFriend>::AppendChangedIndices(pos,
+ st2->dirtyPiece, c, &removed[1], &added[1]);
+
+ // Mark the accumulators as computed.
+ next->accumulator.state[c] = COMPUTED;
+ pos.state()->accumulator.state[c] = COMPUTED;
+
+ // Now update the accumulators listed in info[], where the last element is a sentinel.
+ StateInfo *info[3] =
+ { next, next == pos.state() ? nullptr : pos.state(), nullptr };
+ #ifdef VECTOR
+ for (IndexType j = 0; j < kHalfDimensions / kTileHeight; ++j)
+ {
+ // Load accumulator
+ auto accTile = reinterpret_cast<vec_t*>(
+ &st->accumulator.accumulation[c][0][j * kTileHeight]);
+ for (IndexType k = 0; k < kNumRegs; ++k)
+ acc[k] = vec_load(&accTile[k]);
+
+ for (IndexType i = 0; info[i]; ++i)
+ {
+ // Difference calculation for the deactivated features
+ for (const auto index : removed[i])
+ {
+ const IndexType offset = kHalfDimensions * index + j * kTileHeight;
+ auto column = reinterpret_cast<const vec_t*>(&weights_[offset]);
+ for (IndexType k = 0; k < kNumRegs; ++k)
+ acc[k] = vec_sub_16(acc[k], column[k]);