SOLA
Loading...
Searching...
No Matches
boolean_expression.h
1// Copyright The SOLA Contributors
2//
3// Licensed under the MIT License.
4// For details on the licensing terms, see the LICENSE file.
5// SPDX-License-Identifier: MIT
6
7#ifndef MINHTON_ALGORITHMS_ESEARCH_BOOLEAN_EXPRESSION_H_
8#define MINHTON_ALGORITHMS_ESEARCH_BOOLEAN_EXPRESSION_H_
9
10#include <memory>
11#include <vector>
12
13#include "minhton/algorithms/esearch/evaluation_information.h"
14#include "minhton/algorithms/esearch/fuzzy_value.h"
15#include "minhton/algorithms/esearch/node_data.h"
16
17namespace minhton {
18
19// TODO move into numeric comparison expression
20enum class ComparisonTypes {
21 kEqualTo,
22 kNotEqualTo,
23 kLessThan,
24 kGreater,
25 kLessThanOrEqualTo,
26 kGreaterThanOrEqualTo
27};
28
30public:
31 virtual ~BooleanExpression() = default;
32 virtual FuzzyValue evaluate(NodeData &data, const EvaluationInformation &eval_info) = 0;
33
34 virtual std::vector<NodeData::Key> evaluateMissingAttributes(
35 NodeData &data, const EvaluationInformation &eval_info) const = 0;
36
37 virtual std::vector<NodeData::Key> getRelevantKeys() const = 0;
38 virtual std::vector<NodeData::Key> getRelevantTopicKeys() const = 0;
39
40 virtual uint8_t getDepth() = 0;
41
42 virtual std::string serialize() = 0;
43};
44
46public:
47 explicit AtomicBooleanExpression(NodeData::Key key) : key_(std::move(key)){};
48
49 ~AtomicBooleanExpression() override = default;
50
51 std::vector<NodeData::Key> evaluateMissingAttributes(
52 NodeData &data, const EvaluationInformation &eval_info) const override {
53 if (eval_info.inquire_unknown_attributes && eval_info.inquire_outdated_attributes) {
54 // if we do not have the key, or its outdated, we inquire
55 if (!data.hasKey(key_) ||
56 !data.isValueUpToDate(key_, eval_info.validity_threshold_timestamp)) {
57 return {key_};
58 }
59 return {};
60 }
61
62 if (eval_info.inquire_unknown_attributes && !eval_info.inquire_outdated_attributes) {
63 // if we have the key, we dont have to do anything
64 // if we do not have the key, we inquire
65 if (!data.hasKey(key_)) {
66 return {key_};
67 }
68 return {};
69 }
70
71 if (!eval_info.inquire_unknown_attributes && eval_info.inquire_outdated_attributes) {
72 // if we have the key, we inquire outdated
73 // if we do not have the key, we do not inquire
74 if (data.hasKey(key_) &&
75 !data.isValueUpToDate(key_, eval_info.validity_threshold_timestamp)) {
76 return {key_};
77 }
78 return {};
79 }
80
81 if (!eval_info.inquire_unknown_attributes && !eval_info.inquire_outdated_attributes) {
82 // not inquiring anything
83 return {};
84 }
85
86 throw std::logic_error("should not be reached");
87 }
88
89 FuzzyValue evaluate(NodeData &data, const EvaluationInformation &eval_info) override {
90 if (data.isLocal()) {
91 return evaluateExisting(data, eval_info);
92 }
93
94 if (!data.hasKey(key_)) {
95 if (!eval_info.all_information_present && eval_info.inquire_unknown_attributes) {
96 return FuzzyValue::createUndecided();
97 }
98 return FuzzyValue::createFalse();
99 }
100
101 // we have the key
102
103 if (eval_info.inquire_outdated_attributes &&
104 !data.isValueUpToDate(key_, eval_info.validity_threshold_timestamp)) {
105 if (eval_info.all_information_present) {
106 return FuzzyValue::createFalse();
107 }
108 return FuzzyValue::createUndecided();
109 }
110
111 // the value is up to date, or we do not care about whether the value is up to date or not
112 FuzzyValue value = evaluateExisting(data, eval_info);
113 if (value.isUndecided() && !eval_info.inquire_outdated_attributes && eval_info.permissive) {
114 return FuzzyValue::createTrue();
115 }
116
117 return value;
118 }
119
120 virtual FuzzyValue evaluateExisting(NodeData &data, const EvaluationInformation &eval_info) = 0;
121
122 uint8_t getDepth() override { return 1; }
123
124protected:
125 NodeData::Key key_;
126};
127
129public:
130 explicit OrExpression(std::shared_ptr<BooleanExpression> expr1,
131 std::shared_ptr<BooleanExpression> expr2)
132 : expr1_(std::move(expr1)), expr2_(std::move(expr2)){};
133
134 ~OrExpression() override = default;
135
136 FuzzyValue evaluate(NodeData &data, const EvaluationInformation &eval_info) override {
137 return expr1_->evaluate(data, eval_info) || expr2_->evaluate(data, eval_info);
138 }
139
140 std::vector<NodeData::Key> evaluateMissingAttributes(
141 NodeData &data, const EvaluationInformation &eval_info) const override {
142 EvaluationInformation eval_info_c = eval_info;
143 eval_info_c.all_information_present = false;
144
145 auto expr1_eval = expr1_->evaluate(data, eval_info_c);
146 auto expr2_eval = expr2_->evaluate(data, eval_info_c);
147
148 if (expr1_eval.isTrue() || expr2_eval.isTrue()) {
149 return {};
150 }
151
152 auto missings = expr1_->evaluateMissingAttributes(data, eval_info_c);
153 auto temp_missings = expr2_->evaluateMissingAttributes(data, eval_info_c);
154 missings.insert(missings.end(), temp_missings.begin(), temp_missings.end());
155 return missings;
156 }
157
158 std::vector<NodeData::Key> getRelevantKeys() const override {
159 auto relevants = expr1_->getRelevantKeys();
160 auto temp_relevants = expr2_->getRelevantKeys();
161 relevants.insert(relevants.end(), temp_relevants.begin(), temp_relevants.end());
162 return relevants;
163 }
164
165 std::vector<NodeData::Key> getRelevantTopicKeys() const override {
166 auto relevants = expr1_->getRelevantTopicKeys();
167 auto temp_relevants = expr2_->getRelevantTopicKeys();
168 relevants.insert(relevants.end(), temp_relevants.begin(), temp_relevants.end());
169 return relevants;
170 }
171
172 std::string serialize() override {
173 return "( " + expr1_->serialize() + " OR " + expr2_->serialize() + " )";
174 }
175
176 uint8_t getDepth() override { return expr1_->getDepth() + expr2_->getDepth(); }
177
178private:
179 std::shared_ptr<BooleanExpression> expr1_;
180 std::shared_ptr<BooleanExpression> expr2_;
181};
182
184public:
185 explicit AndExpression(std::shared_ptr<BooleanExpression> expr1,
186 std::shared_ptr<BooleanExpression> expr2)
187 : expr1_(std::move(expr1)), expr2_(std::move(expr2)){};
188
189 ~AndExpression() override = default;
190
191 FuzzyValue evaluate(NodeData &data, const EvaluationInformation &eval_info) override {
192 return expr1_->evaluate(data, eval_info) && expr2_->evaluate(data, eval_info);
193 }
194
195 std::vector<NodeData::Key> evaluateMissingAttributes(
196 NodeData &data, const EvaluationInformation &eval_info) const override {
197 auto missings = expr1_->evaluateMissingAttributes(data, eval_info);
198 auto temp_missings = expr2_->evaluateMissingAttributes(data, eval_info);
199 missings.insert(missings.end(), temp_missings.begin(), temp_missings.end());
200 return missings;
201 }
202
203 std::vector<NodeData::Key> getRelevantKeys() const override {
204 auto relevants = expr1_->getRelevantKeys();
205 auto temp_relevants = expr2_->getRelevantKeys();
206 relevants.insert(relevants.end(), temp_relevants.begin(), temp_relevants.end());
207 return relevants;
208 }
209
210 std::vector<NodeData::Key> getRelevantTopicKeys() const override {
211 auto relevants = expr1_->getRelevantTopicKeys();
212 auto temp_relevants = expr2_->getRelevantTopicKeys();
213 relevants.insert(relevants.end(), temp_relevants.begin(), temp_relevants.end());
214 return relevants;
215 }
216
217 std::string serialize() override {
218 return "( " + expr1_->serialize() + " AND " + expr2_->serialize() + " )";
219 }
220
221 uint8_t getDepth() override { return expr1_->getDepth() + expr2_->getDepth(); }
222
223private:
224 std::shared_ptr<BooleanExpression> expr1_;
225 std::shared_ptr<BooleanExpression> expr2_;
226};
227
229public:
230 explicit NotExpression(std::shared_ptr<BooleanExpression> expr) : expr_(std::move(expr)){};
231
232 ~NotExpression() override = default;
233
234 FuzzyValue evaluate(NodeData &data, const EvaluationInformation &eval_info) override {
235 auto val_pos = expr_->evaluate(data, eval_info);
236 auto val_neg = !val_pos;
237 return val_neg;
238 }
239
240 std::vector<NodeData::Key> evaluateMissingAttributes(
241 NodeData &data, const EvaluationInformation &eval_info) const override {
242 return expr_->evaluateMissingAttributes(data, eval_info);
243 }
244
245 std::vector<NodeData::Key> getRelevantKeys() const override { return expr_->getRelevantKeys(); }
246 std::vector<NodeData::Key> getRelevantTopicKeys() const override {
247 return expr_->getRelevantTopicKeys();
248 }
249
250 std::string serialize() override { return "( NOT " + expr_->serialize() + " )"; }
251
252 uint8_t getDepth() override { return expr_->getDepth(); }
253
254private:
255 std::shared_ptr<BooleanExpression> expr_;
256};
257
259public:
260 explicit PresenceExpression(const NodeData::Key &key) : AtomicBooleanExpression(key){};
261
262 ~PresenceExpression() override = default;
263
264 FuzzyValue evaluateExisting(NodeData &data,
265 [[maybe_unused]] const EvaluationInformation &eval_info) override {
266 if (!data.hasKey(key_)) {
267 return FuzzyValue::createFalse();
268 }
269
270 auto variant = data.getValue(key_);
271 auto pval = std::get_if<bool>(&variant);
272 if (pval != nullptr) {
273 // if value is bool, return value converted to fuzzy value
274 return *pval ? FuzzyValue::createTrue() : FuzzyValue::createFalse();
275 }
276 return FuzzyValue::createTrue();
277 }
278
279 std::vector<NodeData::Key> getRelevantKeys() const override { return {key_}; }
280 std::vector<NodeData::Key> getRelevantTopicKeys() const override { return {key_}; }
281
282 std::string serialize() override { return "( HAS " + key_ + " )"; }
283};
284
286public:
287 explicit StringEqualityExpression(const NodeData::Key &key, std::string value)
288 : AtomicBooleanExpression(key), value_(std::move(value)){};
289
290 ~StringEqualityExpression() override = default;
291
292 FuzzyValue evaluateExisting(NodeData &data,
293 [[maybe_unused]] const EvaluationInformation &eval_info) override {
294 if (!data.hasKey(key_)) {
295 return FuzzyValue::createFalse();
296 }
297 NodeData::Value variant = data.getValue(key_);
298 auto pval = std::get_if<std::string>(&variant);
299 if (pval != nullptr) {
300 if ((*pval) == value_) {
301 return FuzzyValue::createTrue();
302 }
303 }
304
305 return FuzzyValue::createFalse();
306 }
307
308 std::vector<NodeData::Key> getRelevantKeys() const override { return {key_}; }
309 std::vector<NodeData::Key> getRelevantTopicKeys() const override { return {}; }
310
311 std::string serialize() override { return "( " + key_ + " == " + value_ + " )"; }
312
313private:
314 std::string value_;
315};
316
317template <typename NumericType> class NumericComparisonExpression : public AtomicBooleanExpression {
318 static_assert(std::is_same_v<NumericType, int> || std::is_same_v<NumericType, float>,
319 "NumericType must be int or float");
320
321public:
322 explicit NumericComparisonExpression(NodeData::Key key, ComparisonTypes comparison_type,
323 NumericType comparison_value)
325 comparison_type_(comparison_type),
326 comparison_value_(comparison_value){};
327
328 ~NumericComparisonExpression() override = default;
329
330 FuzzyValue evaluateExisting(NodeData &data,
331 [[maybe_unused]] const EvaluationInformation &eval_info) override {
332 if (!data.hasKey(key_)) return FuzzyValue::createFalse();
333
334 NodeData::Value variant = data.getValue(key_);
335
336 bool comparison = false;
337 bool compared = false;
338
339 try {
340 int int_value = std::get<int>(variant);
341 comparison = applyComparison<int>(int_value);
342 compared = true;
343 } catch (std::bad_variant_access const &ex) {
344 }
345
346 if (!compared) {
347 try {
348 float float_value = std::get<float>(variant);
349 comparison = applyComparison<float>(float_value);
350 compared = true;
351 } catch (std::bad_variant_access const &ex) {
352 }
353 }
354
355 if (compared) {
356 if (comparison) {
357 return FuzzyValue::createTrue();
358 }
359 return FuzzyValue::createFalse();
360 }
361 throw std::invalid_argument("Could not compare");
362 }
363
364 std::vector<NodeData::Key> getRelevantKeys() const override { return {key_}; }
365 std::vector<NodeData::Key> getRelevantTopicKeys() const override { return {}; }
366
367 std::string serialize() override {
368 std::string comp_str;
369 switch (comparison_type_) {
370 case ComparisonTypes::kEqualTo:
371 comp_str = "==";
372 break;
373 case ComparisonTypes::kGreater:
374 comp_str = ">";
375 break;
376 case ComparisonTypes::kGreaterThanOrEqualTo:
377 comp_str = ">=";
378 break;
379 case ComparisonTypes::kLessThan:
380 comp_str = "<";
381 break;
382 case ComparisonTypes::kLessThanOrEqualTo:
383 comp_str = "<=";
384 break;
385 case ComparisonTypes::kNotEqualTo:
386 comp_str = "!=";
387 break;
388 }
389
390 return "( " + key_ + " " + comp_str + " " + std::to_string(comparison_value_) + " )";
391 }
392
393private:
394 ComparisonTypes comparison_type_;
395 NumericType comparison_value_;
396
397 template <typename OtherNumericType> bool applyComparison(OtherNumericType evaluation_value) {
398 static_assert(std::is_arithmetic<OtherNumericType>::value, "OtherNumericType must be numeric");
399
400 switch (comparison_type_) {
401 case ComparisonTypes::kEqualTo: {
402 return evaluation_value == comparison_value_;
403 }
404 case ComparisonTypes::kNotEqualTo: {
405 return evaluation_value != comparison_value_;
406 }
407 case ComparisonTypes::kLessThan: {
408 return evaluation_value < comparison_value_;
409 }
410 case ComparisonTypes::kGreater: {
411 return evaluation_value > comparison_value_;
412 }
413 case ComparisonTypes::kLessThanOrEqualTo: {
414 return evaluation_value <= comparison_value_;
415 }
416 case ComparisonTypes::kGreaterThanOrEqualTo: {
417 return evaluation_value >= comparison_value_;
418 }
419 }
420
421 return false;
422 }
423};
424
426public:
427 explicit EmptyExpression() = default;
428 ~EmptyExpression() override = default;
429
430 FuzzyValue evaluate([[maybe_unused]] NodeData &data,
431 [[maybe_unused]] const EvaluationInformation &eval_info) override {
432 return FuzzyValue::createTrue();
433 }
434
435 std::vector<NodeData::Key> evaluateMissingAttributes(
436 [[maybe_unused]] NodeData &data,
437 [[maybe_unused]] const EvaluationInformation &eval_info) const override {
438 return {};
439 }
440
441 std::vector<NodeData::Key> getRelevantKeys() const override { return {}; }
442 std::vector<NodeData::Key> getRelevantTopicKeys() const override { return {}; }
443 std::string serialize() override { return "( empty )"; }
444 uint8_t getDepth() override { return 0; }
445};
446
447} // namespace minhton
448
449#endif
Definition boolean_expression.h:183
Definition boolean_expression.h:45
Definition boolean_expression.h:29
Definition boolean_expression.h:425
Definition fuzzy_value.h:14
Definition node_data.h:20
Definition boolean_expression.h:228
Definition boolean_expression.h:317
Definition boolean_expression.h:128
Definition boolean_expression.h:258
Definition boolean_expression.h:285
Definition minhton_watchdog_ns3.cpp:24
Definition evaluation_information.h:12