说我有
A = [1 2 3]
[4 5 6]
[7 8 9]
我想用创建A nxn的第一行和第一列或最后一行和最后一列填充它多次。例如,一个4x4将会是
A = [1 1 2 3]
[1 1 2 3]
[4 4 5 6]
[7 7 8 9]
一个5x5应该是
A = [1 1 2 3 3]
[1 1 2 3 3]
[4 4 5 6 6]
[7 7 8 9 9]
[7 7 8 9 9]
我知道我可以做A.conservativeResize(4,4)
,这会吸引我
A = [1 2 3 0]
[4 5 6 0]
[7 8 9 0]
[0 0 0 0]
然后我可以一张一张地复制内容,但是使用Eigen可以做到这一点吗?
答案 0 :(得分:1)
您可以使用nullary表达式来解决:
#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
using namespace std;
int main()
{
Matrix3i A;
A.reshaped() = VectorXi::LinSpaced(9,1,9);
cout << A << "\n\n";
int N = 5;
MatrixXi B(N,N);
B = MatrixXi::NullaryExpr(N, N, [&A,N] (Index i,Index j) {
return A( std::max<Index>(0,i-(N-A.rows())),
std::max<Index>(0,j-(N-A.cols())) ); } );
cout << B << "\n\n";
}
另一种方法是创建一个受约束的索引序列,例如[0 0 0 1 2]
:
struct pad {
Index size() const { return m_out_size; }
Index operator[] (Index i) const { return std::max<Index>(0,i-(m_out_size-m_in_size)); }
Index m_in_size, m_out_size;
};
B = A(pad{3,N}, pad{3,N});
此版本需要Eigen的负责人。
您可以轻松构建这些示例,以使它们更加通用和/或将它们包装在函数中。
答案 1 :(得分:0)
请注意,A.conservativeResize(4,4)
不会为您提供一个矩阵,其中添加的行用零填充。本征文档说,
如果需要将值附加到矩阵,它们将被初始化。
新的行和列将充满垃圾,看到零只是一个巧合(除非您使用针对Eigen的特殊预处理程序指令进行编译)。但这意味着不会浪费不必要的时间写零,而无论如何您都将覆盖它。
注意:此代码演示了如何使用原始矩阵在左上角 中获得矩阵:
一次填充多个值的最佳方法是使用Eigen的block operations和setConstant
。例如,如果A
是大小为old_size
x old_size
的矩阵:
A.conservativeResize(n, n);
for (int i = 0; i < n; ++i) {
// Fill the end of each row and column
A.row(i).tail(n - old_size).setConstant(A(i, old_size - 1));
A.col(i).tail(n - old_size).setConstant(A(old_size - 1, i));
}
// Fill the bottom right block
A.bottomRightCorner(n - old_size, n - old_size).setConstant(A(old_size - 1, old_size - 1));
比“高效”更重要的是,这些功能表达了您作为程序员的意图。
编辑:要获得一个填充的矩阵,原始矩阵位于中间,
我只是注意到您的示例垫在原始矩阵的中间,而不是在左上方。在这种情况下,使用conservativeResize()
毫无意义,因为原始值只会复制到左上角。解决方案的概述是:
B
使用
将原始矩阵复制到中间 int start = (n - old_size + 1)/2;
B.block(start, start, old_size, old_size) = A;
使用类似于我上面的示例的块操作填充外部值。