Processors.cpp
Go to the documentation of this file.
1#include "Processors.h"
2
4#include <ArmarXCore/interface/core/UserException.h>
5
13
15{
16 std::vector<std::unique_ptr<processor::SnapshotFilter>>
17 Processors::buildSnapshotFilters(const nlohmann::json& config)
18 {
19 std::vector<std::unique_ptr<processor::SnapshotFilter>> filters;
21 {
22 ARMARX_IMPORTANT << "ADDING SNAPSHOT FREQUENCY FILTER";
23 auto f = std::make_unique<processor::filter::SnapshotFrequencyFilter>();
25 filters.push_back(std::move(f));
26 }
28 {
29 ARMARX_IMPORTANT << "ADDING SNAPSHOT SIMILARITY FILTER";
30 auto f = std::make_unique<processor::filter::SnapshotSimilarityFilter>();
32 filters.push_back(std::move(f));
33 }
35 {
36 ARMARX_IMPORTANT << "ADDING SNAPSHOT IMPORTANCE FILTER";
37 auto f = std::make_unique<processor::filter::SnapshotImportanceFilter>();
39 filters.push_back(std::move(f));
40 }
41 return filters;
42 }
43
44 void
45 Processors::configure(const nlohmann::json& config)
46 {
47 // Global / default snapshot filters:
48 snapFilters = buildSnapshotFilters(config);
49
50 // Segment whitelist: which segments to store. Absent => store all segments.
51 storeSegments.reset();
52 if (config.contains("storeSegments"))
53 {
54 std::set<std::string> whitelist;
55 for (const auto& entry : config["storeSegments"])
56 {
57 whitelist.insert(entry.get<std::string>());
58 }
59 ARMARX_IMPORTANT << "LTM storeSegments whitelist active with " << whitelist.size()
60 << " entries";
61 storeSegments = std::move(whitelist);
62 }
63
64 // Per-segment snapshot filter overrides, keyed by "Core" or "Core/Provider".
65 segmentSnapFilters.clear();
66 if (config.contains("segments"))
67 {
68 for (const auto& [segmentPath, segmentConfig] : config["segments"].items())
69 {
70 ARMARX_IMPORTANT << "ADDING PER-SEGMENT FILTERS FOR " << segmentPath;
71 segmentSnapFilters[segmentPath] = buildSnapshotFilters(segmentConfig);
72 }
73 }
74
75 // Converters
77 {
78 ARMARX_IMPORTANT << "ADDING IMG CONVERTER PNG";
79 auto f = std::make_unique<processor::converter::data::image::PngConverter>();
81 converters.push_back(std::move(f));
82 }
84 {
85 ARMARX_IMPORTANT << "ADDING IMG CONVERTER EXR";
86 auto f = std::make_unique<processor::converter::data::image::ExrConverter>();
88 converters.push_back(std::move(f));
89 }
90 }
91
92 bool
94 {
95 return storeSegments.has_value() || !segmentSnapFilters.empty();
96 }
97
98 bool
99 Processors::isSegmentWhitelisted(const std::string& coreSegmentName,
100 const std::string& providerSegmentName) const
101 {
102 if (!storeSegments.has_value())
103 {
104 // No whitelist configured => store all segments.
105 return true;
106 }
107 const auto& whitelist = *storeSegments;
108 // A core segment is admitted either by its core-segment name or by the
109 // specific provider-segment path.
110 if (whitelist.count(coreSegmentName) > 0)
111 {
112 return true;
113 }
114 if (!providerSegmentName.empty() &&
115 whitelist.count(coreSegmentName + "/" + providerSegmentName) > 0)
116 {
117 return true;
118 }
119 return false;
120 }
121
122 bool
123 Processors::acceptSnapshotForSegment(const std::string& coreSegmentName,
124 const std::string& providerSegmentName,
125 const armem::wm::EntitySnapshot& snapshot,
126 bool simulatedVersion)
127 {
128 // 1. Whitelist: reject snapshots of segments that are not selected for storage.
129 if (!isSegmentWhitelisted(coreSegmentName, providerSegmentName))
130 {
131 return false;
132 }
133
134 // 2. Pick the applicable filter set: provider-specific override, else core-segment
135 // override, else the global filters.
136 const std::string providerPath = coreSegmentName + "/" + providerSegmentName;
137 std::vector<std::unique_ptr<processor::SnapshotFilter>>* filters = &snapFilters;
138 if (auto it = segmentSnapFilters.find(providerPath); it != segmentSnapFilters.end())
139 {
140 filters = &it->second;
141 }
142 else if (auto cit = segmentSnapFilters.find(coreSegmentName);
143 cit != segmentSnapFilters.end())
144 {
145 filters = &cit->second;
146 }
147
148 for (auto& filter : *filters)
149 {
150 if (!filter->accept(snapshot, simulatedVersion))
151 {
152 return false;
153 }
154 }
155 return true;
156 }
157
158 std::map<std::string, processor::SnapshotFilter::FilterStatistics>
160 {
161 std::map<std::string, processor::SnapshotFilter::FilterStatistics> stats;
162 bool recordedOverall = false;
163 std::size_t numFilters = snapFilters.size();
164
165 auto collect = [&](const std::string& keyPrefix,
166 const std::vector<std::unique_ptr<processor::SnapshotFilter>>& filters)
167 {
168 for (const auto& filter_ptr : filters)
169 {
170 auto statistics = filter_ptr->getFilterStatistics();
171 auto recorded = statistics.accepted + statistics.rejected;
172 stats[keyPrefix + filter_ptr->getName()] = statistics;
173 if (recorded > 0)
174 {
175 recordedOverall = true;
176 }
177 }
178 };
179
180 collect("", snapFilters);
181 for (const auto& [segmentPath, filters] : segmentSnapFilters)
182 {
183 numFilters += filters.size();
184 collect(segmentPath + ":", filters);
185 }
186
187 ARMARX_INFO << "Number of active filters: " << numFilters;
188
189 // Only complain about empty statistics if there actually are filters configured.
190 // With a pure segment whitelist (and no filters), recording nothing is expected.
191 if (numFilters > 0 && !recordedOverall)
192 {
193 throw InvalidArgumentException(
194 "NoFilters recorded any data being accepted or rejected, "
195 "cant store empty statistics");
196 }
197 return stats;
198 }
199
200 void
202 {
203 ARMARX_DEBUG << "Resetting statistics for filters";
204 for (const auto& filter_ptr : this->snapFilters)
205 {
206 filter_ptr->resetStatisticsForNewEpisode();
207 }
208 for (const auto& [segmentPath, filters] : this->segmentSnapFilters)
209 {
210 for (const auto& filter_ptr : filters)
211 {
212 filter_ptr->resetStatisticsForNewEpisode();
213 }
214 }
215 }
216} // namespace armarx::armem::server::ltm
std::vector< std::unique_ptr< processor::SnapshotFilter > > snapFilters
Definition Processors.h:77
std::optional< std::set< std::string > > storeSegments
Optional whitelist of segments to store.
Definition Processors.h:81
void configure(const nlohmann::json &config)
std::vector< std::unique_ptr< processor::DataConverter > > converters
Definition Processors.h:92
bool acceptSnapshotForSegment(const std::string &coreSegmentName, const std::string &providerSegmentName, const armem::wm::EntitySnapshot &snapshot, bool simulatedVersion=false)
Decide whether a snapshot of the given segment should be stored to LTM.
std::map< std::string, std::vector< std::unique_ptr< processor::SnapshotFilter > > > segmentSnapFilters
Per-segment snapshot filter overrides, keyed by "CoreSegment" or "CoreSegment/ProviderSegment".
Definition Processors.h:86
std::map< std::string, processor::SnapshotFilter::FilterStatistics > getSnapshotFilterStatistics()
bool hasSegmentSelection() const
Whether any segment-based selection or per-segment filtering is configured.
void resetFilterStatisticsForNewEpisode()
resetFilterStatisticsForNewEpisode runs resetFilterStatisticsForNewEpisode on all snapshot filters
Client-side working memory entity snapshot.
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:190
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:184