EqualityFilter.cpp
Go to the documentation of this file.
1#include "EqualityFilter.h"
2
3#include <list>
4
5#include <IceUtil/Time.h>
6
8
17
19
21{
22 bool
24 {
25 // Thread safety: lock the filter mutex for all mutable state access
26 std::lock_guard<std::mutex> lock(filterMutex_);
27
28 //ARMARX_INFO << "Equality filtering!!!";
29
30 auto start = std::chrono::high_resolution_clock::now();
31
32 const std::string entityId = e.id().getEntityID().str();
33 auto it = lastAcceptedSnapshots.find(entityId);
34
35 // accepting if entityId occurs for the first time
36 if (it == lastAcceptedSnapshots.end())
37 {
38 lastAcceptedSnapshots.emplace(entityId, e);
39 stats.accepted++;
40 auto end = std::chrono::high_resolution_clock::now();
41 stats.end_time = end;
42 stats.additional_time += (end - start);
43 return true;
44 }
45
46 const armem::wm::EntitySnapshot& oldSnapshot = it->second;
47 bool isEqual = checkSnapshotEquality(oldSnapshot, e);
48
49 // equalsDeep() can instead be used to compare the snapshots with less flexibility
50 // bool isEqual = it->second.equalsDeep(e);
51
52 if (isEqual)
53 {
54 stats.rejected++;
55 }
56 else
57 {
58 it->second = e;
59 stats.accepted++;
60 }
61 auto end = std::chrono::high_resolution_clock::now();
62 stats.end_time = end;
63 stats.additional_time += (end - start);
64
65 return !isEqual;
66 }
67
68 bool
69 SnapshotEqualityFilter::checkSnapshotEquality(
70 const armem::wm::EntitySnapshot& oldSnapshot,
71 const armem::wm::EntitySnapshot& newSnapshot)
72 {
73 // load instances into vectors and compare each assuming order of instances
74 // and data inside them stays the same
75 std::vector<aron::data::VariantPtr> oldInstances;
76 std::vector<aron::data::VariantPtr> newInstances;
77
78 oldSnapshot.forEachInstance(
79 [&oldInstances](armem::wm::EntityInstance& i)
80 {
81 oldInstances.push_back(i.data());
82 }
83 );
84
85 newSnapshot.forEachInstance(
86 [&newInstances](armem::wm::EntityInstance& i)
87 {
88 newInstances.push_back(i.data());
89 }
90 );
91
92 if (oldInstances.size() != newInstances.size())
93 {
94 return false;
95 }
96
97 for (size_t i = 0; i < newInstances.size(); i++)
98 {
99 if (!checkInstanceEquality(oldInstances[i], newInstances[i]))
100 {
101 return false;
102 }
103 }
104 return true;
105 }
106
107 bool
108 SnapshotEqualityFilter::checkInstanceEquality(
109 const aron::data::VariantPtr& oldData,
110 const aron::data::VariantPtr& newData)
111 {
112 if (!oldData && !newData)
113 {
114 return true;
115 }
116 if (!oldData || !newData)
117 {
118 //ARMARX_INFO << "nullptr in filtering";
119 return false;
120 }
121
122 // if importance is set and zero, ignore value changes
123 bool zeroImportanceOld = oldData
124 && oldData->getImportance().has_value()
125 && *oldData->getImportance() == 0.f;
126 bool zeroImportanceNew = newData
127 && newData->getImportance().has_value()
128 && *newData->getImportance() == 0.f;
129 if (zeroImportanceOld || zeroImportanceNew)
130 {
131 return true;
132 }
133
134 auto oldDesc = oldData->getDescriptor();
135 auto newDesc = newData->getDescriptor();
137 //ARMARX_INFO << desc_string;
138
139 if (oldDesc != newDesc)
140 {
141 return false;
142 }
143
144 // comparison can be extended for new types
145 // recursive in case of containers, LIST is order-sensitive
146 switch(newDesc)
147 {
149 {
150 auto oldInt = aron::data::Int::DynamicCastAndCheck(oldData);
151 auto newInt = aron::data::Int::DynamicCastAndCheck(newData);
152 return *oldInt == *newInt;
153 }
155 {
156 auto oldFloat = aron::data::Float::DynamicCastAndCheck(oldData);
157 auto newFloat = aron::data::Float::DynamicCastAndCheck(newData);
158 return *oldFloat == *newFloat;
159 }
161 {
162 auto oldDouble = aron::data::Double::DynamicCastAndCheck(oldData);
163 auto newDouble = aron::data::Double::DynamicCastAndCheck(newData);
164 return *oldDouble == *newDouble;
165 }
167 {
168 auto oldLong = aron::data::Long::DynamicCastAndCheck(oldData);
169 auto newLong = aron::data::Long::DynamicCastAndCheck(newData);
170 return *oldLong == *newLong;
171 }
173 {
174 auto oldString = aron::data::String::DynamicCastAndCheck(oldData);
175 auto newString = aron::data::String::DynamicCastAndCheck(newData);
176 return *oldString == *newString;
177 }
179 {
180 auto oldBool = aron::data::Bool::DynamicCastAndCheck(oldData);
181 auto newBool = aron::data::Bool::DynamicCastAndCheck(newData);
182 return *oldBool == *newBool;
183 }
185 {
186 auto oldNdarr = aron::data::NDArray::DynamicCastAndCheck(oldData);
187 auto newNdarr = aron::data::NDArray::DynamicCastAndCheck(newData);
188 return *oldNdarr == *newNdarr;
189 }
191 {
192 auto oldList = aron::data::List::DynamicCastAndCheck(oldData);
193 auto newList = aron::data::List::DynamicCastAndCheck(newData);
194 const auto& oldElems = oldList->getElements();
195 const auto& newElems = newList->getElements();
196
197 if (oldElems.size() != newElems.size())
198 {
199 return false;
200 }
201
202 for (size_t i = 0; i < newElems.size(); i++)
203 {
204 if (!checkInstanceEquality(oldElems[i], newElems[i]))
205 {
206 return false;
207 }
208 }
209 return true;
210 }
212 {
213 auto oldDict = aron::data::Dict::DynamicCastAndCheck(oldData);
214 auto newDict = aron::data::Dict::DynamicCastAndCheck(newData);
215 auto oldKeys = oldDict->getAllKeys();
216 auto newKeys = newDict->getAllKeys();
217
218 if (oldKeys.size() != newKeys.size())
219 {
220 return false;
221 }
222
223 for (const auto& key : newKeys)
224 {
225 if (!oldDict->hasElement(key))
226 {
227 return false;
228 }
229 if (!checkInstanceEquality(oldDict->at(key), newDict->at(key)))
230 {
231 return false;
232 }
233 }
234 return true;
235 }
236 default:
237 {
238 ARMARX_INFO << "data-type not yet supported.";
239 return false; // maybe adjust
240 }
241 }
242 return false;
243
244 }
245
246
247 void
248 SnapshotEqualityFilter::configure(const nlohmann::json& json)
249 {
250 std::lock_guard<std::mutex> lock(filterMutex_);
251
252 stats.start_time = std::chrono::high_resolution_clock::now();
253 }
254
257 {
258 std::lock_guard<std::mutex> lock(filterMutex_);
259 return stats;
260 }
261
262 std::string
264 {
265 return this->NAME;
266 }
267
268} // namespace armarx::armem::server::ltm::processor::filter
std::string str(bool escapeDelimiters=true) const
Get a string representation of this memory ID.
Definition MemoryID.cpp:102
MemoryID getEntityID() const
Definition MemoryID.cpp:310
bool forEachInstance(InstanceFunctionT &&func)
std::mutex filterMutex_
Mutex for thread-safe access to filter state (stats and derived class state) Derived classes should l...
Definition Filter.h:61
virtual bool accept(const armem::wm::EntitySnapshot &e, bool simulatedVersion) override
Client-side working entity instance.
Client-side working memory entity snapshot.
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:179
const std::map< data::Descriptor, std::string > Descriptor2String
Definition Descriptor.h:207
std::shared_ptr< Variant > VariantPtr