[Eigen中文文档] 无矩阵求解器

简介: 本文介绍Eigen的无矩阵求解器。

文档总目录

英文原文(Matrix-free solvers)

ConjugateGradientBiCGSTAB 等迭代求解器可以在无矩阵环境中使用。为此,用户必须提供一个继承 EigenBase<> 并实现以下方法的封装类:

  • Index rows()Index cols():分别返回行数和列数
  • 运算符 * 与类型和 Eigen 稠密列向量(其实际实现属于 internal::generic_product_impl 类的专门化)

Eigen::internal::traits<> 也必须专门针对封装类型。

封装 Eigen::SparseMatrix 的完整示例如下:

#include <iostream>
#include <Eigen/Core>
#include <Eigen/Dense>
#include <Eigen/IterativeLinearSolvers>
#include <unsupported/Eigen/IterativeSolvers>

class MatrixReplacement;
using Eigen::SparseMatrix;

namespace Eigen {
   
namespace internal {
   
  // MatrixReplacement looks-like a SparseMatrix, so let's inherits its traits:
  template<>
  struct traits<MatrixReplacement> :  public Eigen::internal::traits<Eigen::SparseMatrix<double> >
  {
   };
}
}

// Example of a matrix-free wrapper from a user type to Eigen's compatible type
// For the sake of simplicity, this example simply wrap a Eigen::SparseMatrix.
class MatrixReplacement : public Eigen::EigenBase<MatrixReplacement> {
   
public:
  // Required typedefs, constants, and method:
  typedef double Scalar;
  typedef double RealScalar;
  typedef int StorageIndex;
  enum {
   
    ColsAtCompileTime = Eigen::Dynamic,
    MaxColsAtCompileTime = Eigen::Dynamic,
    IsRowMajor = false
  };

  Index rows() const {
    return mp_mat->rows(); }
  Index cols() const {
    return mp_mat->cols(); }

  template<typename Rhs>
  Eigen::Product<MatrixReplacement,Rhs,Eigen::AliasFreeProduct> operator*(const Eigen::MatrixBase<Rhs>& x) const {
   
    return Eigen::Product<MatrixReplacement,Rhs,Eigen::AliasFreeProduct>(*this, x.derived());
  }

  // Custom API:
  MatrixReplacement() : mp_mat(0) {
   }

  void attachMyMatrix(const SparseMatrix<double> &mat) {
   
    mp_mat = &mat;
  }
  const SparseMatrix<double> my_matrix() const {
    return *mp_mat; }

private:
  const SparseMatrix<double> *mp_mat;
};


// Implementation of MatrixReplacement * Eigen::DenseVector though a specialization of internal::generic_product_impl:
namespace Eigen {
   
namespace internal {
   

  template<typename Rhs>
  struct generic_product_impl<MatrixReplacement, Rhs, SparseShape, DenseShape, GemvProduct> // GEMV stands for matrix-vector
  : generic_product_impl_base<MatrixReplacement,Rhs,generic_product_impl<MatrixReplacement,Rhs> >
  {
   
    typedef typename Product<MatrixReplacement,Rhs>::Scalar Scalar;

    template<typename Dest>
    static void scaleAndAddTo(Dest& dst, const MatrixReplacement& lhs, const Rhs& rhs, const Scalar& alpha)
    {
   
      // This method should implement "dst += alpha * lhs * rhs" inplace,
      // however, for iterative solvers, alpha is always equal to 1, so let's not bother about it.
      assert(alpha==Scalar(1) && "scaling is not implemented");
      EIGEN_ONLY_USED_FOR_DEBUG(alpha);

      // Here we could simply call dst.noalias() += lhs.my_matrix() * rhs,
      // but let's do something fancier (and less efficient):
      for(Index i=0; i<lhs.cols(); ++i)
        dst += rhs(i) * lhs.my_matrix().col(i);
    }
  };

}
}

