什么是本征中的伪表达式?

What is pseudo expression in eigen?

充分使用该术语的文档,例如

Pseudo expression providing partial reduction operations
Pseudo expression providing matrix output with given format

但我找不到它的意思。

我相信 Eigen 文档中提到的“伪表达式”实际上是“expression templates”的实例。

在 C++ 中实现诸如数学库之类的东西时,表达式模板的使用是一种常见的技术,或者在任何领域中真正的库,在这些领域中,用户会将多个计算连接在一起以构建一个值。

表达式模板的想法是,它们是一种将计算推迟到实际需要计算的方式,并允许对实际执行计算的方式进行额外程度的控制,例如如果可以在不更改输入参数的情况下逐项执行整个计算,则可能不需要为临时的可能较大的对象分配内存。

无论如何,作为 Eigen 的用户,除了一个细节之外,你不需要真正了解它对表达式模板的使用。永远不要写这样的代码:

auto to_canonical_coords = get_rotation_matrix(theta) * get_translation_matrix(offset);

问题在于对操作进行类型推导,operator* 这里,returns 一个表达式模板实例。表达式模板实例是短暂的;这样的赋值会将一个表达式模板实例赋给一个变量,它可能比它通过引用引用的对象寿命更长或导致其他问题。而是把上面的写成

Eigen::Matrix<double, 3, 3> to_canonical_coords = get_rotation_matrix(theta) * get_translation_matrix(offset);

或使用 Eigen::Matrix<double, 3, 3>.

类型别名的等效项

Eigen 文档提到了这个问题 here。我也相信 Scott Meyers 在 Effective Modern C++ 某处讨论了这个问题。

我认为示例是展示其工作原理的好方法。想象一下这样的代码片段:

void print_types(const Eigen::Matrix<double, 3, 3>& test) {
    std::cout << typeid(test).name() << "\n";
    std::cout << typeid(test.transpose()).name() << "\n";
    std::cout << typeid(test.transpose().eval()).name() << "\n";
}

如果没有 Eigen 的表达式模板编程,你会期望所有这三个都打印出同样的东西:Eigen::Matrix<double, 3, 3>.

但是转置操作实际上 不需要 直到它被使用 - 就像如果你要这样做 A.T * B,你实际上永远不会需要存储转置 A 矩阵,您可以只更改乘法条目的顺序。所以第二次打印输出的实际解压缩结果是Eigen::Transpose<Eigen::Matrix<double, 3, 3>>Eigen::Transpose<...> 的行为与普通的 Eigen::Matrix 非常相似,但实际上不需要计算转置。对于简单的 3x3 矩阵,大多数时候它可能不会有太大的改进,但对于巨型矩阵,跳过计算可以带来非常大的性能提升。

调用 .eval()(就像在第三个打印输出中一样)会将任何中间 Eigen 类型转换回实际的矩阵类型(通过实际进行计算),因此第三行将打印相同的 Eigen::Matrix<double, 3, 3>.

这也适用于其他表达式,例如 typeid(test * test + test).name(),您会看到:

Eigen::CwiseBinaryOp<Eigen::internal::scalar_sum_op<double, double>, Eigen::Product<Eigen::Matrix<double, 3, 3, 0, 3, 3>, Eigen::Matrix<double, 3, 3, 0, 3, 3>, 0> const, Eigen::Matrix<double, 3, 3, 0, 3, 3> const>

这允许 Eigen 更好地优化最终结果的计算方式,但跳过任何中间计算。

我希望这是有道理的,如果没有,请随时发表评论!