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