#pragma once #include #include namespace cgv { namespace math { template class sparse_mat; template void Ax(const sparse_mat& A, const vec&v, vec& r); /* * A sparse matrix column compressed form. */ template class sparse_mat { private: //number of rows unsigned _nrows; //number of columns unsigned _ncols; //column start indices in compressed form vec _cols; //row indices of data vec _rows; //values of matrix entries vec _data; public: sparse_mat(const mat& m, T eps=0) { compress(m,eps); } //return number of rows unsigned nrows() const { return _nrows; } //returns number of columns unsigned ncols() const { return _ncols; } //return number of non zero elements unsigned num_non_zeros() const { return _data.size(); } //cast conversion into full matrix operator mat() { mat m(_nrows,_ncols); m.zeros(); for(unsigned j = 0; j < _ncols; j++) for(unsigned i = _cols(j);i < _cols(j+1); i++) m( _rows(i),j)=_data(i); return m; } //compress void compress(const mat& m, T eps=0) { _nrows = m.nrows(); _ncols = m.ncols(); _cols.resize(m.ncols()+1); unsigned nz = 0; for(unsigned i =0; i < m.nrows(); i++) { for(unsigned j =0; j < m.ncols(); j++) { if(m(i,j) > eps) nz++; } } _rows.resize(nz); _data.resize(nz); nz=0; for(unsigned j =0; j < m.ncols(); j++) { _cols[j]=nz; for(unsigned i =0; i < m.nrows(); i++) { if(m(i,j) > eps) { _data(nz) = m(i,j); _rows(nz) = i; nz++; } } } _cols[m.ncols()]=nz; } ///matrix vector product vec operator*(const vec& v) { assert(_ncols == v.size()); vec r; r.zeros(_nrows); unsigned c; for(c = 0; c < _ncols;c++) for(unsigned i = _cols(c); i < _cols(c+1);i++) r(_rows(i)) += _data(i)*v(c); return r; } //in place multiplication with scalar s sparse_mat& operator*=(const T& s) { _data*=s; return *this; } sparse_mat operator*(const T& s) { sparse_mat m = *this; m*=s; return m; } sparse_mat& operator/=(const T& s) { _data*=s; return *this; } sparse_mat operator/(const T& s) { sparse_mat m = *this; m/=s; return m; } ///transpose matrix void transpose() { vec _colsnew(_nrows+1); _colsnew.zeros(); vec _rowsnew(_data.size()); vec_datanew(_data.size()); vec_colsnew2(_nrows+1); vec _rowsnew2(_data.size()); for(unsigned c = 0; c < _ncols; c++) for(unsigned i = _cols[c]; i < _cols[c+1]; i++) { _colsnew(_rows(i))++; _rowsnew(i) = c; } unsigned sum = 0; for(unsigned i = 0; i < _colsnew.size();i++) { unsigned temp = _colsnew(i); _colsnew(i) = sum; _colsnew2(i) = sum; sum+=temp; } _datanew = _data; _cols= _colsnew; for(unsigned i = 0; i < _data.size();i++) { unsigned idx =_colsnew(_rows(i)); _data(idx)= _datanew(i); _rowsnew2(idx)= _rowsnew(i); _colsnew(_rows(i))++; } _rows = _rowsnew2; unsigned t = _nrows; _nrows = _ncols; _ncols = t; } friend std::ostream& operator<< (std::ostream& out, sparse_mat& sm); friend void Ax(const sparse_mat& A,const vec&v, vec& r); friend void Atx(const sparse_mat& A,const vec&v, vec& r); friend bool low_tri_solve(const sparse_mat& L,const vec& b, vec& x); }; template std::ostream& operator<<(std::ostream& out,sparse_mat& sm) { out << sm._nrows <<" "<< sm._ncols << std::endl; out << sm._cols << std::endl; out << sm._rows << std::endl; out << sm._data << std::endl; return out; } template void Ax(const sparse_mat& A, const vec&v, vec& r) { assert(A._ncols == v.size()); r.zeros(A._nrows); unsigned c; for(c = 0; c < A._ncols;c++) for(unsigned i = A._cols(c); i < A._cols(c+1);i++) r(A._rows(i)) += A._data(i)*v(c); }; template void Atx(const sparse_mat& A, const vec&v, vec& r) { assert(A._nrows == v.size()); r.zeros(A._ncols); unsigned c; for(c = 0; c < A._ncols;c++) for(unsigned i = A._cols(c); i < A._cols(c+1);i++) r(c) += A._data(i)*v(A._rows(i)); } template sparse_mat transpose(const sparse_mat& sm) { sparse_mat m = sm; m.transpose(); return m; } template sparse_mat operator*(const T& s,const sparse_mat& m) { return m*s; } template bool low_tri_solve(const sparse_mat& L,const vec& b, vec& x) { x=b; for(unsigned j = 0; j < x.size(); j++) { //not lower triangular or singular if(L._data(L.rows(L._cols(j))) != j ) return false; x(j) =x(j) / L._data(_cols(j)); for(unsigned i= L._cols(j)+1; i < L._cols(j+1);i++) x(i) = x(i) - L._data(i)*x(j); } return true; } } }