[Eigen中文文档] 深入了解 Eigen - 类层次结构

简介: 本页面介绍了Eigen类层次结构中 Core 类的设计及其相互关系。一般用户可能不需要关注这些细节,但对于高级用户和Eigen开发人员可能会有用。

文档总目录

英文原文(The class hierarchy)

本页面介绍了Eigen类层次结构中 Core 类的设计及其相互关系。一般用户可能不需要关注这些细节,但对于高级用户和Eigen开发人员可能会有用。

原则

Eigen的类层次结构的设计是为了避免虚函数的开销会严重影响性能。相反,Eigen使用奇怪递归模板模式(Curiously Recurring Template Pattern,CRTP)实现多态性。在这个模式中,基类(比如MatrixBase)本质上是一个模板类,派生类(比如Matrix)继承了基类,派生类本身作为模板参数(在这种情况下,MatrixMatrixBase<Matrix>继承)。这样,Eigen可以在编译时解析多态函数调用。

此外,该设计避免了多继承。其中一个原因是,根据我们的经验,一些编译器(如MSVC)无法执行空基类优化,而这对于我们的固定大小类型至关重要。

Core 类

如果你想编写接受或返回Eigen对象的函数,那么你需要了解以下类:

  • Matrix:是指密集的平面矩阵。如果m是一个矩阵,那么例如m+m不再是一个矩阵,它是一个“矩阵表达式”。
  • MatrixBase:指的是密集矩阵表达式。这意味着MatrixBase是可以进行加法、矩阵乘法、LU分解、QR分解等操作的。所有的矩阵表达式类,包括Matrix本身,都继承自MatrixBase
  • Array:指的是普通的密集数组。如果x是一个Array,那么例如x+x就不再是一个Array,而是一个"数组表达式"。
  • ArrayBase:指的是密集数组表达式。这意味着ArrayBase是可以相加、数组乘法以及执行各种数组操作的表达式。所有的数组表达式类,包括Array本身,在继承时都会继承ArrayBase
  • DenseBase:指的是密集(矩阵或数组)表达式。ArrayBaseMatrixBase都继承自DenseBaseDenseBase是所有方法的集合,这些方法适用于密集表达式,无论是矩阵还是数组表达式。例如,block(...)方法就属于DenseBase

基类

这些类是上述五个核心(Core)类的基类。它们更多是内部使用,对于使用Eigen库的用户来说不太常见。

  • PlainObjectBase:表示密集(矩阵或数组)的普通对象,即存储其自己的密集系数数组的对象。例如,resize()方法就在这里。PlainObjectBaseMatrixArray继承。但是,上面我们说Matrix继承了MatrixBaseArray继承了ArrayBase。那么这是否意味着多重继承?不是的,因为PlainObjectBase本身会根据我们是处于矩阵还是数组情形而继承MatrixBaseArrayBase。当我们说Matrix通过PlainObjectBase间接继承MatrixBase时,我们省略了这一点。Array也是同理。

  • DenseCoeffsBase:表示具有密集系数访问器的对象。它是DenseBase的一个基类。DenseCoeffsBase存在的原因是,可用系数访问器的集合取决于密集表达式是否具有直接访问内存的能力(DirectAccessBit标志)。例如,如果x是一个普通矩阵,则x具有直接访问,x.transpose()x.block(...)也具有直接访问,因为它们的系数可以直接从内存中读取,但是x+x没有直接内存访问,因为获取它的任何系数都需要计算(加法),不能直接从内存中读取。

  • EigenBase:表示任何可以计算为普通密集矩阵或数组的东西(即使这可能不是一个好主意)。EigenBase实际上是任何类似于矩阵或数组的东西的绝对基类。它是DenseCoeffsBase的一个基类,因此它位于我们所有密集类的层次结构之下,但它并不限于密集表达式。例如,EigenBase也被对角矩阵、稀疏矩阵等继承。

继承图

Matrix 的继承图如下所示:

EigenBase<Matrix>
  <-- DenseCoeffsBase<Matrix>    (direct access case)
    <-- DenseBase<Matrix>
      <-- MatrixBase<Matrix>
        <-- PlainObjectBase<Matrix>    (matrix case)
          <-- Matrix

Array 的继承图如下所示:

EigenBase<Array>
  <-- DenseCoeffsBase<Array>    (direct access case)
    <-- DenseBase<Array>
      <-- ArrayBase<Array>
        <-- PlainObjectBase<Array>    (array case)
          <-- Array

