制作矩阵的更好方法 - 在 Eigen 中记录操作?
A better way to make matrix - log operations in Eigen?
我正在使用 Eigen 对矩阵和 logs/exp 进行一些计算,但我发现我的表达式有点笨拙(也可能更慢?)。有没有更好的方法来编写这样的计算?
MatrixXd m = MatrixXd::Random(3,3);
m = m * (m.array().log()).matrix();
也就是说,不必先转换为数组,然后再转换回矩阵?
如果您混合使用数组和矩阵运算,则无法真正避免它们,除了某些具有直接作用于矩阵的 cwise
函数的函数(例如,cwiseSqrt()
、cwiseAbs()
).
然而,.array()
和 .matrix()
都不会在优化编译时对运行时产生影响(在任何合理的编译器上)。
如果您认为它更具可读性,您可以使用 unaryExpr()
.
我完全同意 ,并重申 "casts." 没有运行时成本 您可以使用以下玩具程序确认:
#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%),这可能与内存加载方式(未选中)有关。除此之外, "casting" 类型的原因是为了消除任何歧义。举一个明显的例子,考虑 operator *
。在矩阵形式中,应该考虑矩阵乘法,而在数组形式中,它应该是系数乘法。 exp
和 log
的歧义分别是 matrix exponential and matrix logarithm。据推测,您想要明智的元素 exp
和 log
,因此强制转换是必要的。
我正在使用 Eigen 对矩阵和 logs/exp 进行一些计算,但我发现我的表达式有点笨拙(也可能更慢?)。有没有更好的方法来编写这样的计算?
MatrixXd m = MatrixXd::Random(3,3);
m = m * (m.array().log()).matrix();
也就是说,不必先转换为数组,然后再转换回矩阵?
如果您混合使用数组和矩阵运算,则无法真正避免它们,除了某些具有直接作用于矩阵的 cwise
函数的函数(例如,cwiseSqrt()
、cwiseAbs()
).
然而,.array()
和 .matrix()
都不会在优化编译时对运行时产生影响(在任何合理的编译器上)。
如果您认为它更具可读性,您可以使用 unaryExpr()
.
我完全同意
#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%),这可能与内存加载方式(未选中)有关。除此之外, "casting" 类型的原因是为了消除任何歧义。举一个明显的例子,考虑 operator *
。在矩阵形式中,应该考虑矩阵乘法,而在数组形式中,它应该是系数乘法。 exp
和 log
的歧义分别是 matrix exponential and matrix logarithm。据推测,您想要明智的元素 exp
和 log
,因此强制转换是必要的。