艾根C++;就地矩阵乘法

Eigen C++; In-place matrix multiplication

本文关键字:C++ 艾根      更新时间:2023-10-16

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

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

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

B.noalias() = A * B;

我认为,内部必须发生的事情是 以下。B的每一列都应单独处理。 必须将考虑column_i列复制到备份 列column_tmp.然后

B(row_i, column_i) = A.row(row_i) * column_tmp; // dot-product

对于所有column_i=0 到 m。有没有办法在特征中做到这一点 高效并从其优化中获利?

告诉 Eigen 您希望产品"就地"发生的最明确方式可能是:

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

也就是说,不能保证这不会在任何临时情况下产生,您必须为此信任内部特征成本逻辑(特征设计师可能更了解:)......或者通过调试器自己检查,在适当的分析表明这是一个真正的问题而不仅仅是过早的优化之后)。

在我的 Eigen 副本 (3.2.7) 上,上面的直接在Transpose表达式上调用MatrixBase::applyThisOnTheRight,这反过来又可悲地减少到内部B=A*B;applyOnTheLeft也是如此,所以在这种情况下你不走运。

如果您确实需要避免任何nxm 临时,您可以手动按矢量执行产品,如下所示:

for(auto i=0;i<B.cols();++i)
B.col(i) = A * B.col(i);

假设B.rows()<<B.cols(),这将消耗更少的额外内存, 但您可能会在这里错过一些重要的优化;事实上,我想有一个临时仍然可以在这里给出最好的权衡。

是的,对于 3x3 乘以 3xHuge,您的逐列评估确实有意义,但在一般情况下并非如此。例如,如果 n=m=1000,则逐列计算将比当前特征逻辑慢几个数量级。

如果你写:

B.noalias() = A * B;

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

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

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

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

确实是一个选项,让 Eigen 在编译时知道这种信息,尽管必须转置双方有点麻烦。而正确的评估逻辑仍然需要在艾根这边实现。目前未利用此信息。

您的B.noalias() = A * B;示例与"将结果存储在 A 中"不匹配。您所需要的只是A *= B;.如果你确实打算覆盖B,那么你是在撒谎.noalias()