Reputation: 397
I have built a sparse matrix mat
from a list of triplets
Eigen::SparseMatrix<double, Eigen::RowMajor> mat(Nbins,Ndata);
mat.setFromTriplets(tripletList.begin(), tripletList.end());
Now I would like to create a new matrix ret
, which only contains the rows of the previous matrix which are not empty. I do it as follows
Eigen::SparseMatrix<double, Eigen::RowMajor> ret(Nbins,Ndata);
unsigned Nrow=0;
for (unsigned i=0; i<Nbins; ++i) {
auto mrow = mat.row(i);
if (mrow.sum()>0) {
ret.row(Nrow++) = mrow;
}
}
ret.conservativeResize(Nrow,Ndata);
However, doing it this way is slow and inefficient. Slow because quick profiling suggests it spends most of its time on ret.row(Nrow++) = mrow;
. Inefficient because we are also copying all the data twice.
Is there a better solution? I feel one has to fiddle with the inner vectors but I get confused by them and I don't know how user-proof it is to play with them.
EDIT: In my application, matrices are row major, and I want to remove empty rows. mat
is not needed, just ret
. All coefficients are positive hence the way I check for nonzero rows. The triplets are sorted but column-major. There are no duplicate triplets.
Upvotes: 2
Views: 1066
Reputation: 397
Found it! Instead of writing a hand-made setFromTriplets, I went with a modification of the tripletList. The interface of Eigen::Triplet makes it very easy.
//get which rows are empty
std::vector<bool> has_value(Nbins,false);
for (auto tr : tripletList) has_value[tr.row()] = true;
//create map from old to new indices
std::map<unsigned,unsigned> row_map;
unsigned new_idx=0;
for (unsigned old_idx=0; old_idx<Nbins; old_idx++)
if(has_value[old_idx])
row_map[old_idx]=new_idx++;
//make new triplet list, dropping empty rows
std::vector<Eigen::Triplet<double> > newTripletList;
newTripletList.reserve(Ndata);
for (auto tr : tripletList)
newTripletList.push_back(
Eigen::Triplet<double>(row_map[tr.row()],tr.col(),tr.value()));
//form new matrix and return
Eigen::SparseMatrix<double, Eigen::RowMajor> ret(new_idx,Ndata);
ret.setFromTriplets(newTripletList.begin(), newTripletList.end());
Upvotes: 1