All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Matrix.h
Go to the documentation of this file.
1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2  Copyright (c) 2013 The plumed team
3  (see the PEOPLE file at the root of the distribution for a list of names)
4 
5  See http://www.plumed-code.org for more information.
6 
7  This file is part of plumed, version 2.0.
8 
9  plumed is free software: you can redistribute it and/or modify
10  it under the terms of the GNU Lesser General Public License as published by
11  the Free Software Foundation, either version 3 of the License, or
12  (at your option) any later version.
13 
14  plumed is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU Lesser General Public License for more details.
18 
19  You should have received a copy of the GNU Lesser General Public License
20  along with plumed. If not, see <http://www.gnu.org/licenses/>.
21 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
22 #ifndef __PLUMED_tools_Matrix_h
23 #define __PLUMED_tools_Matrix_h
24 #include <vector>
25 #include <string>
26 #include <set>
27 #include <cmath>
28 #include "Exception.h"
30 #include "Log.h"
31 
32 #if defined(F77_NO_UNDERSCORE)
33 /// This is for AIX
34 #define F77_FUNC(name,NAME) name
35 #else
36 /// Default: put the underscore
37 #define F77_FUNC(name,NAME) name ## _
38 /// other cases may be added as we find them...
39 #endif
40 
41 extern "C" {
42 void F77_FUNC(dsyevr,DSYEVR)(const char *jobz, const char *range, const char *uplo, int *n,
43  double *a, int *lda, double *vl, double *vu, int *
44  il, int *iu, double *abstol, int *m, double *w,
45  double *z__, int *ldz, int *isuppz, double *work,
46  int *lwork, int *iwork, int *liwork, int *info);
47 void F77_FUNC(dgetrf,DGETRF)(int* m, int* n, double* da, int* lda, int* ipiv, int* info);
48 void F77_FUNC(dgetri,DGETRI)(int* m, double* da, int* lda, int* ipiv, double* work, int* lwork, int* info);
49 }
50 
51 namespace PLMD{
52 
53 /// Calculate the dot product between two vectors
54 template <typename T> T dotProduct( const std::vector<T>& A, const std::vector<T>& B ){
55  plumed_assert( A.size()==B.size() );
56  T val; for(unsigned i=0;i<A.size();++i){ val+=A[i]*B[i]; }
57  return val;
58 }
59 
60 /// Calculate the dot product between a vector and itself
61 template <typename T> T norm( const std::vector<T>& A ){
62  T val; for(unsigned i=0;i<A.size();++i){ val+=A[i]*A[i]; }
63  return val;
64 }
65 
66 /// This class stores a full matrix and allows one to do some simple matrix operations
67 template <typename T>
68 class Matrix:
69  public MatrixSquareBracketsAccess<Matrix<T>,T>
70  {
71  /// Matrix matrix multiply
72  template <typename U> friend void mult( const Matrix<U>& , const Matrix<U>& , Matrix<U>& );
73  /// Matrix times a std::vector
74  template <typename U> friend void mult( const Matrix<U>&, const std::vector<U>& , std::vector<U>& );
75  /// std::vector times a Matrix
76  template <typename U> friend void mult( const std::vector<U>&, const Matrix<U>&, std::vector<U>& );
77  /// Matrix transpose
78  template <typename U> friend void transpose( const Matrix<U>&, Matrix<U>& );
79  /// Output the entire matrix on a single line
80  template <typename U> friend Log& operator<<(Log&, const Matrix<U>& );
81  /// Output the Matrix in matrix form
82  template <typename U> friend void matrixOut( Log&, const Matrix<U>& );
83  /// Diagonalize a symmetric matrix - returns zero if diagonalization worked
84  template <typename U> friend int diagMat( const Matrix<U>& , std::vector<double>& , Matrix<double>& );
85  /// Calculate the logarithm of the determinant of a symmetric matrix - returns zero if succesfull
86  template <typename U> friend int logdet( const Matrix<U>& , double& );
87  /// Invert a matrix (works for both symmetric and assymetric matrices) - returns zero if sucesfull
88  template <typename U> friend int Invert( const Matrix<U>& , Matrix<double>& );
89  /// Do a cholesky decomposition of a matrix
90  template <typename U> friend void cholesky( const Matrix<U>& , Matrix<U>& );
91  /// Solve a system of equations using the cholesky decomposition
92  template <typename U> friend void chol_elsolve( const Matrix<U>& , const std::vector<U>& , std::vector<U>& );
93 private:
94  /// Number of elements in matrix (nrows*ncols)
95  unsigned sz;
96  /// Number of rows in matrix
97  unsigned rw;
98  /// Number of columns in matrix
99  unsigned cl;
100  /// The data in the matrix
101  std::vector<T> data;
102 public:
103  Matrix(const unsigned nr=0, const unsigned nc=0 ) : sz(nr*nc), rw(nr), cl(nc), data(nr*nc) {}
104  Matrix(const Matrix<T>& t) : sz(t.sz), rw(t.rw), cl(t.cl), data(t.data) {}
105  /// Resize the matrix
106  void resize( const unsigned nr, const unsigned nc ){ rw=nr; cl=nc; sz=nr*nc; data.resize(sz); }
107  /// Return the number of rows
108  inline unsigned nrows() const { return rw; }
109  /// Return the number of columns
110  inline unsigned ncols() const { return cl; }
111  /// Return element i,j of the matrix
112  inline T operator () (const unsigned& i, const unsigned& j) const { return data[j+i*cl]; }
113  /// Return a referenre to element i,j of the matrix
114  inline T& operator () (const unsigned& i, const unsigned& j) { return data[j+i*cl]; }
115  /// Set all elements of the matrix equal to the value of v
116  Matrix<T>& operator=(const T& v){
117  for(unsigned i=0;i<sz;++i){ data[i]=v; }
118  return *this;
119  }
120  /// Set the Matrix equal to another Matrix
122  sz=m.sz;
123  rw=m.rw;
124  cl=m.cl;
125  data=m.data;
126  return *this;
127  }
128  /// Set the Matrix equal to the value of a standard vector - used for readin
129  Matrix<T>& operator=(const std::vector<T>& v){
130  plumed_dbg_assert( v.size()==sz );
131  for(unsigned i=0;i<sz;++i){ data[i]=v[i]; }
132  return *this;
133  }
134  /// Add v to all elements of the Matrix
135  Matrix<T> operator+=(const T& v){
136  for(unsigned i=0;i<sz;++i){ data[i]+=v; }
137  return *this;
138  }
139  /// Matrix addition
141  plumed_dbg_assert( m.rw==rw && m.cl==cl );
142  data+=m.data;
143  return *this;
144  }
145  /// Subtract v from all elements of the Matrix
146  Matrix<T> operator-=(const T& v){
147  for(unsigned i=0;i<sz;++i){ data-=v; }
148  return *this;
149  }
150  /// Matrix subtraction
152  plumed_dbg_assert( m.rw==rw && m.cl==cl );
153  data-=m.data;
154  return *this;
155  }
156  /// Test if the matrix is symmetric or not
157  unsigned isSymmetric() const {
158  if (rw!=cl){ return 0; }
159  unsigned sym=1;
160  for(unsigned i=1;i<rw;++i) for(unsigned j=0;j<i;++j) if( std::fabs(data[i+j*cl]-data[j+i*cl])>1.e-10 ){ sym=0; break; }
161  return sym;
162  }
163 };
164 
165 template <typename T> void mult( const Matrix<T>& A , const Matrix<T>& B , Matrix<T>& C ){
166  plumed_assert(A.cl==B.rw);
167  if( A.rw !=C.rw || B.cl !=C.cl ){ C.resize( A.rw , B.cl ); } C=static_cast<T>( 0 );
168  for(unsigned i=0;i<A.rw;++i) for(unsigned j=0;j<B.cl;++j) for (unsigned k=0; k<A.cl; ++k) C(i,j)+=A(i,k)*B(k,j);
169 }
170 
171 template <typename T> void mult( const Matrix<T>& A, const std::vector<T>& B, std::vector<T>& C){
172  plumed_assert( A.cl==B.size() );
173  if( C.size()!=A.rw ){ C.resize(A.rw); }
174  for(unsigned i=0;i<A.rw;++i){ C[i]= static_cast<T>( 0 ); }
175  for(unsigned i=0;i<A.rw;++i) for(unsigned k=0;k<A.cl;++k) C[i]+=A(i,k)*B[k] ;
176 }
177 
178 template <typename T> void mult( const std::vector<T>& A, const Matrix<T>& B, std::vector<T>& C){
179  plumed_assert( B.rw==A.size() );
180  if( C.size()!=B.cl ){C.resize( B.cl );}
181  for(unsigned i=0;i<B.cl;++i){ C[i]=static_cast<T>( 0 ); }
182  for(unsigned i=0;i<B.cl;++i) for(unsigned k=0;k<B.rw;++k) C[i]+=A[k]*B(k,i);
183 }
184 
185 template <typename T> void transpose( const Matrix<T>& A, Matrix<T>& AT ){
186  if( A.rw!=AT.cl || A.cl!=AT.rw ) AT.resize( A.cl , A.rw );
187  for(unsigned i=0;i<A.cl;++i) for(unsigned j=0;j<A.rw;++j) AT(i,j)=A(j,i);
188 }
189 
190 template <typename T> Log& operator<<(Log& ostr, const Matrix<T>& mat){
191  for(unsigned i=0;i<mat.sz;++i) ostr<<mat.data[i]<<" ";
192  return ostr;
193 }
194 
195 template <typename T> void matrixOut( Log& ostr, const Matrix<T>& mat){
196  for(unsigned i=0;i<mat.rw;++i){
197  for(unsigned j=0;j<mat.cl;++j){ ostr<<mat(i,j)<<" "; }
198  ostr<<"\n";
199  }
200  return;
201 }
202 
203 template <typename T> int diagMat( const Matrix<T>& A, std::vector<double>& eigenvals, Matrix<double>& eigenvecs ){
204 
205  // Check matrix is square and symmetric
206  plumed_assert( A.rw==A.cl ); plumed_assert( A.isSymmetric()==1 );
207  double *da=new double[A.sz]; unsigned k=0; double *evals=new double[ A.cl ];
208  // Transfer the matrix to the local array
209  for (unsigned i=0; i<A.cl; ++i) for (unsigned j=0; j<A.rw; ++j) da[k++]=static_cast<double>( A(j,i) );
210 
211  int n=A.cl; int lwork=-1, liwork=-1, m, info, one=1;
212  double *work=new double[A.cl]; int *iwork=new int[A.cl];
213  double vl, vu, abstol=0.0;
214  int* isup=new int[2*A.cl]; double *evecs=new double[A.sz];
215 
216  F77_FUNC(dsyevr,DSYEVR)("V", "I", "U", &n, da, &n, &vl, &vu, &one, &n ,
217  &abstol, &m, evals, evecs, &n,
218  isup, work, &lwork, iwork, &liwork, &info);
219  if (info!=0) return info;
220 
221  // Retrieve correct sizes for work and iwork then reallocate
222  liwork=iwork[0]; delete [] iwork; iwork=new int[liwork];
223  lwork=static_cast<int>( work[0] ); delete [] work; work=new double[lwork];
224 
225  F77_FUNC(dsyevr,DSYEVR)("V", "I", "U", &n, da, &n, &vl, &vu, &one, &n ,
226  &abstol, &m, evals, evecs, &n,
227  isup, work, &lwork, iwork, &liwork, &info);
228  if (info!=0) return info;
229 
230  if( eigenvals.size()!=A.cl ){ eigenvals.resize( A.cl ); }
231  if( eigenvecs.rw!=A.rw || eigenvecs.cl!=A.cl ){ eigenvecs.resize( A.rw, A.cl ); }
232  k=0;
233  for(unsigned i=0;i<A.cl;++i){
234  eigenvals[i]=evals[i];
235  // N.B. For ease of producing projectors we store the eigenvectors
236  // ROW-WISE in the eigenvectors matrix. The first index is the
237  // eigenvector number and the second the component
238  for(unsigned j=0;j<A.rw;++j){ eigenvecs(i,j)=evecs[k++]; }
239  }
240 
241  // Deallocate all the memory used by the various arrays
242  delete[] da; delete [] work; delete [] evals; delete[] evecs; delete [] iwork; delete [] isup;
243  return 0;
244 }
245 
246 template <typename T> int Invert( const Matrix<T>& A, Matrix<double>& inverse ){
247 
248  if( A.isSymmetric()==1 ){
249  // GAT -- I only ever use symmetric matrices so I can invert them like this.
250  // I choose to do this as I have had problems with the more general way of doing this that
251  // is implemented below.
252  std::vector<double> eval(A.rw); Matrix<double> evec(A.rw,A.cl), tevec(A.rw,A.cl);
253  int err; err=diagMat( A, eval, evec );
254  if(err!=0) return err;
255  for (unsigned i=0; i<A.rw; ++i) for (unsigned j=0; j<A.cl; ++j) tevec(i,j)=evec(j,i)/eval[j];
256  mult(tevec,evec,inverse);
257  } else {
258  double *da=new double[A.sz]; int *ipiv=new int[A.cl];
259  unsigned k=0; int n=A.rw, info;
260  for(unsigned i=0;i<A.cl;++i) for(unsigned j=0;j<A.rw;++j) da[k++]=static_cast<double>( A(j,i) );
261 
262  F77_FUNC(dgetrf, DGETRF)(&n,&n,da,&n,ipiv,&info);
263  if(info!=0) return info;
264 
265  int lwork=-1; double* work=new double[A.cl];
266  F77_FUNC(dgetri, DGETRI)(&n,da,&n,ipiv,work,&lwork,&info);
267  if(info!=0) return info;
268 
269  lwork=static_cast<int>( work[0] ); delete [] work; work=new double[lwork];
270  F77_FUNC(dgetri, DGETRI)(&n,da,&n,ipiv,work,&lwork,&info);
271  if(info!=0) return info;
272 
273  if( inverse.cl!=A.cl || inverse.rw!=A.rw ){ inverse.resize(A.rw,A.cl); }
274  k=0; for(unsigned i=0;i<A.rw;++i) for(unsigned j=0;j<A.cl;++j) inverse(j,i)=da[k++];
275 
276  delete[] work; delete[] ipiv;
277  }
278 
279  return 0;
280 }
281 
282 template <typename T> void cholesky( const Matrix<T>& A, Matrix<T>& B ){
283 
284  plumed_assert( A.rw==A.cl && A.isSymmetric() );
285  Matrix<T> L(A.rw ,A.cl); L=0.;
286  std::vector<T> D(A.rw,0.);
287  for(unsigned i=0; i<A.rw; ++i){
288  L(i,i)=static_cast<T>( 1 );
289  for (unsigned j=0; j<i; ++j){
290  L(i,j)=A(i,j);
291  for (unsigned k=0; k<j; ++k) L(i,j)-=L(i,k)*L(j,k)*D[k];
292  if (D[j]!=0.) L(i,j)/=D[j]; else L(i,j)=static_cast<T>( 0 );
293  }
294  D[i]=A(i,i);
295  for (unsigned k=0; k<i; ++k) D[i]-=L(i,k)*L(i,k)*D[k];
296  }
297 
298  for(unsigned i=0; i<A.rw; ++i) D[i]=(D[i]>0.?sqrt(D[i]):0.);
299  if( B.rw!=A.rw || B.cl!=A.cl ){ B.resize( A.rw, A.cl); }
300  B=0.; for(unsigned i=0; i<A.rw; ++i) for(unsigned j=0; j<=i; ++j) B(i,j)+=L(i,j)*D[j];
301 }
302 
303 template <typename T> void chol_elsolve( const Matrix<T>& M, const std::vector<T>& b, std::vector<T>& y ){
304 
305  plumed_assert( M.rw==M.cl && M(0,1)==0.0 && b.size()==M.rw );
306  if( y.size()!=M.rw ){ y.resize( M.rw ); }
307  for(unsigned i=0;i<M.rw;++i){
308  y[i]=b[i];
309  for(unsigned j=0;j<i;++j) y[i]-=M(i,j)*y[j];
310  y[i]*=1.0/M(i,i);
311  }
312 }
313 
314 template <typename T> int logdet( const Matrix<T>& M, double& ldet ){
315  // Check matrix is square and symmetric
316  plumed_assert( M.rw==M.cl || M.isSymmetric() );
317 
318  double *da=new double[M.sz]; unsigned k=0; double *evals=new double[M.cl];
319  // Transfer the matrix to the local array
320  for (unsigned i=0; i<M.rw; ++i) for (unsigned j=0; j<M.cl; ++j) da[k++]=static_cast<double>( M(j,i) );
321 
322  int n=M.cl; int lwork=-1, liwork=-1, info, m, one=1;
323  double *work=new double[M.rw]; int *iwork=new int[M.rw];
324  double vl, vu, abstol=0.0;
325  int* isup=new int[2*M.rw]; double *evecs=new double[M.sz];
326  F77_FUNC(dsyevr,DSYEVR)("N", "I", "U", &n, da, &n, &vl, &vu, &one, &n ,
327  &abstol, &m, evals, evecs, &n,
328  isup, work, &lwork, iwork, &liwork, &info);
329  if (info!=0) return info;
330 
331  // Retrieve correct sizes for work and iwork then reallocate
332  lwork=static_cast<int>( work[0] ); delete [] work; work=new double[lwork];
333  liwork=iwork[0]; delete [] iwork; iwork=new int[liwork];
334 
335  F77_FUNC(dsyevr,DSYEVR)("N", "I", "U", &n, da, &n, &vl, &vu, &one, &n ,
336  &abstol, &m, evals, evecs, &n,
337  isup, work, &lwork, iwork, &liwork, &info);
338  if (info!=0) return info;
339 
340  // Transfer the eigenvalues and eigenvectors to the output
341  ldet=0; for(unsigned i=0;i<M.cl;i++){ ldet+=log(evals[i]); }
342 
343  // Deallocate all the memory used by the various arrays
344  delete[] da; delete [] work; delete [] evals; delete[] evecs; delete [] iwork; delete [] isup;
345 
346  return 0;
347 }
348 
349 
350 
351 }
352 #endif
Matrix< T > & operator+=(const Matrix< T > &m)
Matrix addition.
Definition: Matrix.h:140
Matrix< T > & operator=(const std::vector< T > &v)
Set the Matrix equal to the value of a standard vector - used for readin.
Definition: Matrix.h:129
Matrix< T > operator-=(const T &v)
Subtract v from all elements of the Matrix.
Definition: Matrix.h:146
TensorGeneric< 3, 3 > inverse(const TensorGeneric< 3, 3 > &t)
Definition: Tensor.h:386
#define F77_FUNC(name, NAME)
Default: put the underscore.
Definition: Matrix.h:37
int Invert(const Matrix< T > &A, Matrix< double > &inverse)
Definition: Matrix.h:246
Matrix< T > & operator=(const Matrix< T > &m)
Set the Matrix equal to another Matrix.
Definition: Matrix.h:121
void const char const char int double int double double int int double int double double int * ldz
Definition: Matrix.h:42
void const char const char * uplo
Definition: Matrix.h:42
void const char const char int double int double double int int double int double double int int double int int * iwork
Definition: Matrix.h:42
void cholesky(const Matrix< T > &A, Matrix< T > &B)
Definition: Matrix.h:282
unsigned ncols() const
Return the number of columns.
Definition: Matrix.h:110
void const char const char int double int double double int int double int double double int int double int int int * liwork
Definition: Matrix.h:42
void const char const char int double int * lda
Definition: Matrix.h:42
Utility class to add [][] access.
void const char const char int double int double * vl
Definition: Matrix.h:42
unsigned rw
Number of rows in matrix.
Definition: Matrix.h:97
Class containing the log stream.
Definition: Log.h:35
void const char * range
Definition: Matrix.h:42
void const char const char int * n
Definition: Matrix.h:42
void transpose(const Matrix< T > &A, Matrix< T > &AT)
Definition: Matrix.h:185
Matrix< T > & operator-=(const Matrix< T > &m)
Matrix subtraction.
Definition: Matrix.h:151
void const char const char int double int double double int int double int double double int int double * work
Definition: Matrix.h:42
void const char const char int double int double double int int double int double double int int double int * lwork
Definition: Matrix.h:42
Matrix(const unsigned nr=0, const unsigned nc=0)
Definition: Matrix.h:103
friend void chol_elsolve(const Matrix< U > &, const std::vector< U > &, std::vector< U > &)
Solve a system of equations using the cholesky decomposition.
void mult(const Matrix< T > &A, const Matrix< T > &B, Matrix< T > &C)
Definition: Matrix.h:165
std::vector< T > data
The data in the matrix.
Definition: Matrix.h:101
friend void transpose(const Matrix< U > &, Matrix< U > &)
Matrix transpose.
unsigned cl
Number of columns in matrix.
Definition: Matrix.h:99
unsigned nrows() const
Return the number of rows.
Definition: Matrix.h:108
friend int diagMat(const Matrix< U > &, std::vector< double > &, Matrix< double > &)
Diagonalize a symmetric matrix - returns zero if diagonalization worked.
T dotProduct(const std::vector< T > &A, const std::vector< T > &B)
Calculate the dot product between two vectors.
Definition: Matrix.h:54
friend void cholesky(const Matrix< U > &, Matrix< U > &)
Do a cholesky decomposition of a matrix.
void const char const char int double int double double int int * iu
Definition: Matrix.h:42
void const char const char int double int double double int int double int double * w
Definition: Matrix.h:42
int logdet(const Matrix< T > &M, double &ldet)
Definition: Matrix.h:314
int diagMat(const Matrix< T > &A, std::vector< double > &eigenvals, Matrix< double > &eigenvecs)
Definition: Matrix.h:203
void const char const char int double int double double int int double int double double int int * isuppz
Definition: Matrix.h:42
T operator()(const unsigned &i, const unsigned &j) const
Return element i,j of the matrix.
Definition: Matrix.h:112
void const char const char int double int double double int int double * abstol
Definition: Matrix.h:42
void int double int int * ipiv
Definition: Matrix.h:47
void const char const char int double int double double * vu
Definition: Matrix.h:42
void const char const char int double int double double int int double int * m
Definition: Matrix.h:42
void int double * da
Definition: Matrix.h:47
Matrix(const Matrix< T > &t)
Definition: Matrix.h:104
unsigned isSymmetric() const
Test if the matrix is symmetric or not.
Definition: Matrix.h:157
void chol_elsolve(const Matrix< T > &M, const std::vector< T > &b, std::vector< T > &y)
Definition: Matrix.h:303
void const char const char int double int double double int int double int double double int int double int int int int * info
Definition: Matrix.h:42
friend int Invert(const Matrix< U > &, Matrix< double > &)
Invert a matrix (works for both symmetric and assymetric matrices) - returns zero if sucesfull...
friend void mult(const Matrix< U > &, const Matrix< U > &, Matrix< U > &)
Matrix matrix multiply.
void resize(const unsigned nr, const unsigned nc)
Resize the matrix.
Definition: Matrix.h:106
unsigned sz
Number of elements in matrix (nrows*ncols)
Definition: Matrix.h:95
Matrix< T > & operator=(const T &v)
Set all elements of the matrix equal to the value of v.
Definition: Matrix.h:116
Matrix< T > operator+=(const T &v)
Add v to all elements of the Matrix.
Definition: Matrix.h:135
void const char const char int double * a
Definition: Matrix.h:42
void const char const char int double int double double int * il
Definition: Matrix.h:42
void matrixOut(Log &ostr, const Matrix< T > &mat)
Definition: Matrix.h:195
This class stores a full matrix and allows one to do some simple matrix operations.
Definition: Matrix.h:68
friend int logdet(const Matrix< U > &, double &)
Calculate the logarithm of the determinant of a symmetric matrix - returns zero if succesfull...
void const char const char int double int double double int int double int double double * z__
Definition: Matrix.h:42
friend void matrixOut(Log &, const Matrix< U > &)
Output the Matrix in matrix form.
T norm(const std::vector< T > &A)
Calculate the dot product between a vector and itself.
Definition: Matrix.h:61