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