libeigen/eigen!2839 Co-authored-by: Rasmus Munk Larsen <rmlarsen@gmail.com>
76 lines
4.0 KiB
Plaintext
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.
|
|
|
|
*/
|
|
|
|
}
|