我有一个 Eigen::MatrixXd
,我想通过逐个元素地应用函数来修改它的所有元素。例如:
MatrixXd m = ...;
for each m[i][j]:
m[i][j] = exp(m[i][j]);
有没有办法实现这个结果?
可以使用Eigen::MatrixBase<>::unaryExpr()
成员函数,例如:
#include <cmath>
#include <iostream>
#include <Eigen/Core>
double Exp(double x) // the functor we want to apply
{
return std::exp(x);
}
int main()
{
Eigen::MatrixXd m(2, 2);
m << 0, 1, 2, 3;
std::cout << m << std::endl << "becomes: ";
std::cout << std::endl << m.unaryExpr(&Exp) << std::endl;
}
vsoftco的回答非常通用,并且对于自定义函数非常好。然而,对于许多常用函数来说,有一种更简单的方法。通过改编他的示例,我们可以使用array
,它看起来像这样:
#include <iostream>
#include <Eigen/Core>
int main()
{
Eigen::MatrixXd m(2, 2);
m << 0, 1, 2, 3;
std::cout << m << "\nbecomes:\n";
std::cout << m.array().exp() << std::endl;
return 0;
}
顺便说一下,在C++11及其以后的版本中,这也适用于lambda函数。
#include <cmath>
#include <iostream>
#include <Eigen/Core>
int main()
{
Eigen::MatrixXd m(2, 2);
m << 0, 1, 2, 3;
std::cout << m << std::endl << " -> "
std::cout << m.unaryExpr([](double x){return x + 1}) << std::endl;
}
&Exp
传递给.unaryExpr()
会导致编译错误(g ++,c + 11,Eigen 3.3.5出现与以下相关的错误:base type 'double (*) (double)'无法成为结构或类类型
)。std :: function
对象并传递它可以解决这个问题。复制@vsoftco的示例:#include <cmath>
#include <iostream>
#include <Eigen/Core>
double Exp(double x)
{
return std::exp(x);
}
int main()
{
Eigen::MatrixXd m(2, 2);
m << 0, 1, 2, 3;
std::function<double(double)> exp_wrap = Exp; //added to @vsoftco's answer
std::cout << m << std::endl << "becomes: ";
std::cout << std::endl << m.unaryExpr(exp_wrap) << std::endl; //and used here
}
我不确定使用std::function
对象(或std::ptr_fun
)相对于传递&Exp
会增加多少开销,但是如果没有这些替代方法,我无法使其正常工作。
谢谢
std::exp
有多个重载,而unaryExpr
无法仅从std::exp
中推断出函数对象的签名(即有多个候选项)。如果您“帮助”编译器指定函数对象类型,例如m.unaryExpr<double(*)(double)>(&std::exp)
,则可以正常工作。 - vsoftcostd::ptr_fun
...,例如请参阅 https://eigen.tuxfamily.org/dox/classEigen_1_1MatrixBase.html#title108 在这种情况下,函数名称根据 C++ 的规则自动衰减为指针,并且函数指针的行为就像一个函数对象。此外,std::ptr_fun
在C++11中已经被弃用,请参阅 http://en.cppreference.com/w/cpp/utility/functional/ptr_fun。 - vsoftcom.unaryExpr(&Expr)
返回的矩阵分配给一个新对象吗? - Shawn Brar