简体   繁体   English

如何对特征中的稀疏矩阵进行不连续块运算

[英]how to do incontinuity block operation on sparse matrix in eigen

i have this in matlab(actually A is a enormous sparse matrix,about 30k*30k. )我在matlab中有这个(实际上A是一个巨大的稀疏矩阵,大约30k * 30k。)

a=[1,3,5,...];
b=[2,4,6,...];
A(a,:)=A(a,:)+A(b,:);
A(b,:)=[]

i would like to perform this opertion (matlab) in c++.But it seems that eigen dosen't allow incontinuity block operation on sparse matrix.我想在 C++ 中执行这个操作(matlab)。但似乎特征不允许对稀疏矩阵进行不连续块操作。 What i did is using igl::slice&igl::slice_into.我所做的是使用 igl::slice&igl::slice_into。

        SparseMatrix < double >A,A1, A2,A3;
        igl::slice(A, a, 1, A1);
        igl::slice(A, b, 1,A2);
        A3 = A1 + A2;
    
        igl::slice_into(A3, index_u, 1, A);
    
VectorXd A_rows_index = VectorXd::LinSpaced(A.rows(), 0, A.rows() - 1);
    VectorXd A_rows_index_after(A_rows_index.size());
    auto it = std::set_difference(A_rows_index.data(), A_rows_index.data() + A_rows_index.size(),
        b.data(), b.data() + b.size(),
        A_rows_index_after.data());
    A_rows_index_after.conservativeResize(std::distance(A_rows_index_after.data(), it)); // resize the result
        igl::slice(A, A_rows_index_after, 1, A);
    A.resize();

but it cost too much time .但它花费了太多时间。 Thus i would like to know is there any other way to perform such operation in c++ which cost less time?因此,我想知道是否有任何其他方法可以在 c++ 中执行这样的操作,从而花费更少的时间? is there anything i miss有什么我想念的吗

If I understand your code correctly, you add even and odd values per column, then shrink the matrix in half.如果我正确理解了您的代码,则每列添加偶数和奇数值,然后将矩阵缩小一半。 I don't think that's an operation that is supported out-of-the-box.我不认为这是开箱即用支持的操作。

The poorly documented InnerIterator is your friend when building operations that are not directly supported.在构建不直接支持的操作时,文档记录不佳的InnerIterator是您的朋友。 I think this should work reasonably fast:我认为这应该工作得相当快:

#include <Eigen/Sparse>

#include <vector>


Eigen::SparseMatrix<double>
fold_even_odd(const Eigen::SparseMatrix<double>& in)
{
  using Triplet = Eigen::Triplet<double>;
  using InnerIterator = Eigen::SparseMatrix<double>::InnerIterator;
  /*
   * Initialize to upper bound of size. This is usually cheaper than
   * reserve + push_back but YMMV
   */
  std::vector<Triplet> triplets(static_cast<std::size_t>(in.nonZeros()));
  std::size_t out = 0;
  for(int col = 0, cols = in.cols(); col < cols; ++col) {
    InnerIterator nonzero(in, col);
    while(nonzero) {
      int row = nonzero.row();
      double value = nonzero.value();
      if(++nonzero && (row & 1) == 0 && nonzero.row() == row + 1) {
        // even followed by odd
        value += nonzero.value();
        ++nonzero;
      }
      triplets[out++] = Triplet(row >> 1, col, value);
    }
  }
  Eigen::SparseMatrix<double> rtrn((in.rows() + 1) >> 1, in.cols());
  rtrn.setFromTriplets(triplets.begin(), triplets.begin() + out);
  return rtrn;
}

There is a little trick we can employ.我们可以使用一个小技巧。 It will (probably) not make the code faster but shorter: When setting triplets, we can specify a function for duplicates.它(可能)不会使代码更快但更短:当设置三元组时,我们可以为重复项指定一个函数。 This can do the addition of successive even and odd elements.这可以添加连续的偶数和奇数元素。

Eigen::SparseMatrix<double>
fold_even_odd2(const Eigen::SparseMatrix<double>& in)
{
  using Triplet = Eigen::Triplet<double>;
  using InnerIterator = Eigen::SparseMatrix<double>::InnerIterator;
  std::vector<Triplet> triplets(static_cast<std::size_t>(in.nonZeros()));
  std::size_t i = 0;
  for(int col = 0, cols = in.cols(); col < cols; ++col)
    for(InnerIterator nonzero(in, col); nonzero; ++nonzero)
      triplets[i++] = Triplet(nonzero.row() >> 1, col, nonzero.value());
  Eigen::SparseMatrix<double> rtrn((in.rows() + 1) >> 1, in.cols());
  rtrn.setFromTriplets(triplets.begin(), triplets.end(),
                       [](double even, double odd) { return even + odd; });
  return rtrn;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM