将一个 Eigen::Matrix 的块复制到同一矩阵的另一个块时,会出现什么别名问题?

When copying a block from an Eigen::Matrix to another block from the same matrix, what aliasing problems can occur?

我想使用 Eigen 将矩阵的一部分复制到矩阵本身的另一部分。我想确保了解别名的后果,以便仅在真正需要时使用 eval()

假设我有以下内容:

MatrixXd M(4,4);
M << 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16;
M.block( some indices ) = M.block( some other indices )

我认为应该考虑 3 种情况:

情况 1:块不重叠

这应该不是问题。一个例子是:

M.topLeftCorner(2,2) = M.bottomRightCorner(2,2);

给我们:link to image

情况2:方块重叠;目标块中的第一个位置在源块的第一个之前

例如:

M.topLeftCorner(2,2) = M.block(1,0,2,2);

在这种情况下,我希望会发生这样的事情:link to image

我认为这不是别名的例子。但是,要获得这样的行为,需要保证元素按顺序一个接一个地复制,从 top-left 一个开始,然后在两个块中逐行进行。

情况三:方块重叠;目标块中的第一个位置在源块的第一个之后

在这里,我希望出现别名。一个例子是:

M.block(1,0,2,2) = M.topLeftCorner(2,2);

结果类似于:link to image

结论

总结一下:

  1. 不会期望在第一种情况下出现别名
  2. 鉴于 "ordered copy" 假设,我不会在第二种情况下假设别名
  3. 我会总是期待在第三种情况下出现别名

这些结论正确吗? "ordered copy" 的假设是否成立?我想矢量化实际上可以使这个假设无效...

你对第 1 点的看法是正确的。如果块不重叠,你就不会有锯齿问题。

但是,对于 2. 和 3.,您可能有也可能没有别名问题,具体取决于 Eigen 版本、目标体系结构和编译器——本质上这些操作的结果是未定义的。也就是说,你不应该依赖当前的行为。

如果你想有一些明确的行为(不使用临时对象),你可以手动循环矩阵的非重叠块。而不是

M.topLeftCorner(2,2) = M.block(1,0,2,2);

你可以这样写:

for(int c=0; c<2; ++c)
    M.block(0,c,2,1) = M.block(0,c+1,2,1);

或者更好的是,重新考虑您的整体算法以避免在矩阵内复制重叠块。

有关别名的更多详细信息,请参阅此页面:http://eigen.tuxfamily.org/dox-devel/group__TopicAliasing.html