xref: /aosp_15_r20/external/eigen/doc/Pitfalls.dox (revision bf2c37156dfe67e5dfebd6d394bad8b2ab5804d4)
1*bf2c3715SXin Linamespace Eigen {
2*bf2c3715SXin Li
3*bf2c3715SXin Li/** \page TopicPitfalls Common pitfalls
4*bf2c3715SXin Li
5*bf2c3715SXin Li
6*bf2c3715SXin Li\section TopicPitfalls_template_keyword Compilation error with template methods
7*bf2c3715SXin Li
8*bf2c3715SXin LiSee this \link TopicTemplateKeyword page \endlink.
9*bf2c3715SXin Li
10*bf2c3715SXin Li
11*bf2c3715SXin Li\section TopicPitfalls_aliasing Aliasing
12*bf2c3715SXin Li
13*bf2c3715SXin LiDon't miss this \link TopicAliasing page \endlink on aliasing,
14*bf2c3715SXin Liespecially if you got wrong results in statements where the destination appears on the right hand side of the expression.
15*bf2c3715SXin Li
16*bf2c3715SXin Li
17*bf2c3715SXin Li\section TopicPitfalls_alignment_issue Alignment Issues (runtime assertion)
18*bf2c3715SXin Li
19*bf2c3715SXin Li%Eigen does explicit vectorization, and while that is appreciated by many users, that also leads to some issues in special situations where data alignment is compromised.
20*bf2c3715SXin LiIndeed, prior to C++17,  C++ does not have quite good enough support for explicit data alignment.
21*bf2c3715SXin LiIn that case your program hits an assertion failure (that is, a "controlled crash") with a message that tells you to consult this page:
22*bf2c3715SXin Li\code
23*bf2c3715SXin Lihttp://eigen.tuxfamily.org/dox/group__TopicUnalignedArrayAssert.html
24*bf2c3715SXin Li\endcode
25*bf2c3715SXin LiHave a look at \link TopicUnalignedArrayAssert it \endlink and see for yourself if that's something that you can cope with.
26*bf2c3715SXin LiIt contains detailed information about how to deal with each known cause for that issue.
27*bf2c3715SXin Li
28*bf2c3715SXin LiNow what if you don't care about vectorization and so don't want to be annoyed with these alignment issues? Then read \link getrid how to get rid of them \endlink.
29*bf2c3715SXin Li
30*bf2c3715SXin Li
31*bf2c3715SXin Li\section TopicPitfalls_auto_keyword C++11 and the auto keyword
32*bf2c3715SXin Li
33*bf2c3715SXin LiIn 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 \c Matrix<> type. Here is an example:
34*bf2c3715SXin Li
35*bf2c3715SXin Li\code
36*bf2c3715SXin LiMatrixXd A, B;
37*bf2c3715SXin Liauto C = A*B;
38*bf2c3715SXin Lifor(...) { ... w = C * v;  ...}
39*bf2c3715SXin Li\endcode
40*bf2c3715SXin Li
41*bf2c3715SXin LiIn this example, the type of C is not a \c MatrixXd but an abstract expression representing a matrix product and storing references to \c A and \c B.
42*bf2c3715SXin LiTherefore, the product of \c A*B will be carried out multiple times, once per iteration of the for loop.
43*bf2c3715SXin LiMoreover, if the coefficients of `A` or `B` change during the iteration, then `C` will evaluate to different values as in the following example:
44*bf2c3715SXin Li
45*bf2c3715SXin Li\code
46*bf2c3715SXin LiMatrixXd A = ..., B = ...;
47*bf2c3715SXin Liauto C = A*B;
48*bf2c3715SXin LiMatrixXd R1 = C;
49*bf2c3715SXin LiA = ...;
50*bf2c3715SXin LiMatrixXd R2 = C;
51*bf2c3715SXin Li\endcode
52*bf2c3715SXin Lifor which we end up with `R1` &ne; `R2`.
53*bf2c3715SXin Li
54*bf2c3715SXin Li
55*bf2c3715SXin LiHere is another example leading to a segfault:
56*bf2c3715SXin Li\code
57*bf2c3715SXin Liauto C = ((A+B).eval()).transpose();
58*bf2c3715SXin Li// do something with C
59*bf2c3715SXin Li\endcode
60*bf2c3715SXin LiThe problem is that \c eval() returns a temporary object (in this case a \c MatrixXd) which is then referenced by the \c Transpose<> expression.
61*bf2c3715SXin LiHowever, this temporary is deleted right after the first line, and then the \c C expression references a dead object.
62*bf2c3715SXin LiOne possible fix consists in applying \c eval() on the whole expression:
63*bf2c3715SXin Li\code
64*bf2c3715SXin Liauto C = (A+B).transpose().eval();
65*bf2c3715SXin Li\endcode
66*bf2c3715SXin Li
67*bf2c3715SXin LiThe same issue might occur when sub expressions are automatically evaluated by %Eigen as in the following example:
68*bf2c3715SXin Li\code
69*bf2c3715SXin LiVectorXd u, v;
70*bf2c3715SXin Liauto C = u + (A*v).normalized();
71*bf2c3715SXin Li// do something with C
72*bf2c3715SXin Li\endcode
73*bf2c3715SXin LiHere the \c normalized() method has to evaluate the expensive product \c A*v to avoid evaluating it twice.
74*bf2c3715SXin LiAgain, one possible fix is to call \c .eval() on the whole expression:
75*bf2c3715SXin Li\code
76*bf2c3715SXin Liauto C = (u + (A*v).normalized()).eval();
77*bf2c3715SXin Li\endcode
78*bf2c3715SXin LiIn this case, \c C will be a regular \c VectorXd object.
79*bf2c3715SXin LiNote that DenseBase::eval() is smart enough to avoid copies when the underlying expression is already a plain \c Matrix<>.
80*bf2c3715SXin Li
81*bf2c3715SXin Li
82*bf2c3715SXin Li\section TopicPitfalls_header_issues Header Issues (failure to compile)
83*bf2c3715SXin Li
84*bf2c3715SXin LiWith all libraries, one must check the documentation for which header to include.
85*bf2c3715SXin LiThe same is true with %Eigen, but slightly worse: with %Eigen, a method in a class may require an additional \c \#include over what the class itself requires!
86*bf2c3715SXin LiFor example, if you want to use the \c cross() method on a vector (it computes a cross-product) then you need to:
87*bf2c3715SXin Li\code
88*bf2c3715SXin Li#include<Eigen/Geometry>
89*bf2c3715SXin Li\endcode
90*bf2c3715SXin LiWe try to always document this, but do tell us if we forgot an occurrence.
91*bf2c3715SXin Li
92*bf2c3715SXin Li
93*bf2c3715SXin Li\section TopicPitfalls_ternary_operator Ternary operator
94*bf2c3715SXin Li
95*bf2c3715SXin LiIn short: avoid the use of the ternary operator <code>(COND ? THEN : ELSE)</code> with %Eigen's expressions for the \c THEN and \c ELSE statements.
96*bf2c3715SXin LiTo see why, let's consider the following example:
97*bf2c3715SXin Li\code
98*bf2c3715SXin LiVector3f A;
99*bf2c3715SXin LiA << 1, 2, 3;
100*bf2c3715SXin LiVector3f B = ((1 < 0) ? (A.reverse()) : A);
101*bf2c3715SXin Li\endcode
102*bf2c3715SXin LiThis example will return <code>B = 3, 2, 1</code>. Do you see why?
103*bf2c3715SXin LiThe reason is that in c++ the type of the \c ELSE statement is inferred from the type of the \c THEN expression such that both match.
104*bf2c3715SXin LiSince \c THEN is a <code>Reverse<Vector3f></code>, the \c ELSE statement A is converted to a <code>Reverse<Vector3f></code>, and the compiler thus generates:
105*bf2c3715SXin Li\code
106*bf2c3715SXin LiVector3f B = ((1 < 0) ? (A.reverse()) : Reverse<Vector3f>(A));
107*bf2c3715SXin Li\endcode
108*bf2c3715SXin LiIn this very particular case, a workaround would be to call A.reverse().eval() for the \c THEN statement, but the safest and fastest is really to avoid this ternary operator with %Eigen's expressions and use a if/else construct.
109*bf2c3715SXin Li
110*bf2c3715SXin Li
111*bf2c3715SXin Li\section TopicPitfalls_pass_by_value Pass-by-value
112*bf2c3715SXin Li
113*bf2c3715SXin LiIf you don't know why passing-by-value is wrong with %Eigen, read this \link TopicPassingByValue page \endlink first.
114*bf2c3715SXin Li
115*bf2c3715SXin LiWhile you may be extremely careful and use care to make sure that all of your code that explicitly uses %Eigen types is pass-by-reference you have to watch out for templates which define the argument types at compile time.
116*bf2c3715SXin Li
117*bf2c3715SXin LiIf a template has a function that takes arguments pass-by-value, and the relevant template parameter ends up being an %Eigen type, then you will of course have the same alignment problems that you would in an explicitly defined function passing %Eigen types by reference.
118*bf2c3715SXin Li
119*bf2c3715SXin LiUsing %Eigen types with other third party libraries or even the STL can present the same problem.
120*bf2c3715SXin Li<code>boost::bind</code> for example uses pass-by-value to store arguments in the returned functor.
121*bf2c3715SXin LiThis will of course be a problem.
122*bf2c3715SXin Li
123*bf2c3715SXin LiThere are at least two ways around this:
124*bf2c3715SXin Li  - If the value you are passing is guaranteed to be around for the life of the functor, you can use boost::ref() to wrap the value as you pass it to boost::bind. Generally this is not a solution for values on the stack as if the functor ever gets passed to a lower or independent scope, the object may be gone by the time it's attempted to be used.
125*bf2c3715SXin Li  - The other option is to make your functions take a reference counted pointer like boost::shared_ptr as the argument. This avoids needing to worry about managing the lifetime of the object being passed.
126*bf2c3715SXin Li
127*bf2c3715SXin Li
128*bf2c3715SXin Li\section TopicPitfalls_matrix_bool Matrices with boolean coefficients
129*bf2c3715SXin Li
130*bf2c3715SXin LiThe current behaviour of using \c Matrix with boolean coefficients is inconsistent and likely to change in future versions of Eigen, so please use it carefully!
131*bf2c3715SXin Li
132*bf2c3715SXin LiA simple example for such an inconsistency is
133*bf2c3715SXin Li
134*bf2c3715SXin Li\code
135*bf2c3715SXin Litemplate<int Size>
136*bf2c3715SXin Livoid foo() {
137*bf2c3715SXin Li  Eigen::Matrix<bool, Size, Size> A, B, C;
138*bf2c3715SXin Li  A.setOnes();
139*bf2c3715SXin Li  B.setOnes();
140*bf2c3715SXin Li
141*bf2c3715SXin Li  C = A * B - A * B;
142*bf2c3715SXin Li  std::cout << C << "\n";
143*bf2c3715SXin Li}
144*bf2c3715SXin Li\endcode
145*bf2c3715SXin Li
146*bf2c3715SXin Lisince calling \c foo<3>() prints the zero matrix while calling \c foo<10>() prints the identity matrix.
147*bf2c3715SXin Li
148*bf2c3715SXin Li*/
149*bf2c3715SXin Li}
150