在有限元分析中,将一些规定的条件应用于大的稀疏矩阵并获得减少的矩阵是很常见的。这可以在MATLAB
,SciPy
和Julia
中轻松实现,例如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
操作在这方面无用。
我可以想到我测试过的两种方法:
D*A*A.transpose()
进行前后相乘我总是使用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;
}
所以任何指针,在这方面都会有用。