diff --git a/fourindex.h b/fourindex.h index 3363a5a..f80359a 100644 --- a/fourindex.h +++ b/fourindex.h @@ -2,6 +2,7 @@ #define _fourindex_included //element of a linked list, indices in a portable way, no bit shifts and endianity problems any more! +//note: nn is never compared with individual indices, so indexing from 1 as well as from 0 is possible template @@ -252,7 +253,7 @@ istream& operator>>(istream &s, fourindex &x) { s>>elem; x.add(i,j,k,l,elem); - s >> i >> j >>k >>ll; + s >> i >> j >>k >>l; } return s; } diff --git a/la_traits.h b/la_traits.h index a14f487..6191724 100644 --- a/la_traits.h +++ b/la_traits.h @@ -87,8 +87,8 @@ static bool bigger(const complex &x, const complex &y) {laerror("complex static bool smaller(const complex &x, const complex &y) {laerror("complex comparison undefined"); return false;} static inline normtype norm (const complex &x) {return abs(x);} static inline void axpy (complex &s, const complex &x, const complex &c) {s+=x*c;} -static void get(int fd, complex &x, bool dimensions=0) {if(sizeof(complex)!=read(fd,&x,sizeof(complex))) laerror("read error");} -static void put(int fd, const complex &x, bool dimensions=0) {if(sizeof(complex)!=write(fd,&x,sizeof(complex))) laerror("write error");} +static inline void get(int fd, complex &x, bool dimensions=0, bool transp=0) {if(sizeof(complex)!=read(fd,&x,sizeof(complex))) laerror("read error");} +static inline void put(int fd, const complex &x, bool dimensions=0, bool transp=0) {if(sizeof(complex)!=write(fd,&x,sizeof(complex))) laerror("write error");} static void multiget(unsigned int n,int fd, complex *x, bool dimensions=0){if((ssize_t)(n*sizeof(complex))!=read(fd,x,n*sizeof(complex))) laerror("read error");} static void multiput(unsigned int n, int fd, const complex *x, bool dimensions=0) {if((ssize_t)(n*sizeof(complex))!=write(fd,x,n*sizeof(complex))) laerror("write error");} @@ -105,8 +105,8 @@ static inline bool bigger(const C &x, const C &y) {return x>y;} static inline bool smaller(const C &x, const C &y) {return xy;} \ static inline bool smaller(const C &x, const C &y) {return x &x) {return x.norm();} \ static inline void axpy (X&s, const X &x, const C c) {s.axpy(c,x);} \ -static void put(int fd, const C &x, bool dimensions=1) {x.put(fd,dimensions);} \ -static void get(int fd, C &x, bool dimensions=1) {x.get(fd,dimensions);} \ +static void put(int fd, const C &x, bool dimensions=1, bool transp=0) {x.put(fd,dimensions,transp);} \ +static void get(int fd, C &x, bool dimensions=1, bool transp=0) {x.get(fd,dimensions,transp);} \ static void multiput(unsigned int n,int fd, const C *x, bool dimensions=1) {for(unsigned int i=0; iy;} static inline bool smaller(const C &x, const C &y) {return x &x) {return x.norm();} static inline void axpy (NRSMat&s, const NRSMat &x, const C c) {s.axpy(c,x);} -static void put(int fd, const C &x, bool dimensions=1) {x.put(fd,dimensions);} -static void get(int fd, C &x, bool dimensions=1) {x.get(fd,dimensions);} +static void put(int fd, const C &x, bool dimensions=1, bool transp=0) {x.put(fd,dimensions);} +static void get(int fd, C &x, bool dimensions=1, bool transp=0) {x.get(fd,dimensions);} static void multiput(unsigned int n,int fd, const C *x, bool dimensions=1) {for(unsigned int i=0; i; //raw I/O template -void NRMat::put(int fd, bool dim) const +void NRMat::put(int fd, bool dim, bool transp) const { errno=0; if(dim) { -if(sizeof(int) != write(fd,&nn,sizeof(int))) laerror("cannot write"); -if(sizeof(int) != write(fd,&mm,sizeof(int))) laerror("cannot write"); +if(sizeof(int) != write(fd,&(transp?mm:nn),sizeof(int))) laerror("cannot write"); +if(sizeof(int) != write(fd,&(transp?nn:mm),sizeof(int))) laerror("cannot write"); } -LA_traits::multiput(nn*mm,fd, + +if(transp) //not particularly efficient + { + for(int j=0; j::put(fd, +#ifdef MATPTR + v[i][j] +#else + v[i*mm+j] +#endif + ,dim,transp); + } +else LA_traits::multiput(nn*mm,fd, #ifdef MATPTR v[0] #else @@ -43,7 +56,7 @@ LA_traits::multiput(nn*mm,fd, } template -void NRMat::get(int fd, bool dim) +void NRMat::get(int fd, bool dim, bool transp) { int nn0,mm0; errno=0; @@ -51,11 +64,23 @@ if(dim) { if(sizeof(int) != read(fd,&nn0,sizeof(int))) laerror("cannot read"); if(sizeof(int) != read(fd,&mm0,sizeof(int))) laerror("cannot read"); -resize(nn0,mm0); +if(transp) resize(mm0,nn0); else resize(nn0,mm0); } else copyonwrite(); -LA_traits::multiget(nn*mm,fd, +if(transp) //not particularly efficient + { + for(int j=0; j::get(fd, +#ifdef MATPTR + v[i][j] +#else + v[i*mm+j] +#endif + ,dim,transp); + } +else LA_traits::multiget(nn*mm,fd, #ifdef MATPTR v[0] #else @@ -184,6 +209,24 @@ const NRVec NRMat::rsum() const return result; } +//block submatrix +template +const NRMat NRMat::submatrix(const int fromrow, const int torow, const int fromcol, const int tocol) const +{ +#ifdef DEBUG +if(fromrow <0 ||fromrow >=nn||torow <0 ||torow >=nn ||fromcol<0||fromcol>=mm||tocol<0||tocol>=mm||fromrow>torow||fromcol>tocol) laerror("bad indices in submatrix"); +#endif +int n=torow-fromrow+1; +int m=tocol-fromcol+1; +NRMat r(n,m); +for(int i=fromrow; i<=torow; ++i) +#ifdef MATPTR + memcpy(r.v[i-fromrow],v[i]+fromcol,m*sizeof(T)); +#else + memcpy(r.v+(i-fromrow)*m,v+i*mm+fromcol,m*sizeof(T)); +#endif +return r; +} // transpose Mat diff --git a/mat.h b/mat.h index f0f6e23..88a798d 100644 --- a/mat.h +++ b/mat.h @@ -73,8 +73,8 @@ public: inline int nrows() const; inline int ncols() const; inline int size() const; - void get(int fd, bool dimensions=1); - void put(int fd, bool dimensions=1) const; + void get(int fd, bool dimensions=1, bool transposed=false); + void put(int fd, bool dimensions=1, bool transposed=false) const; void copyonwrite(); void resize(const int n, const int m); inline operator T*(); //get a pointer to the data @@ -83,6 +83,7 @@ public: NRMat & conjugateme(); // square matrices only const NRMat transpose(bool conj=false) const; const NRMat conjugate() const; + const NRMat submatrix(const int fromrow, const int torow, const int fromcol, const int tocol) const; //there is also independent less efficient routine for generally indexed submatrix void gemm(const T &beta, const NRMat &a, const char transa, const NRMat &b, const char transb, const T &alpha);//this = alpha*op( A )*op( B ) + beta*this /* diff --git a/nonclass.cc b/nonclass.cc index caad05a..18cd396 100644 --- a/nonclass.cc +++ b/nonclass.cc @@ -134,7 +134,7 @@ static void linear_solve_do(NRMat &A, double *B, const int nrhs, const i //take into account some numerical instabilities in dgesv for singular matrices for (int i=0; i0) *det = 0; delete [] ipiv; @@ -643,6 +643,21 @@ NRMat matrixfunction(NRSMat a, double (*f) (double)) return r; } +NRMat realmatrixfunction(NRMat a, double (*f) (double)) +{ + int n = a.nrows(); + NRVec w(n); + diagonalize(a, w, true, false); + + for (int i=0; i u = a; + a.diagmultl(w); + NRMat r(n, n); + r.gemm(0.0, u, 't', a, 'n', 1.0); + return r; +} + + // instantize template to an addresable function complex myclog (const complex &x) { diff --git a/nonclass.h b/nonclass.h index 5235fb8..abb9602 100644 --- a/nonclass.h +++ b/nonclass.h @@ -73,10 +73,12 @@ extern void gdiagonalize(NRMat &a, NRVec< complex > &w, const bool corder=1, int n=0, const int sorttype=0, const bool 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 matrixfunction(NRMat a, complex (*f)(const complex &),const bool adjust=0); //functions on matrices inline NRMat sqrt(const NRSMat &a) { return matrixfunction(a,&sqrt); } +inline NRMat realsqrt(const NRMat &a) { return realmatrixfunction(a,&sqrt); } inline NRMat log(const NRSMat &a) { return matrixfunction(a,&log); } extern NRMat log(const NRMat &a); @@ -119,6 +121,7 @@ linear_solve(a,NULL,&det); return det; } + //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 diff --git a/qsort.h b/qsort.h index 15b0d79..8051b2a 100644 --- a/qsort.h +++ b/qsort.h @@ -1,3 +1,5 @@ +#ifndef _QSORT_H +#define _QSORT_H //general quicksort suitable if we do not want to create extra class for the member type but prefer to encapsulate it into compare and swap soutines //returns parity of the permutation @@ -39,3 +41,5 @@ else {if(i; //raw I/O template -void NRSMat::put(int fd, bool dim) const +void NRSMat::put(int fd, bool dim, bool transp) const { errno=0; if(dim) @@ -40,7 +40,7 @@ LA_traits::multiput(NN2,fd,v,dim); } template -void NRSMat::get(int fd, bool dim) +void NRSMat::get(int fd, bool dim, bool transp) { int nn0[2]; //align at least 8-byte errno=0; diff --git a/smat.h b/smat.h index 2f09ab5..ffd0708 100644 --- a/smat.h +++ b/smat.h @@ -56,8 +56,8 @@ public: void axpy(const T alpha, const NRSMat &x); // this+= a*x inline const T amax() const; const T trace() const; - void get(int fd, bool dimensions=1); - void put(int fd, bool dimensions=1) const; + void get(int fd, bool dimensions=1, bool transp=0); + void put(int fd, bool dimensions=1, bool transp=0) const; void copyonwrite(); void resize(const int n); inline operator T*(); //get a pointer to the data diff --git a/sparsemat.cc b/sparsemat.cc index c584fe7..6ed5d6f 100644 --- a/sparsemat.cc +++ b/sparsemat.cc @@ -60,14 +60,14 @@ extern ssize_t write(int, const void *, size_t); export template -void SparseMat::get(int fd, bool dimen) +void SparseMat::get(int fd, bool dimen, bool transp) { errno=0; SPMatindex dim[2]; if(dimen) { if(2*sizeof(SPMatindex) != read(fd,&dim,2*sizeof(SPMatindex))) laerror("cannot read"); -resize(dim[0],dim[1]); +if(transp) resize(dim[1],dim[0]); else resize(dim[0],dim[1]); int symnon[2]; if(2*sizeof(int) != read(fd,&symnon,2*sizeof(int))) laerror("cannot read"); symmetric=symnon[0]; @@ -84,22 +84,21 @@ do matel *ll = l; l= new matel; l->next= ll; - l->row=dim[0]; - l->col=dim[1]; - LA_traits::get(fd,l->elem,dimen); //general way to work when elem is some complex class again + if(transp) {l->row=dim[1]; l->col=dim[0];} else {l->row=dim[0]; l->col=dim[1];} + LA_traits::get(fd,l->elem,dimen,transp); //general way to work when elem is some complex class again } while(1); list=l; } export template -void SparseMat::put(int fd,bool dimen) const +void SparseMat::put(int fd,bool dimen, bool transp) const { errno=0; if(dimen) { -if(sizeof(SPMatindex) != write(fd,&nn,sizeof(SPMatindex))) laerror("cannot write"); -if(sizeof(SPMatindex) != write(fd,&mm,sizeof(SPMatindex))) laerror("cannot write"); +if(sizeof(SPMatindex) != write(fd,&(transp ? mm : nn),sizeof(SPMatindex))) laerror("cannot write"); +if(sizeof(SPMatindex) != write(fd,&(transp ? nn : mm),sizeof(SPMatindex))) laerror("cannot write"); int symnon[2]; symnon[0]=symmetric; symnon[1]=nonzero; @@ -108,9 +107,9 @@ if(2*sizeof(int) != write(fd,symnon,2*sizeof(int))) laerror("cannot write"); matel *l=list; while(l) { - if(sizeof(SPMatindex) != write(fd,&l->row,sizeof(SPMatindex))) laerror("cannot write"); - if(sizeof(SPMatindex) != write(fd,&l->col,sizeof(SPMatindex))) laerror("cannot write"); - LA_traits::put(fd,l->elem,dimen);//general way to work when elem is some non-scalar class again + if(sizeof(SPMatindex) != write(fd,&(transp ? l->col : l->row),sizeof(SPMatindex))) laerror("cannot write"); + if(sizeof(SPMatindex) != write(fd,&(transp ? l->row : l->col),sizeof(SPMatindex))) laerror("cannot write"); + LA_traits::put(fd,l->elem,dimen,transp);//general way to work when elem is some non-scalar class again l=l->next; } SPMatindex sentinel[2]; @@ -1082,6 +1081,54 @@ return result; } +template +void SparseMat::permuterows(const NRVec &p) +{ +if((SPMatindex)p.size()!=nn) laerror("inconsistent dimension in permuterows"); + +matel *l=list; + +while(l) + { + l->row = p[l->row]; + if(symmetric) l->col= p[l->col]; + l=l->next; + } +} + + +template +void SparseMat::permutecolumns(const NRVec &p) +{ +if((SPMatindex)p.size()!=nn) laerror("inconsistent dimension in permuterows"); + +matel *l=list; + +while(l) + { + if(symmetric) l->row = p[l->row]; + l->col= p[l->col]; + l=l->next; + } +} + +template +void SparseMat::permuteindices(const NRVec &p) +{ +if((SPMatindex)p.size()!=nn) laerror("inconsistent dimension in permuterows"); + +matel *l=list; + +while(l) + { + l->row = p[l->row]; + l->col= p[l->col]; + l=l->next; + } +} + + + template const SparseMat SparseMat::operator*(const SparseMat &rhs) const @@ -1177,6 +1224,8 @@ for(i=0; i SparseMat & SparseMat::oplusequal(const NRMat &rhs) @@ -1196,6 +1245,8 @@ for(SPMatindex i=0; i<(SPMatindex)rhs.nrows(); ++i) return *this; } + + export template SparseMat & SparseMat::oplusequal(const NRSMat &rhs) { @@ -1214,6 +1265,8 @@ for(SPMatindex i=0; i<(SPMatindex)rhs.nrows(); ++i) return *this; } + + export template SparseMat & SparseMat::oplusequal(const SparseMat &rhs) { @@ -1245,8 +1298,8 @@ template SparseMat & SparseMat::oplusequal(const NRMat &rhs);\ template SparseMat & SparseMat::oplusequal(const NRSMat &rhs);\ template ostream& operator<<(ostream &s, const SparseMat &x); \ template istream& operator>>(istream &s, SparseMat &x); \ -template void SparseMat::get(int fd, bool dimen); \ -template void SparseMat::put(int fd, bool dimen) const; \ +template void SparseMat::get(int fd, bool dimen, bool transp); \ +template void SparseMat::put(int fd, bool dimen, bool transp) const; \ template void SparseMat::copyonwrite(); \ template void SparseMat::unsort(); \ template void SparseMat::resize(const SPMatindex n, const SPMatindex m); \ @@ -1280,6 +1333,10 @@ template const SparseMat SparseMat::operator*(const SparseMat &rhs) con template const T SparseMat::dot(const SparseMat &rhs) const; \ template void SparseMat::gemm(const T beta, const SparseMat &a, const char transa, const SparseMat &b, const char transb, const T alpha); \ template void NRVec::gemv(const T beta, const SparseMat &a, const char trans, const T alpha, const NRVec &x);\ +template void SparseMat::permuterows(const NRVec &p);\ +template void SparseMat::permutecolumns(const NRVec &p);\ +template void SparseMat::permuteindices(const NRVec &p);\ + INSTANTIZE(double) diff --git a/sparsemat.h b/sparsemat.h index 9f5b259..bc15f5a 100644 --- a/sparsemat.h +++ b/sparsemat.h @@ -107,12 +107,15 @@ public: void setlist(matel *l) {list=l;} inline SPMatindex nrows() const {return nn;} inline SPMatindex ncols() const {return mm;} - void get(int fd, bool dimensions=1); - void put(int fd, bool dimensions=1) const; + void get(int fd, bool dimensions=1, bool transposed=false); + void put(int fd, bool dimensions=1, bool transposed=false) const; void resize(const SPMatindex n, const SPMatindex m); //destructive void incsize(const SPMatindex n, const SPMatindex m); //increase size without destroying the data void transposeme(); const SparseMat transpose() const; + void permuteindices(const NRVec &p); + void permuterows(const NRVec &p); + void permutecolumns(const NRVec &p); inline void setsymmetric() {if(nn!=mm) laerror("non-square cannot be symmetric"); symmetric=1;} inline void defineunsymmetric() {symmetric=0;} //just define and do nothing with it void setunsymmetric();//unwind the matrix assuming it was indeed symmetric diff --git a/t.cc b/t.cc index 9b9cca0..464cce4 100644 --- a/t.cc +++ b/t.cc @@ -512,7 +512,7 @@ cin>>n; cout <<"difference = "<<(res1-res2).norm()<>n>>k>>m; @@ -1095,5 +1095,15 @@ for(int iter=1; iter<100 && norm>1e-8 ; ++iter) } } +if(1) +{ +NRMat a,b; +cin >>a; +b=realsqrt(a); +cout < &x); \ template istream & operator>>(istream &s, NRVec< T > &x); \ -template void NRVec::put(int fd, bool dim) const; \ -template void NRVec::get(int fd, bool dim); \ +template void NRVec::put(int fd, bool dim, bool transp) const; \ +template void NRVec::get(int fd, bool dim, bool transp); \ @@ -82,7 +82,7 @@ istream & operator>>(istream &s, NRVec &x) //raw I/O template -void NRVec::put(int fd, bool dim) const +void NRVec::put(int fd, bool dim, bool transp) const { errno=0; int pad=1; //align at least 8-byte @@ -95,7 +95,7 @@ LA_traits::multiput(nn,fd,v,dim); } template -void NRVec::get(int fd, bool dim) +void NRVec::get(int fd, bool dim, bool transp) { int nn0[2]; //align at least 8-byte errno=0; diff --git a/vec.h b/vec.h index b48f613..ef306aa 100644 --- a/vec.h +++ b/vec.h @@ -90,8 +90,8 @@ public: void axpy(const T alpha, const T *x, const int stride=1); // this+= a*x void copyonwrite(); void resize(const int n); - void get(int fd, bool dimensions=1); - void put(int fd, bool dimensions=1) const; + void get(int fd, bool dimensions=1, bool transp=0); + void put(int fd, bool dimensions=1, bool transp=0) const; NRVec & normalize(); inline const double norm() const; inline const T amax() const;