/* LA: linear algebra C++ interface library Copyright (C) 2008-2026 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 "csrmat.h" #include "nonclass.h" #include namespace LA { //raw pointers of possibly empty arrays (NULL when empty) template static inline const U *s_ptr(const NRVec &x) {return x.size()? (const U *)x : NULL;} template static inline U *s_wptr(NRVec &x) {return x.size()? (U *)x : NULL;} template CSRMat::CSRMat(const SPMatindex n, const SPMatindex m) : nn(n), mm(m), symmetric(false), rowptr(n+1) { rowptr.clear(); } template CSRMat::CSRMat(const SPMatindex n) : nn(n), mm(n), symmetric(false), rowptr(n+1) { rowptr.clear(); } template CSRMat::CSRMat(const SPMatindex n, const SPMatindex m, const NRVec &rp, const NRVec &c, const NRVec &x) : nn(n), mm(m), symmetric(false), rowptr(rp), col(c), v(x) { #ifdef DEBUG if(rp.size()!=(int)n+1 || rp[0]!=0 || (int)rp[n]!=c.size() || c.size()!=x.size()) laerror("inconsistent arrays in CSRMat constructor"); for(SPMatindex i=0; i=m || (k>rp[i] && c[k]<=c[k-1])) laerror("column index out of range or columns not ascending in CSRMat constructor"); } #endif } template void CSRMat::copyonwrite(bool detachonly, bool deep) { if(rowptr.size()) rowptr.copyonwrite(detachonly); if(col.size()) col.copyonwrite(detachonly); if(v.size()) v.copyonwrite(detachonly,deep); } template void CSRMat::resize(const SPMatindex n, const SPMatindex m) { nn=n; mm=m; symmetric=false; col.resize(0); v.resize(0); if(n==0 && m==0) {rowptr.resize(0); return;} rowptr.resize(n+1); rowptr.clear(); } //counting sort, O(nnz+n+m); the columns of the result are ascending in each row also if they were not in the input template const CSRMat CSRMat::transpose(bool conj) const { CSRMat r(mm,nn); r.symmetric=symmetric; const int nz=v.size(); if(nz==0) return r; const SPMatindex *rp=s_ptr(rowptr), *c=s_ptr(col); const T *x=s_ptr(v); r.col.resize(nz); r.v.resize(nz); SPMatindex *rrp=r.rowptr, *rc=r.col; T *rv=r.v; for(int k=0; k::conjugate(x[k]) : x[k]; } for(SPMatindex j=mm; j>0; --j) rrp[j]=rrp[j-1]; //rrp[j] was advanced to the start of row j+1 rrp[0]=0; return r; } //removes small elements; also sums duplicates (adjacent in sorted rows, only during the construction from coordinates) template void CSRMat::simplify(const typename LA_traits::normtype eps) { const int nz=v.size(); if(nz==0) return; copyonwrite(); SPMatindex *rp=rowptr, *c=col; T *x=v; int p=0, k=0; for(SPMatindex i=0; ieps) {c[p]=cc; x[p]=s; ++p;} } rp[i+1]=p; } if(p void CSRMat::fromcoo(const SPMatindex n, const SPMatindex m, const int nz, const SPMatindex *ri, const SPMatindex *ci, const T *vi) { CSRMat t(m,n); if(nz) { t.col.resize(nz); t.v.resize(nz); SPMatindex *trp=t.rowptr, *tc=t.col; T *tv=t.v; for(int k=0; k=n || ci[k]>=m) laerror("index out of range in CSRMat construction"); #endif ++trp[ci[k]+1]; } for(SPMatindex j=0; j0; --j) trp[j]=trp[j-1]; trp[0]=0; } *this=t.transpose(); simplify(); } //duplicates summed; a symmetric SparseMat (one triangle, complex symmetric) is unfolded without conjugation template CSRMat::CSRMat(const SparseMat &rhs) : nn(0), mm(0), symmetric(false) { const bool sym=rhs.issymmetric(); int nz=0; for(const matel *l=rhs.getlist(); l; l=l->next) nz+= (sym && l->row!=l->col)? 2:1; NRVec ri(nz), ci(nz); NRVec vi(nz); SPMatindex *r=s_wptr(ri), *c=s_wptr(ci); T *x=s_wptr(vi); int p=0; for(const matel *l=rhs.getlist(); l; l=l->next) { r[p]=l->row; c[p]=l->col; x[p++]=l->elem; if(sym && l->row!=l->col) {r[p]=l->col; c[p]=l->row; x[p++]=l->elem;} } fromcoo(rhs.nrows(),rhs.ncols(),nz,r,c,x); symmetric= sym && !LA_traits::is_complex(); } template CSRMat::CSRMat(const SparseSMat &rhs) : nn(rhs.nrows()), mm(rhs.ncols()), symmetric(false), rowptr(nn+1) { const typename LA_traits::normtype eps=LA_precision::normtype>::sparse_epsilon(); typedef typename std::map::const_iterator IT; int nz=0; for(SPMatindex i=0; i *l=rhs.line(i); if(l) for(IT q=l->begin(); q!=l->end(); ++q) if(std::abs(q->second)>eps) ++nz;} col.resize(nz); v.resize(nz); SPMatindex *rp=rowptr, *c=s_wptr(col); T *x=s_wptr(v); int p=0; rp[0]=0; for(SPMatindex i=0; i *l=rhs.line(i); if(l) for(IT q=l->begin(); q!=l->end(); ++q) if(std::abs(q->second)>eps) {c[p]=q->first; x[p++]=q->second;} rp[i+1]=p; } } template CSRMat::CSRMat(const NRMat &rhs) : nn(rhs.nrows()), mm(rhs.ncols()), symmetric(false), rowptr(nn+1) { const typename LA_traits::normtype eps=LA_precision::normtype>::sparse_epsilon(); int nz=0; for(SPMatindex i=0; ieps) ++nz;} col.resize(nz); v.resize(nz); SPMatindex *rp=rowptr, *c=s_wptr(col); T *x=s_wptr(v); int p=0; rp[0]=0; for(SPMatindex i=0; ieps) {c[p]=j; x[p++]=a[j];} rp[i+1]=p; } } //hermitian as NRSMat: the upper triangle is the conjugate of the stored lower one template CSRMat::CSRMat(const NRSMat &rhs) : nn(rhs.nrows()), mm(rhs.ncols()), symmetric(true), rowptr(nn+1) { const typename LA_traits::normtype eps=LA_precision::normtype>::sparse_epsilon(); int nz=0; for(SPMatindex i=0; ieps) ++nz; col.resize(nz); v.resize(nz); SPMatindex *rp=rowptr, *c=s_wptr(col); T *x=s_wptr(v); int p=0; rp[0]=0; for(SPMatindex i=0; ieps) {c[p]=j; x[p++]= j>i? LA_traits::conjugate(a) : a;} } rp[i+1]=p; } } template const T CSRMat::operator()(const SPMatindex i, const SPMatindex j) const { #ifdef DEBUG if(i>=nn || j>=mm) laerror("index out of range in CSRMat::operator()"); #endif if(v.size()==0) return (T)0; const SPMatindex *rp=rowptr, *c=col; const T *x=v; const SPMatindex *q=std::lower_bound(c+rp[i],c+rp[i+1],j); if(q!=c+rp[i+1] && *q==j) return x[q-c]; return (T)0; } template void CSRMat::put(int fd, bool dimensions, bool transp, bool orcaformat) const { if(orcaformat) laerror("ORCA format not supported for CSRMat"); if(transp) {transpose().put(fd,dimensions,false); return;} errno=0; if(dimensions) { if(sizeof(SPMatindex)!=write(fd,&nn,sizeof(SPMatindex))) laerror("cannot write() 1 in CSRMat::put"); if(sizeof(SPMatindex)!=write(fd,&mm,sizeof(SPMatindex))) laerror("cannot write() 2 in CSRMat::put"); } int sym=symmetric; if(sizeof(int)!=write(fd,&sym,sizeof(int))) laerror("cannot write() 3 in CSRMat::put"); rowptr.put(fd,true); col.put(fd,true); v.put(fd,true); } template void CSRMat::get(int fd, bool dimensions, bool transp, bool orcaformat) { if(orcaformat) laerror("ORCA format not supported for CSRMat"); errno=0; SPMatindex dim[2]; if(dimensions) {if(2*sizeof(SPMatindex)!=read(fd,&dim,2*sizeof(SPMatindex))) laerror("read() error 1 in CSRMat::get");} else {dim[0]= transp?mm:nn; dim[1]= transp?nn:mm;} int sym; if(sizeof(int)!=read(fd,&sym,sizeof(int))) laerror("read() error 2 in CSRMat::get"); rowptr.get(fd,true); col.get(fd,true); v.get(fd,true); nn=dim[0]; mm=dim[1]; symmetric=sym; if(rowptr.size()!=(nn||mm ? (int)nn+1 : 0) || col.size()!=v.size()) laerror("inconsistent data in CSRMat::get"); if(transp) transposeme(); } template CSRMat & CSRMat::operator*=(const T &a) { if(a==(T)0) {clear(); return *this;} if(LA_traits::imagpart(a)!=0) symmetric=false; if(v.size()) v*=a; return *this; } template CSRMat & CSRMat::operator=(const T &a) { if(nn!=mm) laerror("assignment of scalar to non-square CSRMat"); resize(nn,mm); symmetric= LA_traits::imagpart(a)==0; if(nn==0 || std::abs(a)<=LA_precision::normtype>::sparse_epsilon()) return *this; col.resize(nn); v.resize(nn); SPMatindex *rp=rowptr, *c=col; T *x=v; for(SPMatindex i=0; i CSRMat & CSRMat::operator+=(const T &a) { if(nn!=mm) laerror("addition of scalar to non-square CSRMat"); if(a==(T)0) return *this; const SPMatindex *rp=s_ptr(rowptr), *c=s_ptr(col); bool all= v.size()>0; if(all) for(SPMatindex i=0; i d(nn); d=a; const bool sym=symmetric; axpy((T)1,d); symmetric= sym && LA_traits::imagpart(a)==0; return *this; } if(LA_traits::imagpart(a)!=0) symmetric=false; v.copyonwrite(); T *x=v; for(SPMatindex i=0; i void CSRMat::axpy(const T alpha, const CSRMat &x0, const bool transp) { if((!transp && (nn!=x0.nn || mm!=x0.mm)) || (transp && (nn!=x0.mm || mm!=x0.nn))) laerror("incompatible dimensions for axpy"); if(alpha==(T)0 || x0.v.size()==0) return; CSRMat xt; if(transp) xt=x0.transpose(); const CSRMat &x= transp? xt : x0; const bool sym= (v.size()==0? nn==mm : symmetric) && x.symmetric && LA_traits::imagpart(alpha)==0; if(v.size()==0) { rowptr=x.rowptr; col=x.col; v=x.v; if(alpha!=(T)1) v*=alpha; symmetric=sym; return; } const SPMatindex *rp=rowptr, *c=col, *xrp=x.rowptr, *xc=x.col; const int nz=v.size(), xnz=x.v.size(); if(nz==xnz && ((rp==xrp && c==xc) || (!memcmp(rp,xrp,(nn+1)*sizeof(SPMatindex)) && !memcmp(c,xc,nz*sizeof(SPMatindex))))) { v.axpy(alpha,x.v); symmetric=sym; return; } const T *a=v, *b=x.v; NRVec nrp(nn+1); SPMatindex *np=nrp; np[0]=0; for(SPMatindex i=0; ixc[q]) ++q; else {++p; ++q;} ++cnt;} np[i+1]=np[i]+cnt+(rp[i+1]-p)+(xrp[i+1]-q); } NRVec ncol(np[nn]); NRVec nv(np[nn]); SPMatindex *nc=ncol; T *y=nv; int k=0; for(SPMatindex i=0; ixc[q]) {nc[k]=xc[q]; y[k++]=alpha*b[q++];} else {nc[k]=c[p]; y[k++]=a[p++]+alpha*b[q++];} } } rowptr=nrp; col=ncol; v=nv; symmetric=sym; } template const typename LA_traits::normtype CSRMat::norm(const T scalar) const { if(scalar==(T)0) return v.size()? v.norm() : (typename LA_traits::normtype)0; if(nn!=mm) laerror("subtraction of scalar from non-square CSRMat in norm()"); const SPMatindex *rp=s_ptr(rowptr), *c=s_ptr(col); const T *x=s_ptr(v); typename LA_traits::normtype sum=0; for(SPMatindex i=0; i::sqrabs(e); } if(!d) sum+=LA_traits::sqrabs(scalar); } return std::sqrt(sum); } template const T CSRMat::dot(const CSRMat &rhs) const { if(nn!=rhs.nn || mm!=rhs.mm) laerror("dot of incompatible CSRMat matrices"); if(v.size()==0 || rhs.v.size()==0) return (T)0; const SPMatindex *rp=rowptr, *c=col, *xrp=rhs.rowptr, *xc=rhs.col; if(rp==xrp && c==xc) return v.dot(rhs.v); const T *a=v, *b=rhs.v; T s=0; for(SPMatindex i=0; ixc[q]) ++q; else s+=LA_traits::conjugate(a[p++])*b[q++]; } } return s; } template const T CSRMat::dot(const NRMat &rhs) const { if((int)nn!=rhs.nrows() || (int)mm!=rhs.ncols()) laerror("dot of incompatible matrices"); if(v.size()==0) return (T)0; const SPMatindex *rp=rowptr, *c=col; const T *a=v; T s=0; for(SPMatindex i=0; i::conjugate(a[k])*b[c[k]]; } return s; } template const T CSRMat::trace() const { if(v.size()==0) return (T)0; const SPMatindex *rp=rowptr, *c=col; const T *x=v; T s=0; for(SPMatindex i=0; i void CSRMat::gemm(const T beta, const CSRMat &a0, const char transa, const CSRMat &b0, const char transb, const T alpha) { const char ta=tolower(transa), tb=tolower(transb); CSRMat at, bt; if(ta!='n') at=a0.transpose(ta=='c'); if(tb!='n') bt=b0.transpose(tb=='c'); const CSRMat &a= ta!='n'? at : a0; const CSRMat &b= tb!='n'? bt : b0; if(a.mm!=b.nn) laerror("incompatible matrices in CSRMat::gemm"); if(beta!=(T)0 && (nn!=a.nn || mm!=b.mm)) laerror("incompatible result matrix in CSRMat::gemm"); const SPMatindex n=a.nn, m=b.mm; CSRMat r(n,m); if(alpha!=(T)0 && a.v.size() && b.v.size()) { const SPMatindex *arp=a.rowptr, *ac=a.col, *brp=b.rowptr, *bc=b.col; const T *av=a.v, *bv=b.v; NRVec marker(m); SPMatindex *mk=marker; for(SPMatindex j=0; j acc(m); T *ac2=acc; for(SPMatindex j=0; j CSRMat & CSRMat::oplusequal(const CSRMat &rhs) { const bool sym= (v.size()==0? nn==mm : symmetric) && rhs.symmetric; const SPMatindex n=nn+rhs.nn, m=mm+rhs.mm; const int nz=v.size(), rnz=rhs.v.size(); NRVec nrp(n+1), ncol(nz+rnz); NRVec nv(nz+rnz); SPMatindex *np=nrp, *nc=s_wptr(ncol); T *y=s_wptr(nv); const SPMatindex *rp=s_ptr(rowptr), *c=s_ptr(col), *rrp=s_ptr(rhs.rowptr), *rc=s_ptr(rhs.col); const T *x=s_ptr(v), *rx=s_ptr(rhs.v); for(SPMatindex i=0; i<=nn; ++i) np[i]= rp? rp[i] : 0; for(SPMatindex i=1; i<=rhs.nn; ++i) np[nn+i]=nz+rrp[i]; for(int k=0; k const CSRMat CSRMat::otimes(const CSRMat &rhs) const { CSRMat r(nn*rhs.nn,mm*rhs.mm); r.symmetric= symmetric && rhs.symmetric; const int nz=v.size(), rnz=rhs.v.size(); if(nz==0 || rnz==0) return r; const SPMatindex *rp=rowptr, *c=col, *brp=rhs.rowptr, *bc=rhs.col; const T *x=v, *bx=rhs.v; r.col.resize(nz*rnz); r.v.resize(nz*rnz); SPMatindex *np=r.rowptr, *nc=r.col; T *y=r.v; int p=0; for(SPMatindex i=0; i void CSRMat::permrows(const SPMatindex *to) { const int nz=v.size(); NRVec nrp(nn+1); SPMatindex *np=nrp; const SPMatindex *rp=rowptr; np[0]=0; for(SPMatindex r=0; r ncol(nz); NRVec nv(nz); SPMatindex *nc=ncol; T *y=nv; const SPMatindex *c=col; const T *x=v; for(SPMatindex r=0; r void CSRMat::permuteme_rows(const NRPerm &p, const bool inverse) { if((SPMatindex)p.size()!=nn) laerror("inconsistent dimension in permuteme_rows"); NRPerm pinv; if(inverse) pinv=p.inverse(); const NRPerm &pp= inverse?pinv:p; NRVec to(nn); for(SPMatindex r=0; r void CSRMat::permuteme_cols(const NRPerm &p, const bool inverse) { if((SPMatindex)p.size()!=mm) laerror("inconsistent dimension in permuteme_cols"); *this=transpose(); permuteme_rows(p,inverse); *this=transpose(); } template void CSRMat::permuteme_both(const NRPerm &p, const NRPerm &q, const bool inverse) { const bool sym= symmetric && p==q; permuteme_rows(p,inverse); permuteme_cols(q,inverse); symmetric=sym; } template void CSRMat::permuterows(const NRVec &p) { if((SPMatindex)p.size()!=nn) laerror("inconsistent dimension in permuterows"); if(nn) permrows(p); symmetric=false; } template void CSRMat::permutecolumns(const NRVec &p) { if((SPMatindex)p.size()!=mm) laerror("inconsistent dimension in permutecolumns"); *this=transpose(); permuterows(p); *this=transpose(); } template void CSRMat::permuteindices(const NRVec &p) { if((SPMatindex)p.size()!=nn || (SPMatindex)p.size()!=mm) laerror("inconsistent dimension in permuteindices"); const bool sym=symmetric; permuterows(p); permutecolumns(p); symmetric=sym; } //square: diagonal (binary search in each row); non-square: diagonal of A^T A (for preconditioning as SparseMat::diagonalof); cache is ignored template const T* CSRMat::diagonalof(NRVec &r, const bool divide, bool cache) const { #ifdef DEBUG if((int)mm!=r.size()) laerror("incompatible vector size in diagonalof()"); #endif NOT_GPU(r); r.copyonwrite(); T *rr=r; const SPMatindex *rp=s_ptr(rowptr), *c=s_ptr(col); const T *x=s_ptr(v); if(nn==mm) { for(SPMatindex i=0; i d(mm); d.clear(); T *dd=d; for(int k=0; k void NRVec::gemv(const T beta, const CSRMat &a, const char trans, const T alpha, const NRVec &x) { const char tr=tolower(trans); const bool tp= tr!='n'; const bool cj= tr=='c' && LA_traits::is_complex(); if((tp?a.nrows():a.ncols())!=(SPMatindex)x.size()) laerror("incompatible sizes in gemv"); #ifdef DEBUG if((tp?a.ncols():a.nrows())!=(SPMatindex)nn) laerror("incompatible result vector in gemv"); #endif NOT_GPU(*this); NOT_GPU(x); copyonwrite(); if(beta==(T)0) clear(); else if(beta!=(T)1) (*this)*=beta; if(alpha==(T)0 || a.length()==0) return; const SPMatindex *rp=a.getrowptr(), *c=a.getcol(); const T *av=a.getval(); const T *xv=x.v; const SPMatindex n=a.nrows(); if(!tp) for(SPMatindex i=0; i::conjugate(av[k])*ax; else for(SPMatindex k=rp[i]; k NRVec::NRVec(const CSRMat &rhs) : NRVec(rhs.nrows()>1?rhs.nrows():rhs.ncols()) { if(rhs.nrows()>1 && rhs.ncols()>1) laerror("cannot construct a vector from a sparse matrix with more than one row/column"); clear(); const SPMatindex *rp=s_ptr(rhs.getrowptr()), *c=s_ptr(rhs.getcol()); const T *x=s_ptr(rhs.getval()); if(!x) return; if(rhs.nrows()>1) {for(SPMatindex i=0; irp[i]) v[i]=x[rp[i]];} else for(SPMatindex k=0; k NRMat::NRMat(const CSRMat &rhs) { nn=rhs.nrows(); mm=rhs.ncols(); count=new int(1); #ifdef CUDALA location=cpu; #endif T *p; #ifdef MATPTR v= new T*[nn]; p=v[0] = new T[mm*nn]; for (int i=1; i< nn; i++) v[i] = v[i-1] + mm; #else p= v = new T[mm*nn]; #endif memset(p,0,nn*mm*sizeof(T)); const SPMatindex *rp=s_ptr(rhs.getrowptr()), *c=s_ptr(rhs.getcol()); const T *x=s_ptr(rhs.getval()); if(x) for(int i=0; i NRMat & NRMat::operator+=(const CSRMat &rhs) { if(nn!=(int)rhs.nrows() || mm!=(int)rhs.ncols()) laerror("incompatible matrices in +="); NOT_GPU(*this); copyonwrite(); const SPMatindex *rp=s_ptr(rhs.getrowptr()), *c=s_ptr(rhs.getcol()); const T *x=s_ptr(rhs.getval()); if(x) for(int i=0; i NRMat & NRMat::operator-=(const CSRMat &rhs) { if(nn!=(int)rhs.nrows() || mm!=(int)rhs.ncols()) laerror("incompatible matrices in -="); NOT_GPU(*this); copyonwrite(); const SPMatindex *rp=s_ptr(rhs.getrowptr()), *c=s_ptr(rhs.getcol()); const T *x=s_ptr(rhs.getval()); if(x) for(int i=0; i void NRMat::gemm(const T &beta, const CSRMat &a, const char transa, const NRMat &b, const char transb, const T &alpha) { const char ta=tolower(transa), tb=tolower(transb); const bool tpa= ta!='n', cja= ta=='c' && LA_traits::is_complex(); const int an= tpa? a.ncols() : a.nrows(), ak= tpa? a.nrows() : a.ncols(); const int bk= tb!='n'? b.ncols() : b.nrows(), bm= tb!='n'? b.nrows() : b.ncols(); if(ak!=bk) laerror("incompatible matrices in NRMat::gemm with CSRMat"); #ifdef DEBUG if(nn!=an || mm!=bm) laerror("incompatible result matrix in NRMat::gemm with CSRMat"); #endif NOT_GPU(*this); copyonwrite(); if(beta==(T)0) clear(); else if(beta!=(T)1) (*this)*=beta; if(alpha==(T)0 || a.length()==0) return; NRMat bt; if(tb!='n') bt=b.transpose(tb=='c'); const NRMat &bb= tb!='n'? bt : b; const SPMatindex *rp=a.getrowptr(), *c=a.getcol(); const T *x=a.getval(); for(SPMatindex i=0; i::conjugate(x[k]) : x[k]); T *d= (*this)[tpa? c[k] : i]; const T *e= bb[tpa? i : c[k]]; for(int j=0; j const NRMat NRMat::operator*(const CSRMat &rhs) const { if((SPMatindex)mm!=rhs.nrows()) laerror("incompatible matrices in NRMat*CSRMat"); NOT_GPU(*this); NRMat r(nn,rhs.ncols()); r.clear(); if(rhs.length()==0) return r; const SPMatindex *rp=rhs.getrowptr(), *c=rhs.getcol(); const T *x=rhs.getval(); for(int i=0; i NRSMat::NRSMat(const CSRMat &rhs) : nn(rhs.nrows()) { if(rhs.nrows()!=rhs.ncols()) laerror("cannot transform rectangular matrix to NRSMat"); #ifdef CUDALA location=cpu; #endif count=new int(1); v=new T[NN2]; memset(v,0,NN2*sizeof(T)); const SPMatindex *rp=s_ptr(rhs.getrowptr()), *c=s_ptr(rhs.getcol()); const T *x=s_ptr(rhs.getval()); if(x) for(int i=0; i SparseMat::SparseMat(const CSRMat &rhs) : nn(rhs.nrows()), mm(rhs.ncols()), symmetric(0), nonzero(0), count(new int(1)), list(NULL), rowsorted(NULL), colsorted(NULL) { for(typename CSRMat::iterator p=rhs.begin(); p.notend(); ++p) add(p->row,p->col,p->elem); } template SparseSMat::SparseSMat(const CSRMat &rhs) : nn(rhs.nrows()), mm(rhs.ncols()), count(new int(1)) { v= new std::map * [nn]; memset(v,0,nn*sizeof(std::map *)); for(typename CSRMat::iterator p=rhs.begin(); p.notend(); ++p) add(p->row,p->col,p->elem,false); } //real and imaginary parts, complex matrices from real ones (nonclass.h): the index arrays stay shared, //unless elements which became zero have to be removed template static const CSRMat s_part(const CSRMat > &a, const NRVec &x, const bool sym) { CSRMat r(a.nrows(),a.ncols()); if(a.length()) { r=CSRMat(a.nrows(),a.ncols(),a.getrowptr(),a.getcol(),x); const R eps=LA_precision::sparse_epsilon(); const R *y=x; for(int k=0; k static const CSRMat > s_cmplx(const CSRMat &a, const bool imag) { CSRMat > r(a.nrows(),a.ncols()); if(a.length()) r=CSRMat >(a.nrows(),a.ncols(),a.getrowptr(),a.getcol(),NRVec >(a.getval(),imag)); if(!imag && a.issymmetric()) r.setsymmetric(); return r; } template<> const CSRMat realpart > >(const CSRMat > &a) {return s_part(a,a.length()? realpart(a.getval()) : NRVec(),a.issymmetric());} template<> const CSRMat realpart > >(const CSRMat > &a) {return s_part(a,a.length()? realpart(a.getval()) : NRVec(),a.issymmetric());} template<> const CSRMat imagpart > >(const CSRMat > &a) {return s_part(a,a.length()? imagpart(a.getval()) : NRVec(),false);} template<> const CSRMat imagpart > >(const CSRMat > &a) {return s_part(a,a.length()? imagpart(a.getval()) : NRVec(),false);} template<> const CSRMat > realmatrix >(const CSRMat &a) {return s_cmplx(a,false);} template<> const CSRMat > realmatrix >(const CSRMat &a) {return s_cmplx(a,false);} template<> const CSRMat > imagmatrix >(const CSRMat &a) {return s_cmplx(a,true);} template<> const CSRMat > imagmatrix >(const CSRMat &a) {return s_cmplx(a,true);} //re + i im: a BLAS axpy of the values if both have the same structure, otherwise a merge template<> const CSRMat > complexmatrix >(const CSRMat &re, const CSRMat &im) {CSRMat > r=s_cmplx(re,false); r.axpy(std::complex(0,1),s_cmplx(im,false)); return r;} template<> const CSRMat > complexmatrix >(const CSRMat &re, const CSRMat &im) {CSRMat > r=s_cmplx(re,false); r.axpy(std::complex(0,1),s_cmplx(im,false)); return r;} #define INSTANTIZE(T) \ template class CSRMat; \ template NRMat::NRMat(const CSRMat &rhs); \ template NRSMat::NRSMat(const CSRMat &rhs); \ template SparseMat::SparseMat(const CSRMat &rhs); \ template SparseSMat::SparseSMat(const CSRMat &rhs); \ template void NRVec::gemv(const T beta, const CSRMat &a, const char trans, const T alpha, const NRVec &x); \ template NRVec::NRVec(const CSRMat &rhs); \ template NRMat & NRMat::operator+=(const CSRMat &rhs); \ template NRMat & NRMat::operator-=(const CSRMat &rhs); \ template void NRMat::gemm(const T &beta, const CSRMat &a, const char transa, const NRMat &b, const char transb, const T &alpha); \ template const NRMat NRMat::operator*(const CSRMat &rhs) const; \ INSTANTIZE(double) INSTANTIZE(float) INSTANTIZE(std::complex) INSTANTIZE(std::complex) }//namespace