/* LA: linear algebra C++ interface library Copyright (C) 2008 Jiri Pittner or This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef _LA_NONCLASS_H_ #define _LA_NONCLASS_H_ #include "vec.h" #include "smat.h" #include "mat.h" #include "la_traits.h" namespace LA { //MISC template const NRSMat twoside_transform(const NRSMat &S, const NRMat &C, bool transp=0) //calculate C^dagger S C { if(transp) { NRMat tmp = C * S; NRMat result(C.nrows(),C.nrows()); result.gemm((T)0,tmp,'n',C,'t',(T)1); return NRSMat(result); } NRMat tmp = S * C; NRMat result(C.ncols(),C.ncols()); result.gemm((T)0,C,'t',tmp,'n',(T)1); return NRSMat(result); } template const NRMat diagonalmatrix(const NRVec &x) { int n=x.size(); NRMat result((T)0,n,n); T *p = result[0]; for(int j=0; j inline const NRMat commutator ( const NRMat &x, const NRMat &y, const bool trx=0, const bool tryy=0) { NRMat r(trx?x.ncols():x.nrows(), tryy?y.nrows():y.ncols()); r.gemm((T)0,x,trx?'t':'n',y,tryy?'t':'n',(T)1); r.gemm((T)1,y,tryy?'t':'n',x,trx?'t':'n',(T)-1); return r; } //more efficient commutator for a special case of full matrices template inline const NRMat anticommutator ( const NRMat &x, const NRMat &y, const bool trx=0, const bool tryy=0) { NRMat r(trx?x.ncols():x.nrows(), tryy?y.nrows():y.ncols()); r.gemm((T)0,x,trx?'t':'n',y,tryy?'t':'n',(T)1); r.gemm((T)1,y,tryy?'t':'n',x,trx?'t':'n',(T)1); return r; } ////////////////////// // LAPACK interface // ////////////////////// #define declare_la(T) \ extern const NRVec diagofproduct(const NRMat &a, const NRMat &b,\ bool trb=0, bool conjb=0); \ extern T trace2(const NRMat &a, const NRMat &b, bool trb=0); \ extern T trace2(const NRSMat &a, const NRSMat &b, const bool diagscaled=0);\ extern T trace2(const NRSMat &a, const NRMat &b, const bool diagscaled=0);\ extern void linear_solve(NRMat &a, NRMat *b, double *det=0,int n=0); \ extern void linear_solve(NRSMat &a, NRMat *b, double *det=0, int n=0); \ extern void linear_solve(NRMat &a, NRVec &b, double *det=0, int n=0); \ extern void linear_solve(NRSMat &a, NRVec &b, double *det=0, int n=0); \ extern void diagonalize(NRMat &a, NRVec::normtype> &w, const bool eivec=1, const bool corder=1, int n=0, NRMat *b=NULL, const int itype=1); \ extern void diagonalize(NRSMat &a, NRVec::normtype> &w, NRMat *v, const bool corder=1, int n=0, NRSMat *b=NULL, const int itype=1);\ extern void singular_decomposition(NRMat &a, NRMat *u, NRVec &s,\ NRMat *v, const bool corder=1, int m=0, int n=0); /*NOTE!!! all versions of diagonalize DESTROY A and generalized diagonalize also B matrix */ declare_la(double) declare_la(complex) // Separate declarations //general nonsymmetric matrix and generalized diagonalization extern void gdiagonalize(NRMat &a, NRVec &wr, NRVec &wi, NRMat *vl, NRMat *vr, const bool corder=1, int n=0, const int sorttype=0, const int biorthonormalize=0, NRMat *b=NULL, NRVec *beta=NULL); extern void gdiagonalize(NRMat &a, NRVec< complex > &w, NRMat< complex >*vl, NRMat< complex > *vr, const bool corder=1, int n=0, const int sorttype=0, const int biorthonormalize=0, NRMat *b=NULL, NRVec *beta=NULL); extern NRMat matrixfunction(NRSMat a, double (*f) (double)); extern NRMat realmatrixfunction(NRMat a, double (*f) (double)); //a has to by in fact symmetric extern NRMat > complexmatrixfunction(NRMat a, double (*fre) (double), double (*fim) (double)); //a has to by in fact symmetric extern NRMat matrixfunction(NRMat a, complex (*f)(const complex &),const bool adjust=0); extern complex sqrtinv(const complex &); extern double sqrtinv(const double); //functions on matrices inline NRMat sqrt(const NRSMat &a) { return matrixfunction(a,&std::sqrt); } inline NRMat sqrtinv(const NRSMat &a) { return matrixfunction(a,&sqrtinv); } inline NRMat realsqrt(const NRMat &a) { return realmatrixfunction(a,&std::sqrt); } inline NRMat realsqrtinv(const NRMat &a) { return realmatrixfunction(a,&sqrtinv); } inline NRMat log(const NRSMat &a) { return matrixfunction(a,&std::log); } extern NRMat log(const NRMat &a); extern NRMat exp0(const NRMat &a); extern const NRMat realpart(const NRMat< complex >&); extern const NRMat imagpart(const NRMat< complex >&); extern const NRMat< complex > realmatrix (const NRMat&); extern const NRMat< complex > imagmatrix (const NRMat&); extern const NRMat< complex > complexmatrix (const NRMat&, const NRMat&); //Cholesky decomposition extern void cholesky(NRMat &a, bool upper=1); extern void cholesky(NRMat > &a, bool upper=1); //inverse by means of linear solve, preserving rhs intact template const NRMat inverse(NRMat a, T *det=0) { #ifdef DEBUG if(a.nrows()!=a.ncols()) laerror("inverse() for non-square matrix"); #endif NRMat result(a.nrows(),a.nrows()); result = (T)1.; a.copyonwrite(); linear_solve(a, &result, det); result.transposeme(); //tested with noncblas return result; } //several matrix norms template typename LA_traits::normtype MatrixNorm(const MAT &A, const char norm); //condition number template typename LA_traits::normtype CondNumber(const MAT &A, const char norm); //general determinant template const typename LA_traits::elementtype determinant(MAT a)//passed by value { typename LA_traits::elementtype det; if(a.nrows()!=a.ncols()) laerror("determinant of non-square matrix"); linear_solve(a,NULL,&det); return det; } //general determinant destructive on input template const typename LA_traits::elementtype determinant_destroy(MAT &a) //passed by reference { typename LA_traits::elementtype det; if(a.nrows()!=a.ncols()) laerror("determinant of non-square matrix"); linear_solve(a,NULL,&det); return det; } //extended linear solve routines template extern int linear_solve_x_(NRMat &A, T *B, const bool eq, const int nrhs, const int ldb, const char trans); //solve Ax = b using zgesvx template inline int linear_solve_x(NRMat > &A, NRVec > &B, const bool eq) { B.copyonwrite(); return linear_solve_x_(A, &B[0], eq, 1, B.size(), 'T'); } //solve AX = B using zgesvx template inline int linear_solve_x(NRMat > &A, NRMat > &B, const bool eq, const bool transpose=true) { B.copyonwrite(); if(transpose) B.transposeme();//because of corder int info(0); info = linear_solve_x_(A, B[0], eq, B.ncols(), B.nrows(), transpose?'T':'N'); if(transpose) B.transposeme(); return info; } #define multiply_by_inverse(P,Q,eq) linear_solve_x(P,Q,eq,false) /* * input: * P,Q - general complex square matrices * eq - use equilibration (man cgesvx) * description: * evaluates matrix expression QP^{-1} as * Z = QP^{-1} * ZP = Q * P^TZ^T = Q^T * Z is computed by solving this linear system instead of computing inverse * of P followed by multiplication by Q * returns: * returns the info parameter of cgesvx * result is stored in Q */ //general submatrix, INDEX will typically be NRVec or even int* //NOTE: in order to check consistency between nrows and rows in rows is a NRVec //some advanced metaprogramming would be necessary //application: e.g. ignoresign=true, equalsigns=true, indexshift= -1 ... elements of Slater overlaps for RHF template const NRMat::elementtype> submatrix(const MAT a, const int nrows, const INDEX rows, const int ncols, const INDEX cols, int indexshift=0, bool ignoresign=false, bool equalsigns=false) { NRMat::elementtype> r(nrows,ncols); if(equalsigns) //make the element zero if signs of both indices are opposite { if(ignoresign) { for(int i=0; i &v); //declaration of template interface to cblas routines with full options available //just to facilitate easy change between float, double, complex in a user code //very incomplete, add new ones as needed template inline void xcopy(int n, const T *x, int incx, T *y, int incy); template inline void xaxpy(int n, const T &a, const T *x, int incx, T *y, int incy); template inline T xdot(int n, const T *x, int incx, const T *y, int incy); //specialized definitions have to be in the header file to be inlineable, eliminating any runtime overhead template<> inline void xcopy (int n, const double *x, int incx, double *y, int incy) { cblas_dcopy(n, x, incx, y, incy); } template<> inline void xaxpy(int n, const double &a, const double *x, int incx, double *y, int incy) { cblas_daxpy(n, a, x, incx, y, incy); } template<> inline double xdot(int n, const double *x, int incx, const double *y, int incy) { return cblas_ddot(n,x,incx,y,incy); } //debugging aid: reconstruct an explicit matrix from the implicit version //which provides gemv only template NRMat reconstructmatrix(const M &implicitmat) { NRMat r(implicitmat.nrows(),implicitmat.ncols()); NRVec rhs(0.,implicitmat.ncols()); NRVec tmp(implicitmat.nrows()); for(int i=0; i