Eigen C ++;就地矩阵乘法

时间:2018-01-17 08:14:11

标签: c++ performance matrix eigen3

使用 Eigen C ++ Matrix库,如何有效地使用它 将 n x n 矩阵 A n x m 矩阵 B 相乘 并将结果存储在 A 中?也就是说,我该怎样才能避免 生成一个临时的 n x m 矩阵,而不是存储 结果直接在 B

对于 m 非常大的应用程序(例如100000) 比 n (例如3),这绝对有意义,因为它避免了 应用非常大的阵列。

以下代码,我无法开始工作:

#define FOO 2

我认为,内部必须发生的事情是 下列。 B 的每一列应单独处理。 必须将正在考虑的列 B.noalias() = A * B; 复制到备份中 专栏column_i。然后,

column_tmp

适用于所有 B(row_i, column_i) = A.row(row_i) * column_tmp; // dot-product = 0到m 。在 Eigen 中有没有办法做到这一点 有效地从优化中获利?

3 个答案:

答案 0 :(得分:4)

告诉Eigen你希望产品“就地”发生的最明显方式可能是:

B.transpose() *= A.transpose();
// or B.applyOnTheLeft(A);

说,不能保证这不会导致任何临时,你必须相信内部的本征成本逻辑(Eigen设计师可能知道更好:) ...或检查通过适当的分析表明这是一个真正的问题,而不仅仅是过早的优化),它通过调试器自己完成。

在我的Eigen副本(3.2.7)上,上面直接在MatrixBase::applyThisOnTheRight表达式上调用Transpose,这反过来又可能在内部减少到B=A*B;与applyOnTheLeft相同,所以在这种情况下你运气不好。

如果你真的需要避免任何 nxm临时,你可以手动执行产品,例如:

for(auto i=0;i<B.cols();++i)
    B.col(i) = A * B.col(i);
假设B.rows()&lt;&lt; B.cols(),这将消耗更少的额外内存, 但是你可能会错过一些重要的优化;事实上,我想暂时还是可以在这里做出最好的权衡。

答案 1 :(得分:2)

是的3x3倍3xHuge你的逐列评估确实有意义,但不是一般情况下。例如,如果n = m = 1000,那么逐列评估将比当前的本征逻辑慢几个数量级。

如果你写:

B.noalias() = A * B;

Eigen将遵循col-by-col评估(因为A在编译时很小),但结果将是错误的,因为B确实是别名,基本上它会生成:

for j = 0..m-1
  B.col(j).noalias() = A * B.col(j);

为了优雅地解决这个问题,我们需要一种方式来说只有不同的列不能别名...建议:

B.transpose() *= A.transpose();

确实是一个选项,让Eigen在编译时知道这种信息,虽然必须转置双方有点麻烦。并且需要在Eigen方面实施适当的评估逻辑。目前,此信息未被利用。

答案 2 :(得分:1)

B.noalias() = A * B;的示例与“#34”不匹配&#34;将结果存储在A&#34;中。 所需要的只是A *= B;。如果你改为打算覆盖B,那么你撒谎 .noalias()