将一个 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);
给我们:
情况2:方块重叠;目标块中的第一个位置在源块的第一个之前
例如:
M.topLeftCorner(2,2) = M.block(1,0,2,2);
在这种情况下,我希望会发生这样的事情:
我认为这不是别名的例子。但是,要获得这样的行为,需要保证元素按顺序一个接一个地复制,从 top-left 一个开始,然后在两个块中逐行进行。
情况三:方块重叠;目标块中的第一个位置在源块的第一个之后
在这里,我希望出现别名。一个例子是:
M.block(1,0,2,2) = M.topLeftCorner(2,2);
结果类似于:
结论
总结一下:
- 我不会期望在第一种情况下出现别名
- 鉴于 "ordered copy" 假设,我不会在第二种情况下假设别名
- 我会总是期待在第三种情况下出现别名
这些结论正确吗? "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
我想使用 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);
给我们:
情况2:方块重叠;目标块中的第一个位置在源块的第一个之前
例如:
M.topLeftCorner(2,2) = M.block(1,0,2,2);
在这种情况下,我希望会发生这样的事情:
我认为这不是别名的例子。但是,要获得这样的行为,需要保证元素按顺序一个接一个地复制,从 top-left 一个开始,然后在两个块中逐行进行。
情况三:方块重叠;目标块中的第一个位置在源块的第一个之后
在这里,我希望出现别名。一个例子是:
M.block(1,0,2,2) = M.topLeftCorner(2,2);
结果类似于:
结论
总结一下:
- 我不会期望在第一种情况下出现别名
- 鉴于 "ordered copy" 假设,我不会在第二种情况下假设别名
- 我会总是期待在第三种情况下出现别名
这些结论正确吗? "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