在Eigen中制作矩阵 - 日志操作的更好方法是什么?

时间:2018-02-17 19:42:17

标签: c++ matrix eigen

我正在玩Eigen用矩阵和日志/ exp进行一些计算,但我发现表达式有点笨拙(也可能更慢?)。是否有更好的方法来编写这样的计算?

MatrixXd m = MatrixXd::Random(3,3);
m = m * (m.array().log()).matrix();

即,不必转换为数组,然后返回矩阵?

2 个答案:

答案 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 *。在矩阵形式中,它应该被认为是矩阵乘法,而在数组形式中,它应该是系数乘法。 explog的模糊性分别为matrix exponentialmatrix logarithm。据推测,你想要明智的元素explog,因此演员是必要的。