切片Eigen SparseMatrix的快速方法

时间:2017-02-25 22:01:03

标签: c++ sparse-matrix eigen

在有限元分析中,将一些规定的条件应用于大的稀疏矩阵并获得减少的矩阵是很常见的。这可以在MATLABSciPyJulia中轻松实现,例如MATLAB

 a=sprand(10000,10000,0.2); % create a random sparse matrix; fill %20
 tic; c=a(1:2:4000,2:3:5000); toc % slice the matrix to get a reduced one  

假设在Eigen中有一个类似的稀疏矩阵,切片特征矩阵的最有效方法是什么。我不关心副本或视图,但该方法需要能够应对非连续切片。后一要求使Eigen block操作在这方面无用。

我可以想到我测试过的两种方法:

  1. 使用for循环迭代列和行,并将值分配给第二个稀疏矩阵(我知道这是一个非常糟糕的主意)。
  2. 使用零和1创建一个虚拟稀疏矩阵,并使用实际矩阵D*A*A.transpose()进行前后相乘
  3. 我总是使用setFromTriplets在Eigen中创建稀疏矩阵,我对稀疏矩阵的求解器和汇编感到满意。但是,这个切片似乎是我目前代码中的瓶颈

    MATLAB与Eigen的时序(使用-O3 -DNDEBUG -march=native)是

     MATLAB:                  0.016 secs
     EIGEN LOOP INDEXING:     193 secs  
     EIGEN PRE-POST MUL:      13.7 secs  
    

    我不知道如何处理的另一种方法是直接操纵[I,J,V]三元组outerIndexPtr, innerIndexPtr, valuePtr

    以下是概念证明代码段

    #include <Eigen/Core>
    #include <Eigen/Sparse>
    
    template<typename T>
    using spmatrix = Eigen::SparseMatrix<T,Eigen::RowMajor>;
    
    
    
    spmatrix<double> sprand(int rows, int cols, double sparsity) {
        std::default_random_engine gen;
        std::uniform_real_distribution<double> dist(0.0,1.0);
        int sparsity_ = sparsity*100;
    
        typedef Eigen::Triplet<double> T;
        std::vector<T> tripletList; tripletList.reserve(rows*cols);
        int counter = 0;
        for(int i=0;i<rows;++i) {
            for(int j=0;j<cols;++j) {
                if (counter % sparsity_ == 0) {
                    auto v_ij=dist(gen);                         
                    tripletList.push_back(T(i,j,v_ij));      
                }
                counter++;
            }
        }
        spmatrix<double> mat(rows,cols);
        mat.setFromTriplets(tripletList.begin(), tripletList.end()); 
        return mat;
    }
    
    
    
    int main() {
        int m=1000,n=10000;
    
        auto a = sprand(n,n,0.05);
        auto b = sprand(m,n,0.1);
        spmatrix<double> c;
        // this is efficient but definitely not the right way to do this
        // c = b*a*b.transpose();   // uncomment to check, much slower than block operation
        c = a.block(0,0,1000,1000); // very fast, Faster than MATLAB (I believe this is just a view)
    
        return 0; 
    }
    

    所以任何指针,在这方面都会有用。

0 个答案:

没有答案