我有一个稀疏线性系统Ax = b
。在我的应用中,A
是一个对称稀疏矩阵,其典型大小约为2500000 x 2500000,在主对角线和另一对角线上(加上与该对角线对称的(都有非零。这使得每行/列有2-3个非零。
为了测试我的代码,我比较了MATLAB和Eigen。我创建了一个1000000 x 1000000的稀疏矩阵A
。在MATLAB中,我简单地使用x = Ab
,大约需要8秒。在Eigen中,我尝试了几个解算器。SuperLU大约需要150秒。简单Cholesky大约需要300秒。UmfPackLU大约需要490秒。这些时间对我来说太长了;在实际数据中,它只是需要很长时间才能发挥作用。与MATLAB相比,其他求解器给出的结果完全不同,迭代求解器花费的时间太长。SimplicialCholesky、SuperLU和UmfPackLU给出了相似的结果(它们在小数点后几位不同(,所以我希望这也一样。特征码:
// prepare sparse matrix A
std::vector<T> tripletList; // I am leaving filling the triplet list out
Eigen::SparseMatrix<float> A(k, k); // k is usually around 2500000, in the test case I described here it is 1000000
A.setFromTriplets(tripletList.begin(), tripletList.end());
A.makeCompressed();
// prepare vector b
Eigen::Map<Eigen::VectorXf> b; // vector b is filled with values
// calculate A x = b and measure time - for SimplicialCholesky
t1 = std::chrono::steady_clock::now();
Eigen::SimplicialCholesky<Eigen::SparseMatrix<float>> solver_chol(A);
x = solver_chol.solve(b);
t2 = std::chrono::steady_clock::now();
log_file << "SimlicialCholeskytime: t2 - t1 = " << std::chrono::duration_cast<std::chrono::seconds>(t2 - t1).count() << " s n";
// calculate A x = b and measure time - for SparseLU
t1 = std::chrono::steady_clock::now();
Eigen::SparseLU<Eigen::SparseMatrix<float>> solver_slu(A);
x = solver_slu.solve(b);
t2 = std::chrono::steady_clock::now();
log_file << "SparseLU time: t2 - t1 = " << std::chrono::duration_cast<std::chrono::seconds>(t2 - t1).count() << " s n";
// calculate A x = b and measure time - for UmfPackLU - here I had to convert to double.
Eigen::SparseMatrix<double> Ad = A.cast <double>();
Ad.makeCompressed();
Eigen::VectorXd bd = b.cast <double>();
t1 = std::chrono::steady_clock::now();
Eigen::UmfPackLU<Eigen::SparseMatrix<double>> solver(Ad);
Eigen::VectorXd xd = solver.solve(bd);
t2 = std::chrono::steady_clock::now();
log_file << "UmfPackLU time: t2 - t1 = " << std::chrono::duration_cast<std::chrono::seconds>(t2 - t1).count() << " s n";
也许我应该提到,计算是在所有8个核心上进行的,所以当我看时间时,我得到了8次,我总结了一下。此外,计算(到目前为止(封装在.dll库.cu中,下一步将通过CUDA进行并行处理。我分别测量了所有方法的时间,以避免一些计数重叠。
我找到了以下可能的解决方案来加快计算速度:
- 使用普通lu,不适用于稀疏系统;
- 链接到BLAS/LAPACK库,我想我已经做到了
- 尝试不同的求解器或包装器,其他求解器并没有给出与MATLAB相同的结果;这里的答案过于具体化
- 多线程,使用已启用优化的编译器(编译器-最大优化,支持速度(,仍然很慢
- 与MATLAB一样,使用UmfPack可以获得类似的性能——它甚至比SimlicialCholesky慢
- 列出了其他可能使用矩阵的库,但我不知道它们会如何处理我的情况
我能做些什么来加快使用Eigen的计算速度吗?所以它需要与MATLAB类似的时间?关于矩阵的大小和稀疏性,我是否使用了正确的求解器?我是否正确使用当前解算器?我是否必须进行一些额外的设置,包括一些其他库?如果不可能的话,还有其他图书馆可以用吗?
我在Windows10,64位的机器上工作。我有Visual Studio 2019。
我最近为我的谱配置求解器尝试了许多线性求解器,我发现"armadillo";是基于openblas库快速求解稠密Ax=b的方法。特征3.3非常慢;setNumbthreads";,我仍然找不到原因。如果你想用Cuda或OpenMP解决它。我强烈建议你使用助理图书馆。它对我的问题很有效。问候
http://www.paralution.com/