5

我有一个双精度的一维特征数组(Eigen::Array<double,Dynamic,Dynamic>),我想修改数组的每个元素。但是,我不确定如何执行此操作。我正在考虑这个:

Eigen::Array<double,Eigen::Dynamic,Eigen::Dynamic> arr1D;
// ...

// Threshold function:
arr1D.unaryExpr([](double& elem)
{
    elem = elem < 0.0 ? 0.0 : 1.0;
}
);

但这似乎有点 hack,因为Eigen Reference示例仅给出了.unaryExpr与返回值的仿函数一起使用的示例(然后整个方法只返回一个不同的数组)。就我而言,我希望避免创建新数组的需要。

我是 Eigen 的新手,所以我想我可能会在这里遗漏一些东西,感谢您的输入。

编辑:我知道我可以简单地将上面的内容替换为arr1D = arr1D >= 0.0,但请注意,这只是一个示例

4

2 回答 2

7

.unaryExpr将“视图”返回到由给定函数转换的原始数据。它不对原始数据进行转换。

您不能更改传递给转换函数的参数。您的代码被编译只是因为您没有触发适当代码的模板实例化。如果将结果赋值给值,则编译失败:

#include <Eigen/Dense>

int main()
{
    using namespace Eigen;

    ArrayXd x, y;
    y = x.unaryExpr([](double& elem)
    {
        elem = elem < 0.0 ? 0.0 : 1.0;
    }); // ERROR: cannot convert const double to double&
}

错误的确切位置在Eigen内部:

EIGEN_STRONG_INLINE const Scalar coeff(Index index) const
{
  return derived().functor()( derived().nestedExpression().coeff(index) );
  //     ^^^^^^^^^^^^^^^^^^^ - your lambda
}

我认为最简单的就地方法Eigen是:

ArrayXd x = ArrayXd::Random(100);
x = x.unaryExpr([](double elem) // changed type of parameter
{
    return elem < 0.0 ? 0.0 : 1.0; // return instead of assignment
});

unaryExpr不返回完整的新数组/矩阵 - 但它返回类似于它的特殊临时对象。

于 2013-10-27T23:18:45.577 回答
0

如果您的值类型相对简单,Evgeny 的答案是迄今为止最好的。

但是,如果您想重新创建real()complex()(访问Scalars 结构的部分),您可以使用const_cast<>它来破解它,这就是real/complex()实际所做的(从 v3.3.3 开始):(注意:此代码仅在 C+ 中测试过+1y,但可以简化。)

struct Value {
  double a{1.5};
  int b{2};
};

// Savage. Use aforemention hack from scalar_real_ref_op.
struct get_mutable_a_direct {
  double& operator()(const Value& v) const {
    return const_cast<Value&>(v).a;
  }
};
// ...
MatrixX<Value> X(2, 2);
auto X_am_direct = CwiseUnaryView<get_mutable_a_direct, MatrixX<Value>>(
    X, get_mutable_a_direct());
X_am_direct.setConstant(20);

我还测试了一个快速包装器,以将上述内容简化为:

struct get_a_flex {
  double& operator()(Value& v) const {
    return v.a;
  }
  const double& operator()(const Value& v) const {
    return v.a;
  }
};
// Less? savage.
auto X_am = unaryExprFlex(X, get_a_flex());
X_am *= 10;
cout << X_ac << endl;

// Works.
const auto& Xc = X;
auto Xc_am = unaryExprFlex(Xc, get_a_flex());
// Xc_am.setConstant(20);  // Fails as desired.
cout << Xc_am << endl;

您可以在此处查看代码片段:unary_view_mutable.cc

注意:如果您想使用 labmda,请务必指明通过以下方式返回参考auto&

auto X_bm = unaryExprFlex(X, [](Value& v) -> auto& { return v.b; });
cout << X_bm << endl;
X_bm.setConstant(10);
cout << X_bm << endl;
于 2017-06-04T08:14:41.207 回答