如何就地修改一维阵列的每个元素?

时间:2013-10-27 22:54:06

标签: c++ arrays eigen

我有一个双精度的一维特征数组(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;
}
);

但这看起来有点像黑客,因为Eigen Reference示例仅提供了.unaryExpr的示例,其中它与一个返回值的仿函数一起使用(然后整个方法只返回一个不同的数组)。就我而言,我希望避免创建新阵列的需要。

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

编辑:我知道我可以使用arr1D = arr1D >= 0.0替换上述内容,但请注意,这只是一个示例

2 个答案:

答案 0 :(得分:7)

.unaryExpr将“view”返回给定函数转换的原始数据。它不会对原始数据进行转换。

您无法更改传递给转换函数的参数。您的代码只是因为您没有触发适当代码的模板实例化而编译的。如果将结果赋值给那么它就无法编译:

#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不会返回全新的数组/矩阵 - 但会返回特殊的临时对象,就像它一样。

答案 1 :(得分:0)

如果您的价值类型相对简单,那么Evgeny的答案是最好的。

但是,如果您想重新创建real()complex()(访问Scalar结构的部分内容),您可以使用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;