/* LA: linear algebra C++ interface library Copyright (C) 2010-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 . */ #ifndef _CSRMAT_H_ #define _CSRMAT_H_ #include #include #include #include #include #include #include #include "la_traits.h" #include "sparsemat.h" #include "sparsesmat.h" #include "vec.h" #include "mat.h" #include "smat.h" namespace LA { //compressed row format read-efficient matrix storage //row i has the elements v[k], column col[k], k=rowptr[i]..rowptr[i+1]-1, columns strictly ascending within a row //the full matrix is always stored; symmetric only declares A = A^dagger (hermitian, real symmetric) e.g. for davidson, lanczos //rowptr, col and v share data independently (copy-on-write), e.g. a scaled copy shares the structure with the original template class CSRMat { protected: SPMatindex nn; SPMatindex mm; bool symmetric; NRVec rowptr; NRVec col; NRVec v; void fromcoo(const SPMatindex n, const SPMatindex m, const int nz, const SPMatindex *ri, const SPMatindex *ci, const T *vi); //sorts, sums duplicates, drops small elements void permrows(const SPMatindex *to); //row r becomes row to[r] public: //iterator over the stored elements in row-major order class iterator { private: const CSRMat *a; SPMatindex row; int k; matel my; void set() {while(rownn && k>=(int)a->rowptr[row+1]) ++row; if(rownn) {my.row=row; my.col=a->col[k]; my.elem=a->v[k]; my.next=NULL;}} public: iterator(): a(NULL), row(0), k(0) {}; iterator(const CSRMat &rhs): a(&rhs), row(0), k(0) {if(a->nn) set();} iterator & operator++() {++k; set(); return *this;} bool notend() const {return a && rownn;} bool operator==(const iterator &rhs) const {return notend()==rhs.notend() && (!notend() || k==rhs.k);} bool operator!=(const iterator &rhs) const {return !(*this==rhs);} const matel & operator*() const {return my;} const matel * operator->() const {return &my;} }; iterator begin() const {return iterator(*this);} iterator end() const {return iterator();} CSRMat() : nn(0), mm(0), symmetric(false) {}; explicit CSRMat(const SPMatindex n, const SPMatindex m); //zero matrix explicit CSRMat(const SPMatindex n); //zero square matrix CSRMat(const SPMatindex n, const SPMatindex m, const NRVec &rowptr, const NRVec &col, const NRVec &v); //shares the arrays explicit CSRMat(const SparseMat &rhs); explicit CSRMat(const SparseSMat &rhs); explicit CSRMat(const NRSMat &rhs); explicit CSRMat(const NRMat &rhs); void copyonwrite(bool detachonly=false, bool deep=true); void resize(const SPMatindex n, const SPMatindex m); //zero matrix void dealloc(void) {resize(0,0);} void clear() {bool sym=symmetric; resize(nn,mm); symmetric=sym;} //zero matrix of the same dimensions and symmetry void swap(CSRMat &rhs) { SPMatindex tmpnn=nn; nn=rhs.nn; rhs.nn=tmpnn; SPMatindex tmpmm=mm; mm=rhs.mm; rhs.mm=tmpmm; bool tmpsymmetric=symmetric; symmetric=rhs.symmetric; rhs.symmetric=tmpsymmetric; rowptr.swap(rhs.rowptr); col.swap(rhs.col); v.swap(rhs.v); } inline SPMatindex nrows() const {return nn;} inline SPMatindex ncols() const {return mm;} inline int length() const {return v.size();} //number of stored elements inline bool issymmetric() const {return symmetric;} inline void setsymmetric() {if(nn!=mm) laerror("non-square cannot be symmetric"); symmetric=true;} //only declares the matrix hermitian inline void setunsymmetric() {symmetric=false;} inline const NRVec & getrowptr() const {return rowptr;} inline const NRVec & getcol() const {return col;} inline const NRVec & getval() const {return v;} const T operator()(const SPMatindex i, const SPMatindex j) const; //element (zero if not stored), binary search in the row void gemv(const T beta, NRVec &r, const char trans, const T alpha, const NRVec &x) const {r.gemv(beta,*this,trans,alpha,x);}; inline const NRVec operator*(const NRVec &rhs) const {NRVec result(nn); result.gemv((T)0,*this,'n',(T)1,rhs); return result;}; const T* diagonalof(NRVec &r, const bool divide=0, bool cache=false) const; //diagonal (diagonal of A^T A for non-square, as SparseMat), or divide r by it const CSRMat transpose(bool conj=false) const; CSRMat & operator*=(const T &a); //multiply by a scalar (the structure stays shared) CSRMat & operator=(const T &a); //a times the unit matrix CSRMat & operator+=(const T &a); //add a to the diagonal CSRMat & operator-=(const T &a) {return *this += -a;} void identity() {*this = (T)1;} void axpy(const T alpha, const CSRMat &x, const bool transp=false); //this += alpha x (alpha x^T); elements cancelled to zero stay stored, see simplify() CSRMat & operator+=(const CSRMat &rhs) {axpy((T)1,rhs); return *this;} CSRMat & operator-=(const CSRMat &rhs) {axpy((T)-1,rhs); return *this;} inline const CSRMat operator*(const T &rhs) const {return CSRMat(*this) *= rhs;} inline const CSRMat operator+(const T &rhs) const {return CSRMat(*this) += rhs;} inline const CSRMat operator-(const T &rhs) const {return CSRMat(*this) -= rhs;} inline const CSRMat operator+(const CSRMat &rhs) const {return CSRMat(*this) += rhs;} inline const CSRMat operator-(const CSRMat &rhs) const {return CSRMat(*this) -= rhs;} const typename LA_traits::normtype norm(const T scalar=(T)0) const; //Frobenius norm of A - scalar I const T dot(const CSRMat &rhs) const; //\sum_{ij} conj(a_ij) b_ij as NRMat::dot const T dot(const NRMat &rhs) const; const T trace() const; void simplify(const typename LA_traits::normtype sparseepsilon=LA_precision::normtype>::sparse_epsilon()); //removes elements with |x| <= sparseepsilon inline const NRMat operator*(const NRMat &rhs) const {NRMat r(nn,rhs.ncols()); r.gemm((T)0,*this,'n',rhs,'n',(T)1); return r;}; void gemm(const T beta, const CSRMat &a, const char transa, const CSRMat &b, const char transb, const T alpha); //this = alpha op(A) op(B) + beta this, sparse result inline const CSRMat operator*(const CSRMat &rhs) const {CSRMat r; r.gemm((T)0,*this,'n',rhs,'n',(T)1); return r;}; CSRMat & oplusequal(const CSRMat &rhs); //direct sum CSRMat & oplusequal(const NRMat &rhs) {return oplusequal(CSRMat(rhs));} CSRMat & oplusequal(const NRSMat &rhs) {return oplusequal(CSRMat(rhs));} const CSRMat oplus(const CSRMat &rhs) const {return CSRMat(*this).oplusequal(rhs);} const CSRMat oplus(const NRMat &rhs) const {return CSRMat(*this).oplusequal(rhs);} const CSRMat oplus(const NRSMat &rhs) const {return CSRMat(*this).oplusequal(rhs);} const CSRMat otimes(const CSRMat &rhs) const; //direct product, (A x B)_{i nB+k, j mB+l} = a_ij b_kl as NRMat::operator| const CSRMat otimes(const NRMat &rhs) const {return otimes(CSRMat(rhs));} const CSRMat otimes(const NRSMat &rhs) const {return otimes(CSRMat(rhs));} //permutations: element of row r goes to row p(r) (with inverse p^{-1}); matrix indices from 0, permutation from 1; the full matrix is stored, so rows means only rows void permuteme_rows(const NRPerm &p, const bool inverse=false); void permuteme_cols(const NRPerm &p, const bool inverse=false); void permuteme_both(const NRPerm &p, const NRPerm &q, const bool inverse=false); const CSRMat permuted_rows(const NRPerm &p, const bool inverse=false) const {CSRMat a(*this); a.permuteme_rows(p,inverse); return a;}; const CSRMat permuted_cols(const NRPerm &p, const bool inverse=false) const {CSRMat a(*this); a.permuteme_cols(p,inverse); return a;}; const CSRMat permuted_both(const NRPerm &p, const NRPerm &q, const bool inverse=false) const {CSRMat a(*this); a.permuteme_both(p,q,inverse); return a;}; void permuterows(const NRVec &p); //as SparseMat: row r goes to row p[r], indices from 0 void permutecolumns(const NRVec &p); void permuteindices(const NRVec &p); //rows and columns void transposeme(bool conj=false) {*this=transpose(conj);} void get(int fd, bool dimensions=1, bool transp=0, bool orcaformat=false); void put(int fd, bool dimensions=1, bool transp=0, bool orcaformat=false) const; }; template inline const CSRMat commutator(const CSRMat &x, const CSRMat &y, const bool trx=0, const bool tryy=0) { CSRMat r; 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; } template inline const CSRMat anticommutator(const CSRMat &x, const CSRMat &y, const bool trx=0, const bool tryy=0) { CSRMat r; 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; } template inline const NRVec NRVec::operator*(const CSRMat &mat) const { NOT_GPU(*this); NRVec result(mat.ncols()); result.gemv((T)0,mat,'t',(T)1,*this); return result; } template std::ostream& operator<<(std::ostream &s, const CSRMat &x) //the same text format as SparseMat { s << (int)x.nrows() << ' ' << (int)x.ncols() << '\n'; for(typename CSRMat::iterator p=x.begin(); p.notend(); ++p) s << (int)p->row << ' ' << (int)p->col << ' ' << (typename LA_traits_io::IOtype)p->elem << '\n'; s << "-1 -1\n"; return s; } template std::istream& operator>>(std::istream &s, CSRMat &x) { SparseMat a; s >> a; x=CSRMat(a); return s; } }//namespace #endif //_CSRMAT_H_