Reputation: 365
I know that in Eigen I can use unaryExpr()
to apply a custom function to my Eigen Matrices and Vectors, e.g.
Eigen::VectorXd vec(4);
vec.unaryExpr([](double d) {
return d * cos(d);
});
to apply custom functions to a Eigen::VectorXd
. But is there also a way to get the position of the current element in my Vector? I want to be able to do something like this:
Eigen::VectorXd vec(4);
vec.unaryExpr([](double d, int index) {
return index * d;
});
which would for example multiply each entry in the vector by it's position.
Upvotes: 2
Views: 6829
Reputation: 18807
Besides using a nullary expression as suggested by @ggael, you can also use a binary expression together with LinSpaced(size, 0, size-1)
:
VectorXd v; // some input vector
v = v.binaryExpr(VectorXd::LinSpaced(v.size(), 0, v.size()-1),
[](double d, double i){return d*i;});
// or much simpler and more efficient in this case:
v = v.cwiseProduct(VectorXd::LinSpaced(v.size(), 0, v.size()-1));
On sufficiently recent versions of Eigen, LinSpaced
should get vectorized (although there are some border cases regarding the last element). binaryExpr
only gets vectorized if the passed functor is vectorized, of course.
N.B.: If you are doing mostly element-wise operations, consider using ArrayXd
instead of VectorXd
.
Upvotes: 2
Reputation: 29205
You can workaround using a nullary expression:
VectorXd v;
v = VectorXd::NullaryExpr([&v](Index i) { return v(i)*i; });
You can do almost everything with a nullary expression: https://eigen.tuxfamily.org/dox/TopicCustomizing_NullaryExpr.html
Upvotes: 2
Reputation: 38287
What you intend to do is nothing but an ordinary for loop:
for (int i = 0; i < vec.size(); ++i)
vec(i) *= i;
So why not keep things simple? If it's supposed to be usable for creating objects, wrap it in a helper function (template).
Besides, what you can do is relying on Eigen's internal order of evaluation. This seems to work, but I am unsure whether I would rely on it:
struct CountingUnaryFct {
double operator()(double d) const { return d*index++; }
mutable int index = 0;
};
vec.unaryExpr(CountingUnaryFct{});
This is a hack of considerable ugliness, as it tricks the unaryExpr
template that requires its function object to have a const
-qualified member operator()(double) const
(not possible with a mutable
-lambda, hence the function object) to accept an instance that actually does mutate its state under the hood. But again, it seems to work reliably, at least on one-dimensional matrices.
Upvotes: 0