xref: /aosp_15_r20/external/eigen/doc/TopicLazyEvaluation.dox (revision bf2c37156dfe67e5dfebd6d394bad8b2ab5804d4)
1*bf2c3715SXin Linamespace Eigen {
2*bf2c3715SXin Li
3*bf2c3715SXin Li/** \page TopicLazyEvaluation Lazy Evaluation and Aliasing
4*bf2c3715SXin Li
5*bf2c3715SXin LiExecutive summary: %Eigen has intelligent compile-time mechanisms to enable lazy evaluation and removing temporaries where appropriate.
6*bf2c3715SXin LiIt will handle aliasing automatically in most cases, for example with matrix products. The automatic behavior can be overridden
7*bf2c3715SXin Limanually by using the MatrixBase::eval() and MatrixBase::noalias() methods.
8*bf2c3715SXin Li
9*bf2c3715SXin LiWhen you write a line of code involving a complex expression such as
10*bf2c3715SXin Li
11*bf2c3715SXin Li\code mat1 = mat2 + mat3 * (mat4 + mat5);
12*bf2c3715SXin Li\endcode
13*bf2c3715SXin Li
14*bf2c3715SXin Li%Eigen determines automatically, for each sub-expression, whether to evaluate it into a temporary variable. Indeed, in certain cases it is better to evaluate a sub-expression into a temporary variable, while in other cases it is better to avoid that.
15*bf2c3715SXin Li
16*bf2c3715SXin LiA traditional math library without expression templates always evaluates all sub-expressions into temporaries. So with this code,
17*bf2c3715SXin Li
18*bf2c3715SXin Li\code vec1 = vec2 + vec3;
19*bf2c3715SXin Li\endcode
20*bf2c3715SXin Li
21*bf2c3715SXin Lia traditional library would evaluate \c vec2 + vec3 into a temporary \c vec4 and then copy \c vec4  into \c vec1. This is of course inefficient: the arrays are traversed twice, so there are a lot of useless load/store operations.
22*bf2c3715SXin Li
23*bf2c3715SXin LiExpression-templates-based libraries can avoid evaluating sub-expressions into temporaries, which in many cases results in large speed improvements.
24*bf2c3715SXin LiThis is called <i>lazy evaluation</i> as an expression is getting evaluated as late as possible.
25*bf2c3715SXin LiIn %Eigen <b>all expressions are lazy-evaluated</b>.
26*bf2c3715SXin LiMore precisely, an expression starts to be evaluated once it is assigned to a matrix.
27*bf2c3715SXin LiUntil then nothing happens beyond constructing the abstract expression tree.
28*bf2c3715SXin LiIn contrast to most other expression-templates-based libraries, however, <b>%Eigen might choose to evaluate some sub-expressions into temporaries</b>.
29*bf2c3715SXin LiThere are two reasons for that: first, pure lazy evaluation is not always a good choice for performance; second, pure lazy evaluation can be very dangerous, for example with matrix products: doing <tt>mat = mat*mat</tt> gives a wrong result if the matrix product is directly evaluated within the destination matrix, because of the way matrix product works.
30*bf2c3715SXin Li
31*bf2c3715SXin LiFor these reasons, %Eigen has intelligent compile-time mechanisms to determine automatically which sub-expression should be evaluated into a temporary variable.
32*bf2c3715SXin Li
33*bf2c3715SXin LiSo in the basic example,
34*bf2c3715SXin Li
35*bf2c3715SXin Li\code mat1 = mat2 + mat3;
36*bf2c3715SXin Li\endcode
37*bf2c3715SXin Li
38*bf2c3715SXin Li%Eigen chooses not to introduce any temporary. Thus the arrays are traversed only once, producing optimized code.
39*bf2c3715SXin LiIf you really want to force immediate evaluation, use \link MatrixBase::eval() eval()\endlink:
40*bf2c3715SXin Li
41*bf2c3715SXin Li\code mat1 = (mat2 + mat3).eval();
42*bf2c3715SXin Li\endcode
43*bf2c3715SXin Li
44*bf2c3715SXin LiHere is now a more involved example:
45*bf2c3715SXin Li
46*bf2c3715SXin Li\code mat1 = -mat2 + mat3 + 5 * mat4;
47*bf2c3715SXin Li\endcode
48*bf2c3715SXin Li
49*bf2c3715SXin LiHere again %Eigen won't introduce any temporary, thus producing a single <b>fused</b> evaluation loop, which is clearly the correct choice.
50*bf2c3715SXin Li
51*bf2c3715SXin Li\section TopicLazyEvaluationWhichExpr Which sub-expressions are evaluated into temporaries?
52*bf2c3715SXin Li
53*bf2c3715SXin LiThe default evaluation strategy is to fuse the operations in a single loop, and %Eigen will choose it except in a few circumstances.
54*bf2c3715SXin Li
55*bf2c3715SXin Li<b>The first circumstance</b> in which %Eigen chooses to evaluate a sub-expression is when it sees an assignment <tt>a = b;</tt> and the expression \c b has the evaluate-before-assigning \link flags flag\endlink.
56*bf2c3715SXin LiThe most important example of such an expression is the \link Product matrix product expression\endlink. For example, when you do
57*bf2c3715SXin Li
58*bf2c3715SXin Li\code mat = mat * mat;
59*bf2c3715SXin Li\endcode
60*bf2c3715SXin Li
61*bf2c3715SXin Li%Eigen will evaluate <tt>mat * mat</tt> into a temporary matrix, and then copies it into the original \c mat.
62*bf2c3715SXin LiThis guarantees a correct result as we saw above that lazy evaluation gives wrong results with matrix products.
63*bf2c3715SXin LiIt also doesn't cost much, as the cost of the matrix product itself is much higher.
64*bf2c3715SXin LiNote that this temporary is introduced at evaluation time only, that is, within operator= in this example.
65*bf2c3715SXin LiThe expression <tt>mat * mat</tt> still return a abstract product type.
66*bf2c3715SXin Li
67*bf2c3715SXin LiWhat if you know that the result does no alias the operand of the product and want to force lazy evaluation? Then use \link MatrixBase::noalias() .noalias()\endlink instead. Here is an example:
68*bf2c3715SXin Li
69*bf2c3715SXin Li\code mat1.noalias() = mat2 * mat2;
70*bf2c3715SXin Li\endcode
71*bf2c3715SXin Li
72*bf2c3715SXin LiHere, since we know that mat2 is not the same matrix as mat1, we know that lazy evaluation is not dangerous, so we may force lazy evaluation. Concretely, the effect of noalias() here is to bypass the evaluate-before-assigning \link flags flag\endlink.
73*bf2c3715SXin Li
74*bf2c3715SXin Li<b>The second circumstance</b> in which %Eigen chooses to evaluate a sub-expression, is when it sees a nested expression such as <tt>a + b</tt> where \c b is already an expression having the evaluate-before-nesting \link flags flag\endlink.
75*bf2c3715SXin LiAgain, the most important example of such an expression is the \link Product matrix product expression\endlink.
76*bf2c3715SXin LiFor example, when you do
77*bf2c3715SXin Li
78*bf2c3715SXin Li\code mat1 = mat2 * mat3 + mat4 * mat5;
79*bf2c3715SXin Li\endcode
80*bf2c3715SXin Li
81*bf2c3715SXin Lithe products <tt>mat2 * mat3</tt> and <tt>mat4 * mat5</tt> gets evaluated separately into temporary matrices before being summed up in <tt>mat1</tt>.
82*bf2c3715SXin LiIndeed, to be efficient matrix products need to be evaluated within a destination matrix at hand, and not as simple "dot products".
83*bf2c3715SXin LiFor small matrices, however, you might want to enforce a "dot-product" based lazy evaluation with lazyProduct().
84*bf2c3715SXin LiAgain, it is important to understand that those temporaries are created at evaluation time only, that is in operator =.
85*bf2c3715SXin LiSee TopicPitfalls_auto_keyword for common pitfalls regarding this remark.
86*bf2c3715SXin Li
87*bf2c3715SXin Li<b>The third circumstance</b> in which %Eigen chooses to evaluate a sub-expression, is when its cost model shows that the total cost of an operation is reduced if a sub-expression gets evaluated into a temporary.
88*bf2c3715SXin LiIndeed, in certain cases, an intermediate result is sufficiently costly to compute and is reused sufficiently many times, that is worth "caching". Here is an example:
89*bf2c3715SXin Li
90*bf2c3715SXin Li\code mat1 = mat2 * (mat3 + mat4);
91*bf2c3715SXin Li\endcode
92*bf2c3715SXin Li
93*bf2c3715SXin LiHere, provided the matrices have at least 2 rows and 2 columns, each coefficient of the expression <tt>mat3 + mat4</tt> is going to be used several times in the matrix product. Instead of computing the sum every time, it is much better to compute it once and store it in a temporary variable. %Eigen understands this and evaluates <tt>mat3 + mat4</tt> into a temporary variable before evaluating the product.
94*bf2c3715SXin Li
95*bf2c3715SXin Li*/
96*bf2c3715SXin Li
97*bf2c3715SXin Li}
98