304 lines
4.9 KiB
C++
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;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|