QMCPACK
MatrixOps.h
Go to the documentation of this file.
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: Paul R. C. Kent, kentpr@ornl.gov, Oak Ridge National Laboratory
8 // Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
9 // Alfredo A. Correa, correaa@llnl.gov, Lawrence Livermore National Laboratory
10 //
11 // File created by: Paul R. C. Kent, kentpr@ornl.gov, Oak Ridge National Laboratory
12 //////////////////////////////////////////////////////////////////////////////////////
13 
14 
15 // http://pathintegrals.info //
16 /////////////////////////////////////////////////////////////
17 
18 #ifndef MATRIX_OPS_H
19 #define MATRIX_OPS_H
20 #include "Blitz.h"
21 
22 #include<iostream> // for std::cerr
23 
26 
27 //void LUdecomp(Array<double, 2>& A, Array<int, 1>& perm, double& sign);
28 
29 //void LUsolve(Array<double, 2>& LU, Array<int, 1>& perm, Array<double, 1>& b);
30 
31 
32 struct lup{ // LU method for decomposition and solution
33 
34 // translated from https://en.wikipedia.org/wiki/LU_decomposition#C_code_example
35 template<class Matrix, class Permutation>
36 static auto decompose(Matrix&& A, Permutation&& P, double tol = std::numeric_limits<double>::epsilon()){
37  throw;
38  std::iota(begin(P), end(P), typename std::decay_t<Permutation>::value_type{0});
39  auto const N = std::min(size(A), size(~A));
40  assert( P.size() >= N );
41 
42  auto&& ret = A({0, N}, {0, N});
43  for(auto i : extension(ret)){
44  if(lup::permute_max_diagonal(A, P, i) < tol) return A({0, i}, {0, i});
45 
46  for(auto&& row : A({i + 1, N})){
47  auto&& urow = row({i + 1, N});
48  std::transform(
49  cbegin(urow), cend(urow), cbegin(A[i]({i + 1, N})), begin(urow),
50  [f = row[i] /= A[i][i]](auto const& a, auto const& b){return a - f*b;}
51  );
52  }
53  }
54  return A({0, N}, {0, N});
55 }
56 
57 template<class Matrix, class Permutation, class VectorSol>
58 static auto solve(Matrix const& LU, Permutation const& P, VectorSol&& x) -> VectorSol&&{
59  return upper_solve(LU, lower_solve(LU, permute(P, x)));
60 }
61 
62 private:
63 
64 template<class Matrix, class Permutation, class Index>
65 static auto permute_max_diagonal(Matrix&& LU, Permutation&& P, Index i){
66  auto mi = std::max_element(begin(LU) + i, end(LU), [i](auto const& a, auto const& b){return std::abs(a[i]) < std::abs(b[i]);}) - begin(LU);
67  swap(LU[i], LU[mi]);
68  std::swap(P [i], P [mi]);
69  return std::abs(LU[i][i]);
70 }
71 
72 template<class Permutation, class Vector>
73 static auto permute(Permutation const& p, Vector&& data) -> Vector&&{
74  assert(size(p) <= size(data));
75  using index = typename Permutation::size_type;
76  for(index i = 0; i != size(p); ++i){
77  index k = p[i];
78  for( ; k > i; k = p[k]){}
79  index pk = p[k];
80  if(k >=i and pk != i){
81  auto const t = data[i];
82  for( ; pk != i; k = pk, pk = p[k]){
83  data[k] = data[pk];
84  };
85  data[k] = t;
86  }
87  }
88  return std::forward<Vector>(data);
89 }
90 
91 template<class LUMatrix, class Vector>
92 static auto lower_solve(LUMatrix const& LU, Vector&& x) -> Vector&&{
93  assert(size(LU) <= size(x));
94  auto const N = size(LU);
95  for(typename LUMatrix::size_type i = 0; i != N; ++i){
96  auto const& Lrowi = LU[i]({0, i});
97  x[i] -= std::inner_product(begin(Lrowi), end(Lrowi), cbegin(x), 0.);
98  }
99  return std::forward<Vector>(x);
100 }
101 
102 template<class LUMatrix, class Vector>
103 static auto upper_solve(LUMatrix const& LU, Vector&& x) -> Vector&&{
104  assert(size(LU) <= size(x));
105  auto const N = size(LU);
106  for(typename LUMatrix::size_type i = N - 1; i >= 0; --i){
107  auto const& Urowi = LU[i]({i + 1, N});
108  (x[i] -= std::inner_product(begin(Urowi), end(Urowi), cbegin(x) + i + 1, 0.)) /= LU[i][i];
109  }
110  return std::forward<Vector>(x);
111 }
112 
113 };
114 
116 
117 void SVdecomp(Array<std::complex<double>, 2>& A,
118  Array<std::complex<double>, 2>& U,
119  Array<double, 1>& S,
120  Array<std::complex<double>, 2>& V);
121 
122 
123 void SymmEigenPairs(const Array<double, 2>& A, int NumPairs, Array<double, 1>& Vals, Array<double, 2>& Vectors);
124 
125 void SymmEigenPairs(const Array<std::complex<double>, 2>& A,
126  int NumPairs,
127  Array<double, 1>& Vals,
128  Array<std::complex<double>, 2>& Vectors);
129 
130 // Orthogonalizes matrix A with the polar decomposition. This returns
131 // the matrix closest to A which is orthogonal. A must be square.
132 void PolarOrthogonalize(Array<std::complex<double>, 2>& A);
133 
135 
136 double InnerProduct(const Array<double, 1>& A, const Array<double, 1>& B);
137 
139 
140 
142 void MatMult(const Array<std::complex<double>, 2>& A,
143  const Array<std::complex<double>, 2>& B,
144  Array<std::complex<double>, 2>& C);
145 
146 double Determinant(const Array<double, 2>& A);
147 std::complex<double> Determinant(const Array<std::complex<double>, 2>& A);
148 
149 /// This function returns the determinant of A and replaces A with its
150 /// cofactors.
152 
153 /// This function returns the worksize needed by the previous function.
154 int DetCofactorsWorksize(int N);
155 
156 
157 /// Complex versions of the functions above
158 std::complex<double> ComplexDetCofactors(Array<std::complex<double>, 2>& A, Array<std::complex<double>, 1>& work);
160 
161 double GJInverse(Array<double, 2>& A);
163 
165 
167 {
168  int m = A.rows();
169  int n = A.cols();
170  Array<double, 2> Atrans(n, m);
171  for (int i = 0; i < m; i++)
172  for (int j = 0; j < n; j++)
173  Atrans(j, i) = A(i, j);
174  A.resize(n, m);
175  A = Atrans;
176 }
177 
178 inline void OutOfPlaceTranspose(Array<std::complex<double>, 2>& A)
179 {
180  int m = A.rows();
181  int n = A.cols();
182  Array<std::complex<double>, 2> Atrans(n, m);
183  for (int i = 0; i < m; i++)
184  for (int j = 0; j < n; j++)
185  Atrans(j, i) = A(i, j);
186  A.resize(n, m);
187  A = Atrans;
188 }
189 
191 {
192  int m = A.rows();
193  int n = A.cols();
194  if (m != n)
196  else
197  {
198  for (int i = 0; i < m; i++)
199  for (int j = i + 1; j < m; j++)
200  std::swap(A(i, j), A(j, i));
201  }
202 }
203 
204 inline void Transpose(Array<std::complex<double>, 2>& A)
205 {
206  int m = A.rows();
207  int n = A.cols();
208  if (m != n)
210  else
211  {
212  for (int i = 0; i < m; i++)
213  for (int j = i + 1; j < m; j++)
214  std::swap(A(i, j), A(j, i));
215  }
216 }
217 
218 
219 inline void Print(const Mat3& A)
220 {
221  fprintf(stderr, "%14.6e %14.6e %14.6e\n", A(0, 0), A(0, 1), A(0, 2));
222  fprintf(stderr, "%14.6e %14.6e %14.6e\n", A(1, 0), A(1, 1), A(1, 2));
223  fprintf(stderr, "%14.6e %14.6e %14.6e\n", A(2, 0), A(2, 1), A(2, 2));
224 }
225 
226 inline void CubicFormula(double a, double b, double c, double d, double& x1, double& x2, double& x3)
227 {
228  double A = b / a;
229  double B = c / a;
230  double C = d / a;
231  double Q = (A * A - 3.0 * B) / 9.0;
232  double R = (2.0 * A * A * A - 9.0 * A * B + 27.0 * C) / 54.0;
233  //cerr << "Q = " << Q << " R = " << R << "\n";
234  if ((R * R) < (Q * Q * Q))
235  {
236  double theta = acos(R / sqrt(Q * Q * Q));
237  double twosqrtQ = 2.0 * sqrt(Q);
238  double third = 1.0 / 3.0;
239  double thirdA = third * A;
240  x1 = -twosqrtQ * cos(third * theta) - thirdA;
241  x2 = -twosqrtQ * cos(third * (theta + 2.0 * M_PI)) - thirdA;
242  x3 = -twosqrtQ * cos(third * (theta - 2.0 * M_PI)) - thirdA;
243  }
244  else
245  {
246  std::cerr << "Complex roots detected in CubicFormula.\n";
247  exit(1);
248  }
249 }
250 
251 
252 inline void TestCubicFormula()
253 {
254  double x1 = 2.3;
255  double x2 = 1.1;
256  double x3 = 9.2;
257  double a = 1.0;
258  double b = -(x1 + x2 + x3);
259  double c = (x1 * x2 + x1 * x3 + x2 * x3);
260  double d = -x1 * x2 * x3;
261 
262  double y1, y2, y3;
263  CubicFormula(a, b, c, d, y1, y2, y3);
264  std::cerr << "y1 = " << y1 << "\n";
265  std::cerr << "y2 = " << y2 << "\n";
266  std::cerr << "y3 = " << y3 << "\n";
267 }
268 
269 
270 inline void EigVals(const Mat3& M, double& lambda1, double& lambda2, double& lambda3)
271 {
272  double a = -1.0;
273  double b = M(0, 0) + M(1, 1) + M(2, 2);
274  double c = (-M(0, 0) * M(1, 1) - M(0, 0) * M(2, 2) - M(1, 1) * M(2, 2) + M(0, 1) * M(1, 0) + M(0, 2) * M(2, 0) +
275  M(1, 2) * M(2, 1));
276  double d = (M(0, 0) * M(1, 1) * M(2, 2) + M(0, 1) * M(1, 2) * M(2, 0) + M(0, 2) * M(1, 0) * M(2, 1) -
277  M(0, 1) * M(1, 0) * M(2, 2) - M(0, 2) * M(1, 1) * M(2, 0) - M(0, 0) * M(1, 2) * M(2, 1));
278  CubicFormula(a, b, c, d, lambda1, lambda2, lambda3);
279 }
280 
281 
282 inline void Eig(const Mat3& M, Mat3& U, Vec3& Lambda)
283 {
284  EigVals(M, Lambda(0), Lambda(1), Lambda(2));
285  for (int i = 0; i < 3; i++)
286  {
287  double L = Lambda(i);
288  U(0, i) = 1.0;
289  U(1, i) = (M(1, 2) / M(0, 2) * (M(0, 0) - L) - M(1, 0)) / (M(1, 1) - M(1, 2) / M(0, 2) * M(0, 1) - L);
290  U(2, i) = ((L - M(1, 1)) * U(1, i) - M(1, 0)) / M(1, 2);
291  double norm = 1.0 / sqrt(U(0, i) * U(0, i) + U(1, i) * U(1, i) + U(2, i) * U(2, i));
292  U(0, i) *= norm;
293  U(1, i) *= norm;
294  U(2, i) *= norm;
295  }
296 }
297 
298 
299 inline double det(const Mat2& C) { return (C(0, 0) * C(1, 1) - C(0, 1) * C(1, 0)); }
300 
301 // inline double det (const Mat3 &C)
302 // {
303 // double d0, d1, d2;
304 // d0 = C(1,1)*C(2,2) - C(1,2)*C(2,1);
305 // d1 = C(1,0)*C(2,2) - C(2,0)*C(1,2);
306 // d2 = C(1,0)*C(2,1) - C(2,0)*C(1,1);
307 // return (C(0,0)*d0 - C(0,1)*d1 + C(0,2)*d2);
308 // }
309 
310 // inline Mat3 Inverse (const Mat3 &A)
311 // {
312 // Mat3 CoFacts, Inv;
313 // CoFacts(0,0) = A(1,1)*A(2,2) - A(1,2)*A(2,1);
314 // CoFacts(0,1) = -(A(1,0)*A(2,2) - A(2,0)*A(1,2));
315 // CoFacts(0,2) = A(1,0)*A(2,1) - A(2,0)*A(1,1);
316 // CoFacts(1,0) = -(A(0,1)*A(2,2) - A(0,2)*A(2,1));
317 // CoFacts(1,1) = A(0,0)*A(2,2) - A(0,2)*A(2,0);
318 // CoFacts(1,2) = -(A(0,0)*A(2,1)-A(0,1)*A(2,0));
319 // CoFacts(2,0) = A(0,1)*A(1,2) - A(0,2)*A(1,1);
320 // CoFacts(2,1) = -(A(0,0)*A(1,2) - A(1,0)*A(0,2));
321 // CoFacts(2,2) = A(0,0)*A(1,1) - A(0,1)*A(1,0);
322 
323 // double det = (A(0,0) * CoFacts(0,0) +
324 // A(0,1) * CoFacts(0,1) +
325 // A(0,2) * CoFacts(0,2));
326 // double detinv = 1.0/det;
327 // Inv(0,0)=CoFacts(0,0)*detinv;
328 // Inv(0,1)=CoFacts(1,0)*detinv;
329 // Inv(0,2)=CoFacts(2,0)*detinv;
330 
331 // Inv(1,0)=CoFacts(0,1)*detinv;
332 // Inv(1,1)=CoFacts(1,1)*detinv;
333 // Inv(1,2)=CoFacts(2,1)*detinv;
334 
335 // Inv(2,0)=CoFacts(0,2)*detinv;
336 // Inv(2,1)=CoFacts(1,2)*detinv;
337 // Inv(2,2)=CoFacts(2,2)*detinv;
338 // return (Inv);
339 // }
340 
341 
342 // inline Mat3 Transpose(const Mat3 &A)
343 // {
344 // Mat3 B;
345 // B(0,0) = A(0,0);
346 // B(0,1) = A(1,0);
347 // B(0,2) = A(2,0);
348 // B(1,0) = A(0,1);
349 // B(1,1) = A(1,1);
350 // B(1,2) = A(2,1);
351 // B(2,0) = A(0,2);
352 // B(2,1) = A(1,2);
353 // B(2,2) = A(2,2);
354 // return (B);
355 // }
356 
358 
359 
361 {
362  Mat3 L;
363  double L00Inv;
364  L = 0.0;
365  L(0, 0) = sqrt(C(0, 0));
366  L00Inv = 1.0 / L(0, 0);
367  L(1, 0) = C(1, 0) * L00Inv;
368  L(2, 0) = C(2, 0) * L00Inv;
369  L(1, 1) = sqrt(C(1, 1) - L(1, 0) * L(1, 0));
370  L(2, 1) = (C(2, 1) - L(2, 0) * L(1, 0)) / L(1, 1);
371  L(2, 2) = sqrt(C(2, 2) - (L(2, 0) * L(2, 0) + L(2, 1) * L(2, 1)));
372  return (L);
373 }
374 
375 
376 inline void TestCholesky()
377 {
378  Mat3 V, D, C, L;
379  V(0, 0) = 1.0;
380  V(0, 1) = 2.0;
381  V(0, 2) = 3.0;
382  V(1, 0) = 6.0;
383  V(1, 1) = 1.0;
384  V(1, 2) = 9.0;
385  V(2, 0) = 7.0;
386  V(2, 1) = 5.0;
387  V(2, 2) = 7.0;
388 
389  D(0, 0) = 1.0;
390  D(0, 1) = 0.0;
391  D(0, 2) = 0.0;
392  D(1, 0) = 0.0;
393  D(1, 1) = 2.0;
394  D(1, 2) = 0.0;
395  D(2, 0) = 0.0;
396  D(2, 1) = 0.0;
397  D(2, 2) = 3.0;
398 
399  C = V * D * Transpose(V);
400  std::cerr << "C = " << C << "\n";
401  std::cerr << "V = " << V << "\n";
402  L = Cholesky(C);
403  std::cerr << "L = " << L << "\n";
404  std::cerr << "L L^T = " << L * Transpose(L) << "\n";
405 
406  Mat3 E, U;
407  Vec3 Lambda;
408  for (int i = 0; i < 10000000; i++)
409  {
410  Eig(C, U, Lambda);
411  //E = Inverse(C);
412  //L = Cholesky (E);
413  }
414 }
415 
416 #endif
double GJInverse(Array< double, 2 > &A)
void LinearLeastSquares(Array< double, 2 > &A, Array< double, 1 > &x, Array< double, 1 > &b)
MakeReturn< UnaryNode< FnFabs, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t abs(const Vector< T1, C1 > &l)
void Print(const Mat3 &A)
Definition: MatrixOps.h:219
void SymmEigenPairs(const Array< double, 2 > &A, int NumPairs, Array< double, 1 > &Vals, Array< double, 2 > &Vectors)
double GJInversePartial(Array< double, 2 > &A)
static auto lower_solve(LUMatrix const &LU, Vector &&x) -> Vector &&
Definition: MatrixOps.h:92
std::complex< double > ComplexDetCofactors(Array< std::complex< double >, 2 > &A, Array< std::complex< double >, 1 > &work)
Complex versions of the functions above.
void MatVecProd(Array< double, 2 > &A, Array< double, 1 > &x, Array< double, 1 > &Ax)
static auto permute_max_diagonal(Matrix &&LU, Permutation &&P, Index i)
Definition: MatrixOps.h:65
static auto solve(Matrix const &LU, Permutation const &P, VectorSol &&x) -> VectorSol &&
Definition: MatrixOps.h:58
void PolarOrthogonalize(Array< std::complex< double >, 2 > &A)
void MatMult(const Array< double, 2 > &A, const Array< double, 2 > &B, Array< double, 2 > &C)
T min(T a, T b)
double DetCofactors(Array< double, 2 > &A, Array< double, 1 > &work)
This function returns the determinant of A and replaces A with its cofactors.
void OuterProduct(const Array< double, 1 > &A, const Array< double, 1 > &B, Array< double, 2 > &AB)
void CholeskyBig(Array< double, 2 > &A)
MakeReturn< UnaryNode< FnCos, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t cos(const Vector< T1, C1 > &l)
Mat3 Cholesky(Mat3 C)
Definition: MatrixOps.h:360
double norm(const zVec &c)
Definition: VectorOps.h:118
MakeReturn< UnaryNode< FnArcCos, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t acos(const Vector< T1, C1 > &l)
int ComplexDetCofactorsWorksize(int N)
Array< double, 2 > Inverse(Array< double, 2 > &A)
const Array< double, 2 > operator*(const Array< double, 2 > &A, const Array< double, 2 > &B)
void Eig(const Mat3 &M, Mat3 &U, Vec3 &Lambda)
Definition: MatrixOps.h:282
void Transpose(Array< double, 2 > &A)
Definition: MatrixOps.h:190
void CubicFormula(double a, double b, double c, double d, double &x1, double &x2, double &x3)
Definition: MatrixOps.h:226
void TestCholesky()
Definition: MatrixOps.h:376
static auto permute(Permutation const &p, Vector &&data) -> Vector &&
Definition: MatrixOps.h:73
MakeReturn< UnaryNode< FnSqrt, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t sqrt(const Vector< T1, C1 > &l)
Definition: MatrixOps.h:32
void TestCubicFormula()
Definition: MatrixOps.h:252
void EigVals(const Mat3 &M, double &lambda1, double &lambda2, double &lambda3)
Definition: MatrixOps.h:270
double B(double x, int k, int i, const std::vector< double > &t)
double Determinant(const Array< double, 2 > &A)
void SVdecomp(Array< double, 2 > &A, Array< double, 2 > &U, Array< double, 1 > &S, Array< double, 2 > &V)
double InnerProduct(const Array< double, 1 > &A, const Array< double, 1 > &B)
static auto upper_solve(LUMatrix const &LU, Vector &&x) -> Vector &&
Definition: MatrixOps.h:103
QMCTraits::FullPrecRealType value_type
void OutOfPlaceTranspose(Array< double, 2 > &A)
Definition: MatrixOps.h:166
int DetCofactorsWorksize(int N)
This function returns the worksize needed by the previous function.
static auto decompose(Matrix &&A, Permutation &&P, double tol=std::numeric_limits< double >::epsilon())
Definition: MatrixOps.h:36
double det(const Mat2 &C)
Definition: MatrixOps.h:299