LArSoft  v06_85_00
Liquid Argon Software toolkit - http://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 <cmath> // std::sqrt()
18 #include <tuple>
19 #include <array>
20 #include <iterator> // std::begin(), std::end()
21 #include <algorithm> // std::for_each()
22 #include <stdexcept> // std::range_error
23 
24 
25 #include "StatCollector.h" // lar::util::identity
26 
27 namespace lar {
28  namespace util {
29 
30  namespace details {
31 
33  template <typename T, unsigned int DIM>
35  using Data_t = T;
36 
37  static constexpr unsigned int Dim = DIM;
38 
39  using Matrix_t = std::array<Data_t, Dim*Dim>;
40  using Vector_t = std::array<Data_t, Dim>;
41 
44  (Matrix_t const& mat, Vector_t const& vec);
45 
46 
47  static constexpr Data_t sqr(Data_t v) { return v*v; }
48  }; // struct FastMatrixOperationsBase<>
49 
50 
86  template <typename T, unsigned int DIM>
89  using Data_t = typename Base_t::Data_t;
90  using Matrix_t = typename Base_t::Matrix_t;
91 
93  static Data_t Determinant(Matrix_t const& mat);
94 
96  static Matrix_t InvertMatrix(Matrix_t const& mat, Data_t det);
97 
100  static Matrix_t InvertSymmetricMatrix(Matrix_t const& mat, Data_t det);
101 
104  { return InvertMatrix(mat, Determinant(mat)); }
105 
108  { return InvertSymmetricMatrix(mat, Determinant(mat)); }
109 
110  }; // struct FastMatrixOperations<>
111 
112  } // namespace details
113  } // namespace util
114 } // namespace lar
115 
116 
117 
118 //******************************************************************************
119 //*** template implementation
120 //***
121 namespace lar {
122  namespace util {
123 
124  namespace details {
125 
126  template <unsigned int NCols>
127  constexpr size_t MatrixIndex(unsigned int row, unsigned int col)
128  { return row * NCols + col; }
129 
130  template <unsigned int N>
132  static constexpr size_t index(unsigned int row, unsigned int col)
133  { return MatrixIndex<N>(row, col); }
134  }; // struct DeterminantHelperBase<>
135 
136  template <typename T, unsigned int N,
137  unsigned int... RnC // all row indices, then all column indices
138  >
141 
142  static T compute(T const* data);
143  }; // struct DeterminantHelper<>
144 
145 
147  template <typename T, unsigned int N,
148  unsigned int R, unsigned int C
149  >
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 
158 
160  template <typename T, unsigned int N,
161  unsigned int R1, unsigned int R2,
162  unsigned int C1, unsigned int C2
163  >
164  struct DeterminantHelper<T, N, R1, R2, C1, C2>:
165  public DeterminantHelperBase<N>
166  {
168  static_assert(R1 < N, "invalid row index specified");
169  static_assert(R2 < N, "invalid row index specified");
170  static_assert(C1 < N, "invalid column index specified");
171  static_assert(C2 < N, "invalid column index specified");
172 
173  static constexpr T sqr(T v) { return v*v; }
174 
175  static T compute(T const* data)
176  {
177  return data[index(R1, C1)] * data[index(R2, C2)]
178  - data[index(R1, C2)] * data[index(R2, C1)];
179  /* // also
180  data[index(R1, C1)] * UpHelper<R2, C2>::compute(data)
181  - data[index(R1, C2)] * UpHelper<R2, C1>::compute(data)
182  */
183  }
184  }; // struct DeterminantHelper<>
185 
186 
188  template <typename T, unsigned int N,
189  unsigned int R1, unsigned int R2, unsigned int R3,
190  unsigned int C1, unsigned int C2, unsigned int C3
191  >
192  struct DeterminantHelper<T, N, R1, R2, R3, C1, C2, C3>:
193  public DeterminantHelperBase<N>
194  {
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 <
203  unsigned int sR1, unsigned int sR2,
204  unsigned int sC1, unsigned int sC2
205  >
207  static T compute(T const* data)
208  {
209  return
210  data[index(R1, C1)] * UpHelper<R2, R3, C2, C3>::compute(data)
211  - data[index(R1, C2)] * UpHelper<R2, R3, C1, C3>::compute(data)
212  + data[index(R1, C3)] * UpHelper<R2, R3, C1, C2>::compute(data)
213  ;
214  }
215  }; // struct DeterminantHelper<>
216 
217 
219  template <typename T, unsigned int N,
220  unsigned int R1, unsigned int R2, unsigned int R3, unsigned int R4,
221  unsigned int C1, unsigned int C2, unsigned int C3, unsigned int C4
222  >
223  struct DeterminantHelper<T, N, R1, R2, R3, R4, C1, C2, C3, C4>:
224  public DeterminantHelperBase<N>
225  {
227  static_assert(R1 < N, "invalid row index specified");
228  static_assert(R2 < N, "invalid row index specified");
229  static_assert(R3 < N, "invalid row index specified");
230  static_assert(R4 < N, "invalid row index specified");
231  static_assert(C1 < N, "invalid column index specified");
232  static_assert(C2 < N, "invalid column index specified");
233  static_assert(C3 < N, "invalid column index specified");
234  static_assert(C4 < N, "invalid column index specified");
235  template <
236  unsigned int sR1, unsigned int sR2, unsigned int sR3,
237  unsigned int sC1, unsigned int sC2, unsigned int sC3
238  >
240  static T compute(T const* data)
241  {
242  return
243  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  }
249  }; // struct DeterminantHelper<>
250 
251 
253  template <typename T>
254  struct FastMatrixOperations<T, 2>:
255  public FastMatrixOperationsBase<T, 2>
256  {
258  static constexpr unsigned int Dim = Base_t::Dim;
259  using Data_t = typename Base_t::Data_t;
260  using Matrix_t = typename Base_t::Matrix_t;
261 
264  { return DeterminantHelper<T, Dim, 0, 1, 0, 1>::compute(mat.data()); }
265 
267  static Matrix_t InvertMatrix(Matrix_t const& mat, Data_t det);
268 
271  static Matrix_t InvertSymmetricMatrix(Matrix_t const& mat, Data_t det);
272 
274  static Matrix_t InvertMatrix(Matrix_t const& mat)
275  { return InvertMatrix(mat, Determinant(mat)); }
276 
279  { return InvertSymmetricMatrix(mat, Determinant(mat)); }
280 
281  }; // struct FastMatrixOperations<T, 2>
282 
283 
285  template <typename T>
286  struct FastMatrixOperations<T, 3>:
287  public FastMatrixOperationsBase<T, 3>
288  {
290  static constexpr unsigned int Dim = Base_t::Dim;
291  using Data_t = typename Base_t::Data_t;
292  using Matrix_t = typename Base_t::Matrix_t;
293 
296  {
297  return
299  }
300 
302  static Matrix_t InvertMatrix(Matrix_t const& mat, Data_t det);
303 
306  static Matrix_t InvertSymmetricMatrix(Matrix_t const& mat, Data_t det);
307 
309  static Matrix_t InvertMatrix(Matrix_t const& mat)
310  { return InvertMatrix(mat, Determinant(mat)); }
311 
314  { return InvertSymmetricMatrix(mat, Determinant(mat)); }
315 
316  }; // struct FastMatrixOperations<T, 3>
317 
318 
320  template <typename T>
321  struct FastMatrixOperations<T, 4>:
322  public FastMatrixOperationsBase<T, 4>
323  {
325  static constexpr unsigned int Dim = Base_t::Dim;
326  using Data_t = typename Base_t::Data_t;
327  using Matrix_t = typename Base_t::Matrix_t;
328 
331  {
333  (mat.data());
334  }
335 
337  static Matrix_t InvertMatrix(Matrix_t const& mat, Data_t det);
338 
341  static Matrix_t InvertSymmetricMatrix(Matrix_t const& mat, Data_t det);
342 
344  static Matrix_t InvertMatrix(Matrix_t const& mat)
345  { return InvertMatrix(mat, Determinant(mat)); }
346 
349  { return InvertSymmetricMatrix(mat, Determinant(mat)); }
350 
351  }; // struct FastMatrixOperations<T, 3>
352 
353 
354 
355  } // namespace details
356  } // namespace util
357 } // namespace lar
358 
359 
360 template <typename T, unsigned int DIM>
362  (Matrix_t const& mat, Vector_t const& vec) -> 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 
377 template <typename T>
379  (Matrix_t const& mat, Data_t det) -> Matrix_t
380 {
381  Matrix_t Inverse;
382  Inverse[0 * Dim + 0] = mat[1 * Dim + 1] / det;
383  Inverse[0 * Dim + 1] = - mat[0 * Dim + 1] / det;
384  Inverse[1 * Dim + 0] = - mat[1 * Dim + 0] / det;
385  Inverse[1 * Dim + 1] = mat[0 * Dim + 0] / det;
386  return Inverse;
387 } // FastMatrixOperations<T, 2>::InvertMatrix()
388 
389 
390 template <typename T>
392  (Matrix_t const& mat, Data_t det) -> Matrix_t
393 {
394  Matrix_t Inverse;
395  Inverse[0 * Dim + 0] = mat[1 * Dim + 1] / det;
396  Inverse[0 * Dim + 1] =
397  Inverse[1 * Dim + 0] = - mat[1 * Dim + 0] / det;
398  Inverse[1 * Dim + 1] = mat[0 * Dim + 0] / det;
399  return Inverse;
400 } // FastMatrixOperations<T, 2>::InvertMatrix()
401 
402 
403 template <typename T>
405  (Matrix_t const& mat, Data_t det) -> Matrix_t
406 {
407  Data_t const* data = mat.data();
408  Matrix_t Inverse;
409  //
410  // Basically using Cramer's rule;
411  // each element [r,c] gets assigned the determinant of the submatrix
412  // after removing c from the rows and r from the columns
413  // (effectively assigning the transpose of the minor matrix)
414  // with the usual sign -1^(r+c)
415  //
416  //
417  Inverse[0 * Dim + 0] = DeterminantHelper<T, 3, 1, 2, 1, 2>::compute(data)/det;
418  Inverse[0 * Dim + 1] = -DeterminantHelper<T, 3, 0, 2, 1, 2>::compute(data)/det;
419  Inverse[0 * Dim + 2] = DeterminantHelper<T, 3, 0, 1, 1, 2>::compute(data)/det;
420  Inverse[1 * Dim + 0] = -DeterminantHelper<T, 3, 1, 2, 0, 2>::compute(data)/det;
421  Inverse[1 * Dim + 1] = DeterminantHelper<T, 3, 0, 2, 0, 2>::compute(data)/det;
422  Inverse[1 * Dim + 2] = -DeterminantHelper<T, 3, 0, 1, 0, 2>::compute(data)/det;
423  Inverse[2 * Dim + 0] = DeterminantHelper<T, 3, 1, 2, 0, 1>::compute(data)/det;
424  Inverse[2 * Dim + 1] = -DeterminantHelper<T, 3, 0, 2, 0, 1>::compute(data)/det;
425  Inverse[2 * Dim + 2] = DeterminantHelper<T, 3, 0, 1, 0, 1>::compute(data)/det;
426  return Inverse;
427 } // FastMatrixOperations<T, 3>::InvertMatrix()
428 
429 
430 template <typename T>
432  (Matrix_t const& mat, Data_t det) -> Matrix_t
433 {
434  //
435  // Same algorithm as InvertMatrix(), but use the fact that the result is
436  // also symmetric
437  //
438  Data_t const* data = mat.data();
439  Matrix_t Inverse;
440  Inverse[0 * Dim + 0] = DeterminantHelper<T, 3, 1, 2, 1, 2>::compute(data)/det;
441  Inverse[0 * Dim + 1] =
442  Inverse[1 * Dim + 0] = -DeterminantHelper<T, 3, 1, 2, 0, 2>::compute(data)/det;
443  Inverse[0 * Dim + 2] =
444  Inverse[2 * Dim + 0] = DeterminantHelper<T, 3, 1, 2, 0, 1>::compute(data)/det;
445  Inverse[1 * Dim + 1] = DeterminantHelper<T, 3, 0, 2, 0, 2>::compute(data)/det;
446  Inverse[1 * Dim + 2] =
447  Inverse[2 * Dim + 1] = -DeterminantHelper<T, 3, 0, 2, 0, 1>::compute(data)/det;
448  Inverse[2 * Dim + 2] = DeterminantHelper<T, 3, 0, 1, 0, 1>::compute(data)/det;
449  return Inverse;
450 } // FastMatrixOperations<T, 3>::InvertSymmetricMatrix()
451 
452 
453 template <typename T>
455  (Matrix_t const& mat, Data_t det) -> Matrix_t
456 {
457  //
458  // Basically using Cramer's rule;
459  // each element [r,c] gets assigned the determinant of the submatrix
460  // after removing c from the rows and r from the columns
461  // (effectively assigning the transpose of the minor matrix)
462  // with the usual sign -1^(r+c)
463  //
464  //
465  Data_t const* data = mat.data();
466  Matrix_t Inverse;
467  Inverse[0 * Dim + 0] = DeterminantHelper<T, 4, 1, 2, 3, 1, 2, 3>::compute(data)/det;
468  Inverse[0 * Dim + 1] = -DeterminantHelper<T, 4, 0, 2, 3, 1, 2, 3>::compute(data)/det;
469  Inverse[0 * Dim + 2] = DeterminantHelper<T, 4, 0, 1, 3, 1, 2, 3>::compute(data)/det;
470  Inverse[0 * Dim + 3] = -DeterminantHelper<T, 4, 0, 1, 2, 1, 2, 3>::compute(data)/det;
471  Inverse[1 * Dim + 0] = -DeterminantHelper<T, 4, 1, 2, 3, 0, 2, 3>::compute(data)/det;
472  Inverse[1 * Dim + 1] = DeterminantHelper<T, 4, 0, 2, 3, 0, 2, 3>::compute(data)/det;
473  Inverse[1 * Dim + 2] = -DeterminantHelper<T, 4, 0, 1, 3, 0, 2, 3>::compute(data)/det;
474  Inverse[1 * Dim + 3] = DeterminantHelper<T, 4, 0, 1, 2, 0, 2, 3>::compute(data)/det;
475  Inverse[2 * Dim + 0] = DeterminantHelper<T, 4, 1, 2, 3, 0, 1, 3>::compute(data)/det;
476  Inverse[2 * Dim + 1] = -DeterminantHelper<T, 4, 0, 2, 3, 0, 1, 3>::compute(data)/det;
477  Inverse[2 * Dim + 2] = DeterminantHelper<T, 4, 0, 1, 3, 0, 1, 3>::compute(data)/det;
478  Inverse[2 * Dim + 3] = -DeterminantHelper<T, 4, 0, 1, 2, 0, 1, 3>::compute(data)/det;
479  Inverse[3 * Dim + 0] = -DeterminantHelper<T, 4, 1, 2, 3, 0, 1, 2>::compute(data)/det;
480  Inverse[3 * Dim + 1] = DeterminantHelper<T, 4, 0, 2, 3, 0, 1, 2>::compute(data)/det;
481  Inverse[3 * Dim + 2] = -DeterminantHelper<T, 4, 0, 1, 3, 0, 1, 2>::compute(data)/det;
482  Inverse[3 * Dim + 3] = DeterminantHelper<T, 4, 0, 1, 2, 0, 1, 2>::compute(data)/det;
483  return Inverse;
484 } // FastMatrixOperations<T, 4>::InvertMatrix()
485 
486 
487 template <typename T>
489  (Matrix_t const& mat, Data_t det) -> Matrix_t
490 {
491  //
492  // Same algorithm as InvertMatrix(), but use the fact that the result is
493  // also symmetric
494  //
495  Data_t const* data = mat.data();
496  Matrix_t Inverse;
497  Inverse[0 * Dim + 0] = DeterminantHelper<T, 4, 1, 2, 3, 1, 2, 3>::compute(data)/det;
498  Inverse[0 * Dim + 1] =
499  Inverse[1 * Dim + 0] = -DeterminantHelper<T, 4, 1, 2, 3, 0, 2, 3>::compute(data)/det;
500  Inverse[0 * Dim + 2] =
501  Inverse[2 * Dim + 0] = DeterminantHelper<T, 4, 1, 2, 3, 0, 1, 3>::compute(data)/det;
502  Inverse[0 * Dim + 3] =
503  Inverse[3 * Dim + 0] = -DeterminantHelper<T, 4, 1, 2, 3, 0, 1, 2>::compute(data)/det;
504  Inverse[1 * Dim + 1] = DeterminantHelper<T, 4, 0, 2, 3, 0, 2, 3>::compute(data)/det;
505  Inverse[1 * Dim + 2] =
506  Inverse[2 * Dim + 1] = -DeterminantHelper<T, 4, 0, 2, 3, 3, 0, 1>::compute(data)/det;
507  Inverse[1 * Dim + 3] =
508  Inverse[3 * Dim + 1] = DeterminantHelper<T, 4, 0, 2, 3, 0, 1, 2>::compute(data)/det;
509  Inverse[2 * Dim + 2] = DeterminantHelper<T, 4, 0, 1, 3, 0, 1, 3>::compute(data)/det;
510  Inverse[2 * Dim + 3] =
511  Inverse[3 * Dim + 2] = -DeterminantHelper<T, 4, 0, 1, 3, 0, 1, 2>::compute(data)/det;
512  Inverse[3 * Dim + 3] = DeterminantHelper<T, 4, 0, 1, 2, 0, 1, 2>::compute(data)/det;
513  return Inverse;
514 } // FastMatrixOperations<T, 4>::InvertSymmetricMatrix()
515 
516 
517 #endif // FASTMATRIXMATHHELPER_H
static Data_t Determinant(Matrix_t const &mat)
Computes the determinant of a matrix.
Namespace for general, non-LArSoft-specific utilities.
Definition: PIDAAlg.h:17
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)
static Matrix_t InvertSymmetricMatrix(Matrix_t const &mat)
Computes the determinant of a matrix.
Int_t col[ntarg]
Definition: Style.C:29
Double_t R
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:40
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.