TRIQS/nda 1.3.0
Multi-dimensional array library for C++
Loading...
Searching...
No Matches
inv.hpp
Go to the documentation of this file.
1// Copyright (c) 2019--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 "../basic_array.hpp"
15#include "../concepts.hpp"
16#include "../exceptions.hpp"
17#include "../lapack/getrf.hpp"
18#include "../lapack/getri.hpp"
19#include "../lapack/getrs.hpp"
21#include "../macros.hpp"
24#include "../mem/policies.hpp"
25#include "../traits.hpp"
26
27#include <utility>
28
29namespace nda::linalg {
30
35
36 namespace detail {
37
38 // Compute the inverse of a 2x2 matrix in place.
39 void inv_in_place_2d(MemoryMatrix auto &&m) { // NOLINT (temporary views are allowed here)
40
41 // calculate the determinant of the matrix
42 auto const det = (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0));
43 if (det == 0.0) NDA_RUNTIME_ERROR << "Error in nda::linalg::inv_in_place: Matrix is not invertible";
44 auto const detinv = 1.0 / det;
45
46 // multiply the adjoint by the inverse determinant
47 std::swap(m(0, 0), m(1, 1));
48 m(0, 0) *= +detinv;
49 m(1, 1) *= +detinv;
50 m(1, 0) *= -detinv;
51 m(0, 1) *= -detinv;
52 }
53
54 // Compute the inverse of a 3x3 matrix in place.
55 void inv_in_place_3d(MemoryMatrix auto &&m) { // NOLINT (temporary views are allowed here)
56 EXPECTS(is_matrix_square(m) and m.extent(0) == 3);
57
58 // calculate the adjoint of the matrix
59 auto adj = stack_array<get_value_t<decltype(m)>, 3, 3>();
60 adj(0, 0) = +m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1);
61 adj(1, 0) = -m(1, 0) * m(2, 2) + m(1, 2) * m(2, 0);
62 adj(2, 0) = +m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0);
63 adj(0, 1) = -m(0, 1) * m(2, 2) + m(0, 2) * m(2, 1);
64 adj(1, 1) = +m(0, 0) * m(2, 2) - m(0, 2) * m(2, 0);
65 adj(2, 1) = -m(0, 0) * m(2, 1) + m(0, 1) * m(2, 0);
66 adj(0, 2) = +m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1);
67 adj(1, 2) = -m(0, 0) * m(1, 2) + m(0, 2) * m(1, 0);
68 adj(2, 2) = +m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0);
69
70 // calculate the determinant of the matrix
71 auto const det = m(0, 0) * adj(0, 0) + m(0, 1) * adj(1, 0) + m(0, 2) * adj(2, 0);
72 if (det == 0.0) NDA_RUNTIME_ERROR << "Error in nda::linalg::inv_in_place: Matrix is not invertible";
73 auto const detinv = 1.0 / det;
74
75 // multiply the adjoint by the inverse determinant
76 m = detinv * adj;
77 }
78
79 } // namespace detail
80
97 template <MemoryMatrix M>
99 void inv_in_place(M &&m) { // NOLINT (temporary views are allowed here)
100 EXPECTS(is_matrix_square(m));
101
102 // use optimized routines for small matrices, otherwise use LAPACK routines
103 auto const dim = m.shape()[0];
104 if (dim == 1) {
105 if (m(0, 0) == 0.0) NDA_RUNTIME_ERROR << "Error in nda::linalg::inv_in_place: Matrix is not invertible";
106 m(0, 0) = 1.0 / m(0, 0);
107 } else if (dim == 2) {
108 detail::inv_in_place_2d(m);
109 } else if (dim == 3) {
110 detail::inv_in_place_3d(m);
111 } else if (dim > 3) {
112 // LU factorization with getrf
114 int info = nda::lapack::getrf(m, ipiv);
115 if (info != 0) NDA_RUNTIME_ERROR << "Error in nda::linalg::inv_in_place: getrf routine failed: info = " << info;
116
117 // calculate the inverse with getri
118 info = nda::lapack::getri(m, ipiv);
119 if (info != 0) NDA_RUNTIME_ERROR << "Error in nda::linalg::inv_in_place: getri routine failed: info = " << info;
120 }
121 }
122
139 template <Matrix M>
141 auto inv(M const &m) {
142 EXPECTS(is_matrix_square(m));
143 auto m_copy = make_regular(m);
144
145 // for device compatible address spaces, we use getrf and getrs, otherwise we call inv_in_place
147 // LU factorization with getrf
148 auto ipiv = vector<int, heap<nda::mem::get_addr_space<M>>>(m_copy.extent(0));
149 int info = nda::lapack::getrf(m_copy, ipiv);
150 if (info != 0) NDA_RUNTIME_ERROR << "Error in nda::linalg::inv: getrf routine failed: info = " << info;
151
152 // calculate the inverse with getrs and the identity matrix
154 info = nda::lapack::getrs(m_copy, B, ipiv);
155 if (info != 0) NDA_RUNTIME_ERROR << "Error in nda::linalg::inv: getrs routine failed: info = " << info;
156 return B;
157 } else {
158 inv_in_place(m_copy);
159 return m_copy;
160 }
161 }
162
164
165} // namespace nda::linalg
166
167namespace nda::clef {
168
169 // Make nda::linalg::inv visible for lazy function calls.
170 using nda::linalg::inv;
171
177
178} // namespace nda::clef
Provides definitions and type traits involving the different memory address spaces supported by nda.
Provides the generic class for arrays.
void swap(nda::basic_array_view< V1, R1, LP1, A1, AP1, OP1 > &a, nda::basic_array_view< V2, R2, LP2, A2, AP2, OP2 > &b)=delete
std::swap is deleted for nda::basic_array_view.
Provides basic functions to create and manipulate arrays and views.
Provides concepts for the nda library.
Provides a custom runtime error class and macros to assert conditions and throw exceptions.
Provides a generic interface to the LAPACK getrf routine.
Provides a generic interface to the LAPACK getri routine.
Provides a generic interface to the LAPACK getrs routine.
auto eye(Int dim)
Create an identity nda::matrix with ones on the diagonal.
decltype(auto) make_regular(A &&a)
Make a given object regular.
auto transpose(A &&a)
Transpose the memory layout of an nda::MemoryArray or an nda::expr_call.
bool is_matrix_square(A const &a, bool print_error=false)
Check if a given matrix is square, i.e. if the first dimension has the same extent as the second dime...
basic_array< ValueType, 1, C_layout, 'V', ContainerPolicy > vector
Alias template of an nda::basic_array with rank 1 and a 'V' algebra.
basic_array< ValueType, 2, Layout, 'M', ContainerPolicy > matrix
Alias template of an nda::basic_array with rank 2 and an 'M' algebra.
nda::basic_array< ValueType, 1+sizeof...(Ns), nda::basic_layout< nda::static_extents(N0, Ns...), nda::C_stride_order< 1+sizeof...(Ns)>, nda::layout_prop_e::contiguous >, 'A', nda::stack< N0 *(Ns *... *1)> > stack_array
Alias template of an nda::basic_array with static extents, contiguous C layout, 'A' algebra and nda::...
constexpr char get_algebra
Constexpr variable that specifies the algebra of a type.
Definition traits.hpp:116
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:182
#define CLEF_MAKE_FNT_LAZY(name)
Macro to make any function lazy, i.e. accept lazy arguments and return a function call expression nod...
Definition make_lazy.hpp:89
auto inv(A &&...__a)
Lazy version of nda::linalg::inv.
Definition inv.hpp:176
int getri(A &&a, IPIV const &ipiv)
Interface to the LAPACK getri routine.
Definition getri.hpp:48
int getrf(A &&a, IPIV &&ipiv)
Interface to the LAPACK getrf routine.
Definition getrf.hpp:58
int getrs(A const &a, B &&b, IPIV const &ipiv)
Interface to the LAPACK getrs routine.
Definition getrs.hpp:53
auto det(M const &m)
Compute the determinant of an matrix .
Definition det.hpp:95
void inv_in_place(M &&m)
Compute the inverse of an matrix .
Definition inv.hpp:99
auto inv(M const &m)
Compute the inverse of an matrix .
Definition inv.hpp:141
static constexpr bool have_host_compatible_addr_space
Constexpr variable that is true if all given types have an address space compatible with Host.
static constexpr bool have_device_compatible_addr_space
Constexpr variable that is true if all given types have an address space compatible with Device.
heap_basic< mem::mallocator< AdrSp > > heap
Alias template of the nda::heap_basic policy using an nda::mem::mallocator.
Definition policies.hpp:52
constexpr bool is_blas_lapack_v
Alias for nda::is_double_or_complex_v.
Definition traits.hpp:92
Provides definitions of various layout policies.
Macros used in the nda library.
Provides functions to create and manipulate matrices, i.e. arrays/view with 'M' algebra.
Defines various memory handling policies.
Contiguous layout policy with Fortran-order (column-major order).
Definition policies.hpp:52
Provides type traits for the nda library.