为什么Eigen对别名的默认假设不一致?

Mus*_*ful 8 c++ eigen eigen3

作为Eigen的新手,我要努力应对一些问题。

使用矩阵乘法,Eigen默认情况下会创建一个临时文件以避免混叠问题:

matA = matA * matA; // works fine (Eigen creates a temporary before assigning)
Run Code Online (Sandbox Code Playgroud)

如果可以安全地假定没有混叠,则可以使用.noalias()进行优化:

matB = matA * matA; // sub-optimal (due to unnecessary temporary)
matB.noalias() = matA * matA; // more efficient
Run Code Online (Sandbox Code Playgroud)

因此,Eigen在默认情况下会避免做出不安全的假设,除非明确告诉您可以假设没有混叠是安全的。到目前为止,一切都很好。

但是,对于许多其他表达式,例如a = a.transpose()Eigen,默认情况下会做出不安全的假设(没有混叠问题),并且需要显式干预以避免该不安全的假设:

a = a.transpose().eval(); // or alternatively: a.transposeInPlace()
Run Code Online (Sandbox Code Playgroud)

因此,如果我们关注效率,则仅当存在潜在的混叠时才注意不够,而在没有潜在的混叠时则不足以注意。我们必须要小心,当有潜在的混淆,并且在没有潜在的混淆,并决定一个特殊的干预措施是有保证的基础上,表达是否涉及矩阵乘法与否。在Eigen中,对于Eigen界面中的这种“默认期望混合”是否有一些设计依据?

Mat*_*att 2

这些评论提供了问题的答案,总结如下:

Eigen 文档有效地提到您不应该这样做a = a.transpose(),但他们也提到 Eigen 使用运行时断言来检测这一点并退出并显示一条消息。问题在于,正如他们所说,一般来说,在编译时无法检测到别名,并且他们更注重效率。b = a.transpose()在创建临时对象时执行操作效率非常低。

本质上,这是一种设计选择。一般来说,本征更喜欢效率,但矩阵乘积是意外混叠的常见来源(并且额外的副本通常比乘积便宜得多)。为了转置更好的使用a.transposeInPlace();。大多数其他表达式几乎没有别名问题,例如,当添加两个矩阵时,只有访问重叠(但不相等)的内存区域才会出现问题。

理由很简单,产品比临时创建 + O(n^2) 复制要昂贵得多。是的,Eigen 就像任何其他 BLAS 库一样,使用 O(n^3) 矩阵乘积算法。理论上,更高效的算法可以带来巨大的乘积(n>3000 甚至更多),更重要的是,它们会在浮点运算(浮点/双精度)时产生巨大且不可接受的舍入误差。

这个决定是在 Eigen 开发的早期阶段做出的,10 年后我宁愿无条件假设没有混叠以保持一致性。