mmcfilters
Public API documentation
Loading...
Searching...
No Matches
LocalEventModel.hpp
1#pragma once
2
3#include "ConnectedSubsetTreeLocalizer.hpp"
4#include "../utils/Common.hpp"
5
6#include <array>
7#include <concepts>
8#include <cstddef>
9#include <cstdint>
10#include <initializer_list>
11#include <limits>
12#include <optional>
13#include <set>
14#include <span>
15#include <stdexcept>
16#include <utility>
17#include <vector>
18
19namespace mmcfilters::local_attributes {
20
21namespace detail {
22struct BinaryVisibilityStateAccess;
23}
24
33 public:
35 static constexpr std::size_t maxNumOffsets = 32;
36
38 explicit ObservationWindow(std::vector<WindowOffset> offsets) : offsets_(std::move(offsets)) { validate(); }
40 ObservationWindow(std::initializer_list<WindowOffset> offsets) : ObservationWindow(std::vector<WindowOffset>(offsets)) {}
41
43 template <std::size_t N>
44 explicit ObservationWindow(const std::array<WindowOffset, N>& offsets) : ObservationWindow(std::vector<WindowOffset>(offsets.begin(), offsets.end())) {}
45
47 [[nodiscard]] std::size_t size() const noexcept { return offsets_.size(); }
49 [[nodiscard]] const WindowOffset& operator[](std::size_t index) const noexcept { return offsets_[index]; }
51 [[nodiscard]] std::span<const WindowOffset> offsets() const noexcept { return offsets_; }
53 [[nodiscard]] auto begin() const noexcept { return offsets_.begin(); }
55 [[nodiscard]] auto end() const noexcept { return offsets_.end(); }
56
57 private:
59 void validate() const {
60 if (offsets_.empty()) {
61 throw std::invalid_argument("ObservationWindow requires at least one offset.");
62 }
63 if (offsets_.size() > maxNumOffsets) {
64 throw std::invalid_argument("ObservationWindow supports at most 32 offsets.");
65 }
66
67 std::size_t numZeroOffsets = 0;
68 for (std::size_t i = 0; i < offsets_.size(); ++i) {
69 if (offsets_[i] == WindowOffset{}) {
70 ++numZeroOffsets;
71 }
72 for (std::size_t j = 0; j < i; ++j) {
73 if (offsets_[i] == offsets_[j]) {
74 throw std::invalid_argument("ObservationWindow does not permit duplicate offsets.");
75 }
76 }
77 }
78 if (numZeroOffsets != 1) {
79 throw std::invalid_argument("ObservationWindow requires the zero offset exactly once.");
80 }
81 }
82
83 std::vector<WindowOffset> offsets_;
84};
85
88 public:
94 BinaryVisibilityState(std::uint32_t bits, std::size_t coordinateCount) : bits_(bits), coordinateCount_(coordinateCount) {
95 if (coordinateCount_ == 0) {
96 throw std::invalid_argument("BinaryVisibilityState requires at least one coordinate.");
97 }
98 if (coordinateCount_ > ObservationWindow::maxNumOffsets) {
99 throw std::invalid_argument("BinaryVisibilityState supports at most 32 coordinates.");
100 }
101 const std::uint32_t validMask = coordinateCount_ == 32 ? std::numeric_limits<std::uint32_t>::max()
102 : (std::uint32_t{1} << coordinateCount_) - std::uint32_t{1};
103 if ((bits_ & ~validMask) != 0) {
104 throw std::invalid_argument("BinaryVisibilityState contains bits outside its coordinate domain.");
105 }
106 }
107
109 [[nodiscard]] std::uint32_t bits() const noexcept { return bits_; }
111 [[nodiscard]] std::size_t coordinateCount() const noexcept { return coordinateCount_; }
112
114 [[nodiscard]] bool isVisible(std::size_t coordinate) const {
115 if (coordinate >= coordinateCount_) {
116 throw std::out_of_range("BinaryVisibilityState coordinate is outside the observation window.");
117 }
118 return (bits_ & (std::uint32_t{1} << coordinate)) != 0;
119 }
120
126 [[nodiscard]] BinaryVisibilityState withEnteringOffsets(std::uint32_t enteringOffsetMask) const {
127 return BinaryVisibilityState(bits_ | enteringOffsetMask, coordinateCount_);
128 }
129
131 friend bool operator==(const BinaryVisibilityState& lhs, const BinaryVisibilityState& rhs) = default;
132
133 private:
135 struct UncheckedConstructionTag {};
136
142 BinaryVisibilityState(UncheckedConstructionTag, std::uint32_t bits, std::size_t coordinateCount) noexcept
143 : bits_(bits), coordinateCount_(coordinateCount) {}
144
145 std::uint32_t bits_ = 0;
146 std::size_t coordinateCount_ = 0;
147
148 friend struct detail::BinaryVisibilityStateAccess;
149};
150
154 std::uint32_t enteringOffsetMask = 0;
155
157 friend bool operator==(const AnchoredEntryMask& lhs, const AnchoredEntryMask& rhs) = default;
158};
159
162 public:
164 AnchoredEntryMap(PixelId anchorPixel, std::vector<std::optional<NodeId>> entries) : anchorPixel_(anchorPixel), entries_(std::move(entries)) {}
165
167 [[nodiscard]] PixelId anchorPixel() const noexcept { return anchorPixel_; }
169 [[nodiscard]] std::size_t size() const noexcept { return entries_.size(); }
171 [[nodiscard]] const std::optional<NodeId>& operator[](std::size_t coordinate) const noexcept { return entries_[coordinate]; }
173 [[nodiscard]] std::span<const std::optional<NodeId>> entries() const noexcept { return entries_; }
174
175 private:
176 PixelId anchorPixel_ = InvalidPixel;
177 std::vector<std::optional<NodeId>> entries_;
178};
179
180using AnchorBranch = std::vector<NodeId>;
181using AnchoredEntrySet = std::set<NodeId>;
182using OrderedAnchoredEntries = std::vector<AnchoredEntryMask>;
183
185template <class Value> struct EventDelta {
189
191 friend bool operator==(const EventDelta& lhs, const EventDelta& rhs) = default;
192};
193
195template <class Value> struct LocalAttributeIncrement {
198
200 friend bool operator==(const LocalAttributeIncrement& lhs, const LocalAttributeIncrement& rhs) = default;
201};
202
204template <class Value> struct NodeAttribute {
207
209 friend bool operator==(const NodeAttribute& lhs, const NodeAttribute& rhs) = default;
210};
211
213template <class Decision>
214concept LocalDecision = requires(const Decision& decision, BinaryVisibilityState state) {
215 typename Decision::Value;
216 { decision.evaluateLocalDecision(state) } -> std::same_as<typename Decision::Value>;
217};
218
220template <class Algebra, class Value>
221concept EventAlgebra = requires(const Algebra& algebra, Value& target, const Value& source) {
222 { algebra.additiveIdentity() } -> std::same_as<Value>;
223 { algebra.addAssign(target, source) } -> std::same_as<void>;
224 { algebra.subtractAssign(target, source) } -> std::same_as<void>;
225};
226
227} // namespace mmcfilters::local_attributes
constexpr NodeId InvalidNode
Sentinel value used to denote an invalid node identifier.
Definition Common.hpp:34
constexpr PixelId InvalidPixel
Sentinel value used to denote an invalid pixel identifier.
Definition Common.hpp:43
Window-coordinate map whose missing entries represent out-of-domain samples.
std::span< const std::optional< NodeId > > entries() const noexcept
Returns every coordinate entry.
const std::optional< NodeId > & operator[](std::size_t coordinate) const noexcept
Returns one coordinate entry.
std::size_t size() const noexcept
Returns the coordinate count.
PixelId anchorPixel() const noexcept
Returns the anchor pixel.
AnchoredEntryMap(PixelId anchorPixel, std::vector< std::optional< NodeId > > entries)
Builds a coordinate-preserving map.
Binary sample-visibility vector encoded in observation-window order.
BinaryVisibilityState withEnteringOffsets(std::uint32_t enteringOffsetMask) const
Returns a state with additional coordinates visible.
bool isVisible(std::size_t coordinate) const
Tests one visibility coordinate.
std::uint32_t bits() const noexcept
Returns the visibility mask.
friend bool operator==(const BinaryVisibilityState &lhs, const BinaryVisibilityState &rhs)=default
Compares visibility masks and coordinate domains.
std::size_t coordinateCount() const noexcept
Returns the coordinate domain size.
BinaryVisibilityState(std::uint32_t bits, std::size_t coordinateCount)
Builds a validated binary state.
Indexed finite set of translated-sample offsets.
ObservationWindow(std::vector< WindowOffset > offsets)
Builds and validates a window.
const WindowOffset & operator[](std::size_t index) const noexcept
Returns one offset without bounds checking.
std::span< const WindowOffset > offsets() const noexcept
Returns all ordered offsets.
ObservationWindow(const std::array< WindowOffset, N > &offsets)
Builds and validates a fixed-size window.
auto end() const noexcept
Returns the past-the-end offset iterator.
ObservationWindow(std::initializer_list< WindowOffset > offsets)
Builds and validates a window.
std::size_t size() const noexcept
Returns the number of offsets.
static constexpr std::size_t maxNumOffsets
Maximum number of offsets representable by one visibility bit mask.
auto begin() const noexcept
Returns the first offset iterator.
Additive event algebra kept separate from the local decision.
Pure local decision from a binary visibility state to one value.
Owning result for one computed scalar attribute layout and buffer.
One inclusion node and the observation coordinates that enter there.
friend bool operator==(const AnchoredEntryMask &lhs, const AnchoredEntryMask &rhs)=default
Compares node and coordinate mask.
std::uint32_t enteringOffsetMask
Coordinates entering at node.
One anchor-specific signed change attached to an anchored entry.
NodeId anchoredEntry
Node where the new coordinates enter.
friend bool operator==(const EventDelta &lhs, const EventDelta &rhs)=default
Compares every event field.
PixelId anchorPixel
Anchor whose local state changed.
Value value
Signed decision difference.
Sum of anchor-specific event deltas attached directly to one node.
friend bool operator==(const LocalAttributeIncrement &lhs, const LocalAttributeIncrement &rhs)=default
Compares node and increment value.
Final bottom-up aggregated attribute value for one node.
friend bool operator==(const NodeAttribute &lhs, const NodeAttribute &rhs)=default
Compares node and attribute value.
Relative row-column offset of one translated local sample.