ampsci
High-precision calculations for one- and two-valence atomic systems
Matrix.hpp
1#pragma once
2#include "qip/Vector.hpp" // for std::vector overloads
3#include <array>
4#include <cassert>
5#include <complex>
6#include <gsl/gsl_blas.h>
7#include <gsl/gsl_complex.h>
8#include <gsl/gsl_complex_math.h>
9#include <gsl/gsl_eigen.h>
10#include <gsl/gsl_linalg.h>
11#include <gsl/gsl_math.h>
12#include <iostream>
13#include <type_traits>
14#include <utility>
15#include <vector>
16
17//! Type trait: true iff T is std::complex<U> for some U
18template <typename T>
19struct is_complex : std::false_type {};
20
21template <typename T>
22struct is_complex<std::complex<T>> : std::true_type {};
23
24//! Convenience variable template: is_complex_v<T> == is_complex<T>::value
25template <typename T>
26constexpr bool is_complex_v = is_complex<T>::value;
27
28//==============================================================================
29/*!
30 @brief Linear algebra: matrices, vectors, views, and solvers.
31 @details
32 Provides matrix and vector types, non-owning views, and a set of
33 linear algebra solvers wrapping LAPACK and GSL.
34
35 ### Core types:
36 - @ref LinAlg::Matrix<T> : owning row-major matrix; supports real and complex
37 element types. Provides arithmetic, GSL interop, and element-wise access.
38 - @ref LinAlg::Vector<T> : owning 1D array; used for eigenvectors, right-hand sides,
39 and eigenvalue arrays.
40
41 ### Views:
42 - @ref LinAlg::View<T> : non-owning strided view over a 1D segment of an array.
43 Used to provide row and column access into a Matrix without copying.
44 Obtained via @ref Matrix::row_view() and @ref Matrix::column_view()
45 - @ref LinAlg::Matrix_view<T> : non-owning view of a 2D subblock of a Matrix.
46
47 ### Solvers:
48 - @ref LinAlg::solve_Axeqb() : solves `Ax = b` via LU decomposition (GSL).
49 - @ref LinAlg::symmhEigensystem() : generalised problem `Av = eBv` or `Av = ev`
50 Several overloads, and templayte for real/complex types
51 (LAPACK `dsygv`/`zhegv`/`dsyevr`/`dsyev`/`zheev`).
52 - @ref LinAlg::genEigensystem() : general non-symmetric real matrix (GSL).
53*/
54namespace LinAlg {
55
56// Forward declaration (Matrix_view constructors accept Matrix<T> by reference)
57template <typename T>
58class Matrix;
59
60/*!
61 @brief Non-owning strided view onto a 1D segment of an array.
62 @details
63 Provides indexed read/write access into an existing array without ownership.
64 The stride allows views over non-contiguous memory (e.g., a column of a
65 row-major matrix).
66
67 Used by @ref Matrix::row_view() and @ref Matrix::column_view().
68*/
69template <typename T>
70class View {
71 std::size_t m_size;
72 std::size_t m_stride;
73 T *m_data;
74
75public:
76 //! Construct view over @p size elements starting at offset @p start, with @p stride
77 View(T *data, std::size_t start, std::size_t size, std::size_t stride)
78 : m_size(size), m_stride(stride), m_data(data + long(start)) {}
79
80 //! Number of elements in the view
81 std::size_t size() const { return m_size; }
82
83 //! [] index access (no range checking), mutable
84 T &operator[](std::size_t i) { return m_data[i * m_stride]; }
85 //! [] index access (no range checking), const
86 T operator[](std::size_t i) const { return m_data[i * m_stride]; }
87
88 //! at(i): element access with range checking, mutable
89 T &at(std::size_t i) {
90 assert(i < m_size);
91 return m_data[i * m_stride];
92 }
93 //! at(i): element access with range checking, const
94 T at(std::size_t i) const {
95 assert(i < m_size);
96 return m_data[i * m_stride];
97 }
98 //! () index access with range checking, mutable
99 T &operator()(std::size_t i) { return at(i); }
100 //! () index access with range checking, const
101 T operator()(std::size_t i) const { return at(i); }
102
103 //! Raw pointer to first viewed element
104 T *data() { return m_data; }
105};
106
107//==============================================================================
108/*!
109 @brief Non-owning 2D view onto a Matrix.
110 @details
111 Provides row/column element access to an existing matrix buffer without
112 ownership or resize capability. Supports both mutable (`Matrix_view<T>`)
113 and read-only (`Matrix_view<const T>`) access.
114
115 Implicitly constructible from `Matrix<T>` (mutable view) and from
116 `const Matrix<T>` (const view only).
117
118 @note Iterators (`begin()`/`end()`) yield raw pointers into the flat buffer.
119*/
120template <typename T>
122 std::size_t m_rows;
123 std::size_t m_cols;
124 T *m_data;
125
126public:
127 //! Construct from raw pointer and dimensions (no ownership)
128 Matrix_view(T *data, std::size_t rows, std::size_t cols)
129 : m_rows(rows), m_cols(cols), m_data(data) {}
130
131 //! Implicit conversion from mutable Matrix (works for both mutable and const view)
132 Matrix_view(Matrix<std::remove_const_t<T>> &m)
133 : m_rows(m.rows()), m_cols(m.cols()), m_data(m.data()) {}
134
135 //! Implicit conversion from const Matrix (only for Matrix_view<const T>)
136 template <typename U = T, typename = std::enable_if_t<std::is_const_v<U>>>
137 Matrix_view(const Matrix<std::remove_const_t<T>> &m)
138 : m_rows(m.rows()), m_cols(m.cols()), m_data(m.data()) {}
139
140 //! Return rows [major index size]
141 std::size_t rows() const { return m_rows; }
142 //! Return columns [minor index size]
143 std::size_t cols() const { return m_cols; }
144 //! Return rows*columns [total array size]
145 std::size_t size() const { return m_rows * m_cols; }
146 //! Bool - is empty? (same as size==0)
147 bool empty() const { return m_rows == 0 || m_cols == 0; }
148
149 //! Raw pointer to first element, mutable
150 T *data() { return m_data; }
151 //! Raw pointer to first element, const
152 const T *data() const { return m_data; }
153
154 //! [] index access (no range checking). [i] returns pointer to ith row, mutable
155 T *operator[](std::size_t i) { return m_data + i * m_cols; }
156 //! [] index access (no range checking). [i] returns const pointer to ith row
157 const T *operator[](std::size_t i) const { return m_data + i * m_cols; }
158
159 //! at(i,j): element access with range checking, mutable
160 T &at(std::size_t i, std::size_t j) {
161 assert(i < m_rows && j < m_cols);
162 return m_data[i * m_cols + j];
163 }
164 //! at(i,j): element access with range checking, const
165 T at(std::size_t i, std::size_t j) const {
166 assert(i < m_rows && j < m_cols);
167 return m_data[i * m_cols + j];
168 }
169 //! at(i,j): element access with range checking, const ref
170 const T &atc(std::size_t i, std::size_t j) const {
171 assert(i < m_rows && j < m_cols);
172 return m_data[i * m_cols + j];
173 }
174
175 //! () index access with range checking, mutable
176 T &operator()(std::size_t i, std::size_t j) { return at(i, j); }
177 //! () index access with range checking, const
178 T operator()(std::size_t i, std::size_t j) const { return at(i, j); }
179
180 //! Iterators over flat data buffer
181 auto begin() { return m_data; }
182 auto end() { return m_data + m_rows * m_cols; }
183 auto cbegin() const { return m_data; }
184 auto cend() const { return m_data + m_rows * m_cols; }
185};
186
187//==============================================================================
188/*!
189 @brief Row-major dense matrix with arithmetic and linear algebra support.
190 @details
191 Owns its data as a contiguous `std::vector<T>` stored in row-major order.
192 Supports scalar types `T = float`, `double`, `std::complex<float>`, and
193 `std::complex<double>`.
194
195 Provides:
196 - Element access via `operator[]` (no bounds checking) and `at()`/`operator()` (bounds-checked).
197 - Basic arithmetic: addition, subtraction, scalar multiply/divide, and matrix
198 multiplication via BLAS.
199 - Linear algebra via GSL: `determinant()`, `inverse()`, `transpose()`.
200 - Conversion utilities: `conj()`, `real()`, `imag()`, `complex()`.
201 - Non-owning views: `row_view()`, `column_view()`, `matrix_view()`.
202 - GSL interop: `as_gsl_view()`.
203
204 @note The scalar `+=` and `-=` operators treat the scalar as a multiple of
205 the identity: `M += a` adds `a` to all diagonal elements. Only valid
206 for square matrices.
207*/
208template <typename T = double>
209class Matrix {
210
211protected:
212 std::size_t m_rows;
213 std::size_t m_cols;
214 std::vector<T> m_data{};
215
216public:
217 //! Default initialiser
218 Matrix() : m_rows(0), m_cols(0) {}
219
220 //! Initialise a blank matrix rows*cols, filled with 0
221 Matrix(std::size_t rows, std::size_t cols)
222 : m_rows(rows), m_cols(cols), m_data(rows * cols) {}
223
224 //! Initialise a matrix rows*cols, filled with 'value'
225 Matrix(std::size_t rows, std::size_t cols, const T &value)
226 : m_rows(rows), m_cols(cols), m_data(rows * cols, value) {}
227
228 //! Initialise a blank square matrix dimension*dimension, filled with 0
229 // excplicit, since don't alow flot->int converions
230 explicit Matrix(std::size_t dimension)
231 : m_rows(dimension), m_cols(dimension), m_data(dimension * dimension) {}
232
233 //! Initialise a matrix from initialiser list. {{},{},{}}. Each row must be
234 //! same length
235 Matrix(std::initializer_list<std::initializer_list<T>> ll)
236 : m_rows(ll.size()), m_cols(ll.begin()->size()), m_data{} {
237 // way to avoid copy?
238 m_data.reserve(m_rows * m_cols);
239 for (auto &l : ll) {
240 m_data.insert(m_data.end(), l.begin(), l.end());
241 }
242 }
243
244 //! Initialise a matrix from single initialiser list. {...}.
245 Matrix(std::size_t rows, std::size_t cols, std::initializer_list<T> l)
246 : m_rows(rows), m_cols(cols), m_data{l} {
247 assert(m_data.size() == rows * cols &&
248 "initializer_list must be rows*cols");
249 }
250
251 //! Initialise a matrix from single initialiser list. {...}.
252 Matrix(std::size_t rows, std::size_t cols, std::vector<T> &&v)
253 : m_rows(rows), m_cols(cols), m_data{std::forward<std::vector<T>>(v)} {
254 assert(m_data.size() == rows * cols &&
255 "initializer_list must be rows*cols");
256 }
257 //! Initialise a matrix from single initialiser list. {...}.
258 Matrix(std::size_t rows, std::size_t cols, const std::vector<T> &v)
259 : m_rows(rows), m_cols(cols), m_data{v} {
260 assert(m_data.size() == rows * cols &&
261 "initializer_list must be rows*cols");
262 }
263
264 //============================================================================
265 //! Resizes matrix to new dimension; all values reset to default
266 void resize(std::size_t rows, std::size_t cols) {
267 m_rows = rows;
268 m_cols = cols;
269 m_data.assign(rows * cols, T{});
270 }
271
272 //! Resizes matrix to new dimension; all values reset to 'value'
273 void resize(std::size_t rows, std::size_t cols, const T &value) {
274 m_rows = rows;
275 m_cols = cols;
276 m_data.assign(rows * cols, value);
277 }
278
279 //============================================================================
280
281 //! Return rows [major index size]
282 std::size_t rows() const { return m_rows; }
283 //! Return columns [minor index size]
284 std::size_t cols() const { return m_cols; }
285 //! Return rows*columns [total array size]
286 std::size_t size() const { return m_data.size(); }
287
288 //! Bool - is empty? (same as size==0)
289 bool empty() const { return m_data.empty(); }
290
291 //! Pointer to first element; for std::complex<T> this is complex<T>*, not T*
292 T *data() { return m_data.data(); }
293 //! Const pointer to first element; for std::complex<T> this is const complex<T>*, not const T*
294 const T *data() const { return m_data.data(); }
295
296 //============================================================================
297
298 //! [] index access (no range checking). [i] returns pointer to ith row, mutable
299 T *operator[](std::size_t i) { return &(m_data[i * m_cols]); }
300 //! [] index access (no range checking). [i] returns const pointer to ith row
301 const T *operator[](std::size_t i) const { return &(m_data[i * m_cols]); }
302
303 //! at(i,j): element access with range checking, mutable
304 T &at(std::size_t row_i, std::size_t col_j) {
305 assert(row_i < m_rows && col_j < m_cols);
306 return m_data[row_i * m_cols + col_j];
307 }
308 //! at(i,j): element access with range checking, const
309 T at(std::size_t row_i, std::size_t col_j) const {
310 assert(row_i < m_rows && col_j < m_cols);
311 return m_data[row_i * m_cols + col_j];
312 }
313
314 //! at(i,j): element access with range checking, const ref
315 const T &atc(std::size_t row_i, std::size_t col_j) const {
316 assert(row_i < m_rows && col_j < m_cols);
317 return m_data[row_i * m_cols + col_j];
318 }
319
320 //! () index access with range checking, mutable
321 T &operator()(std::size_t i, std::size_t j) { return at(i, j); }
322 //! () index access with range checking, const
323 T operator()(std::size_t i, std::size_t j) const { return at(i, j); }
324
325 //============================================================================
326
327 //! iterators for underlying std::vector (entire data)
328 auto begin() { return m_data.begin(); }
329 auto cbegin() const { return m_data.cbegin(); }
330 auto end() { return m_data.end(); }
331 auto cend() const { return m_data.cend(); }
332
333 //! Returns raw c pointer to start of a row
334 // [[deprecated]]
335 const T *row(std::size_t row) const {
336 return m_data.data() + long(row * m_cols);
337 }
338
339 //! Returns a mutable 'View' of a row
340 [[nodiscard]] View<T> row_view(std::size_t row) {
341 return View<T>(this->data(), row * m_cols, m_cols, 1ul);
342 }
343 //! Returns an immutable 'View' of a row
344 [[nodiscard]] View<const T> row_view(std::size_t row) const {
345 return View<const T>(this->data(), row * m_cols, m_cols, 1ul);
346 }
347 //! Returns a mutable 'View' of a column
348 [[nodiscard]] View<T> column_view(std::size_t col) {
349 return View<T>(this->data(), col, m_rows, m_rows);
350 }
351 //! Returns an immutable 'View' of a column
352 [[nodiscard]] View<const T> column_view(std::size_t col) const {
353 return View<const T>(this->data(), col, m_rows, m_rows);
354 }
355
356 //! Returns a mutable view of the entire matrix (no ownership, no resize)
357 [[nodiscard]] Matrix_view<T> matrix_view() {
358 return Matrix_view<T>(m_data.data(), m_rows, m_cols);
359 }
360 //! Returns an immutable view of the entire matrix (no ownership, no resize)
361 [[nodiscard]] Matrix_view<const T> matrix_view() const {
362 return Matrix_view<const T>(m_data.data(), m_rows, m_cols);
363 }
364
365 //============================================================================
366 /*!
367 @brief Returns a GSL matrix view for use with GSL functions (no copy).
368 @details
369 Returns a `gsl_matrix_view` (or `_float_view`, `_complex_view`,
370 `_complex_float_view`) wrapping the matrix data in place. Access the
371 underlying GSL matrix via `.matrix` on the returned object. Allows
372 use of all GSL/BLAS built-in functions without any data copy.
373
374 Supported types: `double`, `float`, `std::complex<double>`,
375 `std::complex<float>`.
376
377 @note Both the `Matrix` and the returned view must remain in scope
378 during use; the view is non-owning.
379 @warning Fails at runtime (assert) for unsupported scalar types.
380 */
381 [[nodiscard]] auto as_gsl_view();
382
383 //! Const GSL matrix view; see as_gsl_view()
384 [[nodiscard]] auto as_gsl_view() const;
385
386 //============================================================================
387 // Basic matrix operations:
388 //============================================================================
389 //============================================================================
390
391 /*!
392 @brief Returns the determinant via LU decomposition (GSL).
393 @details
394 Makes an internal copy of the matrix, performs LU decomposition, and
395 returns the determinant. The original matrix is not modified.
396
397 @return Determinant of the matrix.
398 @note Only available for `T = double` or `T = std::complex<double>`.
399 @warning Only defined for square matrices; asserts otherwise.
400 */
401 [[nodiscard]] T determinant() const;
402
403 /*!
404 @brief Inverts the matrix in place via LU decomposition (GSL).
405 @details
406 Performs LU decomposition on a copy, then overwrites `*this` with its
407 inverse using `gsl_linalg_LU_invert` (or the complex equivalent).
408
409 @return Reference to `*this` (the inverted matrix).
410 @note Only available for `T = double` or `T = std::complex<double>`.
411 @warning Only defined for square matrices; asserts otherwise.
412 */
414
415 /*!
416 @brief Returns inverse of the matrix; original is unchanged.
417 @details
418 Copies `*this` and calls `invert_in_place()` on the copy.
419
420 @note Only available for `T = double` or `T = std::complex<double>`.
421 */
422 [[nodiscard]] Matrix<T> inverse() const {
423 auto inv = *this;
424 return inv.invert_in_place();
425 }
426
427 /*!
428 @brief Returns the transpose of the matrix.
429 @details
430 Allocates and returns a new `Matrix<T>` of size `cols() x rows()` with
431 elements transposed. Uses GSL `gsl_matrix_transpose_memcpy` for `double`,
432 `float`, and their complex variants; falls back to a naive loop for other
433 types.
434
435 @return New matrix of dimensions `cols() x rows()`.
436 */
437 [[nodiscard]] Matrix<T> transpose() const;
438
439 //============================================================================
440
441 //! Constructs a diagonal unit matrix (identity), in place; only for square
443 //! Sets all elements to zero, in place
444 Matrix<T> &zero();
445 // //! M -> M + aI, for I=identity (adds a to diag elements), in place
446 // Matrix<T> &plusIdent(T a = T(1));
447 //============================================================================
448
449 //! Returns conjugate of matrix
450 [[nodiscard]] Matrix<T> conj() const;
451 //! Returns real part of complex matrix (changes type; returns a real matrix)
452 [[nodiscard]] auto real() const;
453 //! Returns imag part of complex matrix (changes type; returns a real matrix)
454 [[nodiscard]] auto imag() const;
455 //! Converts a real to complex matrix (changes type; returns a complex matrix)
456 [[nodiscard]] auto complex() const;
457
458 //! Conjugates matrix, in place
460
461 //============================================================================
462 /*!
463 @brief Elementwise multiply in place: M_ij *= a_ij
464 @details
465 Each element of `*this` is multiplied by the corresponding element of @p a.
466 Matrices must have the same dimensions.
467
468 @param a Matrix whose elements multiply `*this`.
469 @return Reference to `*this`.
470 @warning Dimensions must match; asserts otherwise.
471 */
473
474 /*!
475 @brief Returns new matrix C with C_ij = A_ij * B_ij (elementwise product).
476 @details Calls `a.mult_elements_by(b)` on a copy of @p a.
477 */
478 [[nodiscard]] friend Matrix<T> mult_elements(Matrix<T> a,
479 const Matrix<T> &b) {
480 return a.mult_elements_by(b);
481 }
482
483 //============================================================================
484 //! In-place elementwise addition; dimensions must match
485 Matrix<T> &operator+=(const Matrix<T> &rhs);
486 //! In-place elementwise subtraction; dimensions must match
487 Matrix<T> &operator-=(const Matrix<T> &rhs);
488 //! In-place scalar multiply: M_ij *= x
489 Matrix<T> &operator*=(const T x);
490 //! In-place scalar divide: M_ij /= x
491 Matrix<T> &operator/=(const T x);
492
493 //============================================================================
494 //! Elementwise addition: returns M + N
495 [[nodiscard]] friend Matrix<T> operator+(Matrix<T> lhs,
496 const Matrix<T> &rhs) {
497 return (lhs += rhs);
498 }
499 //! Elementwise subtraction: returns M - N
500 [[nodiscard]] friend Matrix<T> operator-(Matrix<T> lhs,
501 const Matrix<T> &rhs) {
502 return (lhs -= rhs);
503 }
504 //! Scalar multiply: returns x * M
505 [[nodiscard]] friend Matrix<T> operator*(const T x, Matrix<T> rhs) {
506 return (rhs *= x);
507 }
508 //! Scalar multiply: returns M * x
509 [[nodiscard]] friend Matrix<T> operator*(Matrix<T> lhs, const T x) {
510 return (lhs *= x);
511 }
512 //! Scalar divide: returns M / x
513 [[nodiscard]] friend Matrix<T> operator/(Matrix<T> lhs, const T x) {
514 return (lhs /= x);
515 }
516
517 //============================================================================
518 //! M += aI: adds a to diagonal elements (scalar treated as a*Identity)
519 Matrix<T> &operator+=(T aI);
520 //! M -= aI: subtracts a from diagonal elements (scalar treated as a*Identity)
521 Matrix<T> &operator-=(T aI);
522
523 //! Returns M + aI (adds a to diagonal)
524 [[nodiscard]] friend Matrix<T> operator+(Matrix<T> M, T aI) {
525 return (M += aI);
526 }
527 //! Returns M - aI (subtracts a from diagonal)
528 [[nodiscard]] friend Matrix<T> operator-(Matrix<T> M, T aI) {
529 return (M -= aI);
530 }
531
532 //============================================================================
533 //! Matrix multiplication: C_ij = sum_k A_ik*B_kj
534 template <typename U>
535 friend Matrix<U> operator*(const Matrix<U> &a, const Matrix<U> &b);
536
537 //! Prints matrix elements row by row to output stream
538 template <typename U>
539 friend std::ostream &operator<<(std::ostream &os, const Matrix<U> &a);
540};
541
542//==============================================================================
543//==============================================================================
544//==============================================================================
545
546//! Converts bool to CBLAS_TRANSPOSE enum (CblasTrans if true, CblasNoTrans if false)
547inline CBLAS_TRANSPOSE to_cblas_trans(bool trans) {
548 return trans ? CblasTrans : CblasNoTrans;
549}
550
551/*!
552 @brief Matrix multiplication C = op(A) * op(B) via CBLAS GEMM (row-major).
553 @details
554 Computes \f$ C = \mathrm{op}(A)\,\mathrm{op}(B) \f$ where
555 \f$ \mathrm{op}(X) = X \f$ or \f$ X^T \f$ depending on @p trans_A /
556 @p trans_B. @p c is overwritten with the result.
557
558 Wraps CBLAS `gemm` for `double`, `float`, `std::complex<double>`, and
559 `std::complex<float>`.
560
561 @param a Left-hand matrix.
562 @param b Right-hand matrix.
563 @param[out] c Output matrix; must be pre-allocated to the correct size.
564 @param trans_A If true, use \f$A^T\f$ in the product.
565 @param trans_B If true, use \f$B^T\f$ in the product.
566 @warning @p c must not alias @p a or @p b.
567*/
568template <typename T>
569void GEMM(const Matrix<T> &a, const Matrix<T> &b, Matrix<T> *c,
570 bool trans_A = false, bool trans_B = false);
571
572//------------------------------------------------------------------------------
573
574//! 5-matrix contraction for N*N matrices: M_ab = A_ai B_aj C_ij D_ib E_jb, with BLAS
575/*!
576 @details
577 All input matrices are assumed square with the same dimension N.
578 The contraction sums over indices i and j:
579 \f[
580 M_{ab} = \sum_{i,j} A_{ai}\,B_{aj}\,C_{ij}\,D_{ib}\,E_{jb}.
581 \f]
582
583 This implementation evaluates the contraction by looping over the
584 shared index i and using a BLAS GEMM for the inner j-summation:
585 \f[
586 X^{(i)}_{jb} = C_{ij}\,E_{jb}, \qquad
587 Y^{(i)}_{ab} = \sum_j B_{aj}\,X^{(i)}_{jb},
588 \f]
589 followed by the accumulation
590 \f[
591 M_{ab} \mathrel{+}= A_{ai}\,Y^{(i)}_{ab}\,D_{ib}.
592 \f]
593
594 Thus each i-iteration performs one dense matrix multiplication
595 (B * X^{(i)}) via BLAS, while the remaining operations are
596 elementwise scalings and accumulations.
597
598 The routine allocates temporary work matrices X and Y of size NN
599 (reused across i) and writes the result into @p M, which must be
600 preallocated and is overwritten on entry (i.e., initialised to zero).
601
602 @note
603 ~20% faster than Naiive implementation, BUT not easily parallelisable.
604
605 @tparam T Scalar type (float, double, std::complex<...>)
606 @param A,B,C,D,E Input NN matrices
607 @param[out] M Output NN matrix receiving the contraction. Must be previously sized
608*/
609template <typename T>
610void PENTA_GEMM(const Matrix<T> &A, const Matrix<T> &B, const Matrix<T> &C,
611 const Matrix<T> &D, const Matrix<T> &E, Matrix<T> *M);
612
613//! M_ab = A_ai B_aj C_ij D_ib E_jb. Assuming all square matrices. Uses blas.
614/*!
615 @details
616 Calls:
617 \ref PENTA_GEMM(const Matrix<T>&, const Matrix<T>&,
618 const Matrix<T>&, const Matrix<T>&,
619 const Matrix<T>&, Matrix<T>*).
620*/
621template <typename T>
622Matrix<T> PENTA_GEMM(const Matrix<T> &A, const Matrix<T> &B, const Matrix<T> &C,
623 const Matrix<T> &D, const Matrix<T> &E) {
624 Matrix<T> M(A.rows(), A.cols());
625 PENTA_GEMM<T>(A, B, C, D, E, &M);
626 return M;
627}
628
629//-----------
630
631//! 5-matrix contraction for N*N matrices: M_ab = A_ai B_aj C_ij D_ib E_jb, without BLAS, but with optional OpenMP parallelisation
632/*! @details
633 Computes the tensor contraction
634 \f[
635 M_{ab} = \sum_{i,j} A_{ai}\,B_{aj}\,C_{ij}\,D_{ib}\,E_{jb},
636 \f]
637 assuming all input matrices are square with the same dimension.
638
639 This implementation uses explicit nested loops (no BLAS).
640 If @tparam PARALLEL is true, OpenMP pragmas are enabled to
641 parallelise the outer loops.
642
643 For a BLAS-accelerated implementation, see
644 \ref PENTA_GEMM(const Matrix<T>&, const Matrix<T>&,
645 const Matrix<T>&, const Matrix<T>&,
646 const Matrix<T>&, Matrix<T>*).
647
648 Usually, this version will be significantly faster than the BLAS one.
649 However, if it iself is being called in a parallel region, the BLAS one will be faster.
650
651 @tparam T Scalar type: double, float, std::complex
652 @tparam PARALLEL Enable OpenMP parallelisation when true (compile-time)
653 @param A,B,C,D,E Input NN matrices
654 @param[out] M Output NN matrix receiving the contraction. Must be previously sized
655*/
656template <typename T, bool PARALLEL = false>
657void PENTA(const Matrix<T> &A, const Matrix<T> &B, const Matrix<T> &C,
658 const Matrix<T> &D, const Matrix<T> &E, Matrix<T> *M);
659
660//! 5-index contraction for N*N matrices: M_ab = A_ai B_aj C_ij D_ib E_jb, without BLAS, but with optional OpenMP parallelisation
661//! @details calls above
662template <typename T, bool PARALLEL = false>
663Matrix<T> PENTA(const Matrix<T> &A, const Matrix<T> &B, const Matrix<T> &C,
664 const Matrix<T> &D, const Matrix<T> &E) {
665 Matrix<T> M(A.rows(), A.cols());
666 PENTA<T, PARALLEL>(A, B, C, D, E, &M);
667 return M;
668}
669
670//==============================================================================
671//==============================================================================
672//==============================================================================
673
674//! Default relative tolerance for `equal()`: 1e-6 for float, 1e-12 for double
675template <typename T>
676constexpr auto myEps();
677
678/*!
679 @brief Compares two matrices element-wise to within a relative tolerance.
680 @details
681 Returns true iff all elements satisfy
682 \f[
683 |A_{ij} - B_{ij}| \leq |\varepsilon\,(A_{ij} + B_{ij})|.
684 \f]
685 Matrices of different dimensions compare as not equal.
686
687 @param lhs Left matrix.
688 @param rhs Right matrix.
689 @param eps Relative tolerance (default: `myEps<T>()`).
690 @return `true` if all elements agree within @p eps; `false` otherwise.
691*/
692template <typename T>
693bool equal(const Matrix<T> &lhs, const Matrix<T> &rhs, T eps = myEps<T>());
694
695} // namespace LinAlg
696
697#include "Matrix.ipp"
Non-owning 2D view onto a Matrix.
Definition Matrix.hpp:121
std::size_t size() const
Return rows*columns [total array size].
Definition Matrix.hpp:145
T operator()(std::size_t i, std::size_t j) const
() index access with range checking, const
Definition Matrix.hpp:178
T * data()
Raw pointer to first element, mutable.
Definition Matrix.hpp:150
auto begin()
Iterators over flat data buffer.
Definition Matrix.hpp:181
T * operator[](std::size_t i)
[] index access (no range checking). [i] returns pointer to ith row, mutable
Definition Matrix.hpp:155
const T * operator[](std::size_t i) const
[] index access (no range checking). [i] returns const pointer to ith row
Definition Matrix.hpp:157
const T & atc(std::size_t i, std::size_t j) const
at(i,j): element access with range checking, const ref
Definition Matrix.hpp:170
T & at(std::size_t i, std::size_t j)
at(i,j): element access with range checking, mutable
Definition Matrix.hpp:160
Matrix_view(T *data, std::size_t rows, std::size_t cols)
Construct from raw pointer and dimensions (no ownership)
Definition Matrix.hpp:128
T & operator()(std::size_t i, std::size_t j)
() index access with range checking, mutable
Definition Matrix.hpp:176
std::size_t rows() const
Return rows [major index size].
Definition Matrix.hpp:141
bool empty() const
Bool - is empty? (same as size==0)
Definition Matrix.hpp:147
Matrix_view(Matrix< std::remove_const_t< T > > &m)
Implicit conversion from mutable Matrix (works for both mutable and const view)
Definition Matrix.hpp:132
std::size_t cols() const
Return columns [minor index size].
Definition Matrix.hpp:143
T at(std::size_t i, std::size_t j) const
at(i,j): element access with range checking, const
Definition Matrix.hpp:165
const T * data() const
Raw pointer to first element, const.
Definition Matrix.hpp:152
Matrix_view(const Matrix< std::remove_const_t< T > > &m)
Implicit conversion from const Matrix (only for Matrix_view<const T>)
Definition Matrix.hpp:137
Row-major dense matrix with arithmetic and linear algebra support.
Definition Matrix.hpp:209
T at(std::size_t row_i, std::size_t col_j) const
at(i,j): element access with range checking, const
Definition Matrix.hpp:309
const T * row(std::size_t row) const
Returns raw c pointer to start of a row.
Definition Matrix.hpp:335
Matrix< T > & make_identity()
Constructs a diagonal unit matrix (identity), in place; only for square.
Definition Matrix.ipp:97
Matrix< T > & invert_in_place()
Inverts the matrix in place via LU decomposition (GSL).
Definition Matrix.ipp:37
const T & atc(std::size_t row_i, std::size_t col_j) const
at(i,j): element access with range checking, const ref
Definition Matrix.hpp:315
friend Matrix< T > operator/(Matrix< T > lhs, const T x)
Scalar divide: returns M / x.
Definition Matrix.hpp:513
Matrix(std::size_t rows, std::size_t cols, const std::vector< T > &v)
Initialise a matrix from single initialiser list. {...}.
Definition Matrix.hpp:258
std::size_t size() const
Return rows*columns [total array size].
Definition Matrix.hpp:286
const T * data() const
Const pointer to first element; for std::complex<T> this is const complex<T>*, not const T*.
Definition Matrix.hpp:294
friend std::ostream & operator<<(std::ostream &os, const Matrix< U > &a)
Prints matrix elements row by row to output stream.
Matrix_view< const T > matrix_view() const
Returns an immutable view of the entire matrix (no ownership, no resize)
Definition Matrix.hpp:361
void resize(std::size_t rows, std::size_t cols, const T &value)
Resizes matrix to new dimension; all values reset to 'value'.
Definition Matrix.hpp:273
friend Matrix< T > operator+(Matrix< T > lhs, const Matrix< T > &rhs)
Elementwise addition: returns M + N.
Definition Matrix.hpp:495
T * data()
Pointer to first element; for std::complex<T> this is complex<T>*, not T*.
Definition Matrix.hpp:292
std::size_t rows() const
Return rows [major index size].
Definition Matrix.hpp:282
friend Matrix< T > operator+(Matrix< T > M, T aI)
Returns M + aI (adds a to diagonal)
Definition Matrix.hpp:524
friend Matrix< U > operator*(const Matrix< U > &a, const Matrix< U > &b)
Matrix multiplication: C_ij = sum_k A_ik*B_kj.
Matrix< T > conj() const
Returns conjugate of matrix.
Definition Matrix.ipp:117
View< T > row_view(std::size_t row)
Returns a mutable 'View' of a row.
Definition Matrix.hpp:340
Matrix< T > & operator+=(const Matrix< T > &rhs)
In-place elementwise addition; dimensions must match.
Definition Matrix.ipp:172
friend Matrix< T > operator*(const T x, Matrix< T > rhs)
Scalar multiply: returns x * M.
Definition Matrix.hpp:505
auto begin()
iterators for underlying std::vector (entire data)
Definition Matrix.hpp:328
T & at(std::size_t row_i, std::size_t col_j)
at(i,j): element access with range checking, mutable
Definition Matrix.hpp:304
auto complex() const
Converts a real to complex matrix (changes type; returns a complex matrix)
Definition Matrix.ipp:159
auto imag() const
Returns imag part of complex matrix (changes type; returns a real matrix)
Definition Matrix.ipp:148
auto as_gsl_view()
Returns a GSL matrix view for use with GSL functions (no copy).
Definition Matrix.ipp:390
Matrix< T > & conj_in_place()
Conjugates matrix, in place.
Definition Matrix.ipp:128
T * operator[](std::size_t i)
[] index access (no range checking). [i] returns pointer to ith row, mutable
Definition Matrix.hpp:299
Matrix(std::size_t dimension)
Initialise a blank square matrix dimension*dimension, filled with 0.
Definition Matrix.hpp:230
Matrix()
Default initialiser.
Definition Matrix.hpp:218
Matrix(std::size_t rows, std::size_t cols, std::initializer_list< T > l)
Initialise a matrix from single initialiser list. {...}.
Definition Matrix.hpp:245
friend Matrix< T > operator*(Matrix< T > lhs, const T x)
Scalar multiply: returns M * x.
Definition Matrix.hpp:509
T & operator()(std::size_t i, std::size_t j)
() index access with range checking, mutable
Definition Matrix.hpp:321
Matrix< T > & operator/=(const T x)
In-place scalar divide: M_ij /= x.
Definition Matrix.ipp:194
Matrix< T > transpose() const
Returns the transpose of the matrix.
Definition Matrix.ipp:65
Matrix< T > & zero()
Sets all elements to zero, in place.
Definition Matrix.ipp:108
Matrix< T > inverse() const
Returns inverse of the matrix; original is unchanged.
Definition Matrix.hpp:422
View< const T > row_view(std::size_t row) const
Returns an immutable 'View' of a row.
Definition Matrix.hpp:344
Matrix< T > & operator*=(const T x)
In-place scalar multiply: M_ij *= x.
Definition Matrix.ipp:188
bool empty() const
Bool - is empty? (same as size==0)
Definition Matrix.hpp:289
friend Matrix< T > operator-(Matrix< T > lhs, const Matrix< T > &rhs)
Elementwise subtraction: returns M - N.
Definition Matrix.hpp:500
std::size_t cols() const
Return columns [minor index size].
Definition Matrix.hpp:284
View< T > column_view(std::size_t col)
Returns a mutable 'View' of a column.
Definition Matrix.hpp:348
T determinant() const
Returns the determinant via LU decomposition (GSL).
Definition Matrix.ipp:9
Matrix< T > & mult_elements_by(const Matrix< T > &a)
Elementwise multiply in place: M_ij *= a_ij.
Definition Matrix.ipp:224
const T * operator[](std::size_t i) const
[] index access (no range checking). [i] returns const pointer to ith row
Definition Matrix.hpp:301
friend Matrix< T > operator-(Matrix< T > M, T aI)
Returns M - aI (subtracts a from diagonal)
Definition Matrix.hpp:528
auto real() const
Returns real part of complex matrix (changes type; returns a real matrix)
Definition Matrix.ipp:137
Matrix(std::initializer_list< std::initializer_list< T > > ll)
Initialise a matrix from initialiser list. {{},{},{}}. Each row must be same length.
Definition Matrix.hpp:235
Matrix_view< T > matrix_view()
Returns a mutable view of the entire matrix (no ownership, no resize)
Definition Matrix.hpp:357
Matrix(std::size_t rows, std::size_t cols, std::vector< T > &&v)
Initialise a matrix from single initialiser list. {...}.
Definition Matrix.hpp:252
T operator()(std::size_t i, std::size_t j) const
() index access with range checking, const
Definition Matrix.hpp:323
Matrix(std::size_t rows, std::size_t cols)
Initialise a blank matrix rows*cols, filled with 0.
Definition Matrix.hpp:221
friend Matrix< T > mult_elements(Matrix< T > a, const Matrix< T > &b)
Returns new matrix C with C_ij = A_ij * B_ij (elementwise product).
Definition Matrix.hpp:478
Matrix(std::size_t rows, std::size_t cols, const T &value)
Initialise a matrix rows*cols, filled with 'value'.
Definition Matrix.hpp:225
void resize(std::size_t rows, std::size_t cols)
Resizes matrix to new dimension; all values reset to default.
Definition Matrix.hpp:266
View< const T > column_view(std::size_t col) const
Returns an immutable 'View' of a column.
Definition Matrix.hpp:352
Matrix< T > & operator-=(const Matrix< T > &rhs)
In-place elementwise subtraction; dimensions must match.
Definition Matrix.ipp:180
Non-owning strided view onto a 1D segment of an array.
Definition Matrix.hpp:70
T operator[](std::size_t i) const
[] index access (no range checking), const
Definition Matrix.hpp:86
T * data()
Raw pointer to first viewed element.
Definition Matrix.hpp:104
T operator()(std::size_t i) const
() index access with range checking, const
Definition Matrix.hpp:101
View(T *data, std::size_t start, std::size_t size, std::size_t stride)
Construct view over size elements starting at offset start, with stride.
Definition Matrix.hpp:77
T & operator[](std::size_t i)
[] index access (no range checking), mutable
Definition Matrix.hpp:84
std::size_t size() const
Number of elements in the view.
Definition Matrix.hpp:81
T at(std::size_t i) const
at(i): element access with range checking, const
Definition Matrix.hpp:94
T & at(std::size_t i)
at(i): element access with range checking, mutable
Definition Matrix.hpp:89
T & operator()(std::size_t i)
() index access with range checking, mutable
Definition Matrix.hpp:99
constexpr bool is_complex_v
Type trait: true if T is std::complex<U> for some U, false otherwise.
Definition AdamsMoulton.hpp:80
Linear algebra: matrices, vectors, views, and solvers.
Definition Matrix.hpp:54
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:342
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:308
void GEMM(const Matrix< T > &a, const Matrix< T > &b, Matrix< T > *c, bool trans_A=false, bool trans_B=false)
Matrix multiplication C = op(A) * op(B) via CBLAS GEMM (row-major).
Definition Matrix.ipp:248
CBLAS_TRANSPOSE to_cblas_trans(bool trans)
Converts bool to CBLAS_TRANSPOSE enum (CblasTrans if true, CblasNoTrans if false)
Definition Matrix.hpp:547
constexpr auto myEps()
Default relative tolerance for equal(): 1e-6 for float, 1e-12 for double.
Definition Matrix.ipp:446
bool equal(const Matrix< T > &lhs, const Matrix< T > &rhs, T eps=myEps< T >())
Compares two matrices element-wise to within a relative tolerance.
Definition Matrix.ipp:461
Type trait: true iff T is std::complex<U> for some U.
Definition Matrix.hpp:19