TRIQS/nda 2.0.0
Multi-dimensional array library for C++
Loading...
Searching...
No Matches
eig.hpp
Go to the documentation of this file.
1// Copyright (c) 2024--present, The Simons Foundation
2// This file is part of TRIQS/nda and is licensed under the Apache License, Version 2.0.
3// SPDX-License-Identifier: Apache-2.0
4// See LICENSE in the root of this distribution for details.
5
10
11#pragma once
12
13#include "./utils.hpp"
14#include "../basic_array.hpp"
15#include "../blas/tools.hpp"
16#include "../concepts.hpp"
17#include "../declarations.hpp"
18#include "../exceptions.hpp"
19#include "../lapack/geev.hpp"
21#include "../macros.hpp"
24#include "../traits.hpp"
25
26#include <array>
27#include <cmath>
28#include <complex>
29#include <concepts>
30#include <tuple>
31#include <type_traits>
32#include <utility>
33
34namespace nda::linalg {
35
40
62 template <Vector WR, Vector WI>
63 requires(mem::have_host_compatible_addr_space<WR, WI> and AnyOf<get_value_t<WR>, float, double> and have_same_value_type_v<WR, WI>)
64 auto get_geev_eigenvalues(const WR &wr, const WI &wi) {
65 // check the dimensions of the input arrays/views
66 auto const n = wr.size();
67 EXPECTS(n == wi.size());
68
69 // generate eigenvalues
70 using fp_t = get_fp_t<WR>;
71 auto lambda = array<std::complex<fp_t>, 1>(n);
72 for (long i = 0; i < n; ++i) lambda(i) = std::complex<fp_t>(wr(i), wi(i));
73 return lambda;
74 }
75
109 template <Vector WI, Matrix VA>
111 auto unpack_eigenvectors(const WI &wi, const VA &va) {
112 using namespace std::complex_literals;
113
114 // check the dimensions of the input arrays/views
115 auto const n = wi.size();
116 EXPECTS(va.shape() == (std::array<long, 2>{n, n}));
117
118 // unpack eigenvectors
119 using fp_t = get_fp_t<WI>;
120 auto X = matrix<std::complex<fp_t>, F_layout>(n, n);
121 long j = 0;
122 while (j < n) {
123 if (wi(j) > 0.0) {
124 // complex conjugate eigenvalue pair --> we need to unpack the eigenvectors
125 for (long i = 0; i < n; ++i) {
126 X(i, j) = std::complex<fp_t>{va(i, j), va(i, j + 1)};
127 X(i, j + 1) = std::complex<fp_t>{va(i, j), -va(i, j + 1)};
128 }
129 j += 2;
130 } else {
131 // real eigenvalue --> eigenvector is purely real
132 X(range::all, j) = va(range::all, j);
133 ++j;
134 }
135 }
136
137 return X;
138 }
139
163 template <Vector AR, Vector AI, Vector B>
165 auto get_ggev_eigenvalues(const AR &alphar, const AI &alphai, const B &beta) {
166 // check the dimensions of the input arrays/views
167 auto const n = alphar.size();
168 EXPECTS(n == alphai.size());
169 EXPECTS(n == beta.size());
170
171 // generate eigenvalues: lambda_j = (alphar_j + i * alphai_j) / beta_j
172 using fp_t = get_fp_t<AR>;
173 auto lambda = array<std::complex<fp_t>, 1>(n);
174 for (long i = 0; i < n; ++i) lambda(i) = std::complex<fp_t>(alphar(i), alphai(i)) / std::complex<fp_t>(beta(i));
175 return lambda;
176 }
177
196 template <Vector A, Vector B>
197 requires(mem::have_host_compatible_addr_space<A, B> and AnyOf<get_value_t<A>, std::complex<float>, std::complex<double>>
199 auto get_ggev_eigenvalues(const A &alpha, const B &beta) {
200 // check the dimensions of the input arrays/views
201 auto const n = alpha.size();
202 EXPECTS(n == beta.size());
203
204 // generate eigenvalues: lambda_j = alpha_j / beta_j
205 using val_t = get_value_t<A>;
206 auto lambda = array<val_t, 1>(n);
207 for (long i = 0; i < n; ++i) lambda(i) = alpha(i) / beta(i);
208 return lambda;
209 }
210
211 namespace detail {
212
213 // Implementation for complex matrices - straightforward call to geev.
214 template <blas_lapack::BlasArrayCplx<2> A>
215 auto eig_impl(A &&a, char jobvl, char jobvr) { // NOLINT (temporary views are allowed here)
216 using arr_t = array<get_value_t<A>, 1>;
217 using mat_t = matrix<get_value_t<A>, F_layout>;
218 auto const n = a.extent(0);
219
220 // early return if the matrix is empty
221 if (a.empty()) return std::make_tuple(arr_t{}, mat_t{}, mat_t{});
222
223 // allocate outputs
224 auto lambda = arr_t(n);
225 auto U = (jobvl == 'V') ? mat_t(n, n) : mat_t();
226 auto V = (jobvr == 'V') ? mat_t(n, n) : mat_t();
227
228 // make the call to geev
229 int info = lapack::geev(a, lambda, U, V, jobvl, jobvr);
230 if (info != 0) NDA_RUNTIME_ERROR << "Error in nda::linalg::detail::eig_impl: geev routine failed: info = " << info;
231
232 return std::make_tuple(std::move(lambda), std::move(U), std::move(V));
233 }
234
235 // Implementation for real matrices.
236 template <blas_lapack::BlasArrayReal<2> A>
237 auto eig_impl(A &&a, char jobvl, char jobvr) { // NOLINT (temporary views are allowed here)
238 using fp_t = get_fp_t<A>;
239 using arr_t = array<std::complex<fp_t>, 1>;
240 using mat_t = matrix<std::complex<fp_t>, F_layout>;
241 auto const n = a.extent(0);
242
243 // early return if the matrix is empty
244 if (a.empty()) return std::make_tuple(arr_t{}, mat_t{}, mat_t{});
245
246 // allocate outputs
247 auto wr = array<fp_t, 1>(n);
248 auto wi = array<fp_t, 1>(n);
249 auto vl = (jobvl == 'V') ? matrix<fp_t, F_layout>(n, n) : matrix<fp_t, F_layout>{};
250 auto vr = (jobvr == 'V') ? matrix<fp_t, F_layout>(n, n) : matrix<fp_t, F_layout>{};
251
252 // make the call to geev
253 int info = lapack::geev(a, wr, wi, vl, vr, jobvl, jobvr);
254 if (info != 0) NDA_RUNTIME_ERROR << "Error in nda::linalg::detail::eig_impl: geev routine failed: info = " << info;
255
256 // get eigenvalues and eigenvectors from geev output
257 auto lambda = get_geev_eigenvalues(wr, wi);
258 auto U = (jobvl == 'V') ? unpack_eigenvectors(wi, vl) : mat_t{};
259 auto V = (jobvr == 'V') ? unpack_eigenvectors(wi, vr) : mat_t{};
260
261 return std::make_tuple(std::move(lambda), std::move(U), std::move(V));
262 }
263
264 } // namespace detail
265
290 template <blas_lapack::BlasArray<2> A>
292 auto eig_in_place(A &&a) {
293 auto [lambda, U, V] = detail::eig_impl(std::forward<A>(a), 'N', 'V');
294 return std::make_pair(std::move(lambda), std::move(V));
295 }
296
317 template <blas_lapack::BlasArray<2> A>
319 auto eigvals_in_place(A &&a) {
320 auto [lambda, U, V] = detail::eig_impl(std::forward<A>(a), 'N', 'N');
321 return lambda;
322 }
323
340 template <Matrix A>
342 auto eig(A const &a) {
343 auto m_copy = matrix<get_value_t<A>, F_layout>(a);
344 return eig_in_place(m_copy);
345 }
346
360 template <Matrix A>
362 auto eigvals(A const &a) {
363 auto m_copy = matrix<get_value_t<A>, F_layout>(a);
364 return eigvals_in_place(m_copy);
365 }
366
368
369} // namespace nda::linalg
Provides definitions and type traits involving the different memory address spaces supported by nda.
Provides the generic class for arrays.
Provides various traits and utilities for the BLAS interface.
long extent(int i) const noexcept
Get the extent of the ith dimension.
Check if T is the same as any of the types in Us.
Definition concepts.hpp:119
Check if a given type is either a float or double type.
Definition concepts.hpp:97
Provides concepts for the nda library.
Provides various convenient aliases and helper functions for nda::basic_array and nda::basic_array_vi...
Provides a custom runtime error class and macros to assert conditions and throw exceptions.
Provides a generic interface to the LAPACK geev routine.
basic_array< ValueType, Rank, Layout, 'A', ContainerPolicy > array
Alias template of an nda::basic_array with an 'A' algebra.
basic_array< ValueType, 2, Layout, 'M', ContainerPolicy > matrix
Alias template of an nda::basic_array with rank 2 and an 'M' algebra.
constexpr bool have_same_value_type_v
Constexpr variable that is true if all types in As have the same value type as A0.
Definition traits.hpp:225
std::decay_t< decltype(get_first_element(std::declval< A const >()))> get_value_t
Get the value type of an array/view or a scalar type.
Definition traits.hpp:212
typename remove_complex< get_value_t< A > >::type get_fp_t
Get the floating-point type associated with the value type of an array/view/scalar type.
Definition traits.hpp:221
static constexpr bool has_F_layout
Constexpr variable that is true if all given nda::Array types have nda::F_layout.
Definition tools.hpp:79
auto eig(A const &a)
Compute the eigenvalues and right eigenvectors of a general matrix.
Definition eig.hpp:342
auto eigvals(A const &a)
Compute the eigenvalues of a general matrix.
Definition eig.hpp:362
auto get_ggev_eigenvalues(const AR &alphar, const AI &alphai, const B &beta)
Get the complex eigenvalues from nda::lapack::ggev output for real matrices.
Definition eig.hpp:165
auto eig_in_place(A &&a)
Compute the eigenvalues and right eigenvectors of a general matrix in place.
Definition eig.hpp:292
auto get_geev_eigenvalues(const WR &wr, const WI &wi)
Get the complex eigenvalues from nda::lapack::geev output for real matrices.
Definition eig.hpp:64
auto eigvals_in_place(A &&a)
Compute the eigenvalues of a general matrix in place.
Definition eig.hpp:319
auto unpack_eigenvectors(const WI &wi, const VA &va)
Unpack eigenvectors of real matrices from nda::lapack::geev or nda::lapack::ggev output.
Definition eig.hpp:111
int geev(A &&a, WR &&wr, WI &&wi, VL &&vl, VR &&vr, char jobvl='N', char jobvr='V', W1 &&work=vector_value_t< A >{})
Interface to the LAPACK geev routine for real matrices.
Definition geev.hpp:77
static constexpr bool have_host_compatible_addr_space
Constexpr variable that is true if all given types have an address space compatible with Host.
constexpr bool is_blas_lapack_v
Constexpr variable that is true if type T is either of type 'float', double, std::complex<float>' or ...
Definition traits.hpp:95
Provides definitions of various layout policies.
Provides utility functions for the nda::linalg namespace.
Macros used in the nda library.
Provides functions to create and manipulate matrices, i.e. arrays/view with 'M' algebra.
Contiguous layout policy with Fortran-order (column-major order).
Definition policies.hpp:52
Provides type traits for the nda library.