STIR  6.2.0
RunTests.h
Go to the documentation of this file.
1 /*
2  Copyright (C) 2000 PARAPET partners
3  Copyright (C) 2000-2005, Hammersmith Imanet Ltd
4  Copyright (C) 2013, Kris Thielemans
5  Copyright (C) 2013, 2020, 2022, 2023, 2024 University College London
6  Copyright (C) 2018, University of Hull
7  This file is part of STIR.
8 
9  SPDX-License-Identifier: Apache-2.0 AND License-ref-PARAPET-license
10 
11  See STIR/LICENSE.txt for details
12 */
24 #include "stir/VectorWithOffset.h"
25 #include "stir/BasicCoordinate.h"
26 #include "stir/IndexRange.h"
27 #include "stir/stream.h"
28 #include "stir/Bin.h"
29 #include "stir/DetectionPosition.h"
30 #include "stir/ProjDataInMemory.h"
31 #include <iostream>
32 #include <typeinfo>
33 #include <vector>
34 #include <complex>
35 #include <string>
36 
37 START_NAMESPACE_STIR
38 
71 class RunTests
72 {
73 public:
75  explicit RunTests(const double tolerance = 1E-4);
76 
78  virtual ~RunTests();
79 
81 
82  virtual void run_tests() = 0;
83 
85  bool is_everything_ok() const;
86 
88 
89  int main_return_value() const;
90 
92  void set_tolerance(const double tolerance);
93 
95  double get_tolerance() const;
96 
98 
102  bool check(const bool, const std::string& str = "");
103 
109  bool check_if_equal(const std::string& a, const std::string& b, const std::string& str = "");
110  bool check_if_equal(const double a, const double b, const std::string& str = "");
111  // Note: due to current C++ overloading rules, we need copies for every integer type
112  bool check_if_equal(const short a, const short b, const std::string& str = "");
113  bool check_if_equal(const unsigned short a, const unsigned short b, const std::string& str = "");
114  bool check_if_equal(const int a, const int b, const std::string& str = "");
115  bool check_if_equal(const unsigned int a, const unsigned int b, const std::string& str = "");
116  bool check_if_equal(const long a, const long b, const std::string& str = "");
117  bool check_if_equal(const unsigned long a, const unsigned long b, const std::string& str = "");
118 #ifdef BOOST_HAS_LONG_LONG
119  // necessary to cope with std::size_t for instance (on 64 bit systems)
120  bool check_if_equal(const long long a, const long long b, const std::string& str = "");
121  bool check_if_equal(const unsigned long long a, const unsigned long long b, const std::string& str = "");
122 #endif
123  bool check_if_equal(const Bin& a, const Bin& b, const std::string& str = "")
124  {
125  return this->check_if_equal_generic(a, b, str);
126  }
127  template <class T>
128  bool check_if_equal(const DetectionPosition<T>& a, const DetectionPosition<T>& b, const std::string& str = "")
129  {
130  return this->check_if_equal_generic(a, b, str);
131  }
132 
133  // VC 6.0 needs definition of template members in the class def unfortunately.
135  template <class T>
136  bool check_if_equal(const std::complex<T> a, const std::complex<T> b, const std::string& str = "")
137  {
138  return check_if_equal(a.real(), b.real(), str) && check_if_equal(a.imag(), b.imag(), str);
139  }
141  template <class T>
142  bool check_if_equal(const VectorWithOffset<T>& t1, const VectorWithOffset<T>& t2, const std::string& str = "")
143  {
144  if (t1.get_min_index() != t2.get_min_index() || t1.get_max_index() != t2.get_max_index())
145  {
146  std::cerr << "Error: unequal ranges. " << str << std::endl;
147  return everything_ok = false;
148  }
149 
150  for (int i = t1.get_min_index(); i <= t1.get_max_index(); i++)
151  {
152  if (!check_if_equal(t1[i], t2[i], str))
153  {
154  std::cerr << "(at VectorWithOffset<" << typeid(T).name() << "> first mismatch at index " << i << ")\n";
155  return everything_ok = false;
156  }
157  }
158  return true;
159  }
160  // VC 6.0 needs definition of template members in the class def unfortunately.
162  template <class T>
163  bool check_if_equal(const std::vector<T>& t1, const std::vector<T>& t2, const std::string& str = "")
164  {
165  if (t1.size() != t2.size())
166  {
167  std::cerr << "Error: unequal ranges. " << str << std::endl;
168  return everything_ok = false;
169  }
170 
171  bool all_equal = true;
172  for (unsigned int i = 0; i < t1.size(); i++)
173  {
174  if (!check_if_equal(t1[i], t2[i], str))
175  {
176  std::cerr << "(at vector<" << typeid(T).name() << "> mismatch at index " << i << ")\n";
177  all_equal = false;
178  }
179  }
180  return all_equal;
181  }
182 
183  bool check_if_equal(const ProjDataInMemory& t1, const ProjDataInMemory& t2, const std::string& str = "");
184 
185  // VC 6.0 needs definition of template members in the class def unfortunately.
186  template <int n>
187  bool check_if_equal(const IndexRange<n>& t1, const IndexRange<n>& t2, const std::string& str = "")
188  {
189  if (t1 != t2)
190  {
191  std::cerr << "Error: unequal ranges. " << str << std::endl;
192  return everything_ok = false;
193  }
194  else
195  return true;
196  }
198  template <int num_dimensions, class coordT>
201  const std::string& str = "")
202  {
203  if (norm(a - b) > tolerance)
204  {
205  std::cerr << "Error : Unequal Coordinate value are " << a << " and " << b << ". " << str << std::endl;
206  everything_ok = false;
207  return false;
208  }
209  else
210  return true;
211  }
213 
219  bool check_if_zero(const double a, const std::string& str = "");
220  bool check_if_zero(const short a, const std::string& str = "");
221  bool check_if_zero(const unsigned short a, const std::string& str = "");
222  bool check_if_zero(const int a, const std::string& str = "");
223  bool check_if_zero(const unsigned int a, const std::string& str = "");
224  bool check_if_zero(const long a, const std::string& str = "");
225  bool check_if_zero(const unsigned long a, const std::string& str = "");
226 #ifdef BOOST_HAS_LONG_LONG
227  bool check_if_zero(const long long a, const std::string& str = "");
228  bool check_if_zero(const unsigned long long a, const std::string& str = "");
229 #endif
230 
231  // VC needs definition of template members in the class def unfortunately.
233  template <class T>
234  bool check_if_zero(const VectorWithOffset<T>& t, const std::string& str = "")
235  {
236  for (int i = t.get_min_index(); i <= t.get_max_index(); i++)
237  {
238  if (!check_if_zero(t[i], str))
239  {
240  std::cerr << "(at VectorWithOffset<" << typeid(T).name() << "> first mismatch at index " << i << ")\n";
241  return false;
242  }
243  }
244  return true;
245  }
246 
248  template <int num_dimensions, class coordT>
249  bool check_if_zero(const BasicCoordinate<num_dimensions, coordT>& a, const std::string& str = "")
250  {
251  if (norm(a) > tolerance)
252  {
253  std::cerr << "Error : Coordinate value is " << a << " expected 0s. " << str << std::endl;
254  everything_ok = false;
255  return false;
256  }
257  else
258  return true;
259  }
261 
263  template <class T1, class T2>
264  inline bool check_if_less(T1 a, T2 b, const std::string& str = "");
265 
266 protected:
268  double tolerance;
271 
273  template <class T>
274  bool check_if_equal_generic(const T& a, const T& b, const std::string& str)
275  {
276  if (a != b)
277  {
278  std::cerr << "Error : unequal values are " << a << " and " << b << ". " << str << std::endl;
279  everything_ok = false;
280  return false;
281  }
282  else
283  return true;
284  }
285 
287  template <class T>
288  bool check_if_zero_generic(T a, const std::string& str)
289  {
290  if ((a != static_cast<T>(0)))
291  {
292  std::cerr << "Error : 0 value is " << a << " ." << str << std::endl;
293  everything_ok = false;
294  return false;
295  }
296  else
297  return true;
298  }
299 };
300 
301 END_NAMESPACE_STIR
302 
303 START_NAMESPACE_STIR
304 
305 RunTests::RunTests(const double tolerance)
306  : tolerance(tolerance),
307  everything_ok(true)
308 {}
309 
311 {
312 #if defined(_DEBUG) && defined(__MSL__)
313  DebugNewReportLeaks();
314 #endif
315 
316  if (everything_ok)
317  std::cerr << "\nAll tests ok !\n\n" << std::endl;
318  else
319  std::cerr << "\nEnd of tests. Please correct errors !\n\n" << std::endl;
320 }
321 
322 bool
324 {
325  return everything_ok;
326 }
327 
328 int
330 {
331  return everything_ok ? EXIT_SUCCESS : EXIT_FAILURE;
332 }
333 
334 void
335 RunTests::set_tolerance(const double tolerance_v)
336 {
337  tolerance = tolerance_v;
338 }
339 
340 double
342 {
343  return tolerance;
344 }
345 
346 bool
347 RunTests::check(const bool result, const std::string& str)
348 {
349  if (!result)
350  {
351  std::cerr << "Error. " << str << std::endl;
352  everything_ok = false;
353  }
354  return result;
355 }
356 
357 bool
358 RunTests::check_if_equal(const std::string& a, const std::string& b, const std::string& str)
359 {
360  return this->check_if_equal_generic(a, b, str);
361 }
362 
377 bool
378 RunTests::check_if_equal(const double a, const double b, const std::string& str)
379 {
380  const double diff = fabs(b - a);
381  if (diff <= tolerance)
382  return true;
383 
384  const double largest = (std::max(fabs(b), fabs(a)));
385 
386  if (diff > tolerance * largest)
387  {
388  std::cerr << "Error : unequal values are " << a << " and " << b << ". " << str << std::endl;
389  everything_ok = false;
390  return false;
391  }
392  else
393  return true;
394 }
395 
396 bool
397 RunTests::check_if_equal(const short a, const short b, const std::string& str)
398 {
399  return this->check_if_equal_generic(a, b, str);
400 }
401 bool
402 RunTests::check_if_equal(const unsigned short a, const unsigned short b, const std::string& str)
403 {
404  return this->check_if_equal_generic(a, b, str);
405 }
406 bool
407 RunTests::check_if_equal(const int a, const int b, const std::string& str)
408 {
409  return this->check_if_equal_generic(a, b, str);
410 }
411 bool
412 RunTests::check_if_equal(const unsigned int a, const unsigned int b, const std::string& str)
413 {
414  return this->check_if_equal_generic(a, b, str);
415 }
416 bool
417 RunTests::check_if_equal(const long a, const long b, const std::string& str)
418 {
419  return this->check_if_equal_generic(a, b, str);
420 }
421 bool
422 RunTests::check_if_equal(const unsigned long a, const unsigned long b, const std::string& str)
423 {
424  return this->check_if_equal_generic(a, b, str);
425 }
426 #ifdef BOOST_HAS_LONG_LONG
427 bool
428 RunTests::check_if_equal(const long long a, const long long b, const std::string& str)
429 {
430  return this->check_if_equal_generic(a, b, str);
431 }
432 bool
433 RunTests::check_if_equal(const unsigned long long a, const unsigned long long b, const std::string& str)
434 {
435  return this->check_if_equal_generic(a, b, str);
436 }
437 #endif
438 
439 bool
440 RunTests::check_if_equal(const ProjDataInMemory& t1, const ProjDataInMemory& t2, const std::string& str)
441 {
443  {
444  std::cerr << "Error: unequal proj_data_info. " << str << std::endl;
445  return everything_ok = false;
446  }
447 
448  for (auto i1 = t1.begin(), i2 = t2.begin(); i1 != t1.end(); ++i1, ++i2)
449  {
450  if (!check_if_equal(*i1, *i2, str))
451  {
452  return everything_ok = false;
453  }
454  }
455  return true;
456 }
457 
458 bool
459 RunTests::check_if_zero(const short a, const std::string& str)
460 {
461  return this->check_if_zero_generic(a, str);
462 }
463 bool
464 RunTests::check_if_zero(const unsigned short a, const std::string& str)
465 {
466  return this->check_if_zero_generic(a, str);
467 }
468 bool
469 RunTests::check_if_zero(const int a, const std::string& str)
470 {
471  return this->check_if_zero_generic(a, str);
472 }
473 bool
474 RunTests::check_if_zero(const unsigned int a, const std::string& str)
475 {
476  return this->check_if_zero_generic(a, str);
477 }
478 bool
479 RunTests::check_if_zero(const long a, const std::string& str)
480 {
481  return this->check_if_zero_generic(a, str);
482 }
483 bool
484 RunTests::check_if_zero(const unsigned long a, const std::string& str)
485 {
486  return this->check_if_zero_generic(a, str);
487 }
488 #ifdef BOOST_HAS_LONG_LONG
489 bool
490 RunTests::check_if_zero(const long long a, const std::string& str)
491 {
492  return this->check_if_zero_generic(a, str);
493 }
494 bool
495 RunTests::check_if_zero(const unsigned long long a, const std::string& str)
496 {
497  return this->check_if_zero_generic(a, str);
498 }
499 #endif
500 
502 bool
503 RunTests::check_if_zero(const double a, const std::string& str)
504 {
505  if (fabs(a) > tolerance)
506  {
507  std::cerr << "Error : 0 value is " << a << " ." << str << std::endl;
508  everything_ok = false;
509  return false;
510  }
511  else
512  return true;
513 }
514 
515 template <class T1, class T2>
516 bool
517 RunTests::check_if_less(T1 a, T2 b, const std::string& str)
518 {
519  if (a >= b)
520  {
521  std::cerr << "Error : " << a << " is larger than " << b << ", " << str << std::endl;
522  everything_ok = false;
523  return false;
524  }
525  else
526  return true;
527 }
528 
529 END_NAMESPACE_STIR
A class which reads/writes projection data from/to memory.
Definition: ProjDataInMemory.h:38
A class for storing coordinates of a detection.
Definition: DetectionPosition.h:58
iterator begin()
start value for iterating through all elements in the array, see iterator
Definition: ProjDataInMemory.h:209
virtual ~RunTests()
Destructor, outputs a diagnostic message.
Definition: RunTests.h:310
A templated class for vectors, but with indices starting not from 0.
Definition: ArrayFilter1DUsingConvolution.h:31
int get_min_index() const
get value of first valid index
Definition: VectorWithOffset.inl:116
This class defines ranges which can be &#39;irregular&#39;.
Definition: ArrayFunctionObject.h:32
double get_tolerance() const
Get value used in floating point comparisons (see check_* functions)
Definition: RunTests.h:341
Declaration of class stir::ProjDataInMemory.
bool is_everything_ok() const
Returns if all checks were fine upto now.
Definition: RunTests.h:323
bool check_if_zero(const VectorWithOffset< T > &t, const std::string &str="")
use check_if_zero on all elements
Definition: RunTests.h:234
bool check_if_zero(const double a, const std::string &str="")
Definition: RunTests.h:503
Input/output of basic vector-like types to/from streams.
shared_ptr< const ProjDataInfo > get_proj_data_info_sptr() const
Get shared pointer to proj data info.
Definition: ProjData.inl:52
This file declares class stir::BasicCoordinate and some functions acting on stir::BasicCoordinate obj...
bool check_if_zero(const BasicCoordinate< num_dimensions, coordT > &a, const std::string &str="")
compare norm with tolerance
Definition: RunTests.h:249
bool check_if_equal_generic(const T &a, const T &b, const std::string &str)
function that is called by some check_if_equal implementations. It just uses operator!= ...
Definition: RunTests.h:274
bool check_if_equal(const VectorWithOffset< T > &t1, const VectorWithOffset< T > &t2, const std::string &str="")
check equality by comparing ranges and calling check_if_equal on all elements
Definition: RunTests.h:142
Declaration of class stir::DetectionPosition.
A class for storing coordinates and value of a single projection bin.
Definition: Bin.h:48
Declaration of class stir::Bin.
bool check(const bool, const std::string &str="")
Tests if true, str can be used to tell what you are testing.
Definition: RunTests.h:347
void set_tolerance(const double tolerance)
Set value used in floating point comparisons (see check_* functions)
Definition: RunTests.h:335
defines the stir::VectorWithOffset class
bool check_if_equal(const std::vector< T > &t1, const std::vector< T > &t2, const std::string &str="")
check equality by comparing size and calling check_if_equal on all elements
Definition: RunTests.h:163
A base class for making test classesWith a derived class, an application could look like...
Definition: RunTests.h:71
iterator end()
end value for iterating through all elements in the array, see iterator
Definition: ProjDataInMemory.h:219
double norm(const BasicCoordinate< num_dimensions, coordT > &p1)
compute sqrt(inner_product(p1,p1))
Definition: BasicCoordinate.inl:426
This file defines the stir::IndexRange class.
double tolerance
tolerance for comparisons with real values
Definition: RunTests.h:268
class BasicCoordinate<int num_dimensions, typename coordT> defines num_dimensions -dimensional coordi...
Definition: BasicCoordinate.h:53
bool check_if_equal(const std::complex< T > a, const std::complex< T > b, const std::string &str="")
check equality by calling check_if_equal on real and imaginary parts
Definition: RunTests.h:136
int get_max_index() const
get value of last valid index
Definition: VectorWithOffset.inl:123
bool check_if_equal(const BasicCoordinate< num_dimensions, coordT > &a, const BasicCoordinate< num_dimensions, coordT > &b, const std::string &str="")
check equality by comparing norm(a-b) with tolerance
Definition: RunTests.h:199
bool check_if_less(T1 a, T2 b, const std::string &str="")
check if a<b
Definition: RunTests.h:517
bool everything_ok
variable storing current status
Definition: RunTests.h:270
bool check_if_zero_generic(T a, const std::string &str)
function that is called by some check_if_zero implementations. It just uses operator!= ...
Definition: RunTests.h:288
int main_return_value() const
Handy return value for a main() function.
Definition: RunTests.h:329