find a value in a block matrix - c++

I wrote a sparse matrix class, based on Block compressed storage, I wrote almost all the method, but I have not idea to how to write the method findValue(i,j) that give 2 indexes of the original matrix ! the storage consists in four vectors :
`ba_': stored the non zero block (rectangular block in which almost one element is different from zero) of the matrix in top-down left-right order
an_ is the vector of index that points to the first element of the block in the vector ba
aj_ stored the index of the block columns in the blocked matrix.
ai_ stored the first block of each row in the blocked matrix.
the picture clarify anything :
here the following class in which I use two methods to achieve the result, findBlockIndex and findValue(i,j,Brows,Bcols) but I need to get the value of the original i,j index using findValue(i,j) in which i,j are the index in the sparse complete matrix
# include <iosfwd>
# include <vector>
# include <string>
# include <initializer_list>
# include "MatrixException.H"
# include <sstream>
# include <fstream>
# include <algorithm>
# include <iomanip>
// forward declarations
template <typename T, std::size_t R, std::size_t C>
class BCRSmatrix ;
template <typename T, std::size_t R, std::size_t C>
std::ostream& operator<<(std::ostream& os , const BCRSmatrix<T,R,C>& m );
template <typename T, std::size_t Br, std::size_t Bc >
std::vector<T> operator*(const BCRSmatrix<T,Br,Bc>& m, const std::vector<T>& x );
template <typename data_type, std::size_t BR , std::size_t BC>
class BCRSmatrix {
template <typename T, std::size_t R, std::size_t C>
friend std::ostream& operator<<(std::ostream& os , const BCRSmatrix<T,R,C>& m );
template <typename T, std::size_t Br,std::size_t Bc>
friend std::vector<T> operator*(const BCRSmatrix<T,Br,Bc>& m, const std::vector<T>& x );
public:
constexpr BCRSmatrix(std::initializer_list<std::vector<data_type>> dense );
constexpr BCRSmatrix(const std::string& );
virtual ~BCRSmatrix() = default ;
auto constexpr print_block(const std::vector<std::vector<data_type>>& dense,
std::size_t i, std::size_t j) const noexcept ;
auto constexpr validate_block(const std::vector<std::vector<data_type>>& dense,
std::size_t i, std::size_t j) const noexcept ;
auto constexpr insert_block(const std::vector<std::vector<data_type>>& dense,
std::size_t i, std::size_t j) noexcept ;
auto constexpr printBCRS() const noexcept ;
auto constexpr printBlockMatrix() const noexcept ;
auto constexpr size1() const noexcept { return denseRows ;}
auto constexpr size2() const noexcept { return denseCols ;}
auto constexpr printBlock(std::size_t i) const noexcept ;
auto constexpr print() const noexcept ;
private:
std::size_t bn ;
std::size_t bBR ;
std::size_t nnz ;
std::size_t denseRows ;
std::size_t denseCols ;
std::vector<data_type> ba_ ;
std::vector<std::size_t> an_ ;
std::vector<std::size_t> ai_ ;
std::vector<std::size_t> aj_ ;
std::size_t index =0 ;
auto constexpr findBlockIndex(const std::size_t r, const std::size_t c) const noexcept ;
auto constexpr recomposeMatrix() const noexcept ;
auto constexpr findValue(
const std::size_t i, const std::size_t j,
const std::size_t rBlock, const std::size_t cBlock
) const noexcept ;
};
//--------------------------- IMPLEMENTATION
template <typename T, std::size_t BR, std::size_t BC>
constexpr BCRSmatrix<T,BR,BC>::BCRSmatrix(std::initializer_list<std::vector<T>> dense_ )
{
this->denseRows = dense_.size();
auto it = *(dense_.begin());
this->denseCols = it.size();
if( (denseRows*denseCols) % BR != 0 )
{
throw InvalidSizeException("Error block size is not multiple of dense matrix size");
}
std::vector<std::vector<T>> dense(dense_);
bBR = BR*BC ;
bn = denseRows*denseCols/(BR*BC) ;
ai_.resize(denseRows/BR +1);
ai_[0] = 1;
for(std::size_t i = 0; i < dense.size() / BR ; i++)
{
auto rowCount =0;
for(std::size_t j = 0; j < dense[i].size() / BC ; j++)
{
if(validate_block(dense,i,j))
{
aj_.push_back(j+1);
insert_block(dense, i, j);
rowCount ++ ;
}
}
ai_[i+1] = ai_[i] + rowCount ;
}
printBCRS();
}
template <typename T, std::size_t BR, std::size_t BC>
constexpr BCRSmatrix<T,BR,BC>::BCRSmatrix(const std::string& fname)
{
std::ifstream f(fname , std::ios::in);
if(!f)
{
throw OpeningFileException("error opening file in constructor !");
}
else
{
std::vector<std::vector<T>> dense;
std::string line, tmp;
T elem = 0 ;
std::vector<T> row;
std::size_t i=0, j=0 ;
while(getline(f, line))
{
row.clear();
std::istringstream ss(line);
if(i==0)
{
while(ss >> elem)
{
row.push_back(elem);
j++;
}
}
else
{
while(ss >> elem)
row.push_back(elem);
}
dense.push_back(row);
i++;
}
this->denseRows = i;
this->denseCols = j;
bBR = BR*BR ;
bn = denseRows*denseCols/(BR*BC) ;
ai_.resize(denseRows/BR +1);
ai_[0] = 1;
for(std::size_t i = 0; i < dense.size() / BR ; i++)
{
auto rowCount =0;
for(std::size_t j = 0; j < dense[i].size() / BC ; j++)
{
if(validate_block(dense,i,j))
{
aj_.push_back(j+1);
insert_block(dense, i, j);
rowCount ++ ;
}
}
ai_[i+1] = ai_[i] + rowCount ;
}
}
printBCRS();
}
template <typename T,std::size_t BR, std::size_t BC>
inline auto constexpr BCRSmatrix<T,BR,BC>::printBlockMatrix() const noexcept
{
for(auto i=0 ; i < denseRows / BR ; i++)
{
for(auto j=1 ; j <= denseCols / BC ; j++)
{
std::cout << findBlockIndex(i,j) << ' ' ;
}
std::cout << std::endl;
}
}
template <typename T,std::size_t BR,std::size_t BC>
inline auto constexpr BCRSmatrix<T,BR,BC>::printBlock(std::size_t i) const noexcept
{
auto w = i-1 ;
auto k = 0;
for(std::size_t i = 0 ; i < BR ; ++i)
{
for(std::size_t j=0 ; j < BC ; ++j )
{
std::cout << std::setw(8) << ba_.at(an_.at(w)-1+k) << ' ';
k++;
}
}
}
template <typename T,std::size_t BR, std::size_t BC>
inline auto constexpr BCRSmatrix<T,BR,BC>::print_block(const std::vector<std::vector<T>>& dense,
std::size_t i, std::size_t j) const noexcept
{
for(std::size_t m = i * BR ; m < BR * (i + 1); ++m)
{
for(std::size_t n = j * BC ; n < BC * (j + 1); ++n)
std::cout << dense[m][n] << ' ';
std::cout << '\n';
}
}
template <typename T,std::size_t BR, std::size_t BC>
inline auto constexpr BCRSmatrix<T,BR,BC>::validate_block(const std::vector<std::vector<T>>& dense,
std::size_t i, std::size_t j) const noexcept
{
bool nonzero = false ;
for(std::size_t m = i * BR ; m < BR * (i + 1); ++m)
{
for(std::size_t n = j * BC ; n < BC * (j + 1); ++n)
{
if(dense[m][n] != 0) nonzero = true;
}
}
return nonzero ;
}
template <typename T,std::size_t BR, std::size_t BC>
inline auto constexpr BCRSmatrix<T,BR,BC>::insert_block(const std::vector<std::vector<T>>& dense,
std::size_t i, std::size_t j) noexcept
{
bool firstElem = true ;
for(std::size_t m = i * BR ; m < BR * (i + 1); ++m)
{
for(std::size_t n = j * BC ; n < BC * (j + 1); ++n)
{
if(firstElem)
{
an_.push_back(index+1);
firstElem = false ;
}
ba_.push_back(dense[m][n]);
index ++ ;
}
}
}
template <typename T, std::size_t BR,std::size_t BC>
auto constexpr BCRSmatrix<T,BR,BC>::findBlockIndex(const std::size_t r, const std::size_t c) const noexcept
{
for(auto j= ai_.at(r) ; j < ai_.at(r+1) ; j++ )
{
if( aj_.at(j-1) == c )
{
return j ;
}
}
}
template <typename T, std::size_t BR, std::size_t BC>
auto constexpr BCRSmatrix<T,BR,BC>::printBCRS() const noexcept
{
std::cout << "ba_ : " ;
for(auto &x : ba_ )
std::cout << x << ' ' ;
std::cout << std::endl;
std::cout << "an_ : " ;
for(auto &x : an_ )
std::cout << x << ' ' ;
std::cout << std::endl;
std::cout << "aj_ : " ;
for(auto &x : aj_ )
std::cout << x << ' ' ;
std::cout << std::endl;
std::cout << "ai_ : " ;
for(auto &x : ai_ )
std::cout << x << ' ' ;
std::cout << std::endl;
}
template <typename T, std::size_t BR, std::size_t BC>
auto constexpr BCRSmatrix<T,BR,BC>::print() const noexcept
{
//for each BCRS row
for(auto i=0 ; i < denseRows / BR ; i++){
//for each Block sub row.
for(auto rBlock = 0; rBlock < BR; rBlock++){
//for each BCSR col.
for(auto j = 1; j <= denseCols / BC; j++){
//for each Block sub col.
for(auto cBlock = 0; cBlock < BC; cBlock++){
std::cout<< findValue(i, j, rBlock, cBlock) <<'\t';
}
}
std::cout << std::endl;
}
}
}
template <typename T, std::size_t BR,std::size_t BC>
auto constexpr BCRSmatrix<T,BR,BC>::recomposeMatrix() const noexcept
{
std::vector<std::vector<T>> sparseMat(denseRows, std::vector<T>(denseCols, 0));
auto BA_i = 0, AJ_i = 0;
//for each BCSR row
for(auto r = 0; r < denseRows/BR; r++){
//for each Block in row
for(auto nBlock = 0; nBlock < ai_.at(r+1)-ai_.at(r); nBlock++){
//for each subMatrix (Block)
for(auto rBlock = 0; rBlock < BR; rBlock++){
for(auto cBlock = 0; cBlock < BC; cBlock++){
//insert value
sparseMat.at(rBlock + r*BR).at(cBlock + (aj_.at(AJ_i)-1)*BC) = ba_.at(BA_i);
++BA_i;
}
}
++AJ_i;
}
}
return sparseMat;
}
template <typename T, std::size_t BR,std::size_t BC>
auto constexpr BCRSmatrix<T,BR,BC>::findValue(
const std::size_t i, const std::size_t j,
const std::size_t rBlock, const std::size_t cBlock
) const noexcept
{
auto index = findBlockIndex(i,j);
if(index != 0)
return ba_.at(an_.at(index-1)-1 + cBlock + rBlock*BC);
else
return T(0);
}
template <typename T, std::size_t BR,std::size_t BC>
std::ostream& operator<<(std::ostream& os , const BCRSmatrix<T,BR,BC>& m )
{
for(auto i=0 ; i < m.denseRows / BR ; i++)
{
//for each Block sub row.
for(auto rBlock = 0; rBlock < BR; rBlock++)
{
//for each BCSR col.
for(auto j = 1; j <= m.denseCols / BC; j++)
{
//for each Block sub col.
for(auto cBlock = 0; cBlock < BC; cBlock++)
{
os << m.findValue(i, j, rBlock, cBlock) <<'\t';
}
}
os << std::endl;
}
}
return os;
}
template <typename T, std::size_t BR, std::size_t BC>
std::vector<T> operator*(const BCRSmatrix<T,BR,BC>& m, const std::vector<T>& x )
{
std::vector<T> y(x.size());
if(m.size1() != x.size())
{
std::string to = "x" ;
std::string mess = "Error occured in operator* attempt to perfor productor between op1: "
+ std::to_string(m.size1()) + to + std::to_string(m.size2()) +
" and op2: " + std::to_string(x.size());
throw InvalidSizeException(mess.c_str());
}
else
{
auto brows = m.denseRows/BR ;
auto bnze = m.an_.size() ;
auto z=0;
for(auto b=0 ; b < brows ; b++)
{
for(auto j= m.ai_.at(b) ; j <= m.ai_.at(b+1)-1; j++ )
{
for(auto k=0 ; k < BR ; k++ )
{
for(auto t=0 ; t < BC ; t++)
{
y.at(BC*b+k) += m.ba_.at(z) * x.at(BC*(m.aj_.at(j-1)-1)+t) ;
z++ ;
}
}
}
}
}
return y;
}
and this is the main
# include "BCSmatrix.H"
using namespace std;
int main(){
BCRSmatrix<int,2,2> bbcsr1 = {{11,12,13,14,0,0},{0,22,23,0,0,0},{0,0,33,34,35,36},{0,0,0,44,45,0},
{0,0,0,0,0,56},{0,0,0,0,0,66}};
BCRSmatrix<int,2,2> bbcsr2 = {{11,12,0,0,0,0,0,0} ,{0,22,0,0,0,0,0,0} ,{31,32,33,0,0,0,0,0},
{41,42,43,44,0,0,0,0}, {0,0,0,0,55,56,0,0},{0,0,0,0,0,66,67,0},{0,0,0,0,0,0,77,78},{0,0,0,0,0,0,87,88}};
BCRSmatrix<int,2,4> bbcsr3 = {{11,12,0,0,0,0,0,0} ,{0,22,0,0,0,0,0,0} ,{31,32,33,0,0,0,0,0},
{41,42,43,44,0,0,0,0}, {0,0,0,0,55,56,0,0},{0,0,0,0,0,66,67,0},{0,0,0,0,0,0,77,78},{0,0,0,0,0,0,87,88}};
bbcsr3.printBlockMatrix();
bbcsr3.print();
BCRSmatrix<int,2,2> bbcsr4("input17.dat");
bbcsr4.printBlockMatrix();
BCRSmatrix<int,2,4> bbcsr5("input18.dat");
bbcsr5.printBlockMatrix();
cout << bbcsr5 ;
BCRSmatrix<int,4,4> bbcsr6("input18.dat");
bbcsr6.printBlockMatrix();
bbcsr6.print();
cout << bbcsr4 ; //.print();
BCRSmatrix<int,2,4> bbcsr7("input20.dat");
cout << bbcsr7;
bbcsr7.printBlockMatrix();
std::vector<int> v1 = {3,4,0,1,6,8,1,19};
std::vector<int> v01 = {3,4,0,1,6,8,1,19,15,2};
std::vector<int> v2 = bbcsr4 *v1 ;
for(auto& x : v2)
cout << x << ' ' ;
cout << endl;
BCRSmatrix<double,2,2> bbcsr8("input21.dat");
bbcsr8.print() ;
bbcsr8.printBlockMatrix();
return 0;
}

how to write the method findValue(i,j) that give 2 indexes of the original matrix
It is similar to the previous findValue method:
template <typename T, std::size_t BR,std::size_t BC>
auto constexpr BCRSmatrix<T,BR,BC>::myNewfindValue(const std::size_t i, const std::size_t j) const noexcept{
auto index = findBlockIndex(i/BR, j/BC);
if(index != 0)
return ba_.at(an_.at(index-1)-1 + j%BC + (i%BR)*BC);
else
return T(0);
}
To recall this function: you have to do a little change to your findBlockIndex: just change if( aj_.at(j-1) == c ) whit if( aj_.at(j-1) == c+1 ), than you have to modify your for statements in the others functions for(auto j = 1; j <= .. whit for(auto j = 0; j < ...
Let me know if there are problems or this is not the answer you were looking for.
I hope to be of help to you,
best regards Marco.

rename the original findValue as findVal then define a new findValue that take exactly 2 element defined as follow (I know is orrible):
template <typename T, std::size_t BS>
T constexpr SqBCSmatrix<T,BS>::findValue(const std::size_t r, const std::size_t c) const noexcept
{
//for each BCRS row
for(auto i=0 ,k=0; i < denseRows / BS ; i++){
//for each Block sub row.
for(auto rBlock = 0; rBlock < BS; k++ ,rBlock++){
//for each BCSR col.
for(auto j = 1 , l=0; j <= denseCols / BS; j++){
//for each Block sub col.
for(auto cBlock = 0; cBlock < BS; l++ , cBlock++){
if(k == r && c == l )
return findVal(i,j,rBlock, cBlock);
}
}
}
}
return 0;
}

Related

how to convert block compressed row to dense matrix?

I'm interesting to create a class for storing sparse matrix in Block Compressed Sparse Row format this method of storage consist to subdivide the matrix into square block of size sz*sz and stored this block in a vector BA , here you can find most information about link
basically the matrix is stored using 4 vector :
BA contains the elements of the submatrices (blocks) stored in top-down left right order (the first block in the picture of size 2x2 is 11,12,0,22)
AN contains the indices of each starting block of the vector BA (in the pictur case the block size is 2x2 so it contains 1,5 ... )
AJ contains the column index of blocks in the matrix of blocks (the smaller one in the picture)
AI the row pointer vector , it store how many blocks there is in the i-th row ai[i+1]-a[i] = number of block in i-th row
I'm write the constructor for convert a matrix from dense format to BCRS format :
template <typename data_type, std::size_t SZ = 2 >
class BCSRmatrix {
public:
constexpr BCSRmatrix(std::initializer_list<std::vector<data_type>> dense );
auto constexpr validate_block(const std::vector<std::vector<data_type>>& dense,
std::size_t i, std::size_t j) const noexcept ;
auto constexpr insert_block(const std::vector<std::vector<data_type>>& dense,
std::size_t i, std::size_t j) noexcept ;
private:
std::size_t bn ;
std::size_t bSZ ;
std::size_t nnz ;
std::size_t denseRows ;
std::size_t denseCols ;
std::vector<data_type> ba_ ;
std::vector<std::size_t> an_ ;
std::vector<std::size_t> ai_ ;
std::vector<std::size_t> aj_ ;
std::size_t index =0 ;
};
template <typename T, std::size_t SZ>
constexpr BCSRmatrix<T,SZ>::BCSRmatrix(std::initializer_list<std::vector<T>> dense_ )
{
this->denseRows = dense_.size();
auto it = *(dense_.begin());
this->denseCols = it.size();
if( (denseRows*denseCols) % SZ != 0 )
{
throw InvalidSizeException("Error block size is not multiple of dense matrix size");
}
std::vector<std::vector<T>> dense(dense_);
bSZ = SZ*SZ ;
bn = denseRows*denseCols/(SZ*SZ) ;
ai_.resize(denseRows/SZ +1);
ai_[0] = 1;
for(std::size_t i = 0; i < dense.size() / SZ ; i++)
{
auto rowCount =0;
for(std::size_t j = 0; j < dense[i].size() / SZ ; j++)
{
if(validate_block(dense,i,j))
{
aj_.push_back(j+1);
insert_block(dense, i, j);
rowCount ++ ;
}
}
ai_[i+1] = ai_[i] + rowCount ;
}
printBCSR();
}
template <typename T,std::size_t SZ>
inline auto constexpr BCSRmatrix<T,SZ>::validate_block(const std::vector<std::vector<T>>& dense,
std::size_t i, std::size_t j) const noexcept
{
bool nonzero = false ;
for(std::size_t m = i * SZ ; m < SZ * (i + 1); ++m)
{
for(std::size_t n = j * SZ ; n < SZ * (j + 1); ++n)
{
if(dense[m][n] != 0) nonzero = true;
}
}
return nonzero ;
}
template <typename T,std::size_t SZ>
inline auto constexpr BCSRmatrix<T,SZ>::insert_block(const std::vector<std::vector<T>>& dense,
std::size_t i, std::size_t j) noexcept
{
//std::size_t value = index;
bool firstElem = true ;
for(std::size_t m = i * SZ ; m < SZ * (i + 1); ++m)
{
for(std::size_t n = j * SZ ; n < SZ * (j + 1); ++n)
{
if(firstElem)
{
an_.push_back(index+1);
firstElem = false ;
}
ba_.push_back(dense[m][n]);
index ++ ;
}
}
template <typename T, std::size_t SZ>
auto constexpr BCSRmatrix<T,SZ>::printBCSR() const noexcept
{
std::cout << "ba_ : " ;
for(auto &x : ba_ )
std::cout << x << ' ' ;
std::cout << std::endl;
std::cout << "an_ : " ;
for(auto &x : an_ )
std::cout << x << ' ' ;
std::cout << std::endl;
std::cout << "aj_ : " ;
for(auto &x : aj_ )
std::cout << x << ' ' ;
std::cout << std::endl;
std::cout << "ai_ : " ;
for(auto &x : ai_ )
std::cout << x << ' ' ;
std::cout << std::endl;
}
And the main function for test the class :
# include "BCSRmatrix.H"
using namespace std;
int main(){
BCSRmatrix<int,2> bbcsr2 = {{11,12,0,0,0,0,0,0} ,{0,22,0,0,0,0,0,0} ,{31,32,33,0,0,0,0,0},
{41,42,43,44,0,0,0,0}, {0,0,0,0,55,56,0,0},{0,0,0,0,0,66,67,0},{0,0,0,0,0,0,77,78},{0,0,0,0,0,0,87,88}};
BCSRmatrix<int,4> bbcsr3 = {{11,12,0,0,0,0,0,0} ,{0,22,0,0,0,0,0,0} ,{31,32,33,0,0,0,0,0},
{41,42,43,44,0,0,0,0}, {0,0,0,0,55,56,0,0},{0,0,0,0,0,66,67,0},{0,0,0,0,0,0,77,78},{0,0,0,0,0,0,87,88}};
return 0;
}
Now back to the question .. I obtain the 4 vector as in the picture .. but what about backing from this 4 vector to the dense matrix ?
for example how to print out the whole matrix ?
Edit : I've figure out the way to plot the "blocks matrix" the smaller in the picture with relative index of vector AN:
template <typename T,std::size_t SZ>
inline auto constexpr BCSRmatrix<T,SZ>::printBlockMatrix() const noexcept
{
for(auto i=0 ; i < denseRows / SZ ; i++)
{
for(auto j=1 ; j <= denseCols / SZ ; j++)
{
std::cout << findBlockIndex(i,j) << ' ' ;
}
std::cout << std::endl;
}
}
template <typename T, std::size_t SZ>
auto constexpr BCSRmatrix<T,SZ>::findBlockIndex(const std::size_t r, const std::size_t c) const noexcept
{
for(auto j= ai_.at(r) ; j < ai_.at(r+1) ; j++ )
{
if( aj_.at(j-1) == c )
{
return j ;
}
}
}
that when in the main I call :
bbcsr3.printBlockMatrix();
Give me the right result :
1 0 0 0
2 3 0 0
0 0 4 5
0 0 0 6
Now just the whole matrix missing I think that I missed something in may mind .. but should be something easy but I didn't got the point .. any ideas ?
what about backing from this 4 vector to the dense matrix ? for example how to print out the whole matrix ?
Back to the sparse matrix:
template <typename T, std::size_t SZ>
auto constexpr BCSRmatrix<T,SZ>::recomposeMatrix() const noexcept {
std::vector<std::vector<data_type>> sparseMat(denseRows, std::vector<data_type>(denseCols, 0));
auto BA_i = 0, AJ_i = 0;
//for each BCSR row
for(auto r = 0; r < denseRows/SZ; r++){
//for each Block in row
for(auto nBlock = 0; nBlock < ai_.at(r+1)-ai_.at(r); nBlock++){
//for each subMatrix (Block)
for(auto rBlock = 0; rBlock < SZ; rBlock++){
for(auto cBlock = 0; cBlock < SZ; cBlock++){
//insert value
sparseMat.at(rBlock + r*SZ).at(cBlock + (aj_.at(AJ_i)-1)*SZ) = ba_.at(BA_i);
++BA_i;
}
}
++AJ_i;
}
}
return sparseMat;
}
Where:
BA_i and AJ_i are iterators of the respective vectors.
nBlock keeps the numbers of blocks in row given by ai_.
rBlock and cBlockare the iterators of the sub-matrix sz*sz called "Block".
note: an_ remain unused, you can try replacing BA_i whit it.
Print the matrix:
std::vector<std::vector<int>> sparseMat = bbcsr2.recomposeMatrix();
for(auto i = 0; i < sparseMat.size(); i++){
for(auto j = 0; j < sparseMat.at(i).size(); j++)
std::cout<<sparseMat.at(i).at(j) << '\t';
std::cout << std::endl;
}
I'm not sure I wrote the template correctly, anyway the algorithm should work; let me know if there are problems.
EDIT
make sense in a class that is created for saving time and memory storing sparse matrix it certain way than use a vector for reconstruct the whole matrix ?
You're right, my fault; I thought the problem was recompose the Matrix.
I rewritten the methods using findBlockIndex as a reference.
template <typename T, std::size_t SZ>
auto constexpr BCSRmatrix<T,SZ>::printSparseMatrix() const noexcept {
//for each BCSR row
for(auto i=0 ; i < denseRows / SZ ; i++){
//for each Block sub row.
for(auto rBlock = 0; rBlock < SZ; rBlock++){
//for each BCSR col.
for(auto j = 1; j <= denseCols / SZ; j++){
//for each Block sub col.
for(auto cBlock = 0; cBlock < SZ; cBlock++){
std::cout<< findValue(i, j, rBlock, cBlock) <<'\t';
}
}
std::cout << std::endl;
}
}
}
template <typename T, std::size_t SZ>
auto constexpr BCSRmatrix<T,SZ>::findValue(const std::size_t i, const std::size_t j, const std::size_t rBlock, const std::size_t cBlock) const noexcept {
auto index = findBlockIndex(i,j);
if(index != 0)
return ba_.at(an_.at(index-1)-1 + cBlock + /* rBlock*2 */ rBlock*SZ);
}
I hope to be of help to you,
best regards Marco.

Matrix (MCSC format ) product how to perform?

I'm implementing a matrix class in modified compressed sparse column format , I have not idea to how to perform the product , this matrix store all the non zero element in 2 vector (value and index) in particular this format of storing consist of 2 container construct in this way:
aa_ the vector of value, stored in is first matrix-dim element the value of the diagonal, and then all the non zero value off-diagonal
ja_ stored in it's first matrix-dim element the number of non zero off-diagonal element in this way :ja[0]=matrix.dimension +1 then ja_[i] -ja_[i+1] = nnz element of column i+1 , and in the ja[ja_[i]] = index_of_row of the non zero element.
If you would read something about this format you can look here Modified compressed format
I've implemented a class but I would figure out how to perform the matrix product, I hope somebody can help me about
# include <iosfwd>
# include <initializer_list>
# include <iomanip>
# include <cassert>
# include <cmath>
# include <vector>
template <typename data_type> class MCSCmatrix ;
template <typename T>
std::vector<T> operator*(const MCSCmatrix<T>& A ,const std::vector<T>& x)noexcept ;
template <typename data_type>
class MCSCmatrix {
public:
template <typename T>
friend std::vector<T> operator*(const MCSCmatrix<T>& A ,const std::vector<T>& x) noexcept ;
auto constexpr printMCSC() const noexcept ;
private:
std::vector<data_type> aa_ ; // non zero value value
std::vector<std::size_t> ja_ ;
std::size_t dim ;
};
template <typename T>
inline constexpr MCSCmatrix<T>::MCSCmatrix( std::initializer_list<std::vector<T>> row)
{
this->dim = row.size();
auto il = *(row.begin());
if(this-> dim != il.size())
{
throw InvalidSizeException("Matrix Must be square in Modified CSC format ");
}
std::vector<std::vector<T>> temp(row);
aa_.resize(dim+1);
ja_.resize(dim+1);
//std::size_t elemCount = 0;
ja_[0] = dim+2 ;
auto elemCount = 0;
for(auto c = 0 ; c < temp[0].size() ; c++ )
{
elemCount =0 ;
for(auto r = 0 ; r < temp.size() ; r++)
{
if(c==r)
{
aa_[c] = temp[r][c] ;
}
else if(c != r && temp[r][c] !=0)
{
aa_.push_back(temp[r][c]);
ja_.push_back(r+1);
elemCount++ ;
}
}
ja_[c+1] = ja_[c] + elemCount ;
}
printMCSC();
}
template <typename T>
inline auto constexpr MCSCmatrix<T>::printMCSC() const noexcept
{
std::cout << "aa: " ;
for(auto& x : aa_ )
std::cout << x << ' ' ;
std::cout << std::endl;
std::cout << "ja: " ;
for(auto& x : ja_ )
std::cout << x << ' ' ;
std::cout << std::endl;
}
template <typename T>
std::vector<T> operator*(const MCSCmatrix<T>& A ,const std::vector<T>& x) noexcept
{
assert(A.dim == x.size());
std::vector<T> b(x.size());
for(auto i=0 ; i < A.dim ; i++ )
b.at(i) = A.aa_.at(i) * x.at(i) ; // diagonal value
for(auto i=0; i< A.dim ; i++)
{
for(auto k=A.ja_.at(i)-1 ; k < A.ja_.at(i+1)-1 ; k++ )
{
b.at(A.ja_.at(k)-1) += A.aa_.at(k)* x.at(i);
}
}
return b;
}
and here the main function:
# include "ModCSCmatrix.H"
using namespace std;
int main(){
MCSCmatrix<int> m1 = {{11,12,13,14,0,0},{0,22,23,0,0,0},{0,0,33,34,35,36},{0,0,0,44,45,0},
{0,0,0,0,0,56},{0,0,0,0,0,66}};
m1.printMCSC();
MCSCmatrix<double> m100 = {{1.01, 0 , 2.34,0}, {0, 4.07, 0,0},{3.12,0,6.08,0},{1.06,0,2.2,9.9} };
std::vector<double> v1={0,1.3,4.2,0.8};
std::vector<double> v2 = m100*v1 ;
for(auto& x : v2)
cout << x << ' ' ;
cout << endl;
return 0;
}

sparse matrix implemented using vector of map

As I wrote in another post (closed because I found some solution) I have implement a Sparse Matrix Class , the data container is done by a vactor of map where the index of vector rappresent the index of the row of the matrix for each index therefore the vector stored a map !
here the interface:
template <typename element_type>
class SparseMatrix {
public:
template<class T>
friend SparseMatrix<T> operator+(const SparseMatrix<T>& m1 , const SparseMatrix<T>& m2 );
template<class T>
friend SparseMatrix<T> operator-(const SparseMatrix<T>& m1 , const SparseMatrix<T>& m2 );
template <class T>
friend SparseMatrix<T> operator*(const SparseMatrix<T>& m1 , const SparseMatrix<T>& m2 );
public:
// container type ;
using data_type = std::vector<std::map<std::size_t , element_type >> ;
using it_rows = typename std::map<std::size_t , element_type>::iterator ;
SparseMatrix(std::size_t rows , std::size_t cols) : rows{rows} , columns{cols}
{
data.resize(rows);
}
SparseMatrix(std::initializer_list<std::initializer_list<element_type>> l );
SparseMatrix(const std::string );
auto insert(std::size_t i , std::pair<std::size_t, element_type> p )
{
assert( i <= rows && p.first <= columns); // , "Index out of bound" );
data.at(i).insert(p);
}
auto insert(std::size_t i, std::size_t j, element_type val)
{
assert(i<=rows && j <=columns);
data.at(i)[j] = val ;
}
auto identity() noexcept ;
auto diag(const element_type& v) noexcept ;
auto print() const noexcept ;
auto dataType() const noexcept ;
auto traspose() noexcept ;
private:
std::size_t rows ;
std::size_t columns ;
data_type data ; // vector containing row element
};
In the previous post I asked about the traspose matrix .. I found this solution:
template <typename T>
auto SparseMatrix<T>::traspose() noexcept
{
//rows = columns ;
std::swap(rows,columns);
data_type newData ;
newData.resize(rows);
for(std::size_t i=0; i < columns ; i++)
{
for(std::size_t j=0 ; j < rows ; j++)
{
if(data.at(i).find(j) != data.at(i).end())
{
newData.at(j)[i] = data.at(i).at(j) ;
}
}
}
std::swap(data,newData);
}
Now i have no idea to how do compute the matrix product ... could you give me some advice ?
Ok .. thanks to suggeriment recived by #BeyelerStudios i got the poind and wrote the dot product in this way :
template <class T>
SparseMatrix<T> dot(const SparseMatrix<T>& m1 , const SparseMatrix<T>& m2 )
{
if(m1.columns != m2.rows)
{
throw std::runtime_error("Matrix sizes dosent match the dot-product");
}
SparseMatrix<T> result{m1.rows , m2.columns };
for(std::size_t i=0 ; i < result.rows ; i++)
{
for(std::size_t j=0 ; j < result.columns ; j++ )
{
for(std::size_t k=0; k< m1.columns ; k++)
{
if( m1.data.at(i).find(k) != m1.data.at(i).end() &&
m2.data.at(k).find(j) != m2.data.at(k).end() )
{
result.data.at(i)[j] += (m1.data.at(i).at(k) * m2.data.at(k).at(j)) ;
}
}
}
}
return result ;
}
now i open one other post for asking about determinant and inverse !

Weird segmentation fault 11

There are two files:
Matrix.hpp:
template <typename T>
class Matrix {
private:
size_t rows = 0;
size_t cols = 0;
T* data = nullptr;
public:
Matrix() = default;
~Matrix();
Matrix(size_t n, size_t m);
T& operator() (size_t i, size_t j);
};
template <typename T>
Matrix<T>::Matrix(size_t n, size_t m) : rows(n), cols(m) {
try {
data = new T[rows*cols];
} catch (const std::bad_alloc& e) {
std::exit(EXIT_FAILURE);
}
};
template <typename T>
Matrix<T>::~Matrix() {
delete[] data;
}
template <typename T>
T& Matrix<T>::operator()(size_t i, size_t j) {
if (i < rows && i >= 0 && j < cols && j >= 0) {
return data[(i+1)*cols + (j+1)];
} else {
throw std::logic_error("matrix indices out of range");
}
}
and
Main.cpp:
#include <iostream>
#include "Matrix.hpp"
int main() {
size_t n, k;
std::cin >> n >> k;
Matrix<long double> m = {n, k};
for (size_t i = 0; i < m.getNumRows(); ++i) {
for (size_t j = 0; j < m.getNumCols(); ++j) {
std::cin >> m(i,j);
}
}
for (size_t i = 0; i < m.getNumRows(); ++i) {
std::cout << "\n";
for (size_t j = 0; j < m.getNumCols(); ++j) {
std::cout << m(i, j) << " ";
}
}
return 0;
}
When I'm entering something like:
1 2 3 4
I can get
3 4
as answer but sometimes the same input causes Segmentation fault 11 moreover when I'm changing template argument from long double to int, error disappears. How can I fix it?
Your operator function is accessing data outside its bounds.
Passing (0,0) to the function should return data[0]. Currently it returns data[2].
Change line
return data[(i+1)*cols+(j+1)];
to
return data[i*cols+j];

C++ matrix template class slice

In order to learn about C++ templates I am writing a simple Matrix class. So far it has been working well, but I want to add the ability to slice the Matrix to extract a sub-matrix. I am struggling to figure out how to define the size of the return matrix. I have tried the following:
#include <cstdint>
#include <array>
#include <initializer_list>
template<typename T, std::size_t M, std::size_t N>
class Matrix
{
public:
Matrix(void): m_data{0} {}
Matrix(const std::initializer_list<std::initializer_list<T>> m)
{
for(auto i = m.begin(); i != m.end(); i++)
{
for(auto j = i->begin(); j != i->end(); j++)
{
(*this)(i - m.begin(), j - i->begin()) = *j;
}
}
}
T& operator()(const std::size_t i, const std::size_t j)
{
return m_data.at(i + j * N);
}
const T& operator()(const std::size_t i, const std::size_t j) const
{
return m_data.at(i + j * N);
}
template<std::size_t X, std::size_t Y>
Matrix<T,X,Y> slice(const std::size_t iStart, const std::size_t iEnd, const std::size_t jStart, const std::size_t jEnd)
{
Matrix<T,iEnd-iStart+1,jEnd-jStart+1> result;
for(std::size_t i = iStart; i <= iEnd; i++)
{
for(std::size_t j = jStart; j <= jEnd; j++)
{
result(i - iStart, j - jStart) = (*this)(i,j);
}
}
return result;
}
};
int main(void)
{
Matrix<double,3,3> m1 = {{1,2,3},{4,5,6},{7,8,9}};
Matrix<double,2,2> m2 = m1.slice(0,1,0,1);
return 0;
}
But I just get an error saying that 'iEnd' is not a constant expression. What would be the correct way to go about this?
You cannot use function parameters to instantiate templates. You need to pass in the sizes as template arguments to slice:
template<std::size_t iStart, std::size_t iEnd, std::size_t jStart, std::size_t jEnd,
std::size_t I = iEnd-iStart+1, std::size_t J = jEnd-jStart+1>
Matrix<T,I,J> slice()
{
Matrix<T,I,J> result;
///...
return result;
}