[Eigen中文文档] 深入了解 Eigen - Eigen内部发生了什么(二)

这篇具有很好参考价值的文章主要介绍了[Eigen中文文档] 深入了解 Eigen - Eigen内部发生了什么(二)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

文档总目录

英文原文(What happens inside Eigen, on a simple example)

求和表达式的构造

现在我们的向量已经构建完毕,让我们继续下一行:

u = v + w;

操作符 + 返回一个“向量之和”表达式,但实际上此时并不执行计算。执行计算的是运算符=(其调用随后发生)。

现在让我们看看 Eigen 这时做了什么:

v + w

这里,vw 的类型为 VectorXf,它是 typedef 定义的MatrixMatrixMatrixBase 的子类。所以被称为:MatrixBase::operator+(const MatrixBase&)

该运算符的返回类型是:CwiseBinaryOp<internal::scalar_sum_op<float>, VectorXf, VectorXf>

CwiseBinaryOp类是我们第一次接触到表达式模板。如前所述,操作符+本身并不执行任何计算,它只返回一个抽象的“向量和”表达式。由于还有“向量差”和“系数逐个乘积”的表达式,因此我们将它们统一为“系数逐个二元操作”,缩写为CwiseBinaryOp。 “系数逐个”表示按系数进行操作。 “二元”的意思是有两个操作数。

对于

v + w + u;

第一个v + w将返回如上所述的CwiseBinaryOp,因此为了使其编译,需要在CwiseBinaryOp类中定义一个操作符 + ,但是,难道要在每个表达式类中定义所有运算符吗,当然不可能,解决方案是CwiseBinaryOp本身,以及Matrix和所有其他表达式类型,都是MatrixBase的子类。因此,只需在MatrixBase类中定义所有运算符即可。由于MatrixBase是不同子类的共同基类,因此依赖于子类的方面必须从MatrixBase中抽象出来。这被称为多态性。

在C ++中,多态的经典方法是通过虚函数来实现的。这是动态多态性。在这里,不使用动态多态性,因为Eigen的整个设计都基于这样一个假设:所有复杂性、所有抽象都在编译时解决。这是至关重要的:如果抽象无法在编译时解决,Eigen的编译时优化机制就会变得无用,更不用说如果该抽象必须在运行时解决,那么它本身就会产生开销。

在这里,想要的是将单个MatrixBase类作为许多子类的基类,以这样的方式,使得每个MatrixBase对象(无论是矩阵、向量还是任何类型的表达式)在编译时(而不是运行时)知道它是哪个特定的子类对象(即它是矩阵、表达式,以及是什么类型的表达式)。

解决方案是递归模板模式(Curiously Recurring Template Pattern)。

简而言之,MatrixBase采用模板参数Derived。每定义一个子类子类(Subclass),我们实际上是让Subclass继承MatrixBase<Subclass>。关键在于不同的子类继承不同类型的MatrixBase。由于这个原因,每当我们有一个子类的对象,并调用它的一些MatrixBase方法时,即使在 MatrixBase 方法内部,我们仍然记得我们正在讨论哪个特定子类。

这意味着我们可以将几乎所有的方法和运算符放在基类MatrixBase中,并在子类中只保留最少的方法。如果你看一下Eigen中的子类,比如CwiseBinaryOp类,它们只有很少的方法。有coeff()和有时返回系数的coeffRef()方法,有返回行数和列数的rows()cols()方法,但并没有更多的方法。所有的基础方法都在MatrixBase中,因此它只需要为所有类型的表达式、矩阵和向量编写一次即可。

那么,让我们结束这个题外话,回到我们当前正在分析的示例程序中的代码片段:

v + w

现在我们对 MatrixBase 已经很熟悉了,让我们完整地编写此处调用的运算符+的原型(此代码来自 src/Core/MatrixBase.h):

template<typename Derived>
class MatrixBase
{
    // ...

    template<typename OtherDerived>
    const CwiseBinaryOp<internal::scalar_sum_op<typename internal::traits<Derived>::Scalar>, Derived, OtherDerived>
    operator+(const MatrixBase<OtherDerived> &other) const;

    // ...
};

这里的DerivedOtherDerived都是VectorXf

正如我们所说,CwiseBinaryOp也用于其他操作,例如减法,因此它需要另一个模板参数来确定将应用于系数的操作。这个模板参数是一个函数对象(functor),也就是说,它是一个具有operator()的类,因此它的行为类似于函数。在这里,使用的函数对象是internal::scalar_sum_op。它定义在src/Core/Functors.h中。

现在让我们解释一下internal::traitsinternal::scalar_sum_op类需要一个模板参数:要处理的数字类型。当然,在这里我们想传递VectorXf的标量类型(即数字类型),它是float。我们如何确定Derived的标量类型呢?在整个Eigen中,所有的矩阵和表达式类型都定义了一个typedef Scalar,它给出了它的标量类型。例如,VectorXf::Scalarfloattypedef。因此,在这里,如果一切都很简单,我们可以找到Derived的数字类型,如下所示:

typename Derived::Scalar

不幸的是,在这里我们无法这样做,因为编译器会报错,类型Derived还没有定义。因此,我们使用一个变通办法:在src/Core/util/ForwardDeclarations.h中,我们声明(而不是定义!)了所有的子类,比如Matrix,还声明了以下类模板:

template<typename T> struct internal::traits;

在src/Core/Matrix.h中,在定义类Matrix之前,我们为T=Matrix<任意模板参数>定义了internal::traits的部分特化。在这个特化版本中,我们定义了Scalar typedef。因此,当我们实际定义Matrix时,使用 typename internal::traits<Matrix>::Scalar 这样的语句是合法的。

