Eigen unaryExpr():获取元素的索引

Eigen unaryExpr(): get index of element

我知道在 Eigen 中我可以使用 unaryExpr() 将自定义函数应用于我的 Eigen 矩阵和向量,例如

Eigen::VectorXd vec(4);
vec.unaryExpr([](double d) {
    return d * cos(d);
});

将自定义函数应用于 Eigen::VectorXd。但是还有一种方法可以获取当前元素在我的 Vector 中的位置吗?我希望能够做这样的事情:

Eigen::VectorXd vec(4);
vec.unaryExpr([](double d, int index) {
     return index * d;
 });

例如,将向量中的每个条目乘以它的位置。

你打算做的只是一个普通的for循环:

for (int i = 0; i < vec.size(); ++i)
   vec(i) *= i;

那为什么不让事情简单点呢?如果它应该可用于创建对象,请将其包装在辅助函数(模板)中。

此外,您可以做的是依赖Eigen的内部求值顺序。这似乎可行,但我不确定我是否会依赖它:

struct CountingUnaryFct {
   double operator()(double d) const { return d*index++; }
   mutable int index = 0;
};

vec.unaryExpr(CountingUnaryFct{});

这是一个相当丑陋的 hack,因为它欺骗了 unaryExpr 模板,该模板要求其函数对象具有 const 合格的成员 operator()(double) const(不可能使用 mutable-lambda,因此是函数对象)来接受一个实际上确实在幕后改变其状态的实例。但同样,它似乎可以可靠地工作,至少在一维矩阵上是这样。

您可以使用空表达式解决问题:

VectorXd v;
v = VectorXd::NullaryExpr([&v](Index i) { return v(i)*i; });

你几乎可以用空表达式做任何事情:https://eigen.tuxfamily.org/dox/TopicCustomizing_NullaryExpr.html

除了按照@ggael 的建议使用零表达式外,您还可以将二进制表达式与 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));

在足够新的 Eigen 版本上,LinSpaced 应该被矢量化(尽管关于最后一个元素有一些边界情况)。 binaryExpr 当然,只有在传递的仿函数被矢量化时才会被矢量化。

N.B.: 如果你主要做元素操作,考虑使用 ArrayXd 而不是 VectorXd.