Eigen 在不存储中间结果时给出错误的结果

Eigen gives wrong result when not storing intermediate result

为牛顿法编写实现雅可比矩阵的函数我注意到一个非常严重的错误。

调用函数

auto DF = [T](VectorXd y){
    return PhiAndW(y(0),y(1),T).second - MatrixXd::Identity(2,2);
 };

只有returnsPhiAndW(y(0),y(1),T).second的值,省略了MatrixXd::Identity(2,2)的减法。但是如果我将代码更改为

auto DF = [T](VectorXd y){
    MatrixXd mat = PhiAndW(y(0),y(1),T).second - MatrixXd::Identity(2,2);
    return mat;
 };

一切顺畅。

我已尝试重现它,这不是完全相同的行为,但它的行为也不尽如人意:

考虑以下代码:

MatrixXd FF(MatrixXd y){
  return y;
}

int other(){

  auto DF = [](MatrixXd y){
    MatrixXd test = FF(y)  - MatrixXd::Identity(2,2);
    return test;
  };

  std::cout << DF(MatrixXd::Ones(2,2)) <<std::endl;
  std::cout << std::endl;
  std::cout << (MatrixXd::Ones(2,2) - MatrixXd::Identity(2,2))<< std::endl;

}

它将打印

>  1 0
>  0 1 
>
>  1 0 
>  0 1 

到控制台。

但是,如果我将函数 DF 更改为

  auto DF = [](MatrixXd y){
    return FF(y)  - MatrixXd::Identity(2,2);
  };

控制台会打印出

>  2.22045e-15 1.63042e-322
>  2.37152e-322    -0.999998

对于第二个矩阵。 (这只是内存中一些未初始化的垃圾)。

有人可以解释我的代码和我的示例问题发生了什么。我真的不知道这里发生了什么。我特别感兴趣为什么将计算结果保存在临时变量中可以解决问题。

既然评论已经解决了我的问题(非常感谢),我想我会继续回答我的问题,以便其他人看到这个问题已经解决了。

为什么会出现这个问题?

问题在于,例如,两个矩阵的本征乘法的结果类型不是本征矩阵,而是表示乘法并引用我们试图相乘的两个矩阵的某个内部对象。

因此,如果我们使用 auto 关键字,编译器很可能不会为我们设置的变量提供类型 MatrixXd,而是某些内部对象的类型。

有关详细信息,请参阅 Eigen documentation,其中明确指出:

In short: do not use the auto keywords with Eigen's expressions, unless you are 100% sure about what you are doing. In particular, do not use the auto keyword as a replacement for a Matrix<> type

如何防止它发生?

  • 不要使用 auto 关键字,使用显式类型。
  • 对于 lambda 函数,始终指定 return 类型:写入 auto DF = []() -> MatrixXd {...} 而不是 auto DF = []() {...}