Eigen Tensor expressions are evaluated (computed) through several mechanisms. Because expressions are lazy, they are not computed until you explicitly trigger evaluation.
1. Assignment to a Tensor type
Assigning an expression to a Tensor, TensorFixedSize, or TensorMap is the most common way to trigger evaluation.
auto t3 = t1 + t2; // t3 is an Operation (not evaluated)
auto t4 = t3 * 0.2f; // t4 is an Operation (not evaluated)
Tensor<float, 3> result = t4; // The operations are evaluated here
If you know the rank and sizes, assigning to a TensorFixedSize is more efficient:
TensorFixedSize<float, Sizes<4, 4, 2>> result = t5;
2. Using the eval() method
Use .eval() to force an intermediate value to be materialized into a temporary tensor. This is useful for:
- Performance: Preventing a complex sub-expression from being re-computed multiple times (e.g., inside a
broadcast() or reshape() chain). - Correctness (Aliasing): Preventing incorrect results when a tensor is used on both sides of an assignment (e.g.,
Y = Y / Y.sum()...).
Note: The return value of .eval() is itself an Operation, so it does not trigger evaluation immediately. You must still assign it to a Tensor to see results.
// Forces the sum to be computed once before reshaping/broadcasting
Y = Y / (Y.sum(depth_dim).eval().reshape(dims2d).broadcast(bcast));
3. Using TensorRef for partial access
If you only need to access a few specific elements of a large expression, use TensorRef. This avoids materializing the entire result into memory. The expression is evaluated on-the-fly only for the elements you access.
// ref is an Operation, not a Tensor
TensorRef<Tensor<float, 3>> ref = ((t1 + t2) * 0.2f).exp();
// Evaluation happens here for specific elements
float at_0 = ref(0, 0, 0);
// Example of evaluating a chain of operations
auto t3 = t1 + t2;
auto t4 = t3 * 0.2f;
auto t5 = t4.exp();
Tensor<float, 3> result = t5; // Evaluation occurs here