我正在尝试使用Eigen和C ++ 11" auto"使用它的转置对矩阵乘积进行cholesky分解。类型。当我尝试
时出现问题auto c = a * b
auto cTc = c.tranpose() * c;
auto chol = cTc.llt();
我正在使用XCode 6.1,Eigen 3.2.2。我得到的类型错误是here。
这个最小的例子显示了我的机器上的问题。将c
的类型从auto
更改为MatrixXd
,以确保其有效。
#include <iostream>
#include <Eigen/Eigen>
using namespace std;
using namespace Eigen;
int main(int argc, const char * argv[]) {
MatrixXd a = MatrixXd::Random(100, 3);
MatrixXd b = MatrixXd::Random(3, 100);
auto c = a * b;
auto cTc = c.transpose() * c;
auto chol = cTc.llt();
return 0;
}
还有一种方法可以在使用自动时完成这项工作吗?
作为一个附带问题,是否存在性能原因,在每个阶段都没有断言矩阵是MatrixXd
?使用auto可以让Eigen将答案保持为它所想象的任何奇怪的模板表达式。我不确定是否输入MatrixXd会导致问题。
答案 0 :(得分:6)
问题是第一次乘法返回Eigen::GeneralProduct
而不是MatrixXd
而auto
正在拾取返回类型。您可以隐式地从MatrixXd
创建Eigen::GeneralProduct
,因此当您明确声明其正确运行的类型时。见http://eigen.tuxfamily.org/dox/classEigen_1_1GeneralProduct.html
答案 1 :(得分:4)
让我总结一下发生了什么以及为什么这是错误的。首先,让我们使用他们正在采用的类型来实例化auto
个关键字:
typedef GeneralProduct<MatrixXd,MatrixXd> Prod;
Prod c = a * b;
GeneralProduct<Transpose<Prod>,Prod> cTc = c.transpose() * c;
请注意,Eigen是一个表达式模板库。这里,GeneralProduct<>
是表示产品的抽象类型。不执行任何计算。因此,如果您将cTc
复制为MatrixXd
为:
MatrixXd d = cTc;
相当于:
MatrixXd d = c.transpose() * c;
然后产品a*b
将进行两次!因此,在任何情况下,最好在显式临时内评估a*b
,对c^T*c
评估相同:
MatrixXd c = a * b;
MatrixXd cTc = c.transpose() * c;
最后一行:
auto chol = cTc.llt();
也是错误的。如果cTc是抽象产品类型,那么它会尝试实例化一个不可能的抽象产品类型的Cholesky分解。现在,如果cTc
是MatrixXd
,那么您的代码应该可以正常工作,但这仍然不是首选方法,因为方法llt()
更像是实现单行表达式,如:
VectorXd b = ...;
VectorXd x = cTc.llt().solve(b);
如果你想要一个名为Cholesky的对象,那么请使用它的构造函数:
LLT<MatrixXd> chol(cTc);
甚至:
LLT chol(c.transpose()* c);
除非您必须在其他计算中使用c.transpose() * c
,否则它是等效的。
最后,根据a
和b
的大小,最好将cTc
计算为:
MatrixXd cTc = b.transpose() * (a.transpose() * a) * b;
将来(即Eigen 3.3),Eigen将能够看到:
auto c = a * b;
MatrixXd cTc = c.transpose() * c;
作为四个矩阵m0.transpose() * m1.transpose() * m2 * m3
的乘积,并将括号放在正确的位置。但是,它无法知道m0==m3
和m1==m2
,因此如果首选方法是在临时评估a*b
,那么您仍然必须自己完成。
答案 2 :(得分:2)
我不是Eigen
的专家,但像这样的库经常从操作中返回代理对象,然后使用隐式转换或构造函数来强制实际工作。 (表达式模板就是一个极端的例子。)这避免了在许多情况下不必要地复制完整的数据矩阵。不幸的是,auto
很高兴只创建一个代理类型的对象,通常库的用户永远不会明确声明。由于您需要最终计算出数字,因此从投射到MatrixXd
不会产生性能损失。 (Scott Meyers,在“Effective Modern C ++”中,给出了auto
与vector<bool>
一起使用的相关示例,其中operator[](size_t i)
返回代理。)
答案 3 :(得分:0)
不要将auto
与特征表达式一起使用。我碰到了更多&#34;戏剧性的&#34;之前的问题,请参阅
eigen auto type deduction in general product
并且被其中一个特征创造者(Gael)建议不要将auto
与特征表达式一起使用。
从表达式到特定类型(如MatrixXd
)的强制转换应该非常快,除非您需要延迟评估(因为在进行强制转换时会评估结果)。