2013-10-27 64 views
3

我有一个1D本征数组(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,但请注意,这只是一个例子

+0

'unaryExpr'是'const'功能,所以它不会给你修改值的可能性(即给你一个非const引用)。你有没有尝试你的代码?我想它不会编译。 – leemes

+0

@lemes编译好了,但似乎没有修改数组,有点奇怪。 – arman

+0

在这种情况下,实现似乎使用标量值的本地副本将它传递给函子。有什么奇怪的是,它接受一个返回void的函数... – leemes

回答

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不返回完整的新数组/ ma trix - 但它会返回一个特殊的临时对象,它就像它一样。

0

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

但是,如果你想重新real()complex()(访问Scalar S结构的部分),你可以使用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; 
相关问题