I am trying to take the cholesky decomposition of the product of a matrix with its transpose, using Eigen and C++11 "auto" type. The problem comes when I try to do
auto c = a * b
auto cTc = c.tranpose() * c;
auto chol = cTc.llt();
I am using XCode 6.1, Eigen 3.2.2. The type error I get is here.
This minimal example shows the problem on my machine. Change the type of c from auto to MatrixXd to see it work.
#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;
}
Is there a way to make this work while still using auto?
As a side question, is there a performance reason to not assert the matrix is a MatrixXd at each stage? Using auto would allow Eigen to keep the answer as whatever weird template expression it fancies. I'm not sure if typing it as MatrixXd would cause problems or not.
Let me summarize what's is going on and why it's wrong. First of all, let's instantiate the
autokeywords with the types they are taking:Note that Eigen is an expression template library. Here,
GeneralProduct<>is an abstract type representing the product. No computation are performed. Therefore, if you copycTcto aMatrixXdas:which is equivalent to:
then the product
a*bwill be carried out twice! So in any case it is much preferable to evaluatea*bwithin an explicit temporary, and same forc^T*c:The last line:
is also rather wrong. If cTc is an abstract product type, then it tries to instantiate a Cholesky factorization working on a an abstract product type which is not possible. Now, if
cTcis aMatrixXd, then your code should work but this still not the preferred way as the methodllt()is rather to implement one-liner expression like:If you want a named Cholesky object, then rather use its constructor:
or even:
LLT chol(c.transpose() * c);
which is equivalent unless you have to use
c.transpose() * cin other computations.Finally, depending of the sizes of
aandb, it might be preferable to computecTcas:In the future (i.e., Eigen 3.3), Eigen will be able to see:
as a product of four matrices
m0.transpose() * m1.transpose() * m2 * m3and put the parenthesis at the right place. However, it cannot know thatm0==m3andm1==m2, and therefore if the preferred way is to evaluatea*bin a temporary, then you will still have to do it yourself.