使用特征减少 QR 分解

Reduced QR decomposition with eigen

我正在尝试使用 Eigen 解决 class 最小二乘问题 argmin (Ax - b)^2。我知道系统是多定的(即 m >= n,其中 A 是 m x n)并且 A 具有满秩 (n)。我选择使用 Eigen 的稀疏 QR 部分,因为 A 本身是稀疏的。我做到了这一点:

#include <Eigen/Sparse>
#include <Eigen/SparseQR>

void solve_least_squares(const Eigen::SparseMatrix<double>& matrix,
                         const Eigen::VectorXd& rhs)
{
  int m = matrix.rows();
  int n = matrix.cols();

  assert(m >= n);
  assert(matrix.isCompressed());

  Eigen::SparseQR<Eigen::SparseMatrix<double>, Eigen::COLAMDOrdering<int>> decomposition(matrix);

  Eigen::VectorXd t = (decomposition.matrixQ().transpose() * rhs).topRows(n);

  std::cout << t << std::endl;

  Eigen::VectorXd s = decomposition.matrixR().topRows(n).triangularView<Eigen::Upper>().solve(t);

  return decomposition.colsPermutation().inverse()*s;
}

但我想知道这是否是最有效的实现:首先,Eigen 似乎确定 完整 QR 分解而不是简化分解(Qm x m 而不是 m x n)。这看起来很浪费,因为我只需要前 n 行。

在密集的情况下,HouseholderQR中有任何例子 class:

MatrixXf A(MatrixXf::Random(5,3)), thinQ(MatrixXf::Identity(5,3)), Q;
A.setRandom();
HouseholderQR<MatrixXf> qr(A);
Q = qr.householderQ();
thinQ = qr.householderQ() * thinQ; // <- here
std::cout << "The complete unitary matrix Q is:\n" << Q << "\n\n";
std::cout << "The thin matrix Q is:\n" << thinQ << "\n\n";

这里使用矩阵乘法来得到缩减的Q,这似乎比对整个矩阵进行切片更低效。

由于 Eigen 的(密集)SVD 分解提供了计算薄 SVD 的选项,QR 分解是否有类似的选项?

在分解中,Q 因子存储为一系列 Householder 向量,而 matrixQ() 方法本质上是 returns 对该矩阵的引用(它以某种方式重载乘法"as if" 乘以实际矩阵)。当存储为 Householder 矩阵时,Q 表示 Q 的完整部分或薄部分没有区别(实际上,可以就地有效地用向量乘以完整矩阵)。

如果你想解决你的线性系统,你应该写

Eigen::VectorXd s = decomposition.solve(rhs);

顺便说一句:如果您不介意损失一些精度(并且您的矩阵条件足够好),您(在大多数情况下)通过求解正规方程(Matlab 符号)会更快:

x = (A'*A) \ (A'*b) 

并使用稀疏的 Cholesky 分解(例如,Eigen::SimplicialLLTEigen::SimplicialLDLT)。但是用您的实际数据进行基准测试,并检查准确性是否足以满足您的用例(可能在重新使用 Cholesky 分解的细化步骤之后)。