Matrix 求循环的CSR x CSR矩阵乘法

Matrix 求循环的CSR x CSR矩阵乘法,matrix,graph,sparse-matrix,matrix-multiplication,adjacency-matrix,Matrix,Graph,Sparse Matrix,Matrix Multiplication,Adjacency Matrix,我试图找出一个指定长度(k)的无向图中的圈数,该图中的每个顶点都包含顶点u。为此,我试图找出邻接矩阵的k次方。我从边列表创建了图的CSR表示。它工作得真快。但是CSR x CSR乘法部分非常慢(输入大小为500k x 500k矩阵时,似乎需要50分钟)。我想知道一个更好的解决办法。因为这是一个邻接矩阵,有没有更有效的方法?或者有没有更好的CSRxCSR矩阵乘法,我可以看看?我找不到任何CSR XCSR矩阵乘法例子作为算法或C++实现。 void multiply_matrix(std::

我试图找出一个指定长度(k)的无向图中的圈数,该图中的每个顶点都包含顶点u。为此,我试图找出邻接矩阵的k次方。我从边列表创建了图的CSR表示。它工作得真快。但是CSR x CSR乘法部分非常慢(输入大小为500k x 500k矩阵时,似乎需要50分钟)。我想知道一个更好的解决办法。因为这是一个邻接矩阵,有没有更有效的方法?或者有没有更好的CSRxCSR矩阵乘法,我可以看看?我找不到任何CSR XCSR矩阵乘法例子作为算法或C++实现。
    void multiply_matrix(std::vector<int> &adj, std::vector<int> &xadj, std::vector<int> &values, std::vector<int> &adj2, std::vector<int> &xadj2, std::vector<int> &values2, int size)
  {
          std::vector<int> result_adj;
          std::vector<int> result_xadj(size+1,0);
          std::vector<int> result_value(values.size(),0);
          for(int i = 0; i<size; i++)
          {
                  for(int j = 0; j<size; j++)
                  {
                          int result = 0;
                          int startIndex = xadj[i];
                          int endIndex = xadj[i+1];
                          for(int index = startIndex; index<endIndex; index++)
                          {
                                  int currentValRow = values[adj[index]];
                                  bool shouldContinue = false;
                                  for(int colIndex = xadj2[j]; colIndex<xadj2[j+1]; colIndex++)
                                  {
                                          if(adj[index] == adj2[colIndex])
                                          {
                                                  shouldContinue = true;
                                                  break;
                                          }
                                  }
                                  if(!shouldContinue)
                                          continue;
                                  int currentValCol = values2[adj2[index]];
                                  result += currentValCol*currentValRow;
                          }
                          if(result != 0)
                          {
                                  result_xadj[i+1]++;
                                  if(i+2 < result_xadj.size())
                                          result_xadj[i+2] = result_xadj[i+1];
                                  result_adj.push_back(j);
                                  result_value[j] = result;
                          }
                  }
          }
  }
void multiply_矩阵(std::vector&adj,std::vector&xadj,std::vector&values,std::vector&adj2,std::vector&xadj2,std::vector&values2,int size)
{
std::向量结果_adj;
std::向量结果_xadj(大小+1,0);
std::vector result_值(values.size(),0);

对于(int i=0;i我解决了我的问题,并希望与那些同样缺乏所需“术语”的人分享,以查找有关该主题的大量资源。当你搜索“稀疏矩阵乘法”时,很难找到稀疏矩阵x稀疏矩阵。这被称为SpGEMM。有很多关于该过程的信息性论文

我使用的算法的伪代码:

我稍微修改了算法以生成CSR输出。与此相关的挑战似乎是分配结果数组以保存CSR数组(值、索引数组等)。有不同的方法用于解决该问题,例如:

  • 分配与上限一样大的数组。如果矩阵太大,这可能是一个问题。如果您决定这样做,您可以查看:
  • 在为结果分配任何内存之前,可以进行乘法运算以确定结果中非零的数量。由于此空间中不存在内存写入操作,因此结果出来得非常快。因此,可以在“虚拟运行”之后分配结果数组所需的内存
  • 分配一个预先确定的数量,当分配一个新数组并将内容复制到新的、更大的数组不够时
  • 我为CPU(使用OpenMP)和GPU(使用CUDA)实现了该功能。在OpenMP方法中,我使用了一种类似于我列出的选项3的方法。我对每行的结果使用了单独的向量。然后我添加了结果向量。向量方法可能比手动执行重新分配操作慢,但更简单,因此我选择了这种方法,并且速度足够快(测试矩阵有500k行和500k列,乘法运算大约需要1.3秒,在我的测试机器上使用60个线程)。对于GPU方法,我使用选项2。首先我计算了所需的量,然后实际操作发生


    编辑:此方法还可以查找“行走”而不是路径。因此可能会有重复的顶点。

    我强烈建议您使用sparseblas或mkl。有很多关于如何优化矩阵乘法的文献,除非您想花费大量时间阅读有关寄存器和缓存效率的内容,否则不要重新发明轮子。(您还没有将其并行化,这将使其速度变慢)