0

I've run into trouble with a matrix-by-vector multiplication. Namely an innocous-looking expression always return a vector close to [1 0] while a similar-looking expression returns the correct result:

// version WITH temp var, correct
Eigen::Vector3d lcoord_eig(lcoord[0], lcoord[1], lcoord[2]);
auto lcoord2d = P3to2 * lcoord_eig;
std::cout << std::endl << lcoord2d << std::endl;

// version WITHOUT temp var, always [1 0]
auto lcoord2d_2 = P3to2 * Eigen::Vector3d(lcoord[0], lcoord[1], lcoord[2]);
std::cout << std::endl << lcoord2d_2 << std::endl;

where P3to2 is a 2-by-3 matrix (Eigen::MatrixXd) and lcoord is the 3d vector type of some other library, with above code contained in a for-loop.

Some of the output (annotations by me):

-0.0036135
2.1684e-18   // correct

1
0   // [1 0], wrong

0.00209583
0.000388139   // correct

1
5.55112e-17   // [1 0], wrong

0.00148429
-0.000435008   // correct

1
5.55112e-17   // [1 0], wrong

This error took me a long time to spot, and I still don't understand what is going on that would cause the second version to behave like this. What mistake did I make?


Edit: This also happens for constant vectors, like Eigen::Vector3d(.5,.5,.5)

xjcl
  • 12,848
  • 6
  • 67
  • 89
  • As a side note, `std::endl` != `\n`, but [`std::endl` == `\n` + `std::flush`](https://stackoverflow.com/questions/213907/c-stdendl-vs-n). – m7913d Nov 27 '17 at 16:29

1 Answers1

5

My guess (given you haven't included enough information in the question for anyone to reproduce) is that the use of auto is your problem. In your second case, the non working one, I suspect you are left with a dangling reference to the destroyed temporary Vector3D.

The documentations says "do not use the auto keywords with Eigen's expressions, unless you are 100% sure about what you are doing".

If you use an explicit type your program will be clearer and more likely to work.

Alan Stokes
  • 18,815
  • 3
  • 45
  • 64
  • You're right, replacing `auto` with `Eigen::Vector2d` fixes the issue. I didn't know `auto` could be so dangerous! – xjcl Nov 26 '17 at 14:21
  • 1
    @xjcl I'd guess Eigen uses expression templates, that's why – Sopel Nov 26 '17 at 14:21
  • 2
    @Sopel Yes, Eigen uses expression templates indeed, which may bind a temporary to a `const` ref internally, and that binding ceases to be valid at the end of the statement. Use `.eval();` at the end of the expression if you want to force evaluation, like `auto lcoord2d = (P3to2 * lcoord_eig).eval();`. See e.g. [this link](https://stackoverflow.com/a/34762002/3093378) for a bit more details. – vsoftco Nov 26 '17 at 14:48