ampsci
High-precision calculations for one- and two-valence atomic systems
Matrix.ipp
1#pragma once
2
3namespace LinAlg {
4
5//==============================================================================
6template <typename T>
7class View {
8 std::size_t m_size;
9 std::size_t m_stride;
10 T *m_data;
11
12public:
13 View(T *data, std::size_t start, std::size_t size, std::size_t stride)
14 : m_size(size), m_stride(stride), m_data(data + long(start)) {}
15
16 std::size_t size() const { return m_size; }
17
18 //! [] index access (with no range checking). [i][j] returns ith row, jth col
19 T &operator[](std::size_t i) { return m_data[i * m_stride]; }
20 //! As above, but const
21 T operator[](std::size_t i) const { return m_data[i * m_stride]; }
22
23 //! () index access (with range checking). (i,j) returns ith row, jth col
24 T &at(std::size_t i) {
25 assert(i < m_size);
26 return m_data[i * m_stride];
27 }
28 //! As above, but const
29 T at(std::size_t i) const {
30 assert(i < m_size);
31 return m_data[i * m_stride];
32 }
33 //! () index access (with range checking). (i,j) returns ith row, jth col
34 T &operator()(std::size_t i) { return at(i); }
35 //! As above, but const
36 T operator()(std::size_t i) const { return at(i); }
37
38 T *data() { return m_data; }
39};
40
41//==============================================================================
42//! Non-owning 2D view onto a Matrix. Supports element access but not resize.
43//! Use Matrix_view<const T> for a read-only view.
44template <typename T>
46 std::size_t m_rows;
47 std::size_t m_cols;
48 T *m_data;
49
50public:
51 Matrix_view(T *data, std::size_t rows, std::size_t cols)
52 : m_rows(rows), m_cols(cols), m_data(data) {}
53
54 //! Implicit conversion from mutable Matrix (works for both mutable and const view)
55 Matrix_view(Matrix<std::remove_const_t<T>> &m)
56 : m_rows(m.rows()), m_cols(m.cols()), m_data(m.data()) {}
57
58 //! Implicit conversion from const Matrix (only for Matrix_view<const T>)
59 template <typename U = T, typename = std::enable_if_t<std::is_const_v<U>>>
60 Matrix_view(const Matrix<std::remove_const_t<T>> &m)
61 : m_rows(m.rows()), m_cols(m.cols()), m_data(m.data()) {}
62
63 std::size_t rows() const { return m_rows; }
64 std::size_t cols() const { return m_cols; }
65 std::size_t size() const { return m_rows * m_cols; }
66 bool empty() const { return m_rows == 0 || m_cols == 0; }
67
68 T *data() { return m_data; }
69 const T *data() const { return m_data; }
70
71 //! [] index access (no range checking). [i] returns pointer to ith row
72 T *operator[](std::size_t i) { return m_data + i * m_cols; }
73 const T *operator[](std::size_t i) const { return m_data + i * m_cols; }
74
75 //! at(i,j): element access with range checking
76 T &at(std::size_t i, std::size_t j) {
77 assert(i < m_rows && j < m_cols);
78 return m_data[i * m_cols + j];
79 }
80 T at(std::size_t i, std::size_t j) const {
81 assert(i < m_rows && j < m_cols);
82 return m_data[i * m_cols + j];
83 }
84 const T &atc(std::size_t i, std::size_t j) const {
85 assert(i < m_rows && j < m_cols);
86 return m_data[i * m_cols + j];
87 }
88
89 //! (i,j): same as at(i,j)
90 T &operator()(std::size_t i, std::size_t j) { return at(i, j); }
91 T operator()(std::size_t i, std::size_t j) const { return at(i, j); }
92
93 auto begin() { return m_data; }
94 auto end() { return m_data + m_rows * m_cols; }
95 auto cbegin() const { return m_data; }
96 auto cend() const { return m_data + m_rows * m_cols; }
97};
98
99//==============================================================================
100//==============================================================================
101//==============================================================================
102
103//==============================================================================
104// Returns the determinant. Uses GSL; via LU decomposition. Only works for
105// double/complex<double>
106template <typename T>
108 static_assert(std::is_same_v<T, double> ||
109 std::is_same_v<T, std::complex<double>>,
110 "Determinant only works for double");
111
112 assert(rows() == cols() && "Determinant only defined for square matrix");
113 // Make a copy, since this is destructive. (Performs LU decomp)
114 auto LU = *this; // will become LU decomposed version
115 int sLU = 0;
116 auto gsl_view = LU.as_gsl_view();
117 gsl_permutation *permutn = gsl_permutation_alloc(rows());
118 if constexpr (std::is_same_v<T, double>) {
119 gsl_linalg_LU_decomp(&gsl_view.matrix, permutn, &sLU);
120 gsl_permutation_free(permutn);
121 return gsl_linalg_LU_det(&gsl_view.matrix, sLU);
122 } else if constexpr (std::is_same_v<T, std::complex<double>>) {
123 gsl_linalg_complex_LU_decomp(&gsl_view.matrix, permutn, &sLU);
124 gsl_permutation_free(permutn);
125 const auto gsl_cmplx = gsl_linalg_complex_LU_det(&gsl_view.matrix, sLU);
126 // Can probably avoid this copy? doesn't really matter.
127 return {GSL_REAL(gsl_cmplx), GSL_IMAG(gsl_cmplx)};
128 }
129}
130
131//==============================================================================
132// Inverts the matrix, in place. Uses GSL; via LU decomposition. Only works
133// for double/complex<double>.
134template <typename T>
136 static_assert(
137 std::is_same_v<T, double> || std::is_same_v<T, std::complex<double>>,
138 "invert only works for Matrix<double> or Matrix<complex<double>>");
139
140 assert(rows() == cols() && "Inverse only defined for square matrix");
141 int sLU = 0;
142 // gsl_linalg_LU_decomp(m, permutn, &sLU);
143 // gsl_linalg_LU_invx(m, permutn);
144 // In-place inversion gsl_linalg_LU_invx added sometime after GSL v:2.1
145 // Getafix only has 2.1 installed, so can't use this for now
146 auto LU = *this; // copy! to be LU decomposed
147 auto LU_gsl = LU.as_gsl_view();
148 auto iverse_gsl = this->as_gsl_view();
149 gsl_permutation *permutn = gsl_permutation_alloc(m_rows);
150 if constexpr (std::is_same_v<T, double>) {
151 gsl_linalg_LU_decomp(&LU_gsl.matrix, permutn, &sLU);
152 gsl_linalg_LU_invert(&LU_gsl.matrix, permutn, &iverse_gsl.matrix);
153 } else if constexpr (std::is_same_v<T, std::complex<double>>) {
154 gsl_linalg_complex_LU_decomp(&LU_gsl.matrix, permutn, &sLU);
155 gsl_linalg_complex_LU_invert(&LU_gsl.matrix, permutn, &iverse_gsl.matrix);
156 }
157 gsl_permutation_free(permutn);
158 return *this;
159}
160
161template <typename T>
163 auto inverse = *this; // copy
164 return inverse.invert_in_place();
165}
166
167//==============================================================================
168template <typename T>
170 Matrix<T> Tr(m_cols, m_rows);
171 if constexpr (std::is_same_v<T, double>) {
172 auto Tr_gsl = Tr.as_gsl_view();
173 const auto this_gsl = as_gsl_view();
174 gsl_matrix_transpose_memcpy(&Tr_gsl.matrix, &this_gsl.matrix);
175 } else if constexpr (std::is_same_v<T, float>) {
176 auto Tr_gsl = Tr.as_gsl_view();
177 const auto this_gsl = as_gsl_view();
178 gsl_matrix_float_transpose_memcpy(&Tr_gsl.matrix, &this_gsl.matrix);
179 } else if constexpr (std::is_same_v<T, std::complex<double>>) {
180 auto Tr_gsl = Tr.as_gsl_view();
181 const auto this_gsl = as_gsl_view();
182 gsl_matrix_complex_transpose_memcpy(&Tr_gsl.matrix, &this_gsl.matrix);
183 } else if constexpr (std::is_same_v<T, std::complex<float>>) {
184 auto Tr_gsl = Tr.as_gsl_view();
185 const auto this_gsl = as_gsl_view();
186 gsl_matrix_complex_float_transpose_memcpy(&Tr_gsl.matrix, &this_gsl.matrix);
187 } else {
188 // backup, works for any type
189 for (auto i = 0ul; i < Tr.rows(); ++i) {
190 for (auto j = 0ul; j < Tr.cols(); ++j) {
191 Tr[i][j] = (*this)[j][i];
192 }
193 }
194 }
195 return Tr;
196}
197
198//==============================================================================
199// Constructs a diagonal unit matrix (identity)
200template <typename T>
202 assert(m_rows == m_cols && "Can only call make_identity() for square matrix");
203 for (auto i = 0ul; i < m_rows; ++i) {
204 for (auto j = 0ul; j < m_cols; ++j) {
205 at(i, j) = i == j ? T(1) : T(0);
206 }
207 }
208 return *this;
209}
210// Sets all elements to zero
211template <typename T>
213 for (std::size_t i = 0; i < size(); ++i) {
214 m_data[i] = T(0);
215 }
216 return *this;
218
219//==============================================================================
220template <typename T>
222 static_assert(is_complex_v<T>, "conj() only available for complex Matrix");
223 std::vector<T> conj_data;
224 conj_data.reserve(m_data.size());
225 for (std::size_t i = 0; i < m_data.size(); ++i) {
226 conj_data.push_back(std::conj(m_data[i]));
227 }
228 return Matrix<T>{m_rows, m_cols, std::move(conj_data)};
229}
231template <typename T>
233 static_assert(is_complex_v<T>, "conj() only available for complex Matrix");
234 for (std::size_t i = 0; i < m_data.size(); ++i) {
235 m_data[i] = std::conj(m_data[i]);
237 return *this;
239//------------------------------------------------------------------------------
240template <typename T>
241auto Matrix<T>::real() const {
242 static_assert(is_complex_v<T>, "real() only available for complex Matrix");
243 std::vector<typename T::value_type> real_data;
244 real_data.reserve(m_data.size());
245 for (std::size_t i = 0; i < m_data.size(); ++i) {
246 real_data.push_back(std::real(m_data[i]));
247 }
248 return Matrix<typename T::value_type>{m_rows, m_cols, std::move(real_data)};
250//------------------------------------------------------------------------------
251template <typename T>
252auto Matrix<T>::imag() const {
253 static_assert(is_complex_v<T>, "imag() only available for complex Matrix");
254 std::vector<typename T::value_type> imag_data;
255 imag_data.reserve(m_data.size());
256 for (std::size_t i = 0; i < m_data.size(); ++i) {
257 imag_data.push_back(std::imag(m_data[i]));
258 }
259 return Matrix<typename T::value_type>{m_rows, m_cols, std::move(imag_data)};
261//------------------------------------------------------------------------------
262template <typename T>
263auto Matrix<T>::complex() const {
264 static_assert(!is_complex_v<T>, "complex() only available for real Matrix");
265 // use move constructor to avoid default Matrix construction
266 std::vector<std::complex<T>> new_data;
267 new_data.reserve(m_data.size());
268 for (std::size_t i = 0; i < m_data.size(); ++i) {
269 new_data.push_back(m_data[i]);
270 }
271 return Matrix<std::complex<T>>{m_rows, m_cols, std::move(new_data)};
272}
273
274//==============================================================================
275template <typename T>
277 assert(rows() == rhs.rows() && cols() == rhs.cols() &&
278 "Matrices must have same dimensions for addition");
279 using namespace qip::overloads;
280 this->m_data += rhs.m_data;
281 return *this;
282}
283template <typename T>
285 assert(rows() == rhs.rows() && cols() == rhs.cols() &&
286 "Matrices must have same dimensions for subtraction");
287 using namespace qip::overloads;
288 this->m_data -= rhs.m_data;
289 return *this;
290}
291template <typename T>
293 using namespace qip::overloads;
294 this->m_data *= x;
295 return *this;
296}
297template <typename T>
298Matrix<T> &Matrix<T>::operator/=(const T x) {
299 using namespace qip::overloads;
300 this->m_data /= x;
301 return *this;
302}
303
304//==============================================================================
305// Matrix<T> += T : T assumed to be *Identity!
306template <typename T>
308 // Adds 'a' to diagonal elements (Assume a*Ident)
309 assert(m_rows == m_cols && "Can only call M+a for square matrix");
310 for (auto i = 0ul; i < m_rows; ++i) {
311 at(i, i) += aI;
312 }
313 return *this;
314}
315// Matrix<T> -= T : T assumed to be *Identity!
316template <typename T>
318 // Adds 'a' to diagonal elements (Assume a*Ident)
319 assert(m_rows == m_cols && "Can only call M-a for square matrix");
320 for (auto i = 0ul; i < m_rows; ++i) {
321 at(i, i) -= aI;
322 }
323 return *this;
324}
325
326//==============================================================================
327template <typename T>
329 assert(rows() == a.rows() && cols() == a.cols() &&
330 "Matrices must have same dimensions for mult_elements_by");
331 for (auto i = 0ul; i < m_data.size(); ++i) {
332 m_data[i] *= a.m_data[i];
333 }
334 return *this;
335}
336
337//==============================================================================
338template <typename T>
339[[nodiscard]] Matrix<T> operator*(const Matrix<T> &a, const Matrix<T> &b) {
340 // https://www.gnu.org/software/gsl/doc/html/blas.html
341 assert(a.cols() == b.rows() &&
342 "Matrices a and b must have correct dimension for multiplication");
343 Matrix<T> product(a.rows(), b.cols());
344
345 GEMM(a, b, &product);
346
347 return product;
348}
349
350//==============================================================================
351
352// // Matrix multiplication C = A*B. C is overwritten with product, and must be correct size already
353// template <typename T>
354// void GEMM(const Matrix<T> &a, const Matrix<T> &b, Matrix<T> *c, bool trans_A,
355// bool trans_B) {
356// //
357// assert(a.cols() == b.rows() &&
358// "Matrices a and b must have correct dimension for multiplication");
359// assert(c->rows() == a.rows() && c->cols() == b.cols() &&
360// "Matrices c (output) must have correct dimension for multiplication "
361// "of a and b");
362
363// const auto a_gsl = a.as_gsl_view();
364// const auto b_gsl = b.as_gsl_view();
365// auto c_gsl = c->as_gsl_view();
366
367// const auto a_trans = trans_A ? CblasTrans : CblasNoTrans;
368// const auto b_trans = trans_B ? CblasTrans : CblasNoTrans;
369
370// if constexpr (std::is_same_v<T, double>) {
371// gsl_blas_dgemm(a_trans, b_trans, 1.0, &a_gsl.matrix, &b_gsl.matrix, 0.0,
372// &c_gsl.matrix);
373// } else if constexpr (std::is_same_v<T, float>) {
374// gsl_blas_sgemm(a_trans, b_trans, 1.0f, &a_gsl.matrix, &b_gsl.matrix, 0.0f,
375// &c_gsl.matrix);
376// } else if constexpr (std::is_same_v<T, std::complex<double>>) {
377// gsl_blas_zgemm(a_trans, b_trans, GSL_COMPLEX_ONE, &a_gsl.matrix,
378// &b_gsl.matrix, GSL_COMPLEX_ZERO, &c_gsl.matrix);
379// } else if constexpr (std::is_same_v<T, std::complex<float>>) {
380// const gsl_complex_float one{1.0f, 0.0f};
381// const gsl_complex_float zero{0.0f, 0.0f};
382// gsl_blas_cgemm(a_trans, b_trans, one, &a_gsl.matrix, &b_gsl.matrix, zero,
383// &c_gsl.matrix);
384// }
385// }
386
387//==============================================================================
388inline CBLAS_TRANSPOSE to_cblas_trans(bool trans) {
389 return trans ? CblasTrans : CblasNoTrans;
390}
391
392//------------------------------------------------------------------------------
393template <typename T>
394void GEMM(const Matrix<T> &a, const Matrix<T> &b, Matrix<T> *c, bool trans_A,
395 bool trans_B) {
396 assert(c);
397
398 const auto ta = to_cblas_trans(trans_A);
399 const auto tb = to_cblas_trans(trans_B);
400
401 // Effective dimensions:
402 // op(A): (trans_A ? a.cols x a.rows : a.rows x a.cols)
403 // op(B): (trans_B ? b.cols x b.rows : b.rows x b.cols)
404 const int A_rows = static_cast<int>(trans_A ? a.cols() : a.rows());
405 const int A_cols = static_cast<int>(trans_A ? a.rows() : a.cols());
406 const int B_rows = static_cast<int>(trans_B ? b.cols() : b.rows());
407 const int B_cols = static_cast<int>(trans_B ? b.rows() : b.cols());
408
409 // GEMM sizes: C = op(A) * op(B), where
410 // M = rows(op(A)), N = cols(op(B)), K = cols(op(A)) = rows(op(B))
411 const int M = A_rows;
412 const int N = B_cols;
413 const int K = A_cols;
414
415 assert(A_cols == B_rows && "op(A) cols must equal op(B) rows");
416 assert(static_cast<int>(c->rows()) == M && static_cast<int>(c->cols()) == N &&
417 "Output matrix c must be sized MxN");
418
419 // Row-major leading dimensions:
420 // lda = number of columns in A's *storage* (i.e., a.cols()) regardless of trans
421 // same for b, c
422 const int lda = static_cast<int>(a.cols());
423 const int ldb = static_cast<int>(b.cols());
424 const int ldc = static_cast<int>(c->cols());
425
426 if constexpr (std::is_same_v<T, double>) {
427 cblas_dgemm(CblasRowMajor, ta, tb, M, N, K, 1.0, a.data(), lda, b.data(),
428 ldb, 0.0, c->data(), ldc);
429
430 } else if constexpr (std::is_same_v<T, float>) {
431 cblas_sgemm(CblasRowMajor, ta, tb, M, N, K, 1.0f, a.data(), lda, b.data(),
432 ldb, 0.0f, c->data(), ldc);
433
434 } else if constexpr (std::is_same_v<T, std::complex<double>>) {
435 const std::complex<double> alpha{1.0, 0.0};
436 const std::complex<double> beta{0.0, 0.0};
437 cblas_zgemm(CblasRowMajor, ta, tb, M, N, K, &alpha, a.data(), lda, b.data(),
438 ldb, &beta, c->data(), ldc);
439
440 } else if constexpr (std::is_same_v<T, std::complex<float>>) {
441 const std::complex<float> alpha{1.0f, 0.0f};
442 const std::complex<float> beta{0.0f, 0.0f};
443 cblas_cgemm(CblasRowMajor, ta, tb, M, N, K, &alpha, a.data(), lda, b.data(),
444 ldb, &beta, c->data(), ldc);
445
446 } else {
447 static_assert(!sizeof(T), "GEMM: unsupported scalar type");
448 }
449}
450
451//==============================================================================
452// M_ab = A_ai B_aj C_ij D_ib E_jb, using BLAS
453template <typename T>
454void PENTA_GEMM(const Matrix<T> &A, const Matrix<T> &B, const Matrix<T> &C,
455 const Matrix<T> &D, const Matrix<T> &E, Matrix<T> *pM) {
456 //
457 const auto N = A.rows(); // assume all square
458 assert(A.cols() == A.rows() && "Must be square");
459
460 Matrix<T> X(N, N);
461 Matrix<T> Y(N, N);
462 auto &M = *pM;
463
464 // M_ab = A_ai B_aj C_ij D_ib E_jb
465 // = A_ai B_aj X(i)_jb D_ib
466 // = A_ai Y(i)_ab D_ib
467 // X(i)_jb = C_ij * E_j2;
468 // Y(i)_aj = B_ij * X(i)_jb
469
470 for (std::size_t i = 0; i < N; ++i) {
471 for (std::size_t j = 0; j < N; ++j) {
472 const auto cij = C[i][j];
473 for (std::size_t b = 0; b < N; ++b) {
474 X[j][b] = cij * E[j][b];
475 }
476 }
477 GEMM(B, X, &Y);
478 for (std::size_t a = 0; a < N; ++a) {
479 for (std::size_t b = 0; b < N; ++b) {
480 M[a][b] += A[a][i] * Y[a][b] * D[i][b];
481 }
482 }
483 }
484}
485
486// M_ab = A_ai B_aj C_ij D_ib E_jb
487template <typename T, bool PARALLEL>
488void PENTA(const Matrix<T> &A, const Matrix<T> &B, const Matrix<T> &C,
489 const Matrix<T> &D, const Matrix<T> &E, Matrix<T> *pM) {
490 //
491 const auto N = A.rows(); // assume all square
492 assert(A.cols() == A.rows() && "Must be square");
493
494 auto &M = *pM;
495
496 // M_ab = A_ai B_aj C_ij D_ib E_jb
497 if constexpr (PARALLEL) {
498
499#pragma omp parallel for collapse(2)
500 for (std::size_t a = 0; a < N; ++a) {
501 for (std::size_t b = 0; b < N; ++b) {
502 const T *Ba = &B[a][0];
503 T Mab = T(0);
504 for (std::size_t i = 0; i < N; ++i) {
505 const auto AaiDib = A[a][i] * D[i][b];
506 const T *Ci = &C[i][0];
507 for (std::size_t j = 0; j < N; ++j) {
508 Mab += AaiDib * Ba[j] * Ci[j] * E[j][b];
509 }
510 }
511 M[a][b] = Mab;
512 }
513 }
514
515 } else {
516
517 for (std::size_t a = 0; a < N; ++a) {
518 const T *Ba = &B[a][0];
519 for (std::size_t b = 0; b < N; ++b) {
520 T Mab = T(0);
521 for (std::size_t i = 0; i < N; ++i) {
522 const auto AaiDib = A[a][i] * D[i][b];
523 const T *Ci = &C[i][0];
524 for (std::size_t j = 0; j < N; ++j) {
525 Mab += AaiDib * Ba[j] * Ci[j] * E[j][b];
526 }
527 }
528 M[a][b] = Mab;
529 }
530 }
531 }
532}
533
534//==============================================================================
535template <typename T>
537 if constexpr (std::is_same_v<T, double>) {
538 return gsl_matrix_view_array(m_data.data(), m_rows, m_cols);
539 } else if constexpr (std::is_same_v<T, float>) {
540 return gsl_matrix_float_view_array(m_data.data(), m_rows, m_cols);
541 } else if constexpr (std::is_same_v<T, std::complex<double>>) {
542 // reinterpret_cast OK: cppreference.com/w/cpp/numeric/complex
543 return gsl_matrix_complex_view_array(
544 reinterpret_cast<double *>(m_data.data()), m_rows, m_cols);
545 } else if constexpr (std::is_same_v<T, std::complex<float>>) {
546 return gsl_matrix_complex_float_view_array(
547 reinterpret_cast<float *>(m_data.data()), m_rows, m_cols);
548 } else {
549 assert(false && "as_gsl_view() only available for double/float (or complex "
550 "double/float)");
551 }
552}
553
554template <typename T>
556 if constexpr (std::is_same_v<T, double>) {
557 return gsl_matrix_const_view_array(m_data.data(), m_rows, m_cols);
558 } else if constexpr (std::is_same_v<T, float>) {
559 return gsl_matrix_float_const_view_array(m_data.data(), m_rows, m_cols);
560 } else if constexpr (std::is_same_v<T, std::complex<double>>) {
561 return gsl_matrix_complex_const_view_array(
562 reinterpret_cast<const double *>(m_data.data()), m_rows, m_cols);
563 } else if constexpr (std::is_same_v<T, std::complex<float>>) {
564 return gsl_matrix_complex_float_const_view_array(
565 reinterpret_cast<const float *>(m_data.data()), m_rows, m_cols);
566 } else {
567 assert(false && "as_gsl_view() only for available double/float (or complex "
568 "double/float)");
569 }
570}
571
572//==============================================================================
573template <typename T>
574std::ostream &operator<<(std::ostream &os, const Matrix<T> &a) {
575 for (auto i = 0ul; i < a.rows(); ++i) {
576 for (auto j = 0ul; j < a.cols(); ++j) {
577 os << a(i, j) << " ";
578 }
579 os << "\n";
580 }
581 os << "\n";
582 return os;
583}
584
585//==============================================================================
586//==============================================================================
587//==============================================================================
588
589//==============================================================================
590// Helper for equal()
591template <typename T>
592constexpr auto myEps() {
593 if constexpr (std::is_same_v<T, float> ||
594 std::is_same_v<T, std::complex<float>>) {
595 return 1.0e-6f;
596 } else if constexpr (std::is_same_v<T, double> ||
597 std::is_same_v<T, std::complex<double>>) {
598 return 1.0e-12;
599 } else {
600 return 0;
601 }
602}
603
604// Compares two matrices; returns true iff all elements compare relatively to
605// better than eps
606template <typename T>
607bool equal(const Matrix<T> &lhs, const Matrix<T> &rhs, T eps) {
608 if (lhs.rows() != rhs.rows())
609 return false;
610 if (lhs.cols() != rhs.cols())
611 return false;
612 for (auto i = 0ul; i < lhs.rows(); ++i) {
613 for (auto j = 0ul; j < lhs.cols(); ++j) {
614 // need abs on eps in case of complex
615 if (std::abs(lhs(i, j) - rhs(i, j)) >
616 std::abs(eps * (lhs(i, j) + rhs(i, j))))
617 return false;
618 }
619 }
620 return true;
621}
622
623} // namespace LinAlg
Provides a non-owning view onto a Matrix (read/write, but no resize)
Definition Matrix.ipp:45
T * operator[](std::size_t i)
[] index access (no range checking). [i] returns pointer to ith row
Definition Matrix.ipp:72
T & at(std::size_t i, std::size_t j)
at(i,j): element access with range checking
Definition Matrix.ipp:76
T & operator()(std::size_t i, std::size_t j)
(i,j): same as at(i,j)
Definition Matrix.ipp:90
Matrix_view(Matrix< std::remove_const_t< T > > &m)
Implicit conversion from mutable Matrix (works for both mutable and const view)
Definition Matrix.ipp:55
Matrix_view(const Matrix< std::remove_const_t< T > > &m)
Implicit conversion from const Matrix (only for Matrix_view<const T>)
Definition Matrix.ipp:60
Matrix class; row-major.
Definition Matrix.hpp:39
Matrix< T > & make_identity()
Constructs a diagonal unit matrix (identity), in place; only for square.
Definition Matrix.ipp:201
Matrix< T > & invert_in_place()
Inverts the matrix, in place. Uses GSL; via LU decomposition. Only works for double/complex<double>.
Definition Matrix.ipp:135
T * data()
Returns pointer to first element. Note: for std::complex<T>, this is a pointer to complex<T>,...
Definition Matrix.hpp:123
std::size_t rows() const
Return rows [major index size].
Definition Matrix.hpp:112
Matrix< T > conj() const
Returns conjugate of matrix.
Definition Matrix.ipp:221
Matrix< T > & operator+=(const Matrix< T > &rhs)
Overload standard operators: do what expected.
Definition Matrix.ipp:276
auto complex() const
Converts a real to complex matrix (changes type; returns a complex matrix)
Definition Matrix.ipp:263
auto imag() const
Returns imag part of complex matrix (changes type; returns a real matrix)
Definition Matrix.ipp:252
auto as_gsl_view()
Returns gsl_matrix_view (or _float_view, _complex_view, _complex_float_view). Call ....
Definition Matrix.ipp:536
Matrix< T > & conj_in_place()
Conjugates matrix, in place.
Definition Matrix.ipp:232
Matrix< T > transpose() const
Returns transpose of matrix.
Definition Matrix.ipp:169
Matrix< T > & zero()
Sets all elements to zero, in place.
Definition Matrix.ipp:212
Matrix< T > inverse() const
Returns inverse of the matrix. Leaves original matrix intact. Uses GSL; via LU decomposition....
Definition Matrix.ipp:162
std::size_t cols() const
Return columns [minor index size].
Definition Matrix.hpp:114
T determinant() const
Returns the determinant. Uses GSL; via LU decomposition. Only works for double/complex<double>
Definition Matrix.ipp:107
Matrix< T > & mult_elements_by(const Matrix< T > &a)
Muplitplies all the elements by those of matrix a, in place: M_ij *= a_ij.
Definition Matrix.ipp:328
auto real() const
Returns real part of complex matrix (changes type; returns a real matrix)
Definition Matrix.ipp:241
Proved a "view" onto an array.
Definition Matrix.ipp:7
T operator[](std::size_t i) const
As above, but const.
Definition Matrix.ipp:21
T operator()(std::size_t i) const
As above, but const.
Definition Matrix.ipp:36
T & operator[](std::size_t i)
[] index access (with no range checking). [i][j] returns ith row, jth col
Definition Matrix.ipp:19
T at(std::size_t i) const
As above, but const.
Definition Matrix.ipp:29
T & at(std::size_t i)
() index access (with range checking). (i,j) returns ith row, jth col
Definition Matrix.ipp:24
T & operator()(std::size_t i)
() index access (with range checking). (i,j) returns ith row, jth col
Definition Matrix.ipp:34
Defines Matrix, Vector classes, and linear some algebra functions.
Definition Matrix.hpp:26
void PENTA(const Matrix< T > &A, const Matrix< T > &B, const Matrix< T > &C, const Matrix< T > &D, const Matrix< T > &E, Matrix< T > *M)
5-matrix contraction for N*N matrices: M_ab = A_ai B_aj C_ij D_ib E_jb, without BLAS,...
Definition Matrix.ipp:488
void PENTA_GEMM(const Matrix< T > &A, const Matrix< T > &B, const Matrix< T > &C, const Matrix< T > &D, const Matrix< T > &E, Matrix< T > *M)
5-matrix contraction for N*N matrices: M_ab = A_ai B_aj C_ij D_ib E_jb, with BLAS
Definition Matrix.ipp:454
void GEMM(const Matrix< T > &a, const Matrix< T > &b, Matrix< T > *c, bool trans_A=false, bool trans_B=false)
Matrix multiplication C = A*B. C is overwritten with product, and must be correct size already.
Definition Matrix.ipp:394
bool equal(const Matrix< T > &lhs, const Matrix< T > &rhs, T eps=myEps< T >())
Compares two matrices; returns true iff all elements compare relatively to better than eps.
Definition Matrix.ipp:607
namespace qip::overloads provides operator overloads for std::vector
Definition Vector.hpp:451