I've implemented a Modified Compressed Sparse Row matrix class! The class works, but I think that some part of the code is quite crap. There are two passages and the whole code became too expansive ... here I report the principal part for which I have some doubt about elegance and is resources consuming:
template <typename element_type>
class MSRmatrix {
public:
using itype = std::size_t ;
template <typename T>
friend std::ostream& operator<<(std::ostream& os ,const MSRmatrix<T>& m) noexcept ;
template <typename T>
friend MSRmatrix<T> operator+(const MSRmatrix<T>& m1, const MSRmatrix<T>& m2) ;
public:
constexpr MSRmatrix( std::initializer_list<std::vector<element_type>> row) noexcept;
constexpr MSRmatrix( std::string ) noexcept;
constexpr MSRmatrix( std::size_t ) noexcept;
auto constexpr printMSR()const noexcept ;
std::size_t constexpr findIndex(const itype, const itype) const noexcept ;
const element_type operator()(const itype, const itype) const noexcept ;
element_type operator()(const itype, const itype) noexcept ;
auto operator()(const itype, const itype,const element_type val) noexcept ;
auto constexpr print() const noexcept ;
auto constexpr toFile(std::string) noexcept ;
inline auto constexpr nnz() const noexcept { return aa_.size(); }
inline auto constexpr Dim() const noexcept { return dim ; }
private:
itype dim ;
std::vector<itype> ja_ ;
std::vector<element_type> aa_ ;
enum value{ stars };
};
template <typename T>
constexpr MSRmatrix<T>::MSRmatrix( std::initializer_list<std::vector<T>> row ) noexcept : dim{row.size()}
{
this->dim = row.size() ;
auto il = *(row.begin()) ;
if(this-> dim != il.size())
{
std::cerr << "Matrix contained into MSRmatrix format must be square!" << std::endl;
exit(-1);
}
std::vector<std::vector<T>> temp(row);
itype i=0 , j=0 , w=0 , k=0, z=dim;
this->aa_.resize(dim+1);
this->ja_.resize(dim+1);
for(auto& x : row)
{
j=0 ; k=0 ;
for(auto& y : x)
{
if(i==j)
{
aa_.at(i) = y ;
}
if(i != j && y != 0 )
{
aa_.push_back(y);
z++ ;
ja_.push_back(j+1);
if( k==0 )
{
ja_[w] = z+1;
w++ ;
k++ ;
}
}
j++ ;
}
i++ ;
}
while(w <= dim)
{
ja_[w] = z+2 ;
w++ ;
}
# ifdef __DEBUG__
printMSR();
# endif
}
The following method is written to find the index in the original matrix and has the possibility to print out the matrix (reference here)
template <typename T>
std::size_t constexpr MSRmatrix<T>::findIndex(const itype row , const itype col) const noexcept
{
assert( row > 0 && row <= dim && col > 0 && col <= dim );
if(row == col)
{
return row-1;
}
itype i = -1;
if( row == dim )// == ja_.at(row) ) // last row
{
i= (ja_.at(row-1)-1) ;
if(ja_.at(i-1) == col)
return i-1;
}
for(itype i = ja_.at(row-1)-1 ; i < ja_.at(row)-1 ; i++ )
{
if( ja_.at(i) == col )
{
return i;
}
}
return -1;
}
and the last thing, which I think is the most important one, is the method written to insert an element into the matrix. I want to improve it.
template <typename T>
auto MSRmatrix<T>::operator()(const itype r, const itype c, const T val) noexcept
{
if(val != 0)
{
auto i = findIndex(r,c);
if(i != -1 && i < nnz())
{
aa_.at(i) = val;
}
else
{
if(r==c)
{
aa_.at(r) = val ; // the size doesn't change
}
else if( r != c )
{
if( ja_.at(r-1) == ja_.at(r) ) // last line ;
{
ja_.at(r) += 1 ;
i = ja_.at(r-1)-1;
ja_.insert(ja_.begin() + i , c );
aa_.insert(aa_.begin() + i , val);
}
else // general line
{
for(auto i = ja_.at(r-1)-1 ; i < ja_.at(r)-1 ; i++ )
{
if( ja_.at(i) == c )
{
aa_.at(i) = val ;
}
else
{
for(auto ii = r ; ii < dim+1 ; ii++ )
{
ja_.at(ii) +=1 ;
}
ja_.insert(ja_.begin() + i , c );
aa_.insert(aa_.begin() + i , val);
break;
}
//std::cout << ja_.at(r) << std::endl ;
}
}
}
}
}
}
in operator() i return T instead of const T& because if the element is not found it return 0 that is a rvalue !