CGII/framework/include/cgv/math/sparse_mat.h
2018-05-17 16:01:02 +02:00

304 lines
4.9 KiB
C++

#pragma once
#include <cgv/math/vec.h>
#include <cgv/math/mat.h>
namespace cgv {
namespace math {
template <typename T>
class sparse_mat;
template <typename T>
void Ax(const sparse_mat<T>& A, const vec<T>&v, vec<T>& r);
/*
* A sparse matrix column compressed form.
*/
template <typename T>
class sparse_mat
{
private:
//number of rows
unsigned _nrows;
//number of columns
unsigned _ncols;
//column start indices in compressed form
vec<unsigned> _cols;
//row indices of data
vec<unsigned> _rows;
//values of matrix entries
vec<T> _data;
public:
sparse_mat(const mat<T>& 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<T>()
{
mat<T> 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<T>& 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<T> operator*(const vec<T>& v)
{
assert(_ncols == v.size());
vec<T> 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<T>& operator*=(const T& s)
{
_data*=s;
return *this;
}
sparse_mat<T> operator*(const T& s)
{
sparse_mat<T> m = *this;
m*=s;
return m;
}
sparse_mat<T>& operator/=(const T& s)
{
_data*=s;
return *this;
}
sparse_mat<T> operator/(const T& s)
{
sparse_mat<T> m = *this;
m/=s;
return m;
}
///transpose matrix
void transpose()
{
vec<unsigned> _colsnew(_nrows+1);
_colsnew.zeros();
vec<unsigned> _rowsnew(_data.size());
vec<T>_datanew(_data.size());
vec<unsigned>_colsnew2(_nrows+1);
vec<unsigned> _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<< <T>(std::ostream& out, sparse_mat& sm);
friend void Ax<T>(const sparse_mat<T>& A,const vec<T>&v, vec<T>& r);
friend void Atx<T>(const sparse_mat<T>& A,const vec<T>&v, vec<T>& r);
friend bool low_tri_solve(const sparse_mat<T>& L,const vec<T>& b, vec<T>& x);
};
template <typename T>
std::ostream& operator<<(std::ostream& out,sparse_mat<T>& 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 <typename T>
void Ax(const sparse_mat<T>& A, const vec<T>&v, vec<T>& 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 <typename T>
void Atx(const sparse_mat<T>& A, const vec<T>&v, vec<T>& 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 <typename T>
sparse_mat<T> transpose(const sparse_mat<T>& sm)
{
sparse_mat<T> m = sm;
m.transpose();
return m;
}
template <typename T>
sparse_mat<T> operator*(const T& s,const sparse_mat<T>& m)
{
return m*s;
}
template <typename T>
bool low_tri_solve(const sparse_mat<T>& L,const vec<T>& b, vec<T>& 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;
}
}
}