我正在玩Eigen用矩阵和日志/ exp进行一些计算,但我发现表达式有点笨拙(也可能更慢?)。是否有更好的方法来编写这样的计算?
MatrixXd m = MatrixXd::Random(3,3);
m = m * (m.array().log()).matrix();
即,不必转换为数组,然后返回矩阵?
答案 0 :(得分:3)
如果要混合数组和矩阵运算,除了一些具有cwiseSqrt()
函数直接在矩阵上运行的函数(例如cwiseAbs()
,{{}之外,您无法真正避免它们。 1}})。
但是,在使用优化编译时(在任何合理的编译器上),.array()
和.matrix()
都不会对运行时产生影响。
如果您认为更具可读性,则可以使用unaryExpr()
。
答案 1 :(得分:2)
我完全赞同chtz's answer,并重申“强制转换”没有运行时成本。您可以使用以下玩具程序进行确认:
#include "Eigen/Core"
#include <iostream>
#include <chrono>
using namespace Eigen;
int main()
{
typedef MatrixXd matType;
//typedef MatrixXf matType;
volatile int vN = 1024 * 4;
int N = vN;
auto startAlloc = std::chrono::system_clock::now();
matType m = matType::Random(N, N).array().abs();
matType r1 = matType::Zero(N, N);
matType r2 = matType::Zero(N, N);
auto finishAlloc = std::chrono::system_clock::now();
r1 = m * (m.array().log()).matrix();
auto finishLog = std::chrono::system_clock::now();
r2 = m * m.unaryExpr<float(*)(float)>(&std::log);
auto finishUnary = std::chrono::system_clock::now();
std::cout << (r1 - r2).array().abs().maxCoeff() << '\n';
std::cout << "Allocation\t" << std::chrono::duration<double>(finishAlloc - startAlloc).count() << '\n';
std::cout << "Log\t\t" << std::chrono::duration<double>(finishLog - finishAlloc).count() << '\n';
std::cout << "unaryExpr\t" << std::chrono::duration<double>(finishUnary - finishLog).count() << '\n';
return 0;
}
在我的电脑上,第一种形式略有优势(约4%),这可能与内存加载(未选中)的方式有关。除此之外,“铸造”类型的原因是消除任何歧义。有关明确示例,请考虑operator *
。在矩阵形式中,它应该被认为是矩阵乘法,而在数组形式中,它应该是系数乘法。 exp
和log
的模糊性分别为matrix exponential和matrix logarithm。据推测,你想要明智的元素exp
和log
,因此演员是必要的。