稀疏矩阵乘法的特例

时间:2012-04-15 17:12:25

标签: performance algorithm matrix sparse-matrix matrix-multiplication

我正在尝试使用快速算法来查找AtLA操作的结果,其中

  • L - 是具有实数的对称n x n矩阵。
  • A - 是稀疏n x m矩阵,m < n。每行只有一个非零元素,它等于1.还保证每列最多有两个非零元素。

我提出了一种算法,但我觉得应该有比这更快的东西。

让我们将A的每一列表示为具有非零元素的行号对。如果列只有一个非零元素,则其行号列出两次。例如。对于以下矩阵

Sparse matrix example

这样的表示将是

column 0: [0, 2]; column 1: [1, 3]; column 2: [4, 4]

或者我们可以将其列为单个数组:A = [0, 2, 1, 3, 4, 4];现在,L' = LA可以计算为:

for (i = 0; i < A.length; i += 2):
  if A[i] != A[i + 1]:
     # sum of two column vectors, i/2-th column of L'
     L'[i/2] = L[A[i]] + L[A[i + 1]] 
  else:
     L'[i/2] = L[A[i]]

要计算L''=AtL',我们再一次这样做:

for (i = 0; i < A.length; i += 2):
  if A[i] != A[i + 1]:
    # sum of two row vectors, i/2-th row of L''
    L''[i/2] = L'[A[i]] + L'[A[i + 1]]
  else:
    L''[i/2] = L'[A[i]]

这种方法的时间复杂度是O(m n + m n),空间复杂度(得到最终AtLA结果)是O(n n)。我想知道是否可以在空间和/或性能方面将其提高到O(m m)?

3 个答案:

答案 0 :(得分:0)

第二个循环最多组合2m行L',因此如果m远小于n,则将有几行L'从未使用过。

避免计算和存储这些未使用条目的一种方法是将第一个循环更改为函数,并仅在需要时计算L'的各个元素。

def L'(row,col):
  i=col*2
  if A[i] != A[i + 1]:
    # sum of two column vectors, i/2-th column of L'
    return L[row][A[i]] + L[row][A[i + 1]] 
  else:
    return L[row][A[i]]

for (i = 0; i < A.length; i += 2):
  if A[i] != A[i + 1]:
    for (k=0;k<m;k++):
      L''[i/2][k] = L'(A[i],k) + L'(A[i + 1],k)
  else:
    for (k=0;k<m;k++):
      L''[i/2][k] = L'(A[i],k)

这应该具有空间和复杂度O(m * m)

答案 1 :(得分:0)

操作Transpose(A) * L的工作原理如下:

对于A的每一栏,我们看到:

column 1 has `1` in row 1 and 3
column 2 has `1` in row 2 and 4
column 3 has `1` in row 5

输出矩阵B = Transpose(A) * L有三行,等于:

Row(B, 1) = Row(A, 1) + Row(A, 3)
Row(B, 2) = Row(A, 2) + Row(A, 4)
Row(B, 3) = Row(A, 5)

如果我们乘以C = B * A

Column(C, 1) = Column(B, 1) + Column(B, 3)
Column(C, 2) = Column(B, 2) + Column(B, 4)
Column(C, 3) = Column(B, 5)

如果您以算法的方式完成此操作,您应该获得与Peter de Rivaz所建议的非常类似的东西。

答案 2 :(得分:0)

算法的时间复杂度为O(n ^ 2),而不是O(m * n)。 L的行和列的长度为n,A数组的长度为2n。

如果[k]是A的行k为1的列,则可以写:

A[k,i] = δ(a[k],i)

和产品,P = A ^ T * L * A是:

P[i,j] = Σ(k,l) A^T[i,k]*L[k,l]*A[l,j]
       = Σ(k,l) A[k,i]*L[k,l]*A[l,j]
       = Σ(k,l) δ(a[k],i)*L[k,l]*δ(a[l],j)

如果我们转过来看看L的元素会发生什么,我们会看到L [k,l]被加到P [a [k],a [l]],并且很容易得到O (m ^ 2)空间复杂度使用O(n ^ 2)时间复杂度。

因为为所有k = 0..n-1定义了[k],我们知道L的每个元素必须出现在产品的某个位置。因为L中存在O(n ^ 2)个不同的元素,所以你不能比O(n ^ 2)时间复杂度做得更好。