int main()
{
   
  int n = 10;
  Eigen::SparseMatrix<double> S = Eigen::MatrixXd::Random(n,n).sparseView(0.5,1);
  S = S.transpose()*S;

  MatrixReplacement A;
  A.attachMyMatrix(S);

  Eigen::VectorXd b(n), x;
  b.setRandom();

  // Solve Ax = b using various iterative solver with matrix-free version:
  {
   
    Eigen::ConjugateGradient<MatrixReplacement, Eigen::Lower|Eigen::Upper, Eigen::IdentityPreconditioner> cg;
    cg.compute(A);
    x = cg.solve(b);
    std::cout << "CG:       #iterations: " << cg.iterations() << ", estimated error: " << cg.error() << std::endl;
  }

  {
   
    Eigen::BiCGSTAB<MatrixReplacement, Eigen::IdentityPreconditioner> bicg;
    bicg.compute(A);
    x = bicg.solve(b);
    std::cout << "BiCGSTAB: #iterations: " << bicg.iterations() << ", estimated error: " << bicg.error() << std::endl;
  }

  {
   
    Eigen::GMRES<MatrixReplacement, Eigen::IdentityPreconditioner> gmres;
    gmres.compute(A);
    x = gmres.solve(b);
    std::cout << "GMRES:    #iterations: " << gmres.iterations() << ", estimated error: " << gmres.error() << std::endl;
  }

  {
   
    Eigen::DGMRES<MatrixReplacement, Eigen::IdentityPreconditioner> gmres;
    gmres.compute(A);
    x = gmres.solve(b);
    std::cout << "DGMRES:   #iterations: " << gmres.iterations() << ", estimated error: " << gmres.error() << std::endl;
  }

  {
   
    Eigen::MINRES<MatrixReplacement, Eigen::Lower|Eigen::Upper, Eigen::IdentityPreconditioner> minres;
    minres.compute(A);
    x = minres.solve(b);
    std::cout << "MINRES:   #iterations: " << minres.iterations() << ", estimated error: " << minres.error() << std::endl;
  }
}

输出:

CG:       #iterations: 20, estimated error: 8.86333e-14
BiCGSTAB: #iterations: 20, estimated error: 2.10809e-15
GMRES:    #iterations: 10, estimated error: 0
DGMRES:   #iterations: 20, estimated error: 1.10455e-28
MINRES:   #iterations: 20, estimated error: 2.94473e-14
相关文章
|
缓存 测试技术 编译器
[Eigen中文文档] 稠密矩阵分解函数对比
本文介绍了 Eigen 为各种方阵和过约束问题提供的稠密矩阵分解的速度比较。
133 0
|
XML 并行计算 算法
[Eigen中文文档] 求解稀疏线性系统
在Eigen中,有多种方法可用于求解稀疏系数矩阵的线性系统。由于此类矩阵的特殊表示,必须特别小心以获得良好的性能。本文列出了Eigen中可用的稀疏求解器。还介绍了所有这些线性求解器共同的主要步骤。根据矩阵的属性、所需的准确度,最终用户可以调整这些步骤以提高其代码的性能。请注意,并不需要深入了解这些步骤背后的内容:最后一节介绍了一个基础例程,可轻松使用以获取所有可用求解器的性能洞察。
340 0
|
并行计算 算法 测试技术
[Eigen中文文档] 稠密分解方法目录
本文介绍了 Eigen 提供的处理稠密矩阵分解方法的目录。
137 0
|
6月前
|
机器学习/深度学习 算法 搜索推荐
SciPy线性代数库详解:矩阵运算与方程求解
【4月更文挑战第17天】SciPy的`scipy.linalg`模块提供丰富的线性代数功能,包括矩阵运算、线性方程组求解、特征值问题和奇异值分解等,基于BLAS和LAPACK库确保效率与稳定性。关键操作如矩阵乘法使用`dot`函数,转置和共轭转置用`transpose`和`conj`,求解线性方程组有`solve`和迭代方法,计算特征值和向量用`eig`,奇异值分解则依赖`svd`。这个库对科学计算、数据分析和机器学习等领域至关重要。
|
存储
[Eigen中文文档] 就地矩阵分解
从 Eigen 3.3 开始,LU、Cholesky 和 QR 分解可以就地操作,即直接在给定的输入矩阵内操作。当处理大矩阵时,或者当可用内存非常有限(嵌入式系统)时,此功能特别有用。
106 0
|
存储 算法 NoSQL
[Eigen中文文档] 稀疏矩阵操作
在许多应用中(例如,有限元方法),通常要处理非常大的矩阵,其中只有少数系数不为零。在这种情况下,可以通过使用仅存储非零系数的特殊表示来减少内存消耗并提高性能。这样的矩阵称为稀疏矩阵。
463 0
|
6月前
|
算法 Java
行列式表示只需3步,快速掌握矩阵运算!
行列式表示只需3步,快速掌握矩阵运算!
72 0
|
安全 编译器 C++
[Eigen中文文档] 矩阵与向量运算
本文章旨在提供有关如何使用 Eigen 在矩阵、向量和标量之间执行算术操作的概述和一些详细信息。
390 0
|
测试技术
[Eigen中文文档] 线性代数与分解
本节将说明如何求解线性系统,计算各种分解,如 LU、QR、SVD、特征分解……
228 0
[Eigen中文文档] 求解线性最小二乘系统
本文介绍如何使用 Eigen 求解线性最小二乘系统。 本文讨论三种方法 SVD 分解、QR 分解和正规方程。其中,SVD 分解通常最准确但最慢,正规方程式最快但最不准确,QR 分解介于两者之间。
256 0