/* 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 . */ #include #include #include #include #include #include #include #include "sparsesmat.h" namespace LA { //dense times sparse (not necessarily symmetric) //result row i accumulated as sum_k A_ik (row k of rhs), skipping zero A_ik template SparseSMat NRMat::operator*(const SparseSMat &rhs) const { if(mm!=(int)rhs.nrows()) laerror("incompatible sizes in NRMat*SparseSMat"); SparseSMat r(nn,rhs.ncols()); for(int i=0; i *ri=NULL; for(int k=0; k *kl = rhs.line(k); if(aik==(T)0 || !kl) continue; if(!ri) ri = r[i] = new std::map; typename std::map::const_iterator p; for(p=kl->begin(); p!=kl->end(); ++p) (*ri)[p->first] += aik * p->second; //new map element is value-initialized to 0 } } r.simplify(); return r; } //matrix is assummed symmetric, no transposition, but possibly make conjugation template void SparseSMat::gemm(const T beta, const SparseSMat &a, const char transa, const SparseSMat &b, const char transb, const T alpha) { (*this) *= beta; if(alpha==(T)0) return; if(a.nn!=a.mm || b.nn!=b.mm || nn!=mm) laerror("SparseSMat::gemm implemented only for square symmetric matrices"); if(a.nn!=b.nn || a.nn!=nn) laerror("incompatible sizes in SparseSMat::gemm"); copyonwrite(); for(SPMatindex k=0; kempty() && !b.v[k]->empty()) //nonempty in both (allocated rows can be empty, e.g. after cholesky) { NRVec av(a.v[k]->size()); NRVec bv(b.v[k]->size()); NRVec ai(a.v[k]->size()); NRVec bi(b.v[k]->size()); //gather the data typename std::map::iterator p; int i,j; if(tolower(transa)=='c') for(p=a.v[k]->begin(), i=0; p!=a.v[k]->end(); ++p,++i) { ai[i] = p->first; av[i] = LA_traits::conjugate(p->second); } else for(p=a.v[k]->begin(), i=0; p!=a.v[k]->end(); ++p,++i) { ai[i] = p->first; av[i] = p->second; } for(p=b.v[k]->begin(), i=0; p!=b.v[k]->end(); ++p,++i) { bi[i] = p->first; bv[i] = p->second; } //make multiply via blas NRMat prod=av.otimes(bv,tolower(transb)=='c',alpha); //scatter the results -- probably the computational bottleneck for(i=0; i SparseSMat & SparseSMat::operator*=(const T &a) { if(!count) laerror("operator*= on undefined lhs"); if(a==(T)1) return *this; if(a==(T)0) {clear(); return *this;} copyonwrite(); for(SPMatindex i=0; i::iterator p; for(p=v[i]->begin(); p!=v[i]->end(); ++p) p->second *= a; } return *this; } template void SparseSMat::axpy(const T alpha, const SparseSMat &x, const bool transp) { if(nn!=x.nn || mm!=x.mm) laerror("incompatible matrix dimensions in SparseSMat::axpy"); if(alpha==(T)0) return; copyonwrite(); for(SPMatindex i=0; i; typename std::map::iterator p,q; for(p=x.v[i]->begin(); p!=x.v[i]->end(); ++p) { q=v[i]->find(p->first); if(q!=v[i]->end()) q->second += p->second * alpha; else (*v[i])[p->first] = p->second * alpha; } } simplify(); } template void SparseSMat::gemv(const T beta, NRVec &r, const char trans, const T alpha, const NRVec &x) const { if(nn!=r.size() || mm!= x.size()) laerror("incompatible matrix vector dimensions in SparseSMat::gemv"); if(tolower(trans)!='n') laerror("transposition not implemented yet in SparseSMat::gemv"); if(beta==(T)0) r.clear(); else if(beta!=(T)1) r *= beta; //no multiplication by 0, r may be uninitialized if(alpha == (T)0) return; r.copyonwrite(); for(SPMatindex i=0; i::iterator p; for(p=v[i]->begin(); p!=v[i]->end(); ++p) r[i] += x[p->first] * p->second * alpha ; } } template SparseSMat & SparseSMat::operator=(const T &a) { clear(); for(SPMatindex i=0; i; (*v[i])[i] = a; } return *this; } template SparseSMat & SparseSMat::operator+=(const T &a) { copyonwrite(); for(SPMatindex i=0; i::iterator p; p= v[i]->find(i); if(p!=v[i]->end()) p->second+=a; else (*v[i])[i] = a; } else {v[i] = new std::map; (*v[i])[i] = a;} } return *this; } template SparseSMat & SparseSMat::operator-=(const T &a) { copyonwrite(); for(SPMatindex i=0; i::iterator p; p= v[i]->find(i); if(p!=v[i]->end()) p->second-=a; else (*v[i])[i] = -a; } else {v[i] = new std::map; (*v[i])[i] = -a;} } return *this; } template typename LA_traits::normtype SparseSMat::norm(const T scalar) const { typename LA_traits::normtype sum=0; for(SPMatindex i=0; i::iterator p; bool diagonal_present=false; for(p=v[i]->begin(); p!=v[i]->end(); ++p) //loop over all existing elements { if(i==p->first) {diagonal_present=true; sum += LA_traits::sqrabs(p->second - scalar);} else sum += LA_traits::sqrabs(p->second); } if(!diagonal_present) sum += LA_traits::sqrabs(scalar); //there was zero on the diagonal } else sum += LA_traits::sqrabs(scalar); //missing whole line, subtracted diagonal element contributes return std::sqrt(sum); } //get diagonal, do not construct a new object, but store in existing one template const T* SparseSMat::diagonalof(NRVec &r, const bool divide, bool cache) const { if(nn!=mm) laerror("non-square matrix in SparseSMat::diagonalof"); if(nn!=r.size()) laerror("incompatible vector size in diagonalof()"); NRVec *rr; r.copyonwrite(); if(divide) {rr=new NRVec(nn); *rr=(T)0;} else {r=(T)0; rr=&r;} for(SPMatindex i=0; i::iterator p; p= v[i]->find(i); if(p!=v[i]->end()) (*rr)[i] += p->second; } if(divide) { for(unsigned int i=0; i SparseSMat SparseSMat::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("invalid submatrix specification"); } #endif const int m = tocol - fromcol + 1; const int n = torow - fromrow + 1; SparseSMat result(n, m); typename SparseSMat::iterator p(*this); for(; p.notend(); ++p) if(p->row>=fromrow && p->row<= torow && p->col >= fromcol && p->col <= tocol) result.add(p->row-fromrow, p->col-fromcol, p->elem, false); return result; } template void SparseSMat::storesubmatrix(const int fromrow, const int fromcol, const SparseSMat &rhs) { const int tocol = fromcol + rhs.ncols() - 1; const int torow = fromrow + rhs.nrows() - 1; #ifdef DEBUG if(fromrow<0 || fromrow>=nn || torow>=nn || fromcol<0 || fromcol>=mm || tocol>=mm) laerror("bad indices in storesubmatrix"); if(&rhs==this) laerror("storesubmatrix from itself"); #endif copyonwrite(); //store, not add: remove the old elements of the block first for(int i=fromrow; i<=torow; ++i) if(v[i]) v[i]->erase(v[i]->lower_bound((SPMatindex)fromcol), v[i]->upper_bound((SPMatindex)tocol)); typename SparseSMat::iterator p(rhs); for(; p.notend(); ++p) add(p->row+fromrow, p->col+fromcol, p->elem, false); } template void SparseSMat::get(int fd, bool dimen, bool transp, bool orcaformat) { if(orcaformat) laerror("ORCA format not supported for SparseSMat"); errno=0; SPMatindex dim[2]; if(dimen) { if(2*sizeof(SPMatindex)!=read(fd,&dim,2*sizeof(SPMatindex))) laerror("read() error in SparseSMat::get "); if(transp) resize(dim[1],dim[0]); else resize(dim[0],dim[1]); } else clear(); //the read matrix replaces the old contents do { if(2*sizeof(SPMatindex)!=read(fd,&dim,2*sizeof(SPMatindex))) laerror("read() error 2 in SparseSMat::get"); if(dim[0]==(SPMatindex) -1 || dim[1]==(SPMatindex) -1) break; typename LA_traits_io::IOtype tmp; LA_traits::get(fd,tmp,dimen,transp); // general way to work when elem is some complex class again if(transp) add(dim[1],dim[0],tmp,false); else add(dim[0],dim[1],tmp,false); } while(1); } template void SparseSMat::put(int fd, bool dimen, bool transp, bool orcaformat) const { if(orcaformat) laerror("ORCA format not supported for SparseSMat"); errno=0; if(dimen) { if(sizeof(SPMatindex)!=write(fd,&(transp ? mm : nn),sizeof(SPMatindex))) laerror("cannot write() 1 in SparseSMat::put"); if(sizeof(SPMatindex)!=write(fd,&(transp ? nn : mm),sizeof(SPMatindex))) laerror("cannot write() 2 in SparseSMat::put"); } typename SparseSMat::iterator p(*this); for(; p.notend(); ++p) { if(sizeof(SPMatindex)!=write(fd,&(transp ? p->col : p->row),sizeof(SPMatindex))) laerror("cannot write() 3 in SparseSMat::put"); if(sizeof(SPMatindex)!=write(fd,&(transp ? p->row : p->col),sizeof(SPMatindex))) laerror("cannot write() 4 in SparseSMat::put"); typename LA_traits_io::IOtype tmp = p->elem; LA_traits::put(fd,tmp,dimen,transp); // general way to work when elem is some non-scalar class again } SPMatindex sentinel[2]; sentinel[0] = sentinel[1] = (SPMatindex) -1; if(2*sizeof(SPMatindex) != write(fd,&sentinel,2*sizeof(SPMatindex))) laerror("cannot write() 5 in SparseSMat::put"); } /* Commented out by Roman for ICC #define INSTANTIZE(T) \ template void SparseSMat::gemm(const T beta, const SparseSMat &a, const char transa, const SparseSMat &b, const char transb, const T alpha); \ template SparseSMat & SparseSMat::operator*=(const T &a); \ template void SparseSMat::gemv(const T beta, NRVec &r, const char trans, const T alpha, const NRVec &x) const; \ template void SparseSMat::axpy(const T alpha, const SparseSMat &x, const bool transp); \ template SparseSMat & SparseSMat::operator=(const T &a); \ template SparseSMat & SparseSMat::operator+=(const T &a); \ template SparseSMat & SparseSMat::operator-=(const T &a); \ template LA_traits::normtype SparseSMat::norm(const T scalar) const; \ template const T* SparseSMat::diagonalof(NRVec &r, const bool divide, bool cache) const; \ template void SparseSMat::get(int fd, bool dimen, bool transp, bool orcaformat); \ template void SparseSMat::put(int fd, bool dimen, bool transp, bool orcaformat) const; \ INSTANTIZE(double) INSTANTIZE(complex) */ //// forced instantization of functions in the header in the corresponding object file template class SparseSMat; template class SparseSMat >; template class SparseSMat; template class SparseSMat >; template SparseSMat NRMat::operator*(const SparseSMat &rhs) const; template SparseSMat NRMat::operator*(const SparseSMat &rhs) const; template SparseSMat > NRMat >::operator*(const SparseSMat > &rhs) const; template SparseSMat > NRMat >::operator*(const SparseSMat > &rhs) const; /*activate this if needed template void SparseSMat >::put(int fd, bool dimen, bool transp, bool orcaformat) const; template void SparseSMat >::put(int fd, bool dimen, bool transp, bool orcaformat) const; template void SparseSMat >::get(int fd, bool dimen, bool transp, bool orcaformat); template void SparseSMat >::get(int fd, bool dimen, bool transp, bool orcaformat); */ }//namespace