我想替换以下通用矩阵*向量函数
void MV(double *M, double *x, double *y, int n, int m)
{
for (int i = 0; i<n; i++) {
for (int j = 0; j<m; j++) {
y[i] += M[i*m + j] * x[j];
}
}
}
使用Eigen的矩阵*向量运算。这就是我所做的。
void MV2(double *M, double *x, double *y, int n, int m)
{
typedef Eigen::Matrix<double, -1, -1, Eigen::RowMajor> Rm;
Eigen::Map<const Rm> Me(M, n, m);
Eigen::Map<const Rm> xe(x, m, 1);
Eigen::Map<Rm> ye(y, n, 1);
ye = Me*xe;
}
通过一个简单的“hello world”测试(使用GCC 5.3,Ubuntu 16.04),这很好用
int main(void)
{
double M[12];
double x[4];
double y[3];
for(int i=0; i<12; i++) M[i] = i;
for(int i=0; i<4; i++) x[i] = i;
int n = 3, m = 4;
MV(M,x,y,3,4);
printf("%f %f %f\n", y[0], y[1], y[2]);
MV2(M,x,y,3,4);
printf("%f %f %f\n", y[0], y[1], y[2]);
}
但是,我现在在使用Visual Studio 2013编译的主应用程序中使用这些函数。我正在使用由许多小密集矩阵组成的稀疏矩阵运行各种大小的许多小矩阵(例如60x60)。 MV
函数给出了正确的结果,但MV2
函数没有。它也慢了。我做错了什么?
答案 0 :(得分:3)
您忘记了MV2版本中的+=
。然后,关于性能,最好让Eigen在编译时知道何时有向量:
void MV2(const double *M, const double *x, double *y, int n, int m)
{
typedef Eigen::Matrix<double, -1, -1, Eigen::RowMajor> Rm;
Eigen::VectorXd::Map(y,n).noalias() += Rm::Map(M,n,m)
* Eigen::VectorXd::Map(x,m);
}
noalias
允许通过让Eigen知道结果可以写在y
而没有别名问题来避免暂时性。
修改强>
如果M
是对称的,那么您可以按如下方式告诉Eigen:
VectorXd::Map(y,n).noalias() += Rm::Map(M,n,m).selfadjointView<Lower>()
* VectorXd::Map(x,m);