Eigen是否承担锯齿?

时间:2019-08-09 10:28:17

标签: c++ eigen

Matrix multiplication is the only operation in Eigen that assumes aliasing by default

MatrixXf mat1(2,2); 
mat1 << 1, 2,  4, 7;
MatrixXf mat2 = mat1;
auto result = mat1 * mat2;

Eigen在临时矩阵中评估乘积mat1 * mat2,然后在计算后将其用于初始化result。由于result没有出现在右侧,因此我们不需要别名:

MatrixXf result;
result.noalias() = mat1 * mat2;

现在,产品mat1 * mat2被直接评估为result

到目前为止,太好了。但是在这种情况下会发生什么?

template <typename T1, typename T2>
auto multiplication(const T1& A, const T2& B) // I'm using C++17, decltype not needed
{
    return A*B;
}

int main()
{
    auto result = multiplication(mat1, mat2); // say mat1 and mat2 are the same as above
    // or even this
    mat1 = multiplication(mat1, mat2);
    return 0;
}

我会说没有混叠发生,因为multiplication(m1,m2)rvalue,并且由于RVO而直接在result中构造。我对行mat1 = multiplication(mat1, mat2).说的也是一样,然后我们可以说,有一种方法可以将mat1与另一个矩阵相乘,并将结果存储在相同的矩阵mat1中,而无需使用临时方法矩阵(因此,避免混叠)。

问题

Eigen是在这里采用别名还是我的假设正确?

1 个答案:

答案 0 :(得分:5)

关于使用auto关键字,您还应该阅读Common Pitfall

如果你写

MatrixXf mat1, mat2;
auto result = mat1 * mat2;

template <typename T1, typename T2>
auto multiplication(const T1& A, const T2& B) { return A*B; }

然后auto的类型实际上与Product<MatrixXf, MatrixXf>Product<T1,T2>类似,也就是说,此时根本不进行任何计算。

因此

MatrixXf mat1 = MatrixXf::Random(2,2), mat2 = MatrixXf::Random(2,2);

auto result = multiplication(mat1, mat2); // no computation happens here

// this is safe (Eigen assumes aliasing can happen):
mat1 = result; // equivalent to directly assign mat1 = mat1 * mat2;
// Pitfall: "result" no refers to a modified `mat1` object!

// this will give undefined results (you may need bigger matrices to actually see this):
mat1.noalias() = mat1*mat2; // tell Eigen this does not alias, but actually it does.

附录:在注释中指出了赋值和初始化之间的区别。实际上,在初始化过程中,Eigen假定不会发生混叠,例如,以下代码直接分配给结果(无临时变量):

MatrixXf result = mat1 * mat2; // initialization, not assignment!

附录2:如果您写过(假设foo的返回类型为Object

Object A;
A = foo(A);

必须发生某种隐式赋值(如果Object允许,C ++ 11可能会进行移动赋值)。这与

不同
Object A;
Object B = foo(A); // RVO possible (depending on foo).