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