ABACUS develop
Atomic-orbital Based Ab-initio Computation at UStc
Loading...
Searching...
No Matches
Inverse_Matrix.hpp
Go to the documentation of this file.
1//=======================
2// AUTHOR : Peize Lin
3// DATE : 2022-08-17
4//=======================
5
6#ifndef INVERSE_MATRIX_HPP
7#define INVERSE_MATRIX_HPP
8
9#include "Inverse_Matrix.h"
12
13#include <cassert>
14
15template <typename Tdata>
16void Inverse_Matrix<Tdata>::cal_inverse(const Method& method, const double& threshold_condition_number)
17{
18 switch (method)
19 {
20 case Method::potrf:
21 using_potrf();
22 break;
23 case Method::syev:
24 using_syev(threshold_condition_number);
25 break;
26 }
27}
28
29template <typename Tdata>
31{
32 int info;
33 LapackConnector::potrf('U', A.shape[0], A.ptr(), A.shape[0], info);
34 if (info)
35 throw std::range_error("info=" + std::to_string(info) + "\n" + std::string(__FILE__) + " line "
36 + std::to_string(__LINE__));
37
38 LapackConnector::potri('U', A.shape[0], A.ptr(), A.shape[0], info);
39 if (info)
40 throw std::range_error("info=" + std::to_string(info) + "\n" + std::string(__FILE__) + " line "
41 + std::to_string(__LINE__));
42
43 copy_down_triangle();
44}
45
46template <typename T>
48
49// double
50template <>
51struct InverseMatrixTraits<double>
52{
54 using value_type = double;
55 static void syev(RI::Tensor<double>& A, value_type* w, int& info)
56 {
57 ABFs_Construct::PCA::tensor_syev('V', 'U', A, w, info);
58 }
59 static constexpr char gemm_trans = 'T';
60};
61
62// complex<double>
63template <>
64struct InverseMatrixTraits<std::complex<double>>
65{
67 using value_type = double; // eigenvalues are always real
68 static void syev(RI::Tensor<std::complex<double>>& A, value_type* w, int& info)
69 {
70 ABFs_Construct::PCA::tensor_syev('V', 'U', A, w, info);
71 }
72 static constexpr char gemm_trans = 'C';
73};
74
75// float
76template <>
78{
80 using value_type = float;
81 static void syev(RI::Tensor<float>& A, value_type* w, int& info)
82 {
83 ABFs_Construct::PCA::tensor_syev('V', 'U', A, w, info);
84 }
85 static constexpr char gemm_trans = 'T';
86};
87
88// complex<float>
89template <>
90struct InverseMatrixTraits<std::complex<float>>
91{
93 using value_type = float;
94 static void syev(RI::Tensor<std::complex<float>>& A, value_type* w, int& info)
95 {
96 ABFs_Construct::PCA::tensor_syev('V', 'U', A, w, info);
97 }
98 static constexpr char gemm_trans = 'C';
99};
100
101template <typename T>
102inline void Inverse_Matrix<T>::using_syev(const double& threshold_condition_number)
103{
104 using traits = InverseMatrixTraits<T>;
105 using val_t = typename traits::value_type;
106
107 int info;
108 std::vector<val_t> eigen_value(A.shape[0]);
109
110 traits::syev(A, eigen_value.data(), info);
111 if (info)
112 throw std::range_error("info=" + std::to_string(info) + "\n" + std::string(__FILE__) + " line "
113 + std::to_string(__LINE__));
114
115 val_t eigen_value_max = 0;
116 for (const val_t& val: eigen_value)
117 eigen_value_max = std::max(val, eigen_value_max);
118
119 const double threshold = eigen_value_max * threshold_condition_number;
120
121 typename traits::matrix_type eA(A.shape[0], A.shape[1]);
122
123 int ie = 0;
124 for (int i = 0; i != A.shape[0]; ++i)
125 {
126 if (eigen_value[i] > threshold)
127 {
128 BlasConnector::axpy(A.shape[1],
129 sqrt(1.0 / eigen_value[i]),
130 A.ptr() + i * A.shape[1],
131 1,
132 eA.c + ie * eA.nc,
133 1);
134 ++ie;
135 }
136 }
137 // std::cout << "No. of singularity: " << A.shape[0] - ie << std::endl;
138
139 BlasConnector::gemm(traits::gemm_trans, 'N', eA.nc, eA.nc, ie, 1, eA.c, eA.nc, eA.c, eA.nc, 0, A.ptr(), A.shape[1]);
140}
141
142/*
143void Inverse_Matrix::using_syev( const double &threshold_condition_number )
144{
145 std::vector<double> eigen_value(A.nr);
146 LapackConnector::dsyev('V','U',A,eigen_value.data(),info);
147
148 double eigen_value_max = 0;
149 for( const double &ie : eigen_value )
150 eigen_value_max = std::max( ie, eigen_value_max );
151 const double threshold = eigen_value_max * threshold_condition_number;
152
153 ModuleBase::matrix eA( A.nr, A.nc );
154 int ie=0;
155 for( int i=0; i!=A.nr; ++i )
156 if( eigen_value[i] > threshold )
157 {
158 BlasConnector::axpy( A.nc, sqrt(1.0/eigen_value[i]), A.c+i*A.nc,1, eA.c+ie*eA.nc,1 );
159 ++ie;
160 }
161 BlasConnector::gemm( 'T','N', eA.nc,eA.nc,ie, 1, eA.c,eA.nc, eA.c,eA.nc, 0, A.c,A.nc );
162}
163*/
164
165template <typename Tdata>
166void Inverse_Matrix<Tdata>::input(const RI::Tensor<Tdata>& m)
167{
168 assert(m.shape.size() == 2);
169 assert(m.shape[0] == m.shape[1]);
170 this->A = m.copy();
171}
172
173template <typename Tdata>
174void Inverse_Matrix<Tdata>::input(const std::vector<std::vector<RI::Tensor<Tdata>>>& ms)
175{
176 const size_t N0 = ms.size();
177 assert(N0 > 0);
178 const size_t N1 = ms[0].size();
179 assert(N1 > 0);
180 for (size_t Im0 = 0; Im0 < N0; ++Im0)
181 assert(ms[Im0].size() == N1);
182
183 for (size_t Im0 = 0; Im0 < N0; ++Im0)
184 for (size_t Im1 = 0; Im1 < N1; ++Im1)
185 assert(ms[Im0][Im1].shape.size() == 2);
186
187 std::vector<size_t> n0(N0);
188 for (size_t Im0 = 0; Im0 < N0; ++Im0)
189 n0[Im0] = ms[Im0][0].shape[0];
190 std::vector<size_t> n1(N1);
191 for (size_t Im1 = 0; Im1 < N1; ++Im1)
192 n1[Im1] = ms[0][Im1].shape[1];
193
194 for (size_t Im0 = 0; Im0 < N0; ++Im0)
195 for (size_t Im1 = 0; Im1 < N1; ++Im1)
196 assert((ms[Im0][Im1].shape[0] == n0[Im0]) && (ms[Im0][Im1].shape[1] == n1[Im1]));
197
198 const size_t n_all = std::accumulate(n0.begin(), n0.end(), 0);
199 assert(n_all == std::accumulate(n1.begin(), n1.end(), 0));
200 this->A = RI::Tensor<Tdata>({n_all, n_all});
201
202 std::vector<size_t> n0_partial(N0 + 1);
203 std::partial_sum(n0.begin(), n0.end(), n0_partial.begin() + 1);
204 std::vector<size_t> n1_partial(N1 + 1);
205 std::partial_sum(n1.begin(), n1.end(), n1_partial.begin() + 1);
206
207 for (size_t Im0 = 0; Im0 < N0; ++Im0)
208 for (size_t Im1 = 0; Im1 < N1; ++Im1)
209 {
210 const RI::Tensor<Tdata>& m_tmp = ms.at(Im0).at(Im1);
211 for (size_t im0 = 0; im0 < m_tmp.shape[0]; ++im0)
212 for (size_t im1 = 0; im1 < m_tmp.shape[1]; ++im1)
213 this->A(im0 + n0_partial[Im0], im1 + n1_partial[Im1]) = m_tmp(im0, im1);
214 }
215}
216
217template <typename Tdata>
218RI::Tensor<Tdata> Inverse_Matrix<Tdata>::output() const
219{
220 return this->A.copy();
221}
222
223template <typename Tdata>
224std::vector<std::vector<RI::Tensor<Tdata>>> Inverse_Matrix<Tdata>::output(const std::vector<size_t>& n0,
225 const std::vector<size_t>& n1) const
226{
227 assert(std::accumulate(n0.begin(), n0.end(), 0) == this->A.shape[0]);
228 assert(std::accumulate(n1.begin(), n1.end(), 0) == this->A.shape[1]);
229
230 const size_t N0 = n0.size();
231 const size_t N1 = n1.size();
232
233 std::vector<size_t> n0_partial(N0 + 1);
234 std::partial_sum(n0.begin(), n0.end(), n0_partial.begin() + 1);
235 std::vector<size_t> n1_partial(N1 + 1);
236 std::partial_sum(n1.begin(), n1.end(), n1_partial.begin() + 1);
237
238 std::vector<std::vector<RI::Tensor<Tdata>>> ms(N0, std::vector<RI::Tensor<Tdata>>(N1));
239 for (size_t Im0 = 0; Im0 < N0; ++Im0)
240 for (size_t Im1 = 0; Im1 < N1; ++Im1)
241 {
242 RI::Tensor<Tdata>& m_tmp = ms[Im0][Im1] = RI::Tensor<Tdata>({n0[Im0], n1[Im1]});
243 for (size_t im0 = 0; im0 < n0[Im0]; ++im0)
244 for (size_t im1 = 0; im1 < n1[Im1]; ++im1)
245 m_tmp(im0, im1) = this->A(im0 + n0_partial[Im0], im1 + n1_partial[Im1]);
246 }
247 return ms;
248}
249
250template <typename Tdata>
252{
253 for (size_t i0 = 0; i0 < A.shape[0]; ++i0)
254 for (size_t i1 = 0; i1 < i0; ++i1)
255 A(i0, i1) = A(i1, i0);
256}
257
258#endif
static void axpy(const int n, const float alpha, const float *X, const int incX, float *Y, const int incY, base_device::AbacusDevice_t device_type=base_device::AbacusDevice_t::CpuDevice)
Definition blas_connector_vector.cpp:18
static void gemm(const char transa, const char transb, const int m, const int n, const int k, const float alpha, const float *a, const int lda, const float *b, const int ldb, const float beta, float *c, const int ldc, base_device::AbacusDevice_t device_type=base_device::AbacusDevice_t::CpuDevice)
Definition blas_connector_matrix.cpp:21
Method
Definition Inverse_Matrix.h:18
void using_potrf()
Definition Inverse_Matrix.hpp:30
void copy_down_triangle()
Definition Inverse_Matrix.hpp:251
void input(const RI::Tensor< Tdata > &m)
Definition Inverse_Matrix.hpp:166
RI::Tensor< Tdata > output() const
Definition Inverse_Matrix.hpp:218
void using_syev(const double &threshold_condition_number)
Definition Inverse_Matrix.hpp:102
void cal_inverse(const Method &method, const double &threshold_condition_number=0.)
Definition Inverse_Matrix.hpp:16
Definition complexmatrix.h:14
Definition matrix.h:19
std::complex< double > complex
Definition diago_cusolver.cpp:13
This is a wrapper of some LAPACK routines. Row-Major version.
void tensor_syev(char jobz, char uplo, RI::Tensor< T > &a, RI::Global_Func::To_Real_t< T > *w, int &info)
#define threshold
Definition sph_bessel_recursive_test.cpp:4
static void syev(RI::Tensor< double > &A, value_type *w, int &info)
Definition Inverse_Matrix.hpp:55
double value_type
Definition Inverse_Matrix.hpp:54
static void syev(RI::Tensor< float > &A, value_type *w, int &info)
Definition Inverse_Matrix.hpp:81
float value_type
Definition Inverse_Matrix.hpp:80
static void syev(RI::Tensor< std::complex< double > > &A, value_type *w, int &info)
Definition Inverse_Matrix.hpp:68
double value_type
Definition Inverse_Matrix.hpp:67
static void syev(RI::Tensor< std::complex< float > > &A, value_type *w, int &info)
Definition Inverse_Matrix.hpp:94
float value_type
Definition Inverse_Matrix.hpp:93
Definition Inverse_Matrix.hpp:47