Ocean
Loading...
Searching...
No Matches
ValidationPrecision.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#ifndef META_OCEAN_TEST_VALIDATION_PRECISION_H
9#define META_OCEAN_TEST_VALIDATION_PRECISION_H
10
11#include "ocean/test/Test.h"
13
15
16#include <cmath>
17
18namespace Ocean
19{
20
21namespace Test
22{
23
24/**
25 * This class implements a helper class to validate the precision of algorithms or objects across multiple iterations.
26 * The main purpose is to allow a configurable percentage of iterations to be imprecise while still considering the overall test as successful.
27 * This class inherits from Validation and extends it with precision-based validation capabilities.
28 * As this class inherits from Validation, the entire validation can also be invalidated using base class methods (e.g., OCEAN_EXPECT_TRUE, OCEAN_SET_FAILED) for errors unrelated to precision.
29 * @see Validation, ScopedIteration.
30 * @ingroup test
31 */
33{
34 public:
35
36 /**
37 * Creates a new scoped iteration representing one iteration in a precision test.
38 * By default each iteration is considered accurate; call setInaccurate() if the iteration is not precise enough.
39 */
41 {
42 public:
43
44 /**
45 * Creates a new scoped iteration associated with a validation object.
46 */
48
49 /**
50 * Destructs this scoped object and forwards the information to the owning validation.
51 */
52 inline ~ScopedIteration();
53
54 /**
55 * Sets this iteration to be not precise enough.
56 */
57 inline void setInaccurate();
58
59 /**
60 * Sets this iteration to be not precise enough.
61 * This function will also write a message to the error log.
62 * @param expected The expected value
63 * @param actual The actual value
64 * @param file The source file in which the function call happens, e.g., __FILE__, must be valid
65 * @param line The line in the source file in which the function call happens, e.g., __LINE__, must be valid
66 * @tparam T The data type of the expected and actual value
67 */
68 template <typename T>
69 inline void setInaccurate(const T& expected, const T& actual, const char* file, const int line);
70
71 protected:
72
73 /**
74 * Disabled default constructor.
75 */
76 ScopedIteration() = delete;
77
78 /**
79 * Disabled copy constructor.
80 */
82
83 /**
84 * Disabled move constructor.
85 */
87
88 protected:
89
90 /// True, if the iteration is accurate; False, if the iteration was not accurate enough.
91 bool accurate_ = true;
92
93 /// The owner of this scoped object.
95 };
96
97 public:
98
99 /**
100 * Creates a new precision-based validation object with specified threshold.
101 * @param threshold The necessary percent of accurate iterations necessary for a successful verification, with range (0, 1]
102 * @param minimumIterations The minimum number of iterations necessary for a successful verification, with range [1, infinity)
103 */
104 explicit inline ValidationPrecision(const double threshold, const unsigned int minimumIterations = 1u);
105
106 /**
107 * Creates a new validation object associated with a random generator, by default the verified has succeeded.
108 * @param threshold The necessary percent of accurate iterations necessary for a successful verification, with range (0, 1]
109 * @param randomGenerator The random generator which will be used during verification
110 */
111 inline ValidationPrecision(const double threshold, RandomGenerator& randomGenerator, const unsigned int minimumIterations = 1u);
112
113 /**
114 * Explicitly adds a new iteration which is either accurate or not.
115 * @param accurate True, if the iteration was precise enough; False, if the iteration was not precise enough
116 * @see ScopedIteration.
117 */
118 inline void addIteration(const bool accurate);
119
120 /**
121 * Explicitly adds new iterations for which the amount of accurate iterations is known.
122 * @param accurateIterations The number of accurate iterations, with range [0, iterations]
123 * @param iterations The number of new iterations, with range [1, infinity)
124 * @see ScopedIteration.
125 */
126 inline void addIterations(const size_t accurateIterations, const size_t iterations);
127
128 /**
129 * Returns the number of iterations in which the precision has been determined.
130 * @return The number of iterations, with range [0, infinity)
131 */
132 inline uint64_t iterations() const;
133
134 /**
135 * Returns the necessary iterations to allow determining success or failure based on the specified success threshold.
136 * @return The number of necessary iterations, with range [1, infinity)
137 */
138 inline uint64_t necessaryIterations() const;
139
140 /**
141 * Returns whether the number of iterations is not yet sufficient to determine a success or failure.
142 * @return True, if more iterations are required
143 */
144 inline bool needMoreIterations() const;
145
146 /**
147 * Returns if this validation has succeeded.
148 * @return True, if so; False, if the validation has failed
149 */
150 [[nodiscard]] inline bool succeeded() const override;
151
152 /**
153 * Returns the accuracy of all iterations.
154 * Beware: Ensure that at least one iteration has been added.
155 * @return The validation's accuracy, in percent, with range [0, 1]
156 */
157 [[nodiscard]] inline double accuracy() const;
158
159 /**
160 * Returns the defined threshold.
161 * @return The validation object's precision threshold, with range [0, 1]
162 */
163 inline double threshold() const;
164
165 /**
166 * Returns whether this validation object has been set to failed explicitly.
167 * This function is intended for internal use only, use succeeded() instead.
168 * @return True, if so
169 * @see succeeded().
170 */
171 [[nodiscard]] inline bool hasSetFailed() const;
172
173 protected:
174
175 /// The necessary percent of accurate iterations necessary for a successful verification, with range (0, 1]
176 double threshold_ = 1.0;
177
178 /// The number of iterations needed to determine success or failure.
179 uint64_t necessaryIterations_ = 0ull;
180
181 /// The overall number of iterations which have been added.
182 uint64_t iterations_ = 0ull;
183
184 /// The number of iterations which were precise enough, with range [0, iterations_]
185 uint64_t accurateIterations_ = 0ull;
186};
187
188#ifndef OCEAN_SET_INACCURATE
189 #define OCEAN_SET_INACCURATE(scopedIteration, ...) scopedIteration.setInaccurate(__VA_ARGS__, __FILE__, __LINE__);
190#endif
191
193 validationPrecision_(ValidationPrecision)
194{
195 // nothing to do here
196}
197
199{
200 validationPrecision_.addIteration(accurate_);
201}
202
204{
205 accurate_ = false;
206}
207
208template <typename T>
209inline void ValidationPrecision::ScopedIteration::setInaccurate(const T& expected, const T& actual, const char* file, const int line)
210{
211 accurate_ = false;
212
213 ocean_assert(file != nullptr);
214 if (file != nullptr)
215 {
216 Log::error() << "ScopedIteration::setInaccurate() in '" << file << "', in line " << line << ": expected " << expected << ", got " << actual << validationPrecision_.randomGeneratorOutput();
217 }
218}
219
220inline ValidationPrecision::ValidationPrecision(const double threshold, const unsigned int minimumIterations)
221{
222 ocean_assert(threshold > 0.0 && threshold <= 1.0);
223
224 if (threshold > 0.0 && threshold <= 1.0)
225 {
227
228 const double failureRate = 1.0 - threshold_;
229 ocean_assert(failureRate > 0.0);
230
231 const double idealIterations = 1.0 / failureRate;
232
233 ocean_assert(idealIterations <= 1000000000u);
234 necessaryIterations_ = std::max(minimumIterations, (unsigned int)(std::ceil(idealIterations) * 2.0));
235 }
236 else
237 {
239 }
240}
241
242inline ValidationPrecision::ValidationPrecision(const double threshold, RandomGenerator& randomGenerator, const unsigned int minimumIterations) :
243 Validation(randomGenerator)
244{
245 ocean_assert(threshold > 0.0 && threshold <= 1.0);
246
247 if (threshold > 0.0 && threshold <= 1.0)
248 {
250
251 const double failureRate = 1.0 - threshold_;
252 ocean_assert(failureRate > 0.0);
253
254 const double idealIterations = 1.0 / failureRate;
255
256 ocean_assert(idealIterations <= 1000000000u);
257 necessaryIterations_ = std::max(minimumIterations, (unsigned int)(std::ceil(idealIterations) * 2.0));
258 }
259 else
260 {
262 }
263}
264
265inline void ValidationPrecision::addIteration(const bool accurate)
266{
267 ++iterations_;
268
269 if (accurate)
270 {
272 }
273}
274
275inline void ValidationPrecision::addIterations(const size_t accurateIterations, const size_t iterations)
276{
277 ocean_assert(accurateIterations <= iterations);
278 ocean_assert(iterations >= 1);
279
280 if (accurateIterations > iterations)
281 {
283 }
284
285 accurateIterations_ += accurateIterations;
287}
288
289inline uint64_t ValidationPrecision::iterations() const
290{
291 return iterations_;
292}
293
295{
296 ocean_assert(necessaryIterations_ >= 1ull);
297
299}
300
302{
303 ocean_assert(necessaryIterations_ >= 1ull);
304
306}
307
309{
310#ifdef OCEAN_DEBUG
311 succeededChecked_ = true;
312#endif
313
314 ocean_assert(threshold_ > 0.0 && threshold_ <= 1.0);
315
316 if (threshold_ <= 0.0 || threshold_ > 1.0)
317 {
318 return false;
319 }
320
321 const double percent = accuracy();
322
323 if (percent < threshold_)
324 {
325#ifdef OCEAN_USE_GTEST
326
327 std::ostream& stream = std::cerr << "\nFAILED with only " << String::toAString(accuracy() * 100.0, 1u) << "%, threshold is " << String::toAString(threshold() * 100.0, 1u) << "%" << randomGeneratorOutput() << "\n";
328
329 if (needMoreIterations())
330 {
331 stream << "Not enough iterations for the specified success threshold (executed " << iterations_ << " of " << necessaryIterations_ << " necessary iterations)\n";
332 }
333
334 stream << std::endl;
335#endif
336 return false;
337 }
338
339 return succeeded_;
340}
341
342[[nodiscard]] inline double ValidationPrecision::accuracy() const
343{
344 ocean_assert(iterations_ != 0ull);
345
346 if (iterations_ == 0u)
347 {
348 return -1.0;
349 }
350
351 ocean_assert(accurateIterations_ <= iterations_);
352
353 const double percent = double(accurateIterations_) / double(iterations_);
354 ocean_assert(percent >= 0.0 && percent <= 1.0);
355
356 return percent;
357}
358
360{
361 return threshold_;
362}
363
364[[nodiscard]] inline bool ValidationPrecision::hasSetFailed() const
365{
366 return succeeded_ == false;
367}
368
369inline std::ostream& operator<<(std::ostream& stream, const ValidationPrecision& validation)
370{
371 if (validation.hasSetFailed())
372 {
373 stream << "FAILED!" << validation.randomGeneratorOutput();
374 }
375 else
376 {
377 if (validation.accuracy() < validation.threshold())
378 {
379 stream << "FAILED with only " << String::toAString(validation.accuracy() * 100.0, 1u) << "%, threshold is " << String::toAString(validation.threshold() * 100.0, 1u) << "%" << validation.randomGeneratorOutput();
380 }
381 else
382 {
383 stream << String::toAString(validation.accuracy() * 100.0, 1u) << "% succeeded.";
384 }
385 }
386
387 return stream;
388}
389
390template <bool tActive>
391MessageObject<tActive>& operator<<(MessageObject<tActive>& messageObject, const ValidationPrecision& validation)
392{
393 if (validation.hasSetFailed())
394 {
395 messageObject << "FAILED!" << validation.randomGeneratorOutput();
396 }
397 else
398 {
399 if (validation.accuracy() < validation.threshold())
400 {
401 messageObject << "FAILED with only " << String::toAString(validation.accuracy() * 100.0, 1u) << "%, threshold is " << String::toAString(validation.threshold() * 100.0, 1u) << "%" << validation.randomGeneratorOutput();
402 }
403 else
404 {
405 messageObject << String::toAString(validation.accuracy() * 100.0, 1u) << "% succeeded.";
406 }
407 }
408
409 return messageObject;
410}
411
412template <bool tActive>
413MessageObject<tActive>& operator<<(MessageObject<tActive>&& messageObject, const ValidationPrecision& validation)
414{
415 if (validation.hasSetFailed())
416 {
417 messageObject << "FAILED!" << validation.randomGeneratorOutput();
418 }
419 else
420 {
421 if (validation.accuracy() < validation.threshold())
422 {
423 messageObject << "FAILED with only " << String::toAString(validation.accuracy() * 100.0, 1u) << "%, threshold is " << String::toAString(validation.threshold() * 100.0, 1u) << "%" << validation.randomGeneratorOutput();
424 }
425 else
426 {
427 messageObject << String::toAString(validation.accuracy() * 100.0, 1u) << "% succeeded.";
428 }
429 }
430
431 return messageObject;
432}
433
434}
435
436}
437
438#endif // META_OCEAN_TEST_VALIDATION_PRECISION_H
static MessageObject error()
Returns the message for error messages.
Definition Messenger.h:1095
Messenger object, one object for each message.
Definition Messenger.h:448
This class implements a generator for random numbers.
Definition RandomGenerator.h:42
static std::string toAString(const char value)
Converts a value to a string with 8bit character.
This class implements a helper class to validate tests.
Definition Validation.h:105
bool succeededChecked_
True, if the success state of this validation has been checked.
Definition Validation.h:397
void setSucceededFalse()
Sets the succeeded state to false.
Definition Validation.h:913
std::string randomGeneratorOutput() const
Returns a string containing the random generator's initial seed, if any.
Definition Validation.h:903
bool succeeded_
True, if the validation has succeeded; False, if the validation has failed.
Definition Validation.h:390
Creates a new scoped iteration representing one iteration in a precision test.
Definition ValidationPrecision.h:41
ScopedIteration(const ScopedIteration &&)=delete
Disabled move constructor.
void setInaccurate()
Sets this iteration to be not precise enough.
Definition ValidationPrecision.h:203
ValidationPrecision & validationPrecision_
The owner of this scoped object.
Definition ValidationPrecision.h:94
ScopedIteration(const ScopedIteration &)=delete
Disabled copy constructor.
bool accurate_
True, if the iteration is accurate; False, if the iteration was not accurate enough.
Definition ValidationPrecision.h:91
~ScopedIteration()
Destructs this scoped object and forwards the information to the owning validation.
Definition ValidationPrecision.h:198
ScopedIteration()=delete
Disabled default constructor.
This class implements a helper class to validate the precision of algorithms or objects across multip...
Definition ValidationPrecision.h:33
double threshold() const
Returns the defined threshold.
Definition ValidationPrecision.h:359
void addIterations(const size_t accurateIterations, const size_t iterations)
Explicitly adds new iterations for which the amount of accurate iterations is known.
Definition ValidationPrecision.h:275
uint64_t iterations_
The overall number of iterations which have been added.
Definition ValidationPrecision.h:182
ValidationPrecision(const double threshold, const unsigned int minimumIterations=1u)
Creates a new precision-based validation object with specified threshold.
Definition ValidationPrecision.h:220
uint64_t accurateIterations_
The number of iterations which were precise enough, with range [0, iterations_].
Definition ValidationPrecision.h:185
bool needMoreIterations() const
Returns whether the number of iterations is not yet sufficient to determine a success or failure.
Definition ValidationPrecision.h:301
double accuracy() const
Returns the accuracy of all iterations.
Definition ValidationPrecision.h:342
void addIteration(const bool accurate)
Explicitly adds a new iteration which is either accurate or not.
Definition ValidationPrecision.h:265
bool succeeded() const override
Returns if this validation has succeeded.
Definition ValidationPrecision.h:308
uint64_t necessaryIterations() const
Returns the necessary iterations to allow determining success or failure based on the specified succe...
Definition ValidationPrecision.h:294
double threshold_
The necessary percent of accurate iterations necessary for a successful verification,...
Definition ValidationPrecision.h:176
uint64_t iterations() const
Returns the number of iterations in which the precision has been determined.
Definition ValidationPrecision.h:289
uint64_t necessaryIterations_
The number of iterations needed to determine success or failure.
Definition ValidationPrecision.h:179
bool hasSetFailed() const
Returns whether this validation object has been set to failed explicitly.
Definition ValidationPrecision.h:364
std::ostream & operator<<(std::ostream &stream, const TestResult &testResult)
Writes a test result to a stream.
Definition TestResult.h:200
The namespace covering the entire Ocean framework.
Definition Accessor.h:15