I would like to understand how expression templates work in Eigen. I understood that the sum of two dynamical double vectors is performed by something which looks like this :
CwiseBinaryOp< internal::scalar_sum_op<double>, VectorXd const, VectorXd const > operator+(VectorXd const & lhs, VectorXd const & rhs);
I also understood how the difference of two vectors is implemented.
I have two questions.
1. How does the product of a vector by a scalar work?
I have noticed that
CwiseBinaryOp< internal::scalar_product_op<double>, VectorXd const, VectorXd const >
exists but I have the feeling that it is only designed to perform componentwise operations between two vectors. Does it mean that the product of a vector by a scalar correspond to a unary operator, say
CwiseUnaryOp< internal::scalar_product_op<double>, VectorXd const, VectorXd const > ?
2. Can template expressions be built from mixed operations?
For example, in an expression like
x = u + (2*v + (v-w))
is it true that these operations are performed in a nested way like this?
v-w
leads to the construction of an instance of E12*v
leads to the construction of an instance of E22*v + (v-w)
leads to the construction of an instance of E3u + (2*v + (u-w))
leads to the construction of an instance of E4x = u + (2*v + (v-w))
calls the constructor
VectorXd(E4 const &);
or the overloading
VectorXd & operator=(E4 const &);
which evaluates the tree built from the previous steps, with the following aliases:
using diff = internal::scalar_difference_op<double>;
using prod = internal::scalar_product_op<double>;
using sum = internal::scalar_sum_op<double>;
using E1 = CwiseBinaryOp< diff, VectorXd const, VectorXd const >;
using E2 = CwiseUnaryOp< prod, VectorXd const >;
using E3 = CwiseBinaryOp< sum, E1 const, E2 const >;
1. How does the product of a vector by a scalar work?
In Eigen 3.2, it is implemented as a unary-operator, with a functor storing the value of the scalar factor. In Eigen 3.3, it is now implemented as a binary operator between the given matrix expression and a constant expression, something like:
CwiseBinaryOp<scalar_product_op<double,double>,
VectorXd,
CwiseNullaryOp<scalar_constant_op<double>, VectorXd> >
This approach permits to clearly distinguish between s*vec
and vec*s
, and the return type of, e.g., vec*s
is equivalent to the one of vec*VectorxD::Constant(vec.size(),s)
.
2. Can template expressions be built from mixed operations?
Your understanding is correct: first the expressions E1 to E4 are created, then the evaluation starts from the overloaded operator=
generating a code like:
for(i=0;i<x.size();++i)
x[i] = E4.coeff(i);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With