无论如何,我们已经声明了我们的操作符 +。在我们的情况下,DerivedOtherDerived都是VectorXf,因此上述声明相当于:

class MatrixBase<VectorXf>
{
    // ...

    const CwiseBinaryOp<internal::scalar_sum_op<float>, VectorXf, VectorXf>
    operator+(const MatrixBase<VectorXf> &other) const;

    // ...
};

让我们现在跳到src/Core/CwiseBinaryOp.h来看它是如何定义的。它所做的就是返回一个CwiseBinaryOp对象,而这个对象只是存储了对左侧和右侧表达式的引用,CwiseBinaryOp对象也存储了一个(空)函数对象的实例,这里不必在意,因为这只是一个次要的实现细节。

因此,操作符+没有执行任何实际的计算。总之,操作v + w只是返回了一个CwiseBinaryOp类型的对象,它仅仅是存储了对vw的引用而已。文章来源地址https://www.toymoban.com/news/detail-543571.html

到了这里,关于[Eigen中文文档] 深入了解 Eigen - Eigen内部发生了什么(二)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [Eigen中文文档] 矩阵与向量运算

    专栏总目录 英文原文(Matrix and vector arithmetic) 本文章旨在提供有关如何使用 Eigen 在矩阵、向量和标量之间执行算术操作的概述和一些详细信息。 介绍 Eigen 通过重载常见的 C++ 算术运算符(如 + 、 - 、 * )或通过特殊方法(如 dot() 、 cross() 等)提供矩阵/向量算术运算。对于

    2024年01月24日
    浏览(48)
  • [Eigen中文文档] 线性代数与分解

    文档总目录 英文原文(Linear algebra and decomposition) 本节说明如何求解线性系统,计算各种分解,如 LU 、 QR 、 SVD 、 特征分解 …… 求解基本线性系统 问题 :有一个方程组,写成矩阵方程如下: A x = b Ax = b A x = b 其中 A A A 和 b b b 是矩阵(作为一种特殊情况, b b b 也可以是一个

    2024年02月07日
    浏览(42)
  • “深入剖析JVM内部机制:了解Java虚拟机的工作原理“

    标题:深入剖析JVM内部机制:了解Java虚拟机的工作原理 摘要:本文将深入剖析JVM内部机制,详细介绍Java虚拟机的工作原理。我们将探讨JVM的组成部分、类加载过程、内存管理、垃圾回收以及即时编译等关键概念。此外,还将提供示例代码来帮助读者更好地理解JVM的内部机制

    2024年02月11日
    浏览(42)
  • 深入了解HTTP 500内部服务器错误的原因及解决方法

    HTTP 状态代码提供有关在线请求是否成功的信息,如果不成功,则错误是什么。 但是错误消息并不总是很清楚。 “500 内部服务器错误”尤其如此。 此消息表示在连接到服务器期间发生错误,并且无法访问所请求的页面。 但是,它不会告诉你为什么会这样。 幸运的是,有不

    2024年02月08日
    浏览(57)
  • 深入 Hyperf:HTTP 服务启动时发生了什么?

    当我们创建 Hyperf 项目之后,只需要在终端执行 php bin/hyperf.php start 启动命令,等上几秒钟,就可以看到终端输出的 Worker 进程已启动,HTTP 服务监听在 9501 端口的日志信息。 打开浏览器访问 http://127.0.0.1:9501 ,不出意外的话,页面会显示 Hello Hyperf ,说明 HTTP 服务已经在工作了

    2024年02月05日
    浏览(29)
  • MySQL 篇-深入了解索引的内部结构(哈希表、红黑树与 B+ 树)

    🔥博客主页: 【 小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍    文章目录         1.0 索引概述         2.0 索引内部结构特点         2.1 那么哪些数据结构,能够加快查询速度呢?         2.2 二叉搜索树、AVL 树存储结构特点         2.3 红黑树存储结构

    2024年03月14日
    浏览(53)
  • 记录--让我们来深入了解一下前端“三清”是什么

    在前端开发中,我们经常听到关于“三清”的说法,即 window 、 document 、 Object 。这三者分别代表了 BOM(浏览器对象模型)、DOM(文档对象模型)以及 JS 的顶层对象。在这个体系中,我们通过 JavaScript 与浏览器进行深度交互,构建出丰富多彩的网页应用。同时,JS 类也是前端

    2024年02月05日
    浏览(56)
  • 什么是云仓?如何深入了解云仓?云仓运营模式是怎样?

    云仓简单来说就是一种较为先进的第三方仓储,与传统的电商仓库不同的是“云”。“云”就是最近几年特别流行的“云计算”,云仓说白了是在软件上利用云计算以及现代管理方式,硬件上依托仓储设施进行货物流通的一个第三方仓储物流。 云仓的优势近近几年都已经被体

    2024年02月13日
    浏览(42)
  • 什么是认沽期权,深入了解认沽期权的特性与运作方式

    上证50ETF认沽期权和认购期权一样,是我们在进行上证50ETF期权投资的时候必须要做出选择的两个选项。认购期权和认沽期权实际上是做多和做空,现在我们来看看什么是认沽期权,深入了解认沽期权的特性与运作方式。 什么是认沽期权? 一、认沽期权的定义: 认沽期权,又

    2024年01月16日
    浏览(50)
  • 无线路由器1、2、3根天线有什么区别?深入了解MIMO技术的神奇

    前言 “天线越多覆盖越广,天线越多信号越强,总之天线越多路由就越好”——觉得很“常识”的朋友可以继续往下看正文了,觉得小编弱爆了小编是那个什么的估计也不会点进来。还是那句话,我们的干货帖大多数是为了扫盲,欢迎各位大神补充、指正。 首先,大家也应

    2024年02月06日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包