犰狳 eigs_sym:分解失败

Posted

技术标签:

【中文标题】犰狳 eigs_sym:分解失败【英文标题】:Armadillo eigs_sym: decomposition failed 【发布时间】:2017-06-08 23:25:48 【问题描述】:

我正在 Visual Studio 中编写 C++ 代码并使用 Armadillo 7.900.1

我无法让 eigs_sym 函数在 Armadillo 下工作(我使用的是 Armadillo 附带的 lapack 和 blas 版本)。典型的错误信息如下:

error: lapack::stedc(): failed to compute all eigenvalues
warning: eigs_sym(): decomposition failed

产生这个输出的代码是:

sp_mat T(locations, values);
arma::eigs_sym(eigval, eigvec, T, num_eigs_wanted, "sm", tol);

在哪里

T is a 480,000x480,000 sparse matrix. 

如果 T 很小(即 2000x2000)并且 tol 很高(tol = 5),我可以让代码工作。但是一旦 T 约为 20000x20000,那么无论使用什么 tol 或 num_eigs_wanted 值都会出现上述错误。 (我显然改变了“值”和位置”来改变 T 的大小)。

矩阵 T 是对称的、实数的、正定的。

当我在Matlab中调用eigs函数时,完全相同的矩阵没有问题。

有什么想法吗?在我看来,犰狳中的 eigs_sym 似乎被破坏了......人们使用过任何替代品吗?

干杯

【问题讨论】:

你用的是哪个矩阵? 您确定要最小幅度"sm" 特征值吗?它们通常是垃圾并且难以可靠地计算。将"sm" 更改为"lm" 以获得最大幅度(如documentation 中所述)。如果你真的想要最小的,增加想要的特征值的数量:***.com/questions/36059755/… 不——我要求最小的是有原因的。无论如何它不应该工作吗?如果您必须知道,它也不适用于“lm”......相同的错误响应 【参考方案1】:

不是答案,但评论太长了。我可以用下面的代码重现。该矩阵只是一个对角矩阵,对角线上的值从 1 开始递增。特征值显然是 1,2,3,...,并且矩阵是正定且对称的。

#include <iostream>
#include <armadillo>

int main()

  constexpr int N = 20000;
  arma::umat locations(2,N);
  arma::vec values(N);

  for (int i = 0; i < N; ++i)
  
    locations(0,i) = i;
    locations(1,i) = i;
    values(i) = i+1;
  

  arma::sp_mat T(locations, values);

  int num_eigs_wanted = 1;
  arma::vec eigval(num_eigs_wanted);
  arma::mat eigvec(N,num_eigs_wanted);
  double tol = 1e-6;
  arma::eigs_sym(eigval, eigvec, T, num_eigs_wanted, "sm", tol);

  std::cout << eigval << '\n';

编译器标志是

clang++-5.0 -std=c++11 test.cpp -larmadillo

我正在使用带有 MKL 后端的犰狳,我收到了:

warning: eigs_sym(): decomposition failed
[matrix size: 0x1]

这似乎是犰狳的问题,因为当我使用 Eigen 的不受支持的 Arpack 支持时,它工作得很好。

#include <iostream>
#include <Eigen/Sparse>
#include <unsupported/Eigen/ArpackSupport>

int main()

  constexpr int N = 20000;

  std::vector< Eigen::Triplet<double> > triplets;
  triplets.reserve(N);
  for (int i = 0; i < N; ++i)
    triplets.push_back( i,i,i+1 );

  Eigen::SparseMatrix<double> T(N,N);
  T.setFromTriplets(triplets.begin(), triplets.end());

  int num_eigs_wanted = 1;
  double tol = 1e-6;
  Eigen::ArpackGeneralizedSelfAdjointEigenSolver< Eigen::SparseMatrix<double> > eigs_sym;
  eigs_sym.compute(T, num_eigs_wanted, "SM", Eigen::ComputeEigenvectors, tol);
  std::cout << eigs_sym.eigenvalues() << '\n';

您可能还想看看https://github.com/yixuan/spectra/

【讨论】:

干杯! - 快速玩过 Spectra。看起来这可能是最好的解决方案。谢谢。将更新我的进度。【参考方案2】:

感谢@Henri 的所有帮助! Spectra (https://spectralib.org) 是必经之路!

在大小为 480,000 x 480,000 的稀疏矩阵上使用 SymEigsSolver 进行特征值/向量分解需要 3 分 50 秒(i7/16GB RAM)。

大小为 120,000x120,000 的稀疏矩阵需要 20 秒。

没有稳定性问题,程序员可以直接访问 Arnoldi 算法、Ritz 值和公差阈值。

由于 Spectra 完全基于标头,因此也易于使用。只需#include 头文件 - 很简单。您还需要 Eigen,它也可以在上述地址获得(并且它也是基于标头的)。

【讨论】:

以上是关于犰狳 eigs_sym:分解失败的主要内容,如果未能解决你的问题,请参考以下文章

犰狳 C++ LU 分解

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

在犰狳 C++ 中为复杂特征值分解找到不同的值

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

无法使用 Distributions.jl 拟合 MvNormal 分布。错误:PosDefException:矩阵不是正定的; Cholesky 分解失败

矩阵的LU分解