MADNESS  version 0.9
eigen.h
Go to the documentation of this file.
1 /*
2  This file is part of MADNESS.
3 
4  Copyright (C) 2007,2010 Oak Ridge National Laboratory
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 
20  For more information please contact:
21 
22  Robert J. Harrison
23  Oak Ridge National Laboratory
24  One Bethel Valley Road
25  P.O. Box 2008, MS-6367
26 
27  email: harrisonrj@ornl.gov
28  tel: 865-241-3937
29  fax: 865-572-0680
30 
31 
32  $Id$
33 */
34 
35 
36 #ifdef MADNESS_HAS_EIGEN3
37 
38 #include <madness/tensor/tensor.h>
39 using madness::Tensor;
40 
41 #include <iostream>
42 using std::cout;
43 using std::endl;
44 
45 #include <algorithm>
46 using std::min;
47 using std::max;
48 
49 #include <Eigen/Dense>
50 using namespace Eigen;
51 
52 
53 #include <madness/world/print.h>
54 
55 #ifdef MADNESS_FORINT
56 typedef MADNESS_FORINT integer;
57 #else
58 typedef long integer;
59 #endif //MADNESS_FORINT
60 
61 
62 /*
63  The bigest problem with the Eigen3 and Madness interface
64  is in the transposed copy of the matrixes.
65 */
66 
67 namespace madness {
76 //vama template <typename T>
77 //vama void copy_mad2eigen2(long n, const T * restrict p1, T * restrict p0){
78 //vama for (long j=0; j<n; ++j,++p1,++p0) {
79 //vama *p0 = *p1;
80 //vama }
81 //vama }
82 
83  template <typename T>
84  void copy_mad2eigen2(integer n, const T * restrict p1, T * restrict p0){
85 #if 0
86  //vama #ifdef HAVE_MEMMOVE
87  /* Jeff assumes that HAVE_MEMMOVE is a good approximation to HAVE_MEMCPY */
88  memcpy(p0,p1,n); /* memcpy is often significantly faster than what the compiler comes up with */
89 #else
90  for (integer j=0; j<n; ++j,++p1,++p0) { *p0 = *p1; } /*JEFF: Is there a reason to not use memcpy? */
91 #endif
92  }
93 
114  template <typename T>
115  void svd(const Tensor<T>& a, Tensor<T>& U,
116  Tensor< typename Tensor<T>::scalar_type >& s, Tensor<T>& VT) {
117  TENSOR_ASSERT(a.ndim() == 2, "svd requires matrix",a.ndim(),&a);
118  integer m = a.dim(0), n = a.dim(1), rmax = min<int>(m,n);
119 
120  s = Tensor< typename Tensor<T>::scalar_type >(rmax);
121  U = Tensor<T>(m,rmax);
122  VT = Tensor<T>(rmax,n);
123 
124  Eigen::Matrix<T, Dynamic, Dynamic> g(n,m);
125 
126  //a = transpose(a);
127  copy_mad2eigen2( a.size(), a.ptr(), g.data());
128 
129  //g.transposeInPlace();
130  JacobiSVD< Eigen::Matrix<T, Dynamic, Dynamic>,HouseholderQRPreconditioner> svdm(g, ComputeThinU | ComputeThinV);
131 
132  Eigen::Matrix<T, Dynamic, Dynamic> dU = svdm.matrixV();
133  Eigen::Matrix<T, Dynamic, Dynamic> dV = svdm.matrixU();
134 
135  copy_mad2eigen2( s.size(), svdm.singularValues().data(), s.ptr());
136  //g.transposeInPlace();
137  dU.transposeInPlace();
138  copy_mad2eigen2( VT.size(), dV.data(), VT.ptr());
139  copy_mad2eigen2( U.size(), dU.data(), U.ptr());
140 
141  //U = transpose(U);
142  //U = conj_transpose(U); //fool
143 
144  }
145 
146 
147 
148 
165  template <typename T>
166  void gelss(const Tensor<T>& a, const Tensor<T>& b, double rcond,
167  Tensor<T>& x, Tensor< typename Tensor<T>::scalar_type >& s,
168  long& rank, Tensor<typename Tensor<T>::scalar_type>& sumsq) {
169  TENSOR_ASSERT(a.ndim() == 2, "gelss requires matrix",a.ndim(),&a);
170  integer n = a.dim(1), nrhs = b.dim(1);
171  TENSOR_ASSERT(b.ndim() <= 2, "gelss require a vector or matrix for the RHS",b.ndim(),&b);
172  TENSOR_ASSERT(a.dim(0) == b.dim(0), "gelss matrix and RHS must conform",b.ndim(),&b);
173 //
174  s = Tensor< typename Tensor<T>::scalar_type >(n);
175 
176  Tensor<T> AT = transpose(a);
177  Eigen::Matrix<T, Dynamic, Dynamic> g(n,n);
178  copy_mad2eigen2( AT.size(), AT.ptr(), g.data());
179 
180  Tensor<T> bT;
181 
182  if (nrhs == 1) {
183  x = Tensor<T>(n);
184  bT = Tensor<T>(n);
185  bT = copy(b);
186  x = bT; //creating the correct size
187  }
188  else {
189  x = Tensor<T>(n,nrhs);
190  bT = Tensor<T>(n,nrhs);
191  bT = transpose(b);
192  }
193 
194  Eigen::Matrix<T, Dynamic, Dynamic> h(n,nrhs);
195  copy_mad2eigen2( b.size(), bT.ptr(), h.data());
196 
197  rank = 0;
198  JacobiSVD< Eigen::Matrix<T, Dynamic, Dynamic> > svdm(g, ComputeThinU | ComputeThinV);
199  Eigen::Matrix<T, Dynamic, Dynamic> sol = svdm.solve(h);
200  sol.transposeInPlace();
201 
202  copy_mad2eigen2( b.size(), sol.data(), x.ptr());
203 
204  rank = svdm.singularValues().nonZeros(); // in lapack this is different
205  // S(i) <= rcond*S(1) are treated
206  // as zero
207  copy_mad2eigen2( s.size(), svdm.singularValues().data(), s.ptr());
208  }
209 
221  template <typename T>
222  void syev(const Tensor<T>& a,
223  Tensor<T>& V, Tensor< typename Tensor<T>::scalar_type >& e) {
224  TENSOR_ASSERT(a.ndim() == 2, "syev requires a matrix",a.ndim(),&a);
225  TENSOR_ASSERT(a.dim(0) == a.dim(1), "syev requires square matrix",0,&a);
226  integer n = a.dim(0);
227 
228  V = transpose(a); // For Hermitian case
230  Eigen::Matrix<T, Dynamic, Dynamic> g(n,n);
231  copy_mad2eigen2( a.size(), a.ptr(), g.data());
232  Eigen::Matrix<T, Dynamic, Dynamic> gT = g.transpose();
234  SelfAdjointEigenSolver< Eigen::Matrix<T, Dynamic, Dynamic> > sol(gT);
236  Eigen::Matrix<T, Dynamic, Dynamic> ev = sol.eigenvectors();
237 // cout << " ahy" << endl;
238 // cout << ev.transpose() << endl;
239 // cout << endl <<sol.eigenvectors() << endl;
241  V = Tensor<T>(n,n); //fool
242  e = Tensor< typename Tensor<T>::scalar_type >(n);
244 
245  copy_mad2eigen2( e.size(), sol.eigenvalues().data(), e.ptr());
246  //copy_mad2eigen2( e.size(), sol.eigenvalues().data(), e.ptr());
247 
248  //ev.transposeInPlace();
249  copy_mad2eigen2( V.size(), ev.data(), V.ptr());
250 //
251  //V = transpose(V);
252  V = conj_transpose(V);
253  }
254 
255 
256 
257 
267  template <typename T>
268  void cholesky(Tensor<T>& a) {
269  integer n = a.dim(0);
270 
271  Eigen::Matrix<T, Dynamic, Dynamic> g(n,n);
272  copy_mad2eigen2( a.size(), a.ptr(), g.data());
273  g.transposeInPlace();
274 
275  LLT< Eigen::Matrix<T, Dynamic, Dynamic> > ColDec(g);
276  Eigen::Matrix<T, Dynamic, Dynamic> L = ColDec.matrixU(); // remember the transpose effect U->L ;^
277 
278  copy_mad2eigen2( a.size(), L.data(), a.ptr());
279  a = transpose(a);
280 
281  for (int i=0; i<n; ++i)
282  for (int j=0; j<i; ++j)
283  a(i,j) = 0.0;
284  }
285 
299  template <typename T>
300  void gesv(const Tensor<T>& a, const Tensor<T>& b, Tensor<T>& x) {
301  TENSOR_ASSERT(a.ndim() == 2, "gesve requires matrix",a.ndim(),&a);
302  integer n = a.dim(0), m = a.dim(1), nrhs = b.dim(1);
303  TENSOR_ASSERT(m == n, "gesve requires square matrix",0,&a);
304  TENSOR_ASSERT(b.ndim() <= 2, "gesve require a vector or matrix for the RHS",b.ndim(),&b);
305  TENSOR_ASSERT(a.dim(0) == b.dim(0), "gesve matrix and RHS must conform",b.ndim(),&b);
306 /*
307  A must be invertible, if you dont know better use FullPivLu
308  (check it before)
309 */
310 
311  typedef typename TensorTypeData<T>::scalar_type scalar_type;
312  Tensor<T> AT = transpose(a);
313 
314  Eigen::Matrix<T, Dynamic, Dynamic> g(n,n);
315  copy_mad2eigen2( AT.size(), AT.ptr(), g.data());
316 
317  Tensor<T> bT;
318  if (nrhs == 1) {
319  x = Tensor<T>(n);
320  bT = Tensor<T>(n);
321  bT = copy(b);
322  x = bT; //creating the correct size
323  }
324  else {
325  x = Tensor<T>(n,nrhs);
326  bT = transpose(b);
327  }
328 
329  Eigen::Matrix<T, Dynamic, Dynamic> h(n,nrhs);
330  copy_mad2eigen2( b.size(), bT.ptr(), h.data());
331 
332  Eigen::Matrix<T, Dynamic, Dynamic> sol = g.householderQr().solve(h);
333 
334 //vama Matrix<T, Dynamic, Dynamic> sol = g.lu().solve(h);
335  sol.transposeInPlace();
336  copy_mad2eigen2( b.size(), sol.data(), x.ptr());
337  }
338 
353  template <typename T>
354  void sygv(const Tensor<T>& a, const Tensor<T>& B, int itype,
355  Tensor<T>& V, Tensor< typename Tensor<T>::scalar_type >& e) {
356  TENSOR_ASSERT(a.ndim() == 2, "sygv requires a matrix",a.ndim(),&a);
357  TENSOR_ASSERT(a.dim(0) == a.dim(1), "sygv requires square matrix",0,&a);
358  TENSOR_ASSERT(B.ndim() == 2, "sygv requires a matrix",B.ndim(),&a);
359  TENSOR_ASSERT(B.dim(0) == B.dim(1), "sygv requires square matrix",0,&a);
360  integer n = a.dim(0);
361 
362  Tensor<T> b = transpose(B); // For Hermitian case
363  V = transpose(a); // For Hermitian case
364  e = Tensor<typename Tensor<T>::scalar_type>(n);
365 
366  Eigen::Matrix<T, Dynamic, Dynamic> g(n,n);
367  Tensor<T> aT=transpose(a);
368 
369  copy_mad2eigen2( a.size(), aT.ptr(), g.data());
370  Eigen::Matrix<T, Dynamic, Dynamic> gT = g.transpose();
371 
372  Eigen::Matrix<T, Dynamic, Dynamic> h(n,n);
373  Tensor<T> bT=transpose(b);
374 
375  copy_mad2eigen2( b.size(), bT.ptr(), h.data());
376  Eigen::Matrix<T, Dynamic, Dynamic> hT = h.transpose();
377 
378  GeneralizedSelfAdjointEigenSolver<Eigen::Matrix<T, Dynamic, Dynamic>> sol(g, h);
379 
380  Eigen::Matrix<T, Dynamic, Dynamic> ev = sol.eigenvectors();
381 
382  V = Tensor<T>(n,n); //fool
383 
384 
385  ev.transposeInPlace();
386  copy_mad2eigen2( V.size(), ev.data(), V.ptr());
387  copy_mad2eigen2( e.size(), sol.eigenvalues().data(), e.ptr());
388 
389 
390  }
391 }
392 #endif //MADNESS_HAS_EIGEN3
Tensor< double > B
Definition: tdse1d.cc:167
void gesv(const Tensor< T > &a, const Tensor< T > &b, Tensor< T > &x)
Solve Ax = b for general A using the LAPACK *gesv routines.
Definition: lapack.cc:339
NDIM const Function< R, NDIM > & g
Definition: mra.h:2179
#define TENSOR_ASSERT(condition, msg, value, t)
Definition: tensorexcept.h:130
Tensor< T > conj_transpose(const Tensor< T > &t)
Returns a new deep copy of the complex conjugate transpose of the input tensor.
Definition: tensor.h:1954
void gelss(const Tensor< T > &a, const Tensor< T > &b, double rcond, Tensor< T > &x, Tensor< typename Tensor< T >::scalar_type > &s, long &rank, Tensor< typename Tensor< T >::scalar_type > &sumsq)
Solve Ax = b for general A using the LAPACK *gelss routines.
Definition: lapack.cc:393
const double L
Definition: 3dharmonic.cc:123
double V(const Vector< double, 3 > &r)
Definition: apps/ii/hatom_energy.cc:46
void syev(const Tensor< T > &A, Tensor< T > &V, Tensor< typename Tensor< T >::scalar_type > &e)
Real-symmetric or complex-Hermitian eigenproblem.
Definition: lapack.cc:478
Defines and implements most of Tensor.
const T1 &f1 return GTEST_2_TUPLE_() T(f0, f1)
#define max(a, b)
Definition: lda.h:53
Function< T, NDIM > copy(const Function< T, NDIM > &f, const std::shared_ptr< WorldDCPmapInterface< Key< NDIM > > > &pmap, bool fence=true)
Create a new copy of the function with different distribution and optional fence. ...
Definition: mra.h:1835
const mpreal min(const mpreal &x, const mpreal &y)
Definition: mpreal.h:2675
FLOAT a(int j, FLOAT z)
Definition: y1.cc:86
void svd(const Tensor< T > &a, Tensor< T > &U, Tensor< typename Tensor< T >::scalar_type > &s, Tensor< T > &VT)
Compute the singluar value decomposition of an n-by-m matrix using *gesvd.
Definition: lapack.cc:273
int integer
Definition: DFcode/fci/crayio.c:25
const double m
Definition: gfit.cc:199
void cholesky(Tensor< T > &A)
Compute the Cholesky factorization.
Definition: lapack.cc:551
void sygv(const Tensor< T > &A, const Tensor< T > &B, int itype, Tensor< T > &V, Tensor< typename Tensor< T >::scalar_type > &e)
Generalized real-symmetric or complex-Hermitian eigenproblem.
Definition: lapack.cc:519
Tensor< T > transpose(const Tensor< T > &t)
Returns a new deep copy of the transpose of the input tensor.
Definition: tensor.h:1945
#define restrict
Definition: config.h:403
Holds machinery to set up Functions/FuncImpls using various Factories and Interfaces.
Definition: chem/atomutil.cc:45
FLOAT b(int j, FLOAT z)
Definition: y1.cc:79