解决稀疏系统:本征与MATLAB

时间:2020-09-08 12:21:54

标签: matlab eigen

我有一个稀疏的线性系统Ax = b。在我的应用程序中,A是一个对称的稀疏矩阵,其典型大小约为2,500,000 x 2,500,000,在主对角线上和另一对角线上均具有非零值(加上该对角线的对称性)。这使其每行/列为2-3个非零值。

要测试我的代码,我正在比较MATLAB和Eigen。我创建了一个1,000,000 x 1,000,000的稀疏矩阵A。在MATLAB中,我仅使用x = A\b,大约需要8秒钟。在Eigen中,我尝试了几种求解器。 SuperLU大约需要150秒。 SimplicialCholesky大约需要300秒。 UmfPackLU大约需要490 s。这些时间对我来说太长了;在真实数据上,花太长时间才有用。与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进行并行化。为了避免计数重叠,我分别测量了所有方法的时间。

我找到了以下可能的解决方案来加快计算速度:

我可以做些什么来使用Eigen加快计算速度,所以它花费的时间与MATLAB相似?关于矩阵的大小和稀疏性,我是否使用正确的求解器?我是否正确使用当前的求解器?我是否必须进行一些其他设置,包括其他库?如果不可能,还有其他我可以使用的库吗?

我正在Windows 10 64位计算机上工作。我有Visual Studio 2019。

1 个答案:

答案 0 :(得分:0)

最近,我为光谱搭配求解器尝试了许多线性求解器,我发现“ armadillo”是基于openblas库求解密集Ax = b的快速方法。 即使使用“ setNumbthreads”,Eigen3.3也非常慢,我仍然找不到原因。 如果要使用Cuda或OpenMP解决它。我强烈建议您使用Paralution库。它可以很好地解决我的问题。 问候

http://www.paralution.com/

相关问题