本征unaryExpr():获取元素的索引

时间:2019-03-29 09:57:46

标签: c++ eigen eigen3

我知道在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;
 });

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

3 个答案:

答案 0 :(得分:1)

您可以使用无效表达式来解决:

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

您几乎可以使用空表达式来完成所有操作:https://eigen.tuxfamily.org/dox/TopicCustomizing_NullaryExpr.html

答案 1 :(得分:1)

除了使用@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仅在传递的函子被矢量化时才被矢量化。

注意:如果您主要执行基于元素的操作,请考虑使用ArrayXd而不是VectorXd

答案 2 :(得分:0)

您打算做的只是普通的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{});

这是一个相当丑陋的技巧,因为它欺骗了unaryExpr模板,该模板要求其功能对象具有const合格的成员operator()(double) const({{1 }}-lambda,因此是函数对象)接受实际上确实在其内部改变其状态的实例。但是,它似乎至少在一维矩阵上可靠运行。