65 using IntensityBlock = DataBlock<intensity_t, N>;
71 [[nodiscard]] IntensityBlock& intensityBlock(pos_t block) {
return intensity_[block]; }
73 [[nodiscard]] IntensityBlock
const& intensityBlock(pos_t block)
const
75 return intensity_[block];
82 [[nodiscard]] intensity_t intensity(Index node)
const
84 return intensity_[node.pos][node.offset];
87 [[nodiscard]]
constexpr intensity_t intensity(Node node)
const
89 return intensity(derived().
index(node));
92 [[nodiscard]] intensity_t intensity(Code code)
const
94 return intensity(derived().
index(code));
97 [[nodiscard]] intensity_t intensity(Key key)
const
99 return intensity(derived().
index(key));
102 [[nodiscard]] intensity_t intensity(Coord coord, depth_t depth = 0)
const
104 return intensity(derived().
index(coord, depth));
111 void setIntensity(Index node, intensity_t intensity)
115 [
this, intensity](Index node) { intensity_[node.pos][node.offset] = intensity; },
116 [
this, intensity](pos_t pos) { intensity_[pos].fill(intensity); });
119 Node setIntensity(Node node, intensity_t intensity,
bool propagate =
true)
121 return derived().apply(
123 [
this, intensity](Index node) { intensity_[node.pos][node.offset] = intensity; },
124 [
this, intensity](pos_t pos) { intensity_[pos].fill(intensity); }, propagate);
127 Node setIntensity(Code code, intensity_t intensity,
bool propagate =
true)
129 return derived().apply(
131 [
this, intensity](Index node) { intensity_[node.pos][node.offset] = intensity; },
132 [
this, intensity](pos_t pos) { intensity_[pos].fill(intensity); }, propagate);
135 Node setIntensity(Key key, intensity_t intensity,
bool propagate =
true)
137 return setIntensity(derived().toCode(key), intensity, propagate);
140 Node setIntensity(Coord coord, intensity_t intensity,
bool propagate =
true,
143 return setIntensity(derived().toCode(coord, depth), intensity, propagate);
150 void updateIntensity(Index node,
double change)
153 node, [
this, change](Index node) { intensity_[node.pos][node.offset] += change; },
154 [
this, change](pos_t pos) {
155 for (
auto& e : intensity_[pos]) {
161 template <
class UnaryOp,
162 std::enable_if_t<std::is_invocable_v<UnaryOp, intensity_t>,
bool> =
true>
163 void updateIntensity(Index node, UnaryOp unary_op)
167 [
this, unary_op](Index node) {
168 intensity_[node.pos][node.offset] = unary_op(intensity_[node.pos][node.offset]);
170 [
this, unary_op](pos_t pos) {
171 for (
auto& e : intensity_[pos]) {
179 std::enable_if_t<std::is_invocable_v<BinaryOp, Index, intensity_t>,
bool> =
true>
180 void updateIntensity(Index node, BinaryOp binary_op)
184 [
this, binary_op](Index node) {
185 intensity_[node.pos][node.offset] =
186 binary_op(node, intensity_[node.pos][node.offset]);
188 [
this, binary_op](pos_t pos) {
190 for (
auto& e : intensity_[pos]) {
191 e = binary_op(Index(pos, i++), e);
196 Node updateIntensity(Node node,
double change,
bool propagate =
true)
198 return derived().apply(
199 node, [
this, change](Index node) { intensity_[node.pos][node.offset] += change; },
200 [
this, change](pos_t pos) {
201 for (
auto& e : intensity_[pos]) {
208 template <
class UnaryOp,
209 std::enable_if_t<std::is_invocable_v<UnaryOp, intensity_t>,
bool> =
true>
210 Node updateIntensity(Node node, UnaryOp unary_op,
bool propagate =
true)
212 return derived().apply(
214 [
this, unary_op](Index node) {
215 intensity_[node.pos][node.offset] = unary_op(intensity_[node.pos][node.offset]);
217 [
this, unary_op](pos_t pos) {
218 for (
auto& e : intensity_[pos]) {
227 std::enable_if_t<std::is_invocable_v<BinaryOp, Index, intensity_t>,
bool> =
true>
228 Node updateIntensity(Node node, BinaryOp binary_op,
bool propagate =
true)
230 return derived().apply(
232 [
this, binary_op](Index node) {
233 intensity_[node.pos][node.offset] =
234 binary_op(node, intensity_[node.pos][node.offset]);
236 [
this, binary_op](pos_t pos) {
238 for (
auto& e : intensity_[pos]) {
239 e = binary_op(Index(pos, i++), e);
245 Node updateIntensity(Code code,
double change,
bool propagate =
true)
247 return derived().apply(
248 code, [
this, change](Index node) { intensity_[node.pos][node.offset] += change; },
249 [
this, change](pos_t pos) {
250 for (
auto& e : intensity_[pos]) {
257 template <
class UnaryOp,
258 std::enable_if_t<std::is_invocable_v<UnaryOp, intensity_t>,
bool> =
true>
259 Node updateIntensity(Code code, UnaryOp unary_op,
bool propagate =
true)
261 return derived().apply(
263 [
this, unary_op](Index node) {
264 intensity_[node.pos][node.offset] = unary_op(intensity_[node.pos][node.offset]);
266 [
this, unary_op](pos_t pos) {
267 for (
auto& e : intensity_[pos]) {
276 std::enable_if_t<std::is_invocable_v<BinaryOp, Index, intensity_t>,
bool> =
true>
277 Node updateIntensity(Code code, BinaryOp binary_op,
bool propagate =
true)
279 return derived().apply(
281 [
this, binary_op](Index node) {
282 intensity_[node.pos][node.offset] =
283 binary_op(node, intensity_[node.pos][node.offset]);
285 [
this, binary_op](pos_t pos) {
287 for (
auto& e : intensity_[pos]) {
288 e = binary_op(Index(pos, i++), e);
294 Node updateIntensity(Key key,
double change,
bool propagate =
true)
296 return updateIntensity(derived().toCode(key), change, propagate);
299 template <
class UnaryOp,
300 std::enable_if_t<std::is_invocable_v<UnaryOp, intensity_t>,
bool> =
true>
301 Node updateIntensity(Key key, UnaryOp unary_op,
bool propagate =
true)
303 return updateIntensity(derived().toCode(key), unary_op, propagate);
308 std::enable_if_t<std::is_invocable_v<BinaryOp, Index, intensity_t>,
bool> =
true>
309 Node updateIntensity(Key key, BinaryOp binary_op,
bool propagate =
true)
311 return updateIntensity(derived().toCode(key), binary_op, propagate);
314 Node updateIntensity(Coord coord,
double change,
bool propagate =
true,
317 return updateIntensity(derived().toCode(coord, depth), change, propagate);
320 template <
class UnaryOp,
321 std::enable_if_t<std::is_invocable_v<UnaryOp, intensity_t>,
bool> =
true>
322 Node updateIntensity(Coord coord, UnaryOp unary_op,
bool propagate =
true,
325 return updateIntensity(derived().toCode(coord, depth), unary_op, propagate);
330 std::enable_if_t<std::is_invocable_v<BinaryOp, Index, intensity_t>,
bool> =
true>
331 Node updateIntensity(Coord coord, BinaryOp binary_op,
bool propagate =
true,
334 return updateIntensity(derived().toCode(coord, depth), binary_op, propagate);
341 [[nodiscard]]
constexpr PropagationCriteria intensityPropagationCriteria()
344 return prop_criteria_;
347 constexpr void setIntensityPropagationCriteria(PropagationCriteria prop_criteria,
348 bool propagate =
true)
noexcept
350 if (prop_criteria_ == prop_criteria) {
354 prop_criteria_ = prop_criteria;
356 derived().setModified();
359 derived().propagateModified();
374 template <
class Derived2>
376 : intensity_(other.intensity_), prop_criteria_(other.prop_criteria_)
380 template <
class Derived2>
382 : intensity_(std::move(other.intensity_))
383 , prop_criteria_(std::move(other.prop_criteria_))
401 template <
class Derived2>
405 intensity_ = rhs.intensity_;
406 prop_criteria_ = rhs.prop_criteria_;
410 template <
class Derived2>
413 intensity_ = std::move(rhs.intensity_);
414 prop_criteria_ = std::move(rhs.prop_criteria_);
424 std::swap(intensity_, other.intensity_);
425 std::swap(prop_criteria_, other.prop_criteria_);
432 [[nodiscard]]
constexpr Derived& derived() {
return *
static_cast<Derived*
>(
this); }
434 [[nodiscard]]
constexpr Derived
const& derived()
const
436 return *
static_cast<Derived const*
>(
this);
443 void createBlock(Index node)
445 intensity_.emplace_back();
446 intensity_.back().fill(intensity_[node.pos][node.offset]);
453 void resize(std::size_t count)
456 intensity_.resize(count);
463 void reserveImpl(std::size_t new_cap) { intensity_.reserve(new_cap); }
471 auto node = derived().rootIndex();
472 intensity_[node.pos][node.offset] = 0;
479 void fill(Index node, pos_t children)
481 intensity_[children].fill(intensity_[node.pos][node.offset]);
488 void clearImpl() { intensity_.resize(1); }
490 void clearImpl(pos_t) {}
496 void updateBlock(pos_t block, std::array<bool, N> modified_parent)
498 for (offset_t i{}; N != i; ++i) {
499 if (modified_parent[i]) {
500 Index node(block, i);
501 updateNode(node, derived().children(node));
506 void updateNode(Index node, pos_t children)
508 switch (intensityPropagationCriteria()) {
509 case PropagationCriteria::MIN:
510 intensity_[node.pos][node.offset] = min(children);
512 case PropagationCriteria::MAX:
513 intensity_[node.pos][node.offset] = max(children);
515 case PropagationCriteria::MEAN:
516 intensity_[node.pos][node.offset] = mean(children);
518 case PropagationCriteria::NONE:
return;
522 [[nodiscard]]
constexpr intensity_t min(pos_t block)
const
524 intensity_t ret = intensity_[block][0];
525 for (
auto e : intensity_[block]) {
526 ret = std::min(ret, e);
531 [[nodiscard]]
constexpr intensity_t max(pos_t block)
const
533 intensity_t ret = intensity_[block][0];
534 for (
auto e : intensity_[block]) {
535 ret = std::max(ret, e);
540 [[nodiscard]]
constexpr intensity_t mean(pos_t block)
const
542 return std::accumulate(std::cbegin(intensity_[block]), std::cend(intensity_[block]),
544 static_cast<intensity_t
>(N);
551 [[nodiscard]]
bool isPrunable(pos_t block)
const
553 return std::all_of(std::cbegin(intensity_[block]) + 1, std::cend(intensity_[block]),
554 [
a = intensity_[block].front()](
auto b) {
return a ==
b; });
561 [[nodiscard]]
static constexpr std::size_t sizeofNodeTimesN(Index)
noexcept
563 return sizeofBlockLowerBound();
566 [[nodiscard]]
static constexpr std::size_t sizeofBlock(pos_t)
noexcept
568 return sizeofBlockLowerBound();
571 [[nodiscard]]
static constexpr std::size_t sizeofBlockLowerBound()
noexcept
573 return sizeof(
typename decltype(intensity_)::value_type);
576 [[nodiscard]]
static constexpr std::size_t sizeofMap()
noexcept
578 return sizeof(intensity_) +
sizeof(prop_criteria_);
585 [[nodiscard]]
static constexpr MapType mapType()
noexcept {
return MapType::INTENSITY; }
587 [[nodiscard]]
static constexpr std::size_t serializedSizeBlock()
noexcept
589 return sizeof(
typename decltype(intensity_)::value_type);
592 template <
class Container>
593 constexpr std::size_t serializedSize(Container
const& c)
const
595 return c.size() * serializedSizeBlock();
598 template <
class Container>
599 void readNodes(
ReadBuffer& in, Container
const& c)
601 for (
auto const [pos, offsets] : c) {
603 in.read(intensity_[pos].data(), serializedSizeBlock());
605 IntensityBlock intensity;
606 in.read(intensity.data(), serializedSizeBlock());
607 for (offset_t i{}; N != i; ++i) {
608 intensity_[pos][i] = offsets[i] ? intensity[i] : intensity_[pos][i];
614 template <
class BlockRange>
615 void writeBlocks(
WriteBuffer& out, BlockRange
const& blocks)
const
617 for (
auto block : blocks) {
618 out.write(intensity_[block].data(), serializedSizeBlock());
624 Container<IntensityBlock> intensity_;
627 PropagationCriteria prop_criteria_ = PropagationCriteria::MAX;
629 template <
class Derived2, offset_t N2,
class Index2,
class Node2,
class Code2,