FastMatrixMath_test.cc
Go to the documentation of this file.
1 /**
2  * @file FastMatrixMath_test.cc
3  * @brief Tests the classes in SimpleFits.h
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date 20141229
6  * @version 1.0
7  * @see SimpleFits.h
8  *
9  * See http://www.boost.org/libs/test for the Boost test library home page.
10  *
11  * Timing:
12  * not given yet
13  */
14 
15 // define the following symbol to print the matrices
16 // #define FASTMATRIXMATH_TEST_DEBUG
17 
18 // C/C++ standard libraries
19 #include <cmath>
20 #include <limits> // std::numeric_limits<>
21 #include <array>
22 #include <algorithm> // std::generate()
23 #include <random>
24 #include <string>
25 #include <iostream>
26 
27 
28 // Boost libraries
29 /*
30  * Boost Magic: define the name of the module;
31  * and do that before the inclusion of Boost unit test headers
32  * because it will change what they provide.
33  * Among the those, there is a main() function and some wrapping catching
34  * unhandled exceptions and considering them test failures, and probably more.
35  * This also makes fairly complicate to receive parameters from the command line
36  * (for example, a random seed).
37  */
38 #define BOOST_TEST_MODULE ( FastMatrixMath_test )
39 #include "boost/test/unit_test.hpp"
40 
41 // LArSoft libraries
43 
45 
46 //==============================================================================
47 //=== Test code
48 //===
49 
50 constexpr unsigned int static_sqrt(unsigned int n) {
51  // too lazy to copy sqrt from Stroustrup
52  return
53  ((n == 1)? 1:
54  ((n == 4)? 2:
55  ((n == 9)? 3:
56  ((n == 16)? 4:
58 } // static_sqrt()
59 
60 
61 template <typename Array>
62 void PrintMatrix
63  (std::ostream& out, Array const& m, std::string name = "Matrix")
64 {
65 #ifdef FASTMATRIXMATH_TEST_DEBUG
66  const size_t Dim = size_t(std::sqrt(m.size()));
67 
68  out << name << " " << Dim << "x" << Dim << ":";
69  for (size_t r = 0; r < Dim; ++r) {
70  out << "\n |";
71  for (size_t c = 0; c < Dim; ++c)
72  out << " " << m[r * Dim + c];
73  out << " |";
74  } // for
75  out << std::endl;
76 #endif // FASTMATRIXMATH_TEST_DEBUG
77 } // PrintMatrix()
78 
79 
80 template <typename Array>
81 void CheckSymmetric(Array const& m) {
82  const size_t Dim = size_t(std::sqrt(m.size()));
83 
84  for (size_t r = 1; r < Dim; ++r)
85  for (size_t c = r + 1; c < Dim; ++c)
86  BOOST_TEST(m[r * Dim + c] == m[r * Dim + c], 0.001% tolerance());
87 
88 } // CheckSymmetric()
89 
90 
91 template <typename Array>
92 void CheckInverse(Array const& a, Array const& a_inv) {
93 
94  const size_t Dim = size_t(std::sqrt(a.size()));
95  using Data_t = typename Array::value_type;
96 
97  BOOST_TEST(a.size() == a_inv.size());
98 
99  for (size_t r = 0; r < Dim; ++r) {
100  for (size_t c = 0; c < Dim; ++c) {
101  Data_t v = 0.;
102  for (size_t k = 0; k < Dim; ++k) {
103  v += a[r * Dim + k] * a_inv[k * Dim + c];
104  } // for
105  if (r == c) BOOST_TEST(v == Data_t(1), 0.01% tolerance());
106  else BOOST_TEST(v == 0, 1e-5% tolerance());
107  } // for column
108  } // for row
109 
110 } // CheckInverse()
111 
112 
113 template <typename Array>
114 void MatrixTest(Array const& mat) {
115 
116  using Data_t = typename Array::value_type;
117 
118  constexpr unsigned int Dim = static_sqrt(std::tuple_size<Array>::value);
119  static_assert((Dim >= 1) && (Dim <= 4), "Dimension not supported");
120 
121  using FastMatrixOperations
123 
124  Array mat_inv = FastMatrixOperations::InvertMatrix(mat);
125  PrintMatrix(std::cout, mat_inv, "Alleged inverse matrix");
126  CheckInverse(mat, mat_inv);
127 
128 } // MatrixTest()
129 
130 
131 template <typename Array>
132 void MatrixTest(Array const& mat, typename Array::value_type det) {
133 
134  using Data_t = typename Array::value_type;
135 
136  constexpr unsigned int Dim = static_sqrt(std::tuple_size<Array>::value);
137  static_assert((Dim >= 1) && (Dim <= 4), "Dimension not supported");
138 
139  using FastMatrixOperations
141 
142  const Data_t my_det = FastMatrixOperations::Determinant(mat);
143  BOOST_TEST(my_det == det, 1e-4% tolerance());
144 
145  if (std::isnormal(det)) {
146  Array mat_inv = FastMatrixOperations::InvertMatrix(mat, det);
147  PrintMatrix(std::cout, mat_inv, "Alleged inverse matrix");
148  CheckInverse(mat, mat_inv);
149  }
150 } // MatrixTest()
151 
152 
153 template <typename Array>
154 void SymmetricMatrixTest(Array const& mat) {
155 
156  using Data_t = typename Array::value_type;
157 
158  constexpr unsigned int Dim = static_sqrt(std::tuple_size<Array>::value);
159  static_assert((Dim >= 1) && (Dim <= 4), "Dimension not supported");
160 
161  using FastMatrixOperations
163 
164  CheckSymmetric(mat);
165 
166  Array mat_inv = FastMatrixOperations::InvertSymmetricMatrix(mat);
167  PrintMatrix(std::cout, mat_inv, "Alleged inverse matrix");
168  CheckInverse(mat, mat_inv);
169  CheckSymmetric(mat_inv);
170 } // SymmetricMatrixTest()
171 
172 
173 template <typename Array>
174 void SymmetricMatrixTest(Array const& mat, typename Array::value_type det) {
175 
176  using Data_t = typename Array::value_type;
177 
178  constexpr unsigned int Dim = static_sqrt(std::tuple_size<Array>::value);
179  static_assert((Dim >= 1) && (Dim <= 4), "Dimension not supported");
180 
181  using FastMatrixOperations
183 
184  const Data_t my_det = FastMatrixOperations::Determinant(mat);
185  BOOST_TEST(my_det == det, 1e-4% tolerance());
186 
187  if (std::isnormal(det)) {
188  Array mat_inv = FastMatrixOperations::InvertSymmetricMatrix(mat, det);
189  PrintMatrix(std::cout, mat_inv, "Alleged inverse matrix");
190  CheckInverse(mat, mat_inv);
191  CheckSymmetric(mat_inv);
192  }
193 } // SymmetricMatrixTest()
194 
195 
196 
197 template <typename T>
199  using Data_t = T;
200  constexpr unsigned int Dim = 2; // we are testing 2x2 matrices
201 
202  // BUG the double brace syntax is required to work around clang bug 21629
203  // (https://bugs.llvm.org/show_bug.cgi?id=21629)
204  std::array<Data_t, Dim*Dim> matrix = {{
205  Data_t(2), Data_t(3),
206  Data_t(4), Data_t(1)
207  }}; // matrix
208  const Data_t true_det = Data_t(-10);
209 
210  PrintMatrix(std::cout, matrix, "Matrix");
211  MatrixTest(matrix, true_det);
212 } // TestMatrix2x2()
213 
214 
215 template <typename T>
217  using Data_t = T;
218  constexpr unsigned int Dim = 2; // we are testing 2x2 matrices
219 
220  // BUG the double brace syntax is required to work around clang bug 21629
221  // (https://bugs.llvm.org/show_bug.cgi?id=21629)
222  std::array<Data_t, Dim*Dim> matrix = {{
223  Data_t(2), Data_t(3),
224  Data_t(3), Data_t(1)
225  }}; // matrix
226  const Data_t true_det = Data_t(-7);
227 
228  PrintMatrix(std::cout, matrix, "Symmetric matrix");
229  SymmetricMatrixTest(matrix, true_det);
230 
231 } // TestSymmetricMatrix2x2()
232 
233 
234 template <typename T>
236 
237  using Data_t = T;
238  constexpr unsigned int Dim = 3; // we are testing 3x3 matrices
239 
240  // BUG the double brace syntax is required to work around clang bug 21629
241  // (https://bugs.llvm.org/show_bug.cgi?id=21629)
242  std::array<Data_t, Dim*Dim> matrix = {{
243  Data_t(2), Data_t(0), Data_t(3),
244  Data_t(0), Data_t(3), Data_t(0),
245  Data_t(4), Data_t(0), Data_t(1),
246  }}; // matrix
247  const Data_t true_det = Data_t(-30);
248 
249  PrintMatrix(std::cout, matrix, "Matrix");
250  MatrixTest(matrix, true_det);
251 
252 } // TestMatrix3x3_1()
253 
254 
255 template <typename T>
257 
258  using Data_t = T;
259  constexpr unsigned int Dim = 3; // we are testing 3x3 matrices
260 
261  // BUG the double brace syntax is required to work around clang bug 21629
262  // (https://bugs.llvm.org/show_bug.cgi?id=21629)
263  std::array<Data_t, Dim*Dim> matrix = {{
264  Data_t(2), Data_t(4), Data_t(3),
265  Data_t(0), Data_t(3), Data_t(0),
266  Data_t(4), Data_t(0), Data_t(1),
267  }}; // matrix
268  const Data_t true_det = Data_t(-30);
269 
270  PrintMatrix(std::cout, matrix, "Matrix");
271  MatrixTest(matrix, true_det);
272 
273 } // TestMatrix3x3_2()
274 
275 
276 
277 template <typename T>
279 
280  using Data_t = T;
281  constexpr unsigned int Dim = 3; // we are testing 3x3 matrices
282 
283  // BUG the double brace syntax is required to work around clang bug 21629
284  // (https://bugs.llvm.org/show_bug.cgi?id=21629)
285  std::array<Data_t, Dim*Dim> matrix = {{
286  Data_t(2), Data_t(0), Data_t(3),
287  Data_t(0), Data_t(3), Data_t(0),
288  Data_t(3), Data_t(0), Data_t(1),
289  }}; // matrix
290  const Data_t true_det = Data_t(-21);
291 
292  PrintMatrix(std::cout, matrix, "Symmetric matrix");
293  SymmetricMatrixTest(matrix, true_det);
294 
295 } // TestSymmetricMatrix3x3()
296 
297 
298 template <typename T>
300 
301  using Data_t = T;
302  constexpr unsigned int Dim = 4; // we are testing 4x4 matrices
303 
304  // BUG the double brace syntax is required to work around clang bug 21629
305  // (https://bugs.llvm.org/show_bug.cgi?id=21629)
306  std::array<Data_t, Dim*Dim> matrix = {{
307  Data_t(2), Data_t(0), Data_t(3), Data_t(0),
308  Data_t(0), Data_t(3), Data_t(0), Data_t(6),
309  Data_t(4), Data_t(0), Data_t(1), Data_t(0),
310  Data_t(0), Data_t(2), Data_t(0), Data_t(7)
311  }}; // matrix
312  const Data_t true_det = Data_t(-90);
313 
314  PrintMatrix(std::cout, matrix, "Matrix");
315  MatrixTest(matrix, true_det);
316 
317 } // TestMatrix4x4_1()
318 
319 
320 template <typename T>
322 
323  using Data_t = T;
324  constexpr unsigned int Dim = 4; // we are testing 4x4 matrices
325 
326  // BUG the double brace syntax is required to work around clang bug 21629
327  // (https://bugs.llvm.org/show_bug.cgi?id=21629)
328  std::array<Data_t, Dim*Dim> matrix = {{
329  Data_t(2), Data_t(0), Data_t(3), Data_t(0),
330  Data_t(5), Data_t(3), Data_t(0), Data_t(6),
331  Data_t(4), Data_t(0), Data_t(1), Data_t(0),
332  Data_t(3), Data_t(2), Data_t(0), Data_t(7)
333  }}; // matrix
334  const Data_t true_det = Data_t(-90);
335 
336  PrintMatrix(std::cout, matrix, "Matrix");
337  MatrixTest(matrix, true_det);
338 
339 } // TestMatrix4x4_2()
340 
341 
342 template <typename T, unsigned int Dim>
343 void TestMatrix_N(unsigned int N = 100) {
344 
345  using Data_t = T;
346 
347  std::default_random_engine engine;
348  std::uniform_real_distribution<Data_t> uniform(Data_t(-10.), Data_t(10.));
349 
350  std::array<Data_t, Dim*Dim> matrix;
351  for (unsigned int i = 0; i < N; ++i) {
352 
353  std::generate(matrix.begin(), matrix.end(),
354  [&engine, &uniform] { return uniform(engine); }
355  );
356 
357  PrintMatrix(std::cout, matrix, "Matrix");
358  MatrixTest(matrix);
359  } // for
360 
361 } // TestMatrix_N()
362 
363 
364 template <typename T, unsigned int Dim>
366 
367  using Data_t = T;
368 
369  std::array<Data_t, Dim*Dim> matrix;
370  matrix.fill(Data_t(0));
371 
372  PrintMatrix(std::cout, matrix, "Empty matrix");
373  MatrixTest(matrix, Data_t(0));
374  PrintMatrix(std::cout, matrix, "Empty symmetric matrix");
375  SymmetricMatrixTest(matrix, Data_t(0));
376 
377 } // TestNullMatrix()
378 
379 
380 
381 template <typename T>
383 
384  using Data_t = T;
385  constexpr unsigned int Dim = 4; // we are testing 4x4 matrices
386 
387  // BUG the double brace syntax is required to work around clang bug 21629
388  // (https://bugs.llvm.org/show_bug.cgi?id=21629)
389  std::array<Data_t, Dim*Dim> matrix = {{
390  Data_t(2), Data_t(0), Data_t(3), Data_t(0),
391  Data_t(0), Data_t(3), Data_t(0), Data_t(2),
392  Data_t(3), Data_t(0), Data_t(1), Data_t(0),
393  Data_t(0), Data_t(2), Data_t(0), Data_t(7)
394  }}; // matrix
395  const Data_t true_det = Data_t(-119);
396 
397  PrintMatrix(std::cout, matrix, "Symmetric matrix");
398  SymmetricMatrixTest(matrix, true_det);
399 
400 } // TestSymmetricMatrix4x4()
401 
402 
403 //------------------------------------------------------------------------------
404 //--- registration of tests
405 //
406 // Boost needs now to know which tests we want to run.
407 // Tests are "automatically" registered, hence the BOOST_AUTO_TEST_CASE()
408 // macro name. The argument is a name for the test; each test will have a
409 // number of checks and it will fail if any of them does.
410 //
411 
412 //
413 // Matrix tests
414 //
415 BOOST_AUTO_TEST_CASE(Matrix2x2RealTest) {
416  TestMatrix2x2<double>();
417  TestSymmetricMatrix2x2<double>();
418 
419  TestMatrix_N<double, 2>();
420  TestNullMatrix<double, 2>();
421 }
422 
423 BOOST_AUTO_TEST_CASE(Matrix3x3RealTest) {
424  TestMatrix3x3_1<double>();
425  TestMatrix3x3_2<double>();
426  TestSymmetricMatrix3x3<double>();
427 
428  TestMatrix_N<double, 3>();
429  TestNullMatrix<double, 3>();
430 }
431 
432 BOOST_AUTO_TEST_CASE(Matrix4x4RealTest) {
433  TestMatrix4x4_1<double>();
434  TestMatrix4x4_2<double>();
435  TestSymmetricMatrix4x4<double>();
436 
437  TestMatrix_N<double, 4>();
438  TestNullMatrix<double, 4>();
439 }
static QCString name
Definition: declinfo.cpp:673
void TestSymmetricMatrix4x4()
std::string string
Definition: nybbler.cc:12
constexpr unsigned int static_sqrt(unsigned int n)
void TestSymmetricMatrix3x3()
auto const tolerance
void CheckSymmetric(Array const &m)
void SymmetricMatrixTest(Array const &mat)
void TestMatrix2x2()
void TestNullMatrix()
Classes with hard-coded (hence "fast") matrix math.
void TestMatrix3x3_1()
const double e
Provides "fast" matrix operations.
#define Array
Definition: scanner.cpp:11549
void TestSymmetricMatrix2x2()
std::void_t< T > n
const double a
static int max(int a, int b)
void PrintMatrix(std::ostream &out, Array const &m, std::string name="Matrix")
void MatrixTest(Array const &mat)
BOOST_AUTO_TEST_CASE(Matrix2x2RealTest)
void TestMatrix_N(unsigned int N=100)
void TestMatrix4x4_2()
void CheckInverse(Array const &a, Array const &a_inv)
void TestMatrix3x3_2()
QTextStream & endl(QTextStream &s)
void TestMatrix4x4_1()