/* 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) template SparseSMat NRMat::operator*(const SparseSMat &rhs) const { SparseSMat r(nn,rhs.ncols()); if(mm!=rhs.nrows()) laerror("incompatible sizes in NRMat*SparseSMat"); for(SPMatindex k=0; k * kl = rhs.line(k); if(kl) { //gather the data typename std::map::iterator p; int i,j; NRVec kline(kl->size()); NRVec klineind(kl->size()); for(p=kl->begin(), i=0; p!=kl->end(); ++p,++i) { klineind[i] = p->first; kline[i] = p->second; } NRVec kcol = column(k); //multiply NRMat prod=kcol.otimes(kline,false,1.); //scatter the results for(i=0; i 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; k 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"); r *= beta; 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"); #endif 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) { errno=0; SPMatindex dim[2]; if(dimen) { if(2*sizeof(SPMatindex)!=read(fd,&dim,2*sizeof(SPMatindex))) laerror("read() error in SparseSMat::get "); resize(dim[0],dim[1]); } else copyonwrite(); 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[0],dim[1],tmp,false); else add(dim[1],dim[0],tmp,false); } while(1); } template void SparseSMat::put(int fd, bool dimen, bool transp) const { errno=0; if(dimen) { if(sizeof(SPMatindex)!=write(fd,&nn,sizeof(SPMatindex))) laerror("cannot write() 1 in SparseSMat::put"); if(sizeof(SPMatindex)!=write(fd,&mm,sizeof(SPMatindex))) laerror("cannot write() 2 in SparseSMat::put"); } typename SparseSMat::iterator p(*this); for(; p.notend(); ++p) { if(sizeof(SPMatindex)!=write(fd,&(p->row),sizeof(SPMatindex))) laerror("cannot write() 3 in SparseSMat::put"); if(sizeof(SPMatindex)!=write(fd,&(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); \ template void SparseSMat::put(int fd, bool dimen, bool transp) const; \ INSTANTIZE(double) INSTANTIZE(complex) */ //// forced instantization of functions in the header in the corresponding object file template class SparseSMat; template class SparseSMat >; /*activate this if needed template void SparseSMat >::put(int fd, bool dimen, bool transp) const; template void SparseSMat >::get(int fd, bool dimen, bool transp); */ }//namespace