1 //////////////////////////////////////////////////////////////////////////////////////
2 // This file is distributed under the University of Illinois/NCSA Open Source License.
3 // See LICENSE file in top directory for details.
4 //
5 // Copyright (c) 2016 Jeongnim Kim and QMCPACK developers.
6 //
7 // File developed by: Ken Esler, kpesler@gmail.com, University of Illinois at Urbana-Champaign
8 // Miguel Morales, moralessilva2@llnl.gov, Lawrence Livermore National Laboratory
9 // Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
10 // Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
11 // Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
12 //
13 // File created by: Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
14 //////////////////////////////////////////////////////////////////////////////////////
15
16
17 /** @file
18 * @brief Define determinant operators
19 */
20 #ifndef OHMMS_NUMERIC_DETERMINANT_H
21 #define OHMMS_NUMERIC_DETERMINANT_H
22
23 #include <algorithm>
24 #include "OhmmsPETE/TinyVector.h"
25 #include "OhmmsPETE/OhmmsVector.h"
26 #include "OhmmsPETE/OhmmsMatrix.h"
27 #include "CPU/BLAS.hpp"
28 #include "config/stdlib/math.hpp"
29 #include "CPU/SIMD/inner_product.hpp"
30 #include "Numerics/determinant_operators.h"
31
32 namespace qmcplusplus
33 {
34 /** LU factorization of double */
LUFactorization(int n,int m,double * restrict a,int n0,int * restrict piv)35 inline void LUFactorization(int n, int m, double* restrict a, int n0, int* restrict piv)
36 {
37 int status;
38 dgetrf(n, m, a, n0, piv, status);
39 }
40
41 /** LU factorization of float */
LUFactorization(int n,int m,float * restrict a,const int & n0,int * restrict piv)42 inline void LUFactorization(int n, int m, float* restrict a, const int& n0, int* restrict piv)
43 {
44 int status;
45 sgetrf(n, m, a, n0, piv, status);
46 }
47
48 /** LU factorization of std::complex<double> */
LUFactorization(int n,int m,std::complex<double> * restrict a,int n0,int * restrict piv)49 inline void LUFactorization(int n, int m, std::complex<double>* restrict a, int n0, int* restrict piv)
50 {
51 int status;
52 zgetrf(n, m, a, n0, piv, status);
53 }
54
55 /** LU factorization of complex<float> */
LUFactorization(int n,int m,std::complex<float> * restrict a,int n0,int * restrict piv)56 inline void LUFactorization(int n, int m, std::complex<float>* restrict a, int n0, int* restrict piv)
57 {
58 int status;
59 cgetrf(n, m, a, n0, piv, status);
60 }
61
62 /** Inversion of a double matrix after LU factorization*/
InvertLU(int n,double * restrict a,int n0,int * restrict piv,double * restrict work,int n1)63 inline void InvertLU(int n, double* restrict a, int n0, int* restrict piv, double* restrict work, int n1)
64 {
65 int status;
66 dgetri(n, a, n0, piv, work, n1, status);
67 }
68
69 /** Inversion of a float matrix after LU factorization*/
InvertLU(const int & n,float * restrict a,const int & n0,int * restrict piv,float * restrict work,const int & n1)70 inline void InvertLU(const int& n,
71 float* restrict a,
72 const int& n0,
73 int* restrict piv,
74 float* restrict work,
75 const int& n1)
76 {
77 int status;
78 sgetri(n, a, n0, piv, work, n1, status);
79 }
80
81 /** Inversion of a std::complex<double> matrix after LU factorization*/
InvertLU(int n,std::complex<double> * restrict a,int n0,int * restrict piv,std::complex<double> * restrict work,int n1)82 inline void InvertLU(int n,
83 std::complex<double>* restrict a,
84 int n0,
85 int* restrict piv,
86 std::complex<double>* restrict work,
87 int n1)
88 {
89 int status;
90 zgetri(n, a, n0, piv, work, n1, status);
91 }
92
93 /** Inversion of a complex<float> matrix after LU factorization*/
InvertLU(int n,std::complex<float> * restrict a,int n0,int * restrict piv,std::complex<float> * restrict work,int n1)94 inline void InvertLU(int n,
95 std::complex<float>* restrict a,
96 int n0,
97 int* restrict piv,
98 std::complex<float>* restrict work,
99 int n1)
100 {
101 int status;
102 cgetri(n, a, n0, piv, work, n1, status);
103 }
104
105 /** @}*/
106
107 /** inverse a matrix
108 * @param x starting address of an n-by-m matrix
109 * @param n rows
110 * @param m cols
111 * @param work workspace array
112 * @param pivot integer pivot array
113 * @return determinant
114 */
115 template<class T>
Invert(T * restrict x,int n,int m,T * restrict work,int * restrict pivot)116 inline T Invert(T* restrict x, int n, int m, T* restrict work, int* restrict pivot)
117 {
118 T detvalue(1.0);
119 LUFactorization(n, m, x, n, pivot);
120 for (int i = 0, ip = 1; i < m; i++, ip++)
121 {
122 if (pivot[i] == ip)
123 detvalue *= x[i * m + i];
124 else
125 detvalue *= -x[i * m + i];
126 }
127 InvertLU(n, x, n, pivot, work, n);
128 return detvalue;
129 }
130
131 /** determinant of a matrix
132 * @param x starting address of an n-by-m matrix
133 * @param n rows
134 * @param m cols
135 * @param pivot integer pivot array
136 * @return determinant
137 */
138 template<class T>
Determinant(T * restrict x,int n,int m,int * restrict pivot)139 inline T Determinant(T* restrict x, int n, int m, int* restrict pivot)
140 {
141 T detvalue(1.0);
142 LUFactorization(n, m, x, n, pivot);
143 for (int i = 0, ip = 1; i < m; i++, ip++)
144 {
145 if (pivot[i] == ip)
146 detvalue *= x[i * m + i];
147 else
148 detvalue *= -x[i * m + i];
149 }
150 return detvalue;
151 }
152
153 /** inverse a matrix
154 * @param x starting address of an n-by-m matrix
155 * @param n rows
156 * @param m cols
157 * @return determinant
158 *
159 * Workspaces are handled internally.
160 */
161 template<class T>
Invert(T * restrict x,int n,int m)162 inline T Invert(T* restrict x, int n, int m)
163 {
164 std::vector<int> pivot(n);
165 std::vector<T> work(n);
166 return Invert(x, n, m, work.data(), pivot.data());
167 }
168
169 template<class T, class T1>
InvertWithLog(T * restrict x,int n,int m,T * restrict work,int * restrict pivot,std::complex<T1> & logdet)170 inline void InvertWithLog(T* restrict x, int n, int m, T* restrict work, int* restrict pivot, std::complex<T1>& logdet)
171 {
172 LUFactorization(n, m, x, n, pivot);
173 logdet = std::complex<T1>();
174 for (int i = 0; i < n; i++)
175 logdet += std::log(std::complex<T1>((pivot[i] == i + 1) ? x[i * m + i] : -x[i * m + i]));
176 InvertLU(n, x, n, pivot, work, n);
177 }
178
179 /** invert a matrix
180 * \param M a matrix to be inverted
181 * \param getdet bool, if true, calculate the determinant
182 * \return the determinant
183 */
184 template<class MatrixA>
185 inline typename MatrixA::value_type invert_matrix(MatrixA& M, bool getdet = true)
186 {
187 typedef typename MatrixA::value_type value_type;
188 const int n = M.rows();
189 std::vector<int> pivot(n);
190 std::vector<value_type> work(n);
191 LUFactorization(n, n, M.data(), n, pivot.data());
192 value_type det0 = 1.0;
193 if (getdet)
194 // calculate determinant
195 {
196 int sign = 1;
197 for (int i = 0; i < n; ++i)
198 {
199 if (pivot[i] != i + 1)
200 sign *= -1;
201 det0 *= M(i, i);
202 }
203 det0 *= static_cast<value_type>(sign);
204 }
205 InvertLU(n, M.data(), n, pivot.data(), work.data(), n);
206 return det0;
207 }
208
209 /** determinant ratio with a row substitution
210 * @param Minv inverse matrix
211 * @param newv row vector
212 * @param rowchanged row index to be replaced
213 * @return \f$ M^{new}/M\f$
214 */
215 template<typename MatA, typename VecB>
DetRatioByRow(const MatA & Minv,const VecB & newv,int rowchanged)216 inline typename MatA::value_type DetRatioByRow(const MatA& Minv, const VecB& newv, int rowchanged)
217 {
218 return simd::dot(Minv[rowchanged], newv.data(), Minv.cols());
219 //return BLAS::dot(Minv.cols(),Minv[rowchanged],newv.data());
220 }
221
222 /** determinant ratio with a column substitution
223 * @param Minv inverse matrix
224 * @param newv column vector
225 * @param colchanged column index to be replaced
226 * @return \f$ M^{new}/M\f$
227 */
228 template<typename MatA, typename VecB>
DetRatioByColumn(const MatA & Minv,const VecB & newv,int colchanged)229 inline typename MatA::value_type DetRatioByColumn(const MatA& Minv, const VecB& newv, int colchanged)
230 {
231 //use BLAS dot since the stride is not uniform
232 return simd::dot(Minv.cols(), Minv.data() + colchanged, Minv.cols(), newv.data(), 1);
233 }
234
235 /** update a inverse matrix by a row substitution
236 * @param Minv in/out inverse matrix
237 * @param newrow row vector
238 * @param rvec workspace
239 * @param rvecinv workspace
240 * @param rowchanged row index to be replaced
241 * @param c_ratio determinant-ratio with the row replacement
242 */
243 template<class MatA, class VecT>
InverseUpdateByRow(MatA & Minv,VecT & newrow,VecT & rvec,VecT & rvecinv,int rowchanged,typename MatA::value_type c_ratio)244 inline void InverseUpdateByRow(MatA& Minv,
245 VecT& newrow,
246 VecT& rvec,
247 VecT& rvecinv,
248 int rowchanged,
249 typename MatA::value_type c_ratio)
250 {
251 //using gemv+ger
252 det_row_update(Minv.data(), newrow.data(), Minv.cols(), rowchanged, c_ratio, rvec.data(), rvecinv.data());
253 //int ncols=Minv.cols();
254 //typename MatA::value_type ratio_inv=1.0/c_ratio;
255 //for(int j=0; j<ncols; j++) {
256 // if(j == rowchanged) continue;
257 // typename MatA::value_type temp = 0.0;
258 // for(int k=0; k<ncols; k++) temp += newrow[k]*Minv(j,k);
259 // temp *= -ratio_inv;
260 // for(int k=0; k<ncols; k++) Minv(j,k) += temp*Minv(rowchanged,k);
261 //}
262 //for(int k=0; k<ncols; k++) Minv(rowchanged,k) *= ratio_inv;
263 }
264
265 template<typename MatA, typename VecT>
InverseUpdateByColumn(MatA & Minv,VecT & newcol,VecT & rvec,VecT & rvecinv,int colchanged,typename MatA::value_type c_ratio)266 inline void InverseUpdateByColumn(MatA& Minv,
267 VecT& newcol,
268 VecT& rvec,
269 VecT& rvecinv,
270 int colchanged,
271 typename MatA::value_type c_ratio)
272 {
273 det_col_update(Minv.data(), newcol.data(), Minv.rows(), colchanged, c_ratio, rvec.data(), rvecinv.data());
274 //int nrows=Minv.rows();
275 //typename MatA::value_type ratio_inv=1.0/c_ratio;
276 //for(int i=0; i<nrows; i++) {
277 // if(i == colchanged) continue;
278 // typename MatA::value_type temp = 0.0;
279 // for(int k=0; k<nrows; k++) temp += newcol[k]*Minv(k,i);
280 // temp *= -ratio_inv;
281 // for(int k=0; k<nrows; k++) Minv(k,i) += temp*Minv(k,colchanged);
282 //}
283 //for(int k=0; k<nrows; k++) Minv(k,colchanged) *= ratio_inv;
284 }
285
286 } // namespace qmcplusplus
287 #endif
288