C++ c++;大特征分解速度

C++ c++;大特征分解速度,c++,eigen,armadillo,eigen3,C++,Eigen,Armadillo,Eigen3,作为我的管道的一部分,我需要对一个6000x6000的大矩阵进行特征分解。矩阵是稠密的,所以除非我简化这个问题(如果可能的话请确保),否则就不能使用稀疏方法 现在我在玩玩具数据。对于513x513矩阵,使用特征库需要约6.5秒,而对于2049x2049矩阵,则需要约130秒,这听起来令人望而却步,因为增加不是线性的。这是通过使用Eigen::SelfAdjointEigenSolver实现的,而使用其他方法,如Eigen::EigenSolver或Eigen::ComplexEigenSolve

作为我的管道的一部分,我需要对一个6000x6000的大矩阵进行特征分解。矩阵是稠密的,所以除非我简化这个问题(如果可能的话请确保),否则就不能使用稀疏方法

现在我在玩玩具数据。对于513x513矩阵,使用特征库需要约6.5秒,而对于2049x2049矩阵,则需要约130秒,这听起来令人望而却步,因为增加不是线性的。这是通过使用
Eigen::SelfAdjointEigenSolver
实现的,而使用其他方法,如
Eigen::EigenSolver
Eigen::ComplexEigenSolver
我没有得到显著的改进。当我用arma::eig_sym尝试犰狳时也发生了同样的情况,即使使用选项“dc”`也会得到更快但近似的结果。Armadillo有一些只返回前X个特征值的加速方法,但这只适用于稀疏方法。目前,我可能不需要前10-20个特征值


有没有一种方法或库/方法可以显著提高我的速度?

我建议尝试Arpack Eigen。我从Octave/Matlab知道,它可以在一秒钟内计算出随机2049x2049的最大特征值,在5-20秒内计算出最大的10个特征值,
eigs(兰德(2049),10)
。 现在,它的文档
帮助EIG
指向ARPACK。Arpack本征值 允许您从更大的矩阵请求10个特征值,如下所示:
SymEigsSolvereigs(&op,10,30)

用于检索大型矩阵的少数特征值

计算最大和最小10个特征值的示例代码如下所示:

#include <Eigen/Core>
#include <Eigen/Eigenvalues>
#include <MatOp/DenseGenMatProd.h>
#include <MatOp/DenseSymShiftSolve.h>
#include <SymEigsSolver.h>
#include <iostream>

using namespace Spectra;

int main()
{
    srand(0);
    // We are going to calculate the eigenvalues of M
    Eigen::MatrixXd A = Eigen::MatrixXd::Random(1000, 1000);
    Eigen::MatrixXd M = A.transpose() * A;

    // Matrix operation objects
    DenseGenMatProd<double> op_largest(M);
    DenseSymShiftSolve<double> op_smallest(M);

    // Construct solver object, requesting the largest 10 eigenvalues
    SymEigsSolver< double, LARGEST_MAGN, DenseGenMatProd<double> >
        eigs_largest(&op_largest, 10, 30);

    // Initialize and compute
    eigs_largest.init();
    eigs_largest.compute();

    std::cout << "Largest 10 Eigenvalues :\n" <<
        eigs_largest.eigenvalues() << std::endl;

    // Construct solver object, requesting the smallest 10 eigenvalues
    SymEigsShiftSolver< double, LARGEST_MAGN, DenseSymShiftSolve<double> >
        eigs_smallest(&op_smallest, 10, 30, 0.0);

    eigs_smallest.init();
    eigs_smallest.compute();
    std::cout << "Smallest 10 Eigenvalues :\n" <<
        eigs_smallest.eigenvalues() << std::endl;

    return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间谱;
int main()
{
srand(0);
//我们要计算M的特征值
特征::矩阵XXD A=特征::矩阵XXD::随机(10001000);
本征::矩阵M=A.转置()*A;
//矩阵运算对象
DenseGenMatProd op_最大(M);
密度SYMBOSHIFTSOLVE op_最小(M);
//构造解算器对象,请求最大的10个特征值
SymEigsSolver<双精度、最大值、最大值、最大值>
EIG最大(和op最大,10,30);
//初始化并计算
eigs_max.init();
eigs_max.compute();

如果你只需要几个最高或最小的特征向量,那么就有更有效的方法。这正是我提到的,这可能是一个足够好的解决办法。这些方法是什么?任何指针请?Lapack提供了这样的例程。关于你的数字,我使用
Eigen::Sel仅获得2049x2049矩阵的7.5sFadJointiegensolver
和280s表示6000x6000矩阵。请确保编译时启用了编译器优化。当然,这仍然是禁止的,最好使用只提取第一个特征向量的专用算法。ARPACK-Eigen现在被取代。并且
ncv
参数应该大约是0的两到三倍f要求特征值,因此
eigs(&op,10,30)
可能更合适。@yixuan谢谢你的更正,我编辑了我的答案。