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 = []() {...}
为牛顿法编写实现雅可比矩阵的函数我注意到一个非常严重的错误。
调用函数
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 = []() {...}