TRIQS/nda 1.3.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
57 template <Vector WR, Vector WI>
58 requires(mem::have_host_compatible_addr_space<WR, WI> and std::same_as<double, get_value_t<WR>> and have_same_value_type_v<WR, WI>)
59 auto get_geev_eigenvalues(const WR &wr, const WI &wi) {
60 // check the dimensions of the input arrays/views
61 auto const n = wr.size();
62 EXPECTS(n == wi.size());
63
64 // generate eigenvalues
65 auto lambda = array<std::complex<double>, 1>(n);
66 for (long i = 0; i < n; ++i) lambda(i) = std::complex<double>(wr(i), wi(i));
67 return lambda;
68 }
69
95 template <Vector WI, Matrix VA>
96 requires(mem::have_host_compatible_addr_space<WI, VA> and std::same_as<double, get_value_t<WI>> and have_same_value_type_v<WI, VA>)
97 auto get_geev_eigenvectors(const WI &wi, const VA &va) {
98 using namespace std::complex_literals;
99
100 // check the dimensions of the input arrays/views
101 auto const n = wi.size();
102 EXPECTS(va.shape() == (std::array<long, 2>{n, n}));
103
104 // unpack eigenvectors
105 auto X = matrix<std::complex<double>, F_layout>(n, n);
106 long j = 0;
107 while (j < n) {
108 if (wi(j) > 0.0) {
109 // complex conjugate eigenvalue pair --> we need to unpack the eigenvectors
110 for (long i = 0; i < n; ++i) {
111 X(i, j) = std::complex<double>{va(i, j), va(i, j + 1)};
112 X(i, j + 1) = std::complex<double>{va(i, j), -va(i, j + 1)};
113 }
114 j += 2;
115 } else {
116 // real eigenvalue --> eigenvector is purely real
117 X(nda::range::all, j) = va(nda::range::all, j);
118 ++j;
119 }
120 }
121
122 return X;
123 }
124
125 namespace detail {
126
127 // Implementation for complex matrices - straightforward call to geev.
128 template <MemoryMatrix A>
130 auto eig_impl(A &&a, char jobvl, char jobvr) { // NOLINT (temporary views are allowed here)
131 using arr_t = array<get_value_t<A>, 1>;
132 using mat_t = matrix<get_value_t<A>, F_layout>;
133 auto const n = a.extent(0);
134
135 // early return if the matrix is empty
136 if (a.empty()) return std::make_tuple(arr_t{}, mat_t{}, mat_t{});
137
138 // allocate outputs
139 auto lambda = arr_t(n);
140 auto U = (jobvl == 'V') ? mat_t(n, n) : mat_t();
141 auto V = (jobvr == 'V') ? mat_t(n, n) : mat_t();
142
143 // make the call to geev
144 int info = nda::lapack::geev(a, lambda, U, V, jobvl, jobvr);
145 if (info != 0) NDA_RUNTIME_ERROR << "Error in nda::linalg::detail::eig_impl: geev routine failed: info = " << info;
146
147 return std::make_tuple(std::move(lambda), std::move(U), std::move(V));
148 }
149
150 // Implementation for real matrices.
151 template <MemoryMatrix A>
152 requires(std::same_as<double, get_value_t<A>>)
153 auto eig_impl(A &&a, char jobvl, char jobvr) { // NOLINT (temporary views are allowed here)
154 using arr_t = array<std::complex<double>, 1>;
155 using mat_t = matrix<std::complex<double>, F_layout>;
156 auto const n = a.extent(0);
157
158 // early return if the matrix is empty
159 if (a.empty()) return std::make_tuple(arr_t{}, mat_t{}, mat_t{});
160
161 // allocate outputs
162 auto wr = array<double, 1>(n);
163 auto wi = array<double, 1>(n);
164 auto vl = (jobvl = 'V') ? matrix<double, F_layout>(n, n) : matrix<double, F_layout>{};
165 auto vr = (jobvr = 'V') ? matrix<double, F_layout>(n, n) : matrix<double, F_layout>{};
166
167 // make the call to geev
168 int info = nda::lapack::geev(a, wr, wi, vl, vr, jobvl, jobvr);
169 if (info != 0) NDA_RUNTIME_ERROR << "Error in nda::linalg::detail::eig_impl: geev routine failed: info = " << info;
170
171 // get eigenvalues and eigenvectors from geev output
172 auto lambda = get_geev_eigenvalues(wr, wi);
173 auto U = (jobvl == 'V') ? get_geev_eigenvectors(wi, vl) : mat_t{};
174 auto V = (jobvr == 'V') ? get_geev_eigenvectors(wi, vr) : mat_t{};
175
176 return std::make_tuple(std::move(lambda), std::move(U), std::move(V));
177 }
178
179 } // namespace detail
180
202 template <MemoryMatrix A>
204 auto eig_in_place(A &&a) {
205 auto [lambda, U, V] = detail::eig_impl(std::forward<A>(a), 'N', 'V');
206 return std::make_pair(std::move(lambda), std::move(V));
207 }
208
228 template <MemoryMatrix A>
230 auto eigvals_in_place(A &&a) {
231 auto [lambda, U, V] = detail::eig_impl(std::forward<A>(a), 'N', 'N');
232 return lambda;
233 }
234
245 template <Matrix A>
247 auto eig(A const &a) {
248 auto m_copy = matrix<get_value_t<A>, F_layout>(a);
249 return eig_in_place(m_copy);
250 }
251
262 template <MemoryMatrix A>
264 auto eigvals(A const &a) {
265 auto m_copy = matrix<get_value_t<A>, F_layout>(a);
266 return eigvals_in_place(m_copy);
267 }
268
270
271} // namespace nda::linalg
Provides definitions and type traits involving the different memory address spaces supported by nda.
Provides the generic class for arrays.
long extent(int i) const noexcept
Get the extent of the ith dimension.
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:186
static constexpr bool has_F_layout
Constexpr variable that is true if the given nda::Array type has nda::F_layout.
Definition tools.hpp:73
int geev(A &&a, WR &&wr, WI &&wi, VL &&vl, VR &&vr, char jobvl='N', char jobvr='V')
Interface to the LAPACK geev routine for real matrices.
Definition geev.hpp:71
auto eig_in_place(A &&a)
Compute the eigenvalues and right eigenvectors of a general matrix.
Definition eig.hpp:204
auto get_geev_eigenvectors(const WI &wi, const VA &va)
Get the complex left/right eigenvectors from nda::lapack::geev output for real matrices.
Definition eig.hpp:97
auto eigvals(A const &a)
Compute the eigenvalues of a general matrix.
Definition eig.hpp:264
auto eig(A const &a)
Compute the eigenvalues and right eigenvectors of a general matrix.
Definition eig.hpp:247
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:59
auto eigvals_in_place(A &&a)
Compute the eigenvalues of a general matrix.
Definition eig.hpp:230
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_complex_v
Constexpr variable that is true if type T is a std::complex type.
Definition traits.hpp:65
constexpr bool is_blas_lapack_v
Alias for nda::is_double_or_complex_v.
Definition traits.hpp:92
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 various traits and utilities for the BLAS interface.
Provides type traits for the nda library.