如何优化矩阵乘法运算

时间:2011-05-19 16:39:14

标签: c++ matrix matrix-multiplication

我需要在我的应用程序中执行很多矩阵操作。最耗时的是矩阵乘法。我这样实现了它

template<typename T>
Matrix<T> Matrix<T>::operator * (Matrix& matrix)
{


    Matrix<T> multipliedMatrix = Matrix<T>(this->rows,matrix.GetColumns(),0);

    for (int i=0;i<this->rows;i++)
    {
        for (int j=0;j<matrix.GetColumns();j++)
        {
            multipliedMatrix.datavector.at(i).at(j) = 0;
            for (int k=0;k<this->columns ;k++)
            {
                multipliedMatrix.datavector.at(i).at(j) +=  datavector.at(i).at(k) * matrix.datavector.at(k).at(j);
            }
            //cout<<(*multipliedMatrix)[i][j]<<endl;
        }
    }
    return multipliedMatrix;
}

有没有办法以更好的方式写它?到目前为止,矩阵乘法运算占用了我的应用程序的大部分时间。也许是有好/快的库来做这种事情? 但是我不能使用使用图形卡进行数学运算的库,因为我在带有集成显卡的笔记本电脑上工作。

6 个答案:

答案 0 :(得分:6)

到目前为止,{p> Eigen是迄今为止速度最快的线性代数库之一。它写得很好,而且质量很高。此外,它使用表达式模板,使编写更易读的代码。刚刚发布的第3版使用OpenMP进行数据并行。

#include <iostream>
#include <Eigen/Dense>

using Eigen::MatrixXd;

int main()
{
  MatrixXd m(2,2);
  m(0,0) = 3;
  m(1,0) = 2.5;
  m(0,1) = -1;
  m(1,1) = m(1,0) + m(0,1);
  std::cout << m << std::endl;
}

答案 1 :(得分:4)

Boost uBLAS我认为绝对是这种方式。 Boost经过精心设计,经过充分测试,可用于许多应用领域。

答案 2 :(得分:2)

考虑GNU Scientific LibraryMV++

如果您对C没问题,BLAS是一个低级库,它包含C和C包装的FORTRAN指令,并且使用了大量更高级别的数学库。

我对此一无所知,但另一个选项可能是Meschach seems to have decent performance

编辑:关于您不想使用使用显卡的库的评论,我会指出在许多情况下,使用显卡的库是标准(非GPU)库的专用实现。例如,BLAS的各种实现是listed on it's Wikipedia page,只有一些是为了利用你的GPU而设计的。

答案 3 :(得分:1)

有一本名为Introduction to Algorithms的书。您可以查看动态编程一章。它有一个很好的矩阵乘法算法,使用动态编程。值得一读。好吧,这个信息是为了你想要编写自己的逻辑而不是使用库。

答案 4 :(得分:1)

有很多算法可以进行有效的矩阵乘法。

Algorithms for efficient matrix multiplication

查看算法,找到实现。

您也可以为它进行多线程实现。

答案 5 :(得分:0)

我要做的是减少被调用的at(i)运算符的数量。例如,在这个循环中:

for (int i=0;i<this->rows;i++)     
{        
    for (int j=0;j<matrix.GetColumns();j++)  
    {          
         multipliedMatrix.datavector.at(i).at(j) = 0;     
         for (int k=0;k<this->columns ;k++)          
         {               
               multipliedMatrix.datavector.at(i).at(j) +=  datavector.at(i).at(k) * matrix.datavector.at(k).at(j);            
         } 
     }
 } 

通过在每个j和每个k循环内执行at(i)运算符,您会浪费大量时间。

我要做的是:

for (int i=0;i<this->rows;i++)     
{   
    // I don't know the type of this object, but let's call it type MatrixRow     
    MatrixRow & mmi = multipliedMatrix.datavector.at(i);
    MatrixRow & dvi = datavector.at(i);
    for (int j=0;j<matrix.GetColumns();j++)  
    {          
         // I don't know the type of this either, but let's say it's a double
         double &mmij  = mmi.at(j);
         mmij = 0;
         for (int k=0;k<this->columns ;k++)          
         {               
               mmij +=  dvi.at(k) * matrix.datavector.at(k).at(j);            
         } 
     }
 } 

上述建议可能在语法上不正确,但您明白了。

此外,如果你的内存是连续分配的,你可以通过不对每个j和每个k进行查找来获得更高的加速,而是使用适当的指针增量。

此外,数组边界可能效率低下,因为这些查找被大量调用,并且每次调用函数或正在进行解除引用时。这是this->rowsmatrix.GetColumns()this->columns可以存储在适当的整数中。这可能会提高很多速度。