TRIQS/nda 2.0.0
Multi-dimensional array library for C++
Loading...
Searching...
No Matches
gelss_worker.hpp
Go to the documentation of this file.
1// Copyright (c) 2020--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 "./gesvd.hpp"
14#include "../algorithms.hpp"
15#include "../arithmetic.hpp"
16#include "../basic_array.hpp"
17#include "../declarations.hpp"
18#include "../exceptions.hpp"
21#include "../linalg.hpp"
24#include "../traits.hpp"
25
26#include <itertools/itertools.hpp>
27
28#include <algorithm>
29#include <array>
30#include <cmath>
31#include <complex>
32#include <optional>
33#include <utility>
34#include <vector>
35
36namespace nda::lapack {
37
42
83 template <typename T>
84 requires is_blas_lapack_v<T>
86 public:
88 using value_type = T;
89
92
97 [[nodiscard]] int n_var() const { return N_; }
98
103 [[nodiscard]] array<fp_type, 1> const &S_vec() const { return s_; }
104
114 gelss_worker(matrix_const_view<T> A) : M_(A.extent(0)), N_(A.extent(1)), s_(std::min(M_, N_)) {
115 if (N_ > M_) NDA_RUNTIME_ERROR << "Error in nda::lapack::gelss_worker: Matrix A cannot have more columns than rows";
116
117 // initialize matrices
118 matrix<T, F_layout> A_work{A};
119 matrix<T, F_layout> U(M_, M_);
120 matrix<T, F_layout> V_H(N_, N_);
121
122 // calculate the SVD: A = U * \Sigma * V^H
123 gesvd(A_work, s_, U, V_H);
124
125 // calculate the pseudo inverse A^{+} = V * \Sigma^{+} * U^H
126 matrix<fp_type, F_layout> S_plus(N_, M_);
127 S_plus = 0.;
128 for (long i : range(s_.size())) S_plus(i, i) = 1.0 / s_(i);
129 A_plus_ = dagger(V_H) * S_plus * dagger(U);
130
131 // set U_N^H
132 if (N_ < M_) U_N_H_ = dagger(U)(range(N_, M_), range(M_));
133 }
134
149 auto operator()(matrix_const_view<T> B, std::optional<long> /* inner_matrix_dim */ = {}) const {
150 using std::sqrt;
151 fp_type err = 0.0;
152 if (M_ != N_) {
153 std::vector<fp_type> err_vec;
154 for (long i : range(B.shape()[1])) err_vec.push_back(frobenius_norm(U_N_H_ * B(range::all, range(i, i + 1))) / sqrt(B.shape()[0]));
155 err = *std::ranges::max_element(err_vec);
156 }
157 return std::pair<matrix<T>, fp_type>{A_plus_ * B, err};
158 }
159
170 auto operator()(vector_const_view<T> b, std::optional<long> /*inner_matrix_dim*/ = {}) const {
171 using std::sqrt;
172 fp_type err = 0.0;
173 if (M_ != N_) err = nda::linalg::norm(U_N_H_ * b) / sqrt(b.size());
174 return std::pair<vector<T>, fp_type>{A_plus_ * b, err};
175 }
176
177 private:
178 // Number of rows (M) and columns (N) of the Matrix A.
179 long M_, N_;
180
181 // Pseudo inverse of A, i.e. A^{+} = V * \Sigma^{+} * U^H.
182 matrix<T> A_plus_;
183
184 // U_N^H defining the error of the least squares problem.
185 matrix<T> U_N_H_;
186
187 // Array containing the singular values.
189 };
190
213 public:
218 int n_var() const { return lss_herm_.n_var(); }
219
224 [[nodiscard]] array<double, 1> const &S_vec() const { return lss_.S_vec(); }
225
230 gelss_worker_hermitian(matrix_const_view<std::complex<double>> A) : lss_(A), lss_herm_(vstack(A, conj(A))) {}
231
243 auto operator()(matrix_const_view<std::complex<double>> B, std::optional<long> inner_matrix_dim = {}) const {
244 if (not inner_matrix_dim.has_value())
245 NDA_RUNTIME_ERROR << "Error in nda::lapack::gelss_worker_hermitian: Inner matrix dimension required for hermitian least square fitting";
246 long d = *inner_matrix_dim;
247
248 // take the inner 'adjoint' of a matrix C:
249 // * reshape C -> C': (M, N) -> (M, N', d, d)
250 // * for each m and n: C'(m, n, :, :) -> C'(m, n, :, :)^/dagger
251 // * reshape C' -> C: (M, N', d, d) -> (M, N)
252 auto inner_adjoint = [d](auto &C) {
253 NDA_ASSERT2(C.shape()[1] % (d * d) == 0, "Error in nda::lapack::gelss_worker_hermitian: Data shape incompatible with inner matrix dimension");
254 auto shape = C.shape();
255
256 // get extent N' of second dimension
257 long N = shape[1] / (d * d);
258
259 // reshape, transpose and take the complex conjugate
260 array<std::complex<double>, 4> arr_dag =
261 conj(permuted_indices_view<encode(std::array{0, 1, 3, 2})>(reshape(C, std::array{shape[0], N, d, d})));
262
263 // return the result in a new matrix
264 return matrix<std::complex<double>>{reshape(std::move(arr_dag), shape)};
265 };
266
267 // solve the extended system vstack(A, A*) * X = vstack(B, B_dag)
268 auto B_dag = inner_adjoint(B);
269 auto [x, err] = lss_herm_(vstack(B, B_dag));
270
271 // resymmetrize the results to cure small hermiticity violations
272 return std::pair<matrix<std::complex<double>>, double>{0.5 * (x + inner_adjoint(x)), err};
273 }
274
275 private:
276 // Worker for the original least squares problem.
277 gelss_worker<std::complex<double>> lss_;
278
279 // Worker for the extended least squares problem.
280 gelss_worker<std::complex<double>> lss_herm_;
281 };
282
284
285} // namespace nda::lapack
Provides various algorithms to be used with nda::Array objects.
Provides lazy expressions for nda::Array types.
Provides the generic class for arrays.
auto const & shape() const noexcept
Get the shape of the view/array.
long size() const noexcept
Get the total size of the view/array.
int n_var() const
Get the number of variables of the given problem.
auto operator()(matrix_const_view< std::complex< double > > B, std::optional< long > inner_matrix_dim={}) const
Solve the least squares problem for a given right hand side matrix .
array< double, 1 > const & S_vec() const
Get the singular values of the original matrix .
gelss_worker_hermitian(matrix_const_view< std::complex< double > > A)
Construct a new worker object for a given matrix .
auto operator()(vector_const_view< T > b, std::optional< long >={}) const
Solve the least squares problem for a given right hand side vector .
array< fp_type, 1 > const & S_vec() const
Get the singular values, i.e. the diagonal elements of the matrix .
gelss_worker(matrix_const_view< T > A)
Construct a new worker object for a given matrix .
get_fp_t< T > fp_type
Floating point type of the value_type.
auto operator()(matrix_const_view< T > B, std::optional< long >={}) const
Solve the least squares problem for a given right hand side matrix .
T value_type
Value type of the given problem.
int n_var() const
Get the number of variables of the given problem, i.e. the size of the vector .
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/cuSOLVER gesvd routine.
auto permuted_indices_view(A &&a)
Permute the indices/dimensions of an nda::basic_array or nda::basic_array_view.
auto reshape(A &&a, std::array< Int, R > const &new_shape)
Reshape an nda::basic_array or nda::basic_array_view.
matrix< get_value_t< A > > vstack(A const &a, B const &b)
Stack two 2-dimensional arrays/views vertically.
auto sqrt(A &&a)
Function sqrt for non-matrix nda::ArrayOrScalar types (lazy and coefficient-wise for nda::Array types...
auto min(A &&a, B &&b)
Function min for nda::ArrayOrScalar types (lazy and coefficient-wise for nda::Array types).
ArrayOfRank< 2 > auto dagger(M const &m)
Get the conjugate transpose of 2-dimensional array/view.
double frobenius_norm(A const &a)
Calculate the Frobenius norm of a 2-dimensional array.
decltype(auto) conj(A &&a)
Function conj for nda::ArrayOrScalar types (lazy and coefficient-wise for nda::Array types with a com...
basic_array< ValueType, Rank, Layout, 'A', ContainerPolicy > array
Alias template of an nda::basic_array with an 'A' algebra.
basic_array_view< ValueType const, 1, Layout, 'V', default_accessor, borrowed<> > vector_const_view
Same as nda::vector_view except for const value types.
basic_array_view< ValueType const, 2, Layout, 'M', default_accessor, borrowed<> > matrix_const_view
Same as nda::matrix_view except for const value types.
basic_array< ValueType, 2, Layout, 'M', ContainerPolicy > matrix
Alias template of an nda::basic_array with rank 2 and an 'M' algebra.
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
int gesvd(A &&a, S &&s, U &&u, VH &&vh, W1 &&work=vector_value_t< A >{}, W2 &&rwork=vector_fp_t< A >{})
Interface to the LAPACK/cuSOLVER gesvd routine.
Definition gesvd.hpp:71
double norm(X const &x, double p=2.0)
Calculate the -norm of a 1-dimensional array/view with scalar elements.
Definition norm.hpp:49
constexpr uint64_t encode(std::array< int, N > const &a)
Encode a std::array<int, N> in a uint64_t.
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 functions to transform the memory layout of an nda::basic_array or nda::basic_array_view.
Includes all relevant headers for the linear algebra functionality.
Provides some custom implementations of standard mathematical functions used for lazy,...
Provides functions to create and manipulate matrices, i.e. arrays/view with 'M' algebra.
Provides type traits for the nda library.