另一个矩阵表达式类的继承图如下,此处用SomeMatrixXpr表示:

EigenBase<SomeMatrixXpr>
  <-- DenseCoeffsBase<SomeMatrixXpr>    (direct access or no direct access case)
    <-- DenseBase<SomeMatrixXpr>
      <-- MatrixBase<SomeMatrixXpr>
        <-- SomeMatrixXpr

另一个数组表达式类的继承图如下,此处用SomeMatrixXpr表示:

EigenBase<SomeArrayXpr>
  <-- DenseCoeffsBase<SomeArrayXpr>    (direct access or no direct access case)
    <-- DenseBase<SomeArrayXpr>
      <-- ArrayBase<SomeArrayXpr>
        <-- SomeArrayXpr

最后,一个不是密集表达式的示例,例如对角矩阵。相应的继承图如下:

EigenBase<DiagonalMatrix>
  <-- DiagonalBase<DiagonalMatrix>
    <-- DiagonalMatrix
相关文章
|
8月前
|
并行计算 算法 测试技术
[Eigen中文文档] 稠密分解方法目录
本文介绍了 Eigen 提供的处理稠密矩阵分解方法的目录。
76 0
|
8月前
|
C++
[Eigen中文文档] 按值将Eigen对象传递给函数
对于 Eigen,这一点更为重要:按值传递固定大小的可向量化 Eigen 对象不仅效率低下,而且可能是非法的或使程序崩溃! 原因是这些 Eigen 对象具有对齐修饰符,在按值传递时会不遵守这些修饰符。
71 0
|
8月前
|
存储 C语言 C++
|
8月前
|
存储 编译器
|
8月前
|
存储 算法 NoSQL
[Eigen中文文档] 稀疏矩阵操作
在许多应用中(例如,有限元方法),通常要处理非常大的矩阵,其中只有少数系数不为零。在这种情况下,可以通过使用仅存储非零系数的特殊表示来减少内存消耗并提高性能。这样的矩阵称为稀疏矩阵。
222 0
|
8月前
[Eigen中文文档] 编写以特征类型为参数的函数(一)
Eigen使用表达式模板的方式导致每个表达式的类型可能都不同。如果将这样的表达式传递给一个需要Matrix类型参数的函数,则表达式将隐式地被评估为一个临时Matrix,然后再传递给函数。这意味着失去了表达式模板的好处。
81 0
|
8月前
|
存储 索引
[Eigen中文文档] 扩展/自定义Eigen(三)
本页面针对非常高级的用户,他们不害怕处理一些Eigen的内部细节。在大多数情况下,可以通过使用自定义一元或二元函数避免使用自定义表达式,而极其复杂的矩阵操作可以通过零元函数(nullary-expressions)来实现,如前一页所述。 本页面通过示例介绍了如何在Eigen中实现新的轻量级表达式类型。它由三个部分组成:表达式类型本身、包含有关表达式编译时信息的特性类和评估器类,用于将表达式评估为矩阵。
67 1
|
8月前
|
存储 对象存储 索引
[Eigen中文文档] 扩展/自定义Eigen(二)
CwiseNullaryOp 类的主要目的是定义过程矩阵,例如由Ones()、Zero()、Constant()、Identity()和Random()方法返回的常量或随机矩阵。然而,通过一些想象力,可以用最小的努力实现非常复杂的矩阵操作,因此很少需要实现新的表达式。
69 0
|
8月前
|
测试技术 API C++
[Eigen中文文档] 扩展/自定义Eigen(一)
在本节中,将介绍如何向MatrixBase添加自定义方法。由于所有表达式和矩阵类型都继承自MatrixBase,因此将方法添加到MatrixBase会立即使其对所有表达式可用!一个典型的用例是,使Eigen与另一个API兼容。
111 0
|
8月前
|
存储 编译器 对象存储
[Eigen中文文档] 包含Eigen对象的结构体
如果定义的结构体包含固定大小的可向量化 Eigen 类型成员,则必须确保对其调用 operator new 来分配正确的对齐缓冲区。如果仅使用足够新的编译器(例如,GCC>=7、clang>=5、MSVC>=19.12)以 [c++17] 模式编译,那么编译器会自动处理所有事情,可以跳过本节。 否则,必须重载它的 operator new 以便它生成正确对齐的指针(例如,Vector4d 和 AVX 的 32 字节对齐)。幸运的是,Eigen 为提供了一个宏 EIGEN_MAKE_ALIGNED_OPERATOR_NEW 来完成这项工作。
122 0