удалить пустые строки из Eigen :: SparseMatrix - PullRequest
0 голосов
/ 05 июня 2018

Я построил разреженную матрицу mat из списка триплетов

Eigen::SparseMatrix<double, Eigen::RowMajor> mat(Nbins,Ndata);
mat.setFromTriplets(tripletList.begin(), tripletList.end());

Теперь я хотел бы создать новую матрицу ret, которая содержит только строки предыдущей матрицы, которыене пустой.Я делаю это следующим образом

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);

Однако делать это медленно и неэффективно.Медленный, потому что быстрое профилирование предполагает, что он проводит большую часть своего времени на ret.row(Nrow++) = mrow;.Неэффективно, потому что мы также копируем все данные дважды.

Есть ли лучшее решение?Я чувствую, что нужно возиться с внутренними векторами, но они меня смущают, и я не знаю, насколько это удобно для пользователя, играть с ними.

РЕДАКТИРОВАТЬ: В моем приложении матрицы являются основными рядами,и я хочу удалить пустые строки.mat не нужен, просто ret.Все коэффициенты положительны, поэтому я проверяю ненулевые строки.Триплеты отсортированы, но по столбцу.Там нет дубликатов триплетов.

1 Ответ

0 голосов
/ 07 июня 2018

Нашли это!Вместо того, чтобы писать вручную setFromTriplets, я пошел с модификацией tripletList.Интерфейс Eigen :: Triplet делает это очень просто.

//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());
...