Files
eigen/doc/TopicEigenExpressionTemplates.dox

76 lines
4.0 KiB
Plaintext

namespace Eigen {
/** \page TopicEigenExpressionTemplates Expression templates in Eigen
Arithmetic operators and most methods in %Eigen do not compute anything by themselves. Instead they
return a small \em expression \em object that merely describes the computation to be performed and
stores references to the operands. The actual computation happens later, typically when the whole
expression is assigned to a destination. This technique is known as <i>expression templates</i>,
and understanding its user-visible consequences helps to write both correct and fast %Eigen code.
\eigenAutoToc
\section TopicETHow How it works
Consider:
\code
VectorXf a(50), b(50), c(50), d(50);
a = 3*b + 4*c + 5*d;
\endcode
The right-hand side does not create any temporary vector. The subexpression \c 3*b is an object of
type <tt>CwiseBinaryOp<scalar_product_op, ..., ...></tt> that just stores the scalar and a reference
to \c b; the additions nest similar objects around it. The complete type of the right-hand side
encodes the whole expression tree at compile time. Only when this expression is assigned to \c a
does %Eigen generate a single evaluation loop, morally equivalent to:
\code
for (int i = 0; i < 50; ++i)
a[i] = 3*b[i] + 4*c[i] + 5*d[i];
\endcode
The benefits are that the arrays are traversed only once, no temporary objects are created, and the
single fused loop can be unrolled and vectorized (see \ref TopicVectorization). Consequently, you
should not be afraid of writing large expressions: doing so gives %Eigen more opportunities for
optimization. A step-by-step tour of the machinery behind this example is given in
\ref TopicInsideEigenExample, and the involved class hierarchy is described in
\ref TopicClassHierarchy.
Not every subexpression is evaluated lazily: matrix products, for instance, are evaluated into
temporaries in most contexts, both for performance and for correctness in the face of aliasing.
The rules governing which subexpressions are evaluated where are documented in
\ref TopicLazyEvaluation.
\section TopicETConsequences What it means in practice
Because an "expression" is not a matrix, a few things deserve attention:
- <b>Do not use \c auto to capture an expression</b> unless you know exactly what you are doing:
the deduced type is the expression type, not a plain matrix, so the computation re-runs every
time the variable is used, and the expression may hold dangling references to destroyed
temporaries. See \ref TopicPitfalls_auto_keyword.
- <b>Assignment evaluates coefficient-wise into the destination</b>, so if the destination also
appears on the right-hand side, coefficients may be read after they have been overwritten. This
is the aliasing problem, explained in \ref TopicAliasing. Use .eval(), an xxxInPlace() method,
or \link MatrixBase::noalias() noalias()\endlink as appropriate.
- <b>Functions should accept expressions, not just matrices.</b> Take parameters of type
<tt>const MatrixBase<Derived>&</tt> (or ArrayBase, DenseBase, EigenBase, or Ref) so that
arbitrary expressions can be passed without evaluating them into a temporary; see
\ref TopicFunctionTakingEigenTypes.
- <b>Materializing an expression</b> is done with \link DenseBase::eval() .eval()\endlink, which
returns a plain matrix or array (and is a no-op when the expression already is one), or by
assigning the expression to a plain object.
- <b>The two branches of the ternary operator <tt>?:</tt></b> must have a common type, which two
different expression types usually do not; use \c if/\c else or evaluate the branches. See
\ref TopicPitfalls_ternary_operator.
\section TopicETExtending Extending the expression system
Coefficient-wise custom operations rarely need a new expression type: a functor passed to
unaryExpr(), binaryExpr(), or NullaryExpr() is usually enough (see \ref TopicCustomizing_Functors
and \ref TopicCustomizing_NullaryExpr). When a genuinely new expression type is required,
\ref TopicNewExpressionType walks through a complete example.
*/
}