LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
FastMatrixMathHelper.h
Go to the documentation of this file.
1 
13 #ifndef FASTMATRIXMATHHELPER_H
14 #define FASTMATRIXMATHHELPER_H 1
15 
16 // C/C++ standard libraries
17 #include <algorithm> // std::for_each()
18 #include <array>
19 #include <cmath> // std::sqrt()
20 #include <iterator> // std::begin(), std::end()
21 #include <stdexcept> // std::range_error
22 #include <tuple>
23 
24 #include "lardataalg/Utilities/StatCollector.h" // lar::util::identity
25 
26 namespace lar {
27  namespace util {
28 
29  namespace details {
30 
32  template <typename T, unsigned int DIM>
34  using Data_t = T;
35 
36  static constexpr unsigned int Dim = DIM;
37 
38  using Matrix_t = std::array<Data_t, Dim * Dim>;
39  using Vector_t = std::array<Data_t, Dim>;
40 
42  static Vector_t MatrixVectorProduct(Matrix_t const& mat, Vector_t const& vec);
43 
44  static constexpr Data_t sqr(Data_t v) { return v * v; }
45  }; // struct FastMatrixOperationsBase<>
46 
82  template <typename T, unsigned int DIM>
85  using Data_t = typename Base_t::Data_t;
86  using Matrix_t = typename Base_t::Matrix_t;
87 
89  static Data_t Determinant(Matrix_t const& mat);
90 
92  static Matrix_t InvertMatrix(Matrix_t const& mat, Data_t det);
93 
96  static Matrix_t InvertSymmetricMatrix(Matrix_t const& mat, Data_t det);
97 
100  {
101  return InvertMatrix(mat, Determinant(mat));
102  }
103 
106  {
107  return InvertSymmetricMatrix(mat, Determinant(mat));
108  }
109 
110  }; // struct FastMatrixOperations<>
111 
112  } // namespace details
113  } // namespace util
114 } // namespace lar
115 
116 //******************************************************************************
117 //*** template implementation
118 //***
119 namespace lar {
120  namespace util {
121 
122  namespace details {
123 
124  template <unsigned int NCols>
125  constexpr size_t MatrixIndex(unsigned int row, unsigned int col)
126  {
127  return row * NCols + col;
128  }
129 
130  template <unsigned int N>
132  static constexpr size_t index(unsigned int row, unsigned int col)
133  {
134  return MatrixIndex<N>(row, col);
135  }
136  }; // struct DeterminantHelperBase<>
137 
138  template <typename T,
139  unsigned int N,
140  unsigned int... RnC // all row indices, then all column indices
141  >
144 
145  static T compute(T const* data);
146  }; // struct DeterminantHelper<>
147 
149  template <typename T, unsigned int N, unsigned int R, unsigned int C>
150  struct DeterminantHelper<T, N, R, C> : public DeterminantHelperBase<N> {
152  static_assert(R < N, "invalid row index specified");
153  static_assert(C < N, "invalid column index specified");
154 
155  static T compute(T const* data) { return data[index(R, C)]; }
156  }; // struct DeterminantHelper<>
157 
159  template <typename T,
160  unsigned int N,
161  unsigned int R1,
162  unsigned int R2,
163  unsigned int C1,
164  unsigned int C2>
165  struct DeterminantHelper<T, N, R1, R2, C1, C2> : public DeterminantHelperBase<N> {
167  static_assert(R1 < N, "invalid row index specified");
168  static_assert(R2 < N, "invalid row index specified");
169  static_assert(C1 < N, "invalid column index specified");
170  static_assert(C2 < N, "invalid column index specified");
171 
172  static constexpr T sqr(T v) { return v * v; }
173 
174  static T compute(T const* data)
175  {
176  return data[index(R1, C1)] * data[index(R2, C2)] -
177  data[index(R1, C2)] * data[index(R2, C1)];
178  /* // also
179  data[index(R1, C1)] * UpHelper<R2, C2>::compute(data)
180  - data[index(R1, C2)] * UpHelper<R2, C1>::compute(data)
181  */
182  }
183  }; // struct DeterminantHelper<>
184 
186  template <typename T,
187  unsigned int N,
188  unsigned int R1,
189  unsigned int R2,
190  unsigned int R3,
191  unsigned int C1,
192  unsigned int C2,
193  unsigned int C3>
194  struct DeterminantHelper<T, N, R1, R2, R3, C1, C2, C3> : public DeterminantHelperBase<N> {
196  static_assert(R1 < N, "invalid row index specified");
197  static_assert(R2 < N, "invalid row index specified");
198  static_assert(R3 < N, "invalid row index specified");
199  static_assert(C1 < N, "invalid column index specified");
200  static_assert(C2 < N, "invalid column index specified");
201  static_assert(C3 < N, "invalid column index specified");
202  template <unsigned int sR1, unsigned int sR2, unsigned int sC1, unsigned int sC2>
204  static T compute(T const* data)
205  {
206  return data[index(R1, C1)] * UpHelper<R2, R3, C2, C3>::compute(data) -
207  data[index(R1, C2)] * UpHelper<R2, R3, C1, C3>::compute(data) +
208  data[index(R1, C3)] * UpHelper<R2, R3, C1, C2>::compute(data);
209  }
210  }; // struct DeterminantHelper<>
211 
213  template <typename T,
214  unsigned int N,
215  unsigned int R1,
216  unsigned int R2,
217  unsigned int R3,
218  unsigned int R4,
219  unsigned int C1,
220  unsigned int C2,
221  unsigned int C3,
222  unsigned int C4>
223  struct DeterminantHelper<T, N, R1, R2, R3, R4, C1, C2, C3, C4>
224  : public DeterminantHelperBase<N> {
226  static_assert(R1 < N, "invalid row index specified");
227  static_assert(R2 < N, "invalid row index specified");
228  static_assert(R3 < N, "invalid row index specified");
229  static_assert(R4 < N, "invalid row index specified");
230  static_assert(C1 < N, "invalid column index specified");
231  static_assert(C2 < N, "invalid column index specified");
232  static_assert(C3 < N, "invalid column index specified");
233  static_assert(C4 < N, "invalid column index specified");
234  template <unsigned int sR1,
235  unsigned int sR2,
236  unsigned int sR3,
237  unsigned int sC1,
238  unsigned int sC2,
239  unsigned int sC3>
241  static T compute(T const* data)
242  {
243  return data[index(R1, C1)] * UpHelper<R2, R3, R4, C2, C3, C4>::compute(data) -
244  data[index(R1, C2)] * UpHelper<R2, R3, R4, C1, C3, C4>::compute(data) +
245  data[index(R1, C3)] * UpHelper<R2, R3, R4, C1, C2, C4>::compute(data) -
246  data[index(R1, C4)] * UpHelper<R2, R3, R4, C1, C2, C3>::compute(data);
247  }
248  }; // struct DeterminantHelper<>
249 
251  template <typename T>
252  struct FastMatrixOperations<T, 2> : public FastMatrixOperationsBase<T, 2> {
254  static constexpr unsigned int Dim = Base_t::Dim;
255  using Data_t = typename Base_t::Data_t;
256  using Matrix_t = typename Base_t::Matrix_t;
257 
260  {
262  }
263 
265  static Matrix_t InvertMatrix(Matrix_t const& mat, Data_t det);
266 
269  static Matrix_t InvertSymmetricMatrix(Matrix_t const& mat, Data_t det);
270 
272  static Matrix_t InvertMatrix(Matrix_t const& mat)
273  {
274  return InvertMatrix(mat, Determinant(mat));
275  }
276 
279  {
280  return InvertSymmetricMatrix(mat, Determinant(mat));
281  }
282 
283  }; // struct FastMatrixOperations<T, 2>
284 
286  template <typename T>
287  struct FastMatrixOperations<T, 3> : public FastMatrixOperationsBase<T, 3> {
289  static constexpr unsigned int Dim = Base_t::Dim;
290  using Data_t = typename Base_t::Data_t;
291  using Matrix_t = typename Base_t::Matrix_t;
292 
295  {
297  }
298 
300  static Matrix_t InvertMatrix(Matrix_t const& mat, Data_t det);
301 
304  static Matrix_t InvertSymmetricMatrix(Matrix_t const& mat, Data_t det);
305 
307  static Matrix_t InvertMatrix(Matrix_t const& mat)
308  {
309  return InvertMatrix(mat, Determinant(mat));
310  }
311 
314  {
315  return InvertSymmetricMatrix(mat, Determinant(mat));
316  }
317 
318  }; // struct FastMatrixOperations<T, 3>
319 
321  template <typename T>
322  struct FastMatrixOperations<T, 4> : public FastMatrixOperationsBase<T, 4> {
324  static constexpr unsigned int Dim = Base_t::Dim;
325  using Data_t = typename Base_t::Data_t;
326  using Matrix_t = typename Base_t::Matrix_t;
327 
330  {
332  }
333 
335  static Matrix_t InvertMatrix(Matrix_t const& mat, Data_t det);
336 
339  static Matrix_t InvertSymmetricMatrix(Matrix_t const& mat, Data_t det);
340 
342  static Matrix_t InvertMatrix(Matrix_t const& mat)
343  {
344  return InvertMatrix(mat, Determinant(mat));
345  }
346 
349  {
350  return InvertSymmetricMatrix(mat, Determinant(mat));
351  }
352 
353  }; // struct FastMatrixOperations<T, 3>
354 
355  } // namespace details
356  } // namespace util
357 } // namespace lar
358 
359 template <typename T, unsigned int DIM>
361  Vector_t const& vec)
362  -> Vector_t
363 {
364  // not really fast, but there is probably not much to fasten...
365  Vector_t res;
366  Data_t const* mat_row = mat.data();
367  for (size_t r = 0; r < Dim; ++r) {
368  Data_t elem = Data_t(0);
369  for (size_t c = 0; c < Dim; ++c)
370  elem += *(mat_row++) * vec[c];
371  res[r] = elem;
372  } // for
373  return res;
374 } // FastMatrixOperationsBase<>::MatrixVectorProduct()
375 
376 template <typename T>
378  -> Matrix_t
379 {
380  Matrix_t Inverse;
381  Inverse[0 * Dim + 0] = mat[1 * Dim + 1] / det;
382  Inverse[0 * Dim + 1] = -mat[0 * Dim + 1] / det;
383  Inverse[1 * Dim + 0] = -mat[1 * Dim + 0] / det;
384  Inverse[1 * Dim + 1] = mat[0 * Dim + 0] / det;
385  return Inverse;
386 } // FastMatrixOperations<T, 2>::InvertMatrix()
387 
388 template <typename T>
390  Data_t det) -> Matrix_t
391 {
392  Matrix_t Inverse;
393  Inverse[0 * Dim + 0] = mat[1 * Dim + 1] / det;
394  Inverse[0 * Dim + 1] = Inverse[1 * Dim + 0] = -mat[1 * Dim + 0] / det;
395  Inverse[1 * Dim + 1] = mat[0 * Dim + 0] / det;
396  return Inverse;
397 } // FastMatrixOperations<T, 2>::InvertMatrix()
398 
399 template <typename T>
401  -> Matrix_t
402 {
403  Data_t const* data = mat.data();
404  Matrix_t Inverse;
405  //
406  // Basically using Cramer's rule;
407  // each element [r,c] gets assigned the determinant of the submatrix
408  // after removing c from the rows and r from the columns
409  // (effectively assigning the transpose of the minor matrix)
410  // with the usual sign -1^(r+c)
411  //
412  //
413  Inverse[0 * Dim + 0] = DeterminantHelper<T, 3, 1, 2, 1, 2>::compute(data) / det;
414  Inverse[0 * Dim + 1] = -DeterminantHelper<T, 3, 0, 2, 1, 2>::compute(data) / det;
415  Inverse[0 * Dim + 2] = DeterminantHelper<T, 3, 0, 1, 1, 2>::compute(data) / det;
416  Inverse[1 * Dim + 0] = -DeterminantHelper<T, 3, 1, 2, 0, 2>::compute(data) / det;
417  Inverse[1 * Dim + 1] = DeterminantHelper<T, 3, 0, 2, 0, 2>::compute(data) / det;
418  Inverse[1 * Dim + 2] = -DeterminantHelper<T, 3, 0, 1, 0, 2>::compute(data) / det;
419  Inverse[2 * Dim + 0] = DeterminantHelper<T, 3, 1, 2, 0, 1>::compute(data) / det;
420  Inverse[2 * Dim + 1] = -DeterminantHelper<T, 3, 0, 2, 0, 1>::compute(data) / det;
421  Inverse[2 * Dim + 2] = DeterminantHelper<T, 3, 0, 1, 0, 1>::compute(data) / det;
422  return Inverse;
423 } // FastMatrixOperations<T, 3>::InvertMatrix()
424 
425 template <typename T>
427  Data_t det) -> Matrix_t
428 {
429  //
430  // Same algorithm as InvertMatrix(), but use the fact that the result is
431  // also symmetric
432  //
433  Data_t const* data = mat.data();
434  Matrix_t Inverse;
435  Inverse[0 * Dim + 0] = DeterminantHelper<T, 3, 1, 2, 1, 2>::compute(data) / det;
436  Inverse[0 * Dim + 1] = Inverse[1 * Dim + 0] =
438  Inverse[0 * Dim + 2] = Inverse[2 * Dim + 0] =
440  Inverse[1 * Dim + 1] = DeterminantHelper<T, 3, 0, 2, 0, 2>::compute(data) / det;
441  Inverse[1 * Dim + 2] = Inverse[2 * Dim + 1] =
443  Inverse[2 * Dim + 2] = DeterminantHelper<T, 3, 0, 1, 0, 1>::compute(data) / det;
444  return Inverse;
445 } // FastMatrixOperations<T, 3>::InvertSymmetricMatrix()
446 
447 template <typename T>
449  -> Matrix_t
450 {
451  //
452  // Basically using Cramer's rule;
453  // each element [r,c] gets assigned the determinant of the submatrix
454  // after removing c from the rows and r from the columns
455  // (effectively assigning the transpose of the minor matrix)
456  // with the usual sign -1^(r+c)
457  //
458  //
459  Data_t const* data = mat.data();
460  Matrix_t Inverse;
461  Inverse[0 * Dim + 0] = DeterminantHelper<T, 4, 1, 2, 3, 1, 2, 3>::compute(data) / det;
462  Inverse[0 * Dim + 1] = -DeterminantHelper<T, 4, 0, 2, 3, 1, 2, 3>::compute(data) / det;
463  Inverse[0 * Dim + 2] = DeterminantHelper<T, 4, 0, 1, 3, 1, 2, 3>::compute(data) / det;
464  Inverse[0 * Dim + 3] = -DeterminantHelper<T, 4, 0, 1, 2, 1, 2, 3>::compute(data) / det;
465  Inverse[1 * Dim + 0] = -DeterminantHelper<T, 4, 1, 2, 3, 0, 2, 3>::compute(data) / det;
466  Inverse[1 * Dim + 1] = DeterminantHelper<T, 4, 0, 2, 3, 0, 2, 3>::compute(data) / det;
467  Inverse[1 * Dim + 2] = -DeterminantHelper<T, 4, 0, 1, 3, 0, 2, 3>::compute(data) / det;
468  Inverse[1 * Dim + 3] = DeterminantHelper<T, 4, 0, 1, 2, 0, 2, 3>::compute(data) / det;
469  Inverse[2 * Dim + 0] = DeterminantHelper<T, 4, 1, 2, 3, 0, 1, 3>::compute(data) / det;
470  Inverse[2 * Dim + 1] = -DeterminantHelper<T, 4, 0, 2, 3, 0, 1, 3>::compute(data) / det;
471  Inverse[2 * Dim + 2] = DeterminantHelper<T, 4, 0, 1, 3, 0, 1, 3>::compute(data) / det;
472  Inverse[2 * Dim + 3] = -DeterminantHelper<T, 4, 0, 1, 2, 0, 1, 3>::compute(data) / det;
473  Inverse[3 * Dim + 0] = -DeterminantHelper<T, 4, 1, 2, 3, 0, 1, 2>::compute(data) / det;
474  Inverse[3 * Dim + 1] = DeterminantHelper<T, 4, 0, 2, 3, 0, 1, 2>::compute(data) / det;
475  Inverse[3 * Dim + 2] = -DeterminantHelper<T, 4, 0, 1, 3, 0, 1, 2>::compute(data) / det;
476  Inverse[3 * Dim + 3] = DeterminantHelper<T, 4, 0, 1, 2, 0, 1, 2>::compute(data) / det;
477  return Inverse;
478 } // FastMatrixOperations<T, 4>::InvertMatrix()
479 
480 template <typename T>
482  Data_t det) -> Matrix_t
483 {
484  //
485  // Same algorithm as InvertMatrix(), but use the fact that the result is
486  // also symmetric
487  //
488  Data_t const* data = mat.data();
489  Matrix_t Inverse;
490  Inverse[0 * Dim + 0] = DeterminantHelper<T, 4, 1, 2, 3, 1, 2, 3>::compute(data) / det;
491  Inverse[0 * Dim + 1] = Inverse[1 * Dim + 0] =
493  Inverse[0 * Dim + 2] = Inverse[2 * Dim + 0] =
495  Inverse[0 * Dim + 3] = Inverse[3 * Dim + 0] =
497  Inverse[1 * Dim + 1] = DeterminantHelper<T, 4, 0, 2, 3, 0, 2, 3>::compute(data) / det;
498  Inverse[1 * Dim + 2] = Inverse[2 * Dim + 1] =
500  Inverse[1 * Dim + 3] = Inverse[3 * Dim + 1] =
502  Inverse[2 * Dim + 2] = DeterminantHelper<T, 4, 0, 1, 3, 0, 1, 3>::compute(data) / det;
503  Inverse[2 * Dim + 3] = Inverse[3 * Dim + 2] =
505  Inverse[3 * Dim + 3] = DeterminantHelper<T, 4, 0, 1, 2, 0, 1, 2>::compute(data) / det;
506  return Inverse;
507 } // FastMatrixOperations<T, 4>::InvertSymmetricMatrix()
508 
509 #endif // FASTMATRIXMATHHELPER_H
TRandom r
Definition: spectrum.C:23
static Data_t Determinant(Matrix_t const &mat)
Computes the determinant of a matrix.
Namespace for general, non-LArSoft-specific utilities.
Definition: PIDAAlg.h:26
static Matrix_t InvertSymmetricMatrix(Matrix_t const &mat)
Computes the determinant of a matrix.
static Matrix_t InvertMatrix(Matrix_t const &mat)
Computes the determinant of a matrix.
static constexpr size_t index(unsigned int row, unsigned int col)
static Matrix_t InvertMatrix(Matrix_t const &mat)
Computes the determinant of a matrix.
Classes gathering simple statistics.
static Matrix_t InvertMatrix(Matrix_t const &mat, Data_t det)
Computes the determinant of a matrix, using the provided determinant.
static Matrix_t InvertSymmetricMatrix(Matrix_t const &mat, Data_t det)
Base class with common definitions for "fast" matrix operations.
Provides "fast" matrix operations.
static T compute(T const *data)
Int_t col[ntarg]
Definition: Style.C:29
static Matrix_t InvertSymmetricMatrix(Matrix_t const &mat)
Computes the determinant of a matrix.
static Matrix_t InvertMatrix(Matrix_t const &mat)
Computes the determinant of a matrix.
static Matrix_t InvertSymmetricMatrix(Matrix_t const &mat)
Computes the determinant of a matrix.
static constexpr unsigned int Dim
matrix dimensions
Float_t mat
Definition: plot.C:38
static Data_t Determinant(Matrix_t const &mat)
Computes the determinant of a matrix.
static Vector_t MatrixVectorProduct(Matrix_t const &mat, Vector_t const &vec)
Returns the product of a square matrix times a column vector.
static Matrix_t InvertMatrix(Matrix_t const &mat)
Computes the determinant of a matrix.
constexpr size_t MatrixIndex(unsigned int row, unsigned int col)
static Matrix_t InvertSymmetricMatrix(Matrix_t const &mat)
Computes the determinant of a matrix.
LArSoft-specific namespace.
static Data_t Determinant(Matrix_t const &mat)
Computes the determinant of a matrix.