对于太大的矩阵,特征值分解失败,犰狳 eigs_sym()

Posted

技术标签:

【中文标题】对于太大的矩阵,特征值分解失败,犰狳 eigs_sym()【英文标题】:Eigenvalue decomposition fails with armadillo eigs_sym() for too large matrices 【发布时间】:2016-04-25 13:56:48 【问题描述】:

我最近安装了犰狳并尝试了稀疏矩阵的特征值问题。不幸的是,分解失败是参数“N”(下面的代码)太大,例如1000. 我想知道这里发生了什么。矩阵不是很复杂——它有对角线结构。

更新

Mathematica 也有这个矩阵的问题。它告诉我 Arnoldi 算法不会收敛。也许我需要在 arnoldi arpack 例程中手动指定一些参数以确保收敛?

这是我的代码:

#include <armadillo>

int main ()

    double N = 1000.0;

    // create matrix
    int kmin = 0;
    int kmax = static_cast<int>( std::floor( N/2.0 ) );
    int dim = (kmax - kmin) + 1;

    // locations and values in sparse matrices
    arma::umat hc_locations (2, 3*dim-2);
    arma::vec hc_values (3*dim-2);

    // diagonal part
    for (int k=0; k<dim; k++)
    
        hc_locations (0,k) = k;
        hc_locations (1,k) = k;
        hc_values (k) = 2.0/N*static_cast<double>(kmin + k)*( 2.0*( N-2.0*static_cast<double>(k + kmin) ) - 1.0 );

    
    // upper and lower diagonal
    for (int k=0; k<dim-1; k++)
    
        hc_locations (0,k+dim) = k;
        hc_locations (1,k+dim) = k+1;
        hc_values (k+dim) = 2.0/N*std::sqrt( ( static_cast<double>(k+1+kmin) ) *
                                             ( static_cast<double>(k+1+kmin) ) *
                                             ( N - static_cast<double>(2*(k+1+kmin)) + 1.0 ) * 
                                             ( N - static_cast<double>(2*(k+1+kmin)) + 2.0 ) );

        hc_locations (0, k+2*dim-1) = k+1;
        hc_locations (1, k+2*dim-1) = k;
        hc_values (k+2*dim-1) = 2.0/N*std::sqrt ( ( static_cast<double>(k+1+kmin) ) * 
                                                   ( static_cast<double>(k+1+kmin) ) *
                                                   ( N - static_cast<double>(2*(k+kmin)) ) *
                                                   ( N - static_cast<double>(2*(k+kmin)) - 1.0 ) );
    

    arma::sp_mat Ham(hc_locations, hc_values);

    // eigenvalue problem
    arma::vec eigval;
    arma::mat eigvec;

    arma::eigs_sym( eigval, eigvec, Ham, 3, "sa"); 

【问题讨论】:

【参考方案1】:

对于大小为 2000 左右的小矩阵,通常更容易找到所有特征值和特征向量,因为这些方法不太容易受到近奇异矩阵的影响。

我替换了你的代码

arma::eigs_sym( eigval, eigvec, Ham, 3, "sa"); 

arma::mat fullMat = arma::mat(Ham);
arma::eig_sym( eigval, eigvec, fullMat);

在我 2015 年末的 Macbook Pro 上,编译后的程序只需不到一秒钟的时间即可解决。

【讨论】:

我刚刚解决了这个问题。问题在于 ARPACK 库,更具体地说,Armadillo 库不允许您像原始 ARPACK 库那样指定 Krylov 基的大小和最大迭代次数。这个矩阵的最小特征值之间的距离对于 5 阶的基础来说太小了(默认犰狳 2*nev+1)。我在 fortran 中编写了类似的程序,对于矩阵大小 N=10000,我需要 90 阶的基本大小才能使用 Arnoldi 迭代收敛。 Mathematica 10.0 还允许您指定基向量的数量和最大迭代次数。它有效。

以上是关于对于太大的矩阵,特征值分解失败,犰狳 eigs_sym()的主要内容,如果未能解决你的问题,请参考以下文章

犰狳 eigs_sym:分解失败

犰狳 C++ LU 分解

矩阵的奇异值分解

在犰狳中使用相同的内存进行LU分解

qr分解怎么求特征向量,求矩阵E的特征值和特征向量

在 C++ 中返回多个矩阵(犰狳库)