#ifndef SPARSEMATRIX_H #define SPARSEMATRIX_H #include #include "MatrixLibrary.h" #include namespace ATC_matrix { /** * @struct TRI_COORD * @brief Triplet SparseMatrix entry */ template struct TRI_COORD { TRI_COORD(INDEX row=0, INDEX col=0); TRI_COORD(INDEX row, INDEX col, T val, bool add_to=0); INDEX i, j; T v; bool add; }; template void ParMultAB(MPI_Comm comm, const SparseMatrix& A, const Matrix& B, DenseMatrix& C); /** * @class SparseMatrix * @brief Stores data in triplet format or CRS format */ template class SparseMatrix : public Matrix { //* SparseMatrix-Vector multiplication (S * v) friend DenseVector operator*(const SparseMatrix &A, const Vector& x); //* SparseMatrix-DenseMatrix multiplication (S * F) friend DenseMatrix operator*(const SparseMatrix &A, const Matrix& D); //* SparseMatrix-DiagonalMatrix multiplication (S * D) friend SparseMatrix operator*(const SparseMatrix &A, const DiagonalMatrix& D); //* SparseMatrix-SparseMatrix multiplication (S * S) friend SparseMatrix operator*(const SparseMatrix &A, const SparseMatrix &B); //* computes the product of a SparseMatrix tranpose with a SparseVector (M'*v). friend SparseVector operator*(const SparseMatrix &M, const SparseVector &v); //* computes the product of a SparseMatrix tranpose with a SparseVector (M'*v). friend SparseVector operator*(const SparseVector &v, const SparseMatrix &M); template friend void ParMultAB(MPI_Comm comm, const SparseMatrix& A, const Matrix& B, DenseMatrix& C); public: SparseMatrix(INDEX rows=0, INDEX cols=0); SparseMatrix(const SparseMatrix& c); SparseMatrix(const DenseMatrix& c); SparseMatrix(INDEX* rows, INDEX* cols, T* vals, INDEX size, INDEX nRows, INDEX nCols, INDEX nRowsCRS); virtual ~SparseMatrix() { _delete(); } //* General index by value (requires a binary search on the row) T operator()(INDEX i, INDEX j) const; //* General index by reference (requires a binary search on the row) T& operator()(INDEX i, INDEX j); //* General flat index by value operator (by nth nonzero) T operator[](INDEX i) const; //* General flat index by reference operator (by nth nonzero) T& operator[](INDEX i); //* sets a value to index i,j void set(INDEX i, INDEX j, T v); //* adds a value to index i,j void add(INDEX i, INDEX j, T v); //* return a triplet value of the ith nonzero TRIPLET triplet(INDEX i) const; //* full reset - completely wipes out all SparseMatrix data void reset(INDEX rows=0, INDEX cols=0, bool zero=true); //* only changes the bounds of the matrix, no deletion void resize(INDEX rows=0, INDEX cols=0, bool zero=true); //* reset - from DenseMatrix - this will be SLOW void reset(const DenseMatrix& D, double TOL=-1.0); //* copy data void copy(const T * ptr, INDEX rows=0, INDEX cols=0); void dense_copy(DenseMatrix& D) const; DenseMatrix dense_copy(void) const; //* returns true if the matrix has no nonzero elements bool empty() const; //* returns the user-specified number of rows INDEX nRows() const; INDEX nRowsCRS() const; //* returns the user-specified number of cols INDEX nCols() const; //* returns the number of non-zero elements INDEX size() const; //* returns the number of non-zeros in a row INDEX RowSize(INDEX r) const; //* returns a pointer to the CRS list of rows inline INDEX* rows() const; //* returns a pointer to the CRS list of cols inline INDEX* cols() const; //* returns a pointer to the nonzero data inline T* ptr() const; //* checks if the index i,j falls in the user-specified range bool in_range(INDEX i, INDEX j) const; //* check if the total matrix has a value set for an index pair bool has_entry(INDEX i, INDEX j) const; //* check if the uncompressed part of the matrix has a value set for an index pair bool has_entry_uncompressed(INDEX i, INDEX j) const; //* check if the compressed part matrix has a value set for an index pair bool has_entry_compressed(INDEX i, INDEX j) const; //* check if the matrix has been compressed at least once bool has_template(void) const; /* * \section assignment operators */ //* copies SparseMatrix R to this SparseMatrix& operator=(const SparseMatrix &R); //* sets all nonzero values to a constant SparseMatrix& operator=(const T v); //* scales all nonzero values by a constant SparseMatrix& operator*=(const T &a); //* calls operator*= of base class SparseMatrix& operator*=(const SparseMatrix &a); // Adds two matrices together. SparseMatrix& operator+=(const SparseMatrix & R); /* * \section Multiplication operations */ //----------------------------------------------------------------------------- // multiply sparse matrix by a vector //----------------------------------------------------------------------------- virtual void MultMv(const Vector& v, DenseVector& c) const { compress(*this); GCK(*this, v, this->nCols() != v.size(), "SparseMatrix * Vector") // resize c if necessary if (c.size() != this->nRows()) { c.resize(this->nRows()); c.zero(); } INDEX i, j; for (i = 0; i < this->_nRowsCRS; i++) for (j = this->_ia[i]; j < this->_ia[i + 1]; j++) c(i) += this->_val[j] * v(this->_ja[j]); } //----------------------------------------------------------------------------- // multiply sparse matrix by dense matrix //----------------------------------------------------------------------------- virtual void MultAB(const Matrix& B, DenseMatrix& C) const { GCK(*this, B, this->nCols() != B.nRows(), "SparseMatrix * DenseMatrix") const INDEX J = B.nCols(); INDEX i, ik, j; for (i = 0; i < this->_nRowsCRS; i++) for (ik = this->_ia[i]; ik < this->_ia[i + 1]; ik++) for (j = 0; j < J; j++) C(i, j) += this->_val[ik] * B(this->_ja[ik], j); // C(i,j) = S(i,k) * B(k, j) } //----------------------------------------------------------------------------- // Multiplies this SparseMatrix transposed times a vector //----------------------------------------------------------------------------- virtual DenseVector transMat(const Vector &x) const { compress(*this); DenseVector y(nCols(), true); GCK(*this, x, nRows()!=x.size(),"operator *: Sparse matrix incompatible with Vector.") INDEX i, ij; for(i=0; i<_nRowsCRS; i++) for(ij=_ia[i]; ij<_ia[i+1]; ij++) y(_ja[ij]) += _val[ij]*x(i); return y; } //----------------------------------------------------------------------------- // Matrix Transpose/DenseMatrix multiply //----------------------------------------------------------------------------- virtual DenseMatrix transMat(const DenseMatrix &D) const { compress(*this); GCK(*this, D, nRows()!=D.nRows(),"transMat: Sparse matrix incompatible with DenseMatrix.") DenseMatrix C(nCols(), D.nCols(), true); // initialized to zero INDEX j, k, ki; for (k=0; k<_nRowsCRS; k++) for (ki=_ia[k]; ki<_ia[k+1]; ki++) for (j=0; j transMat(const SparseMatrix &D) const { compress(*this); GCK(*this, D, nRows()!=D.nRows(),"transMat: Sparse matrix incompatible with DenseMatrix.") DenseMatrix C(nCols(), D.nCols(), true); // initialized to zero INDEX k, ki, kj; for (k=0; k<_nRowsCRS; k++) for (kj=D._ia[k]; kj transpose() const; SparseMatrix& row_scale(const Vector &v); SparseMatrix& col_scale(const Vector &v); DenseVector col_sum() const; DenseVector column_count() const; DiagonalMatrix diag() const; DiagonalMatrix row_sum_lump() const; void row(INDEX i, DenseVector& row, DenseVector& indx) const; void weighted_least_squares(const SparseMatrix &N, const DiagonalMatrix &D); void set_all_elements_to(const T &v); T row_max(INDEX row) const; T row_min(INDEX row) const; /* * \section I/O functions */ //* outputs this SparseMatrix to a formatted string std::string to_string() const; using Matrix::matlab; //* writes a command to recreate this matrix in matlab to a stream void matlab(std::ostream &o, const std::string &name="S") const; //* prints a row histogram for each row void print_row_histogram(const std::string &name, INDEX nbins = 10) const; //* prints a histogram of the values in a row void print_row_histogram(INDEX row, INDEX nbins) const; //* prints the current triplets void print_triplets() const; //! Writes the matrix to a binary file (after a compress). void binary_write(std::fstream& f) const; //! Reads a SparseMatrix from a binary file. (wipes out any original data) void binary_read(std::fstream& f); //* Dump templated type to disk; operation not safe for all types void write_restart(FILE *f) const; /* * \section Utility functions */ //* converts all triplets and merges with CRS void compress(); //* converts T to CRS static void compress(const SparseMatrix &C); //* sorts and returns the # of unique triplets INDEX CountUniqueTriplets(); private: //* creates a CRS structure void _create(INDEX size, INDEX nrows); //* clears all memory and nulls references void _delete(); //* copies all data from another SparseMatrix void _copy(const SparseMatrix &C); //* general sparse matrix assignment void _set_equal(const Matrix &r); //* returns the first row with a nonzero in it (from the CRS structure only) int _first_nonzero_row_crs() const; /* * \section CRS storage variables */ protected: T * _val; // matrix non-zeros INDEX *_ia, *_ja; // ptrs to rows, column indexes INDEX _size, _nRowsCRS; // # of non-zeros, rows bool hasTemplate_; void copy(const SparseMatrix &C); //* new (unsorted triplet values - won't intersect CRS values) mutable std::vector > _tri; /* * \section User specified variables */ INDEX _nRows, _nCols; static T _zero; }; } // end namespace #include "SparseMatrix-inl.h" #endif