【问题标题】:Does Divide & Conquer Matrix Multiplication perform the same amount of additions/subtractions as the Classical Matrix multiplication?分治矩阵乘法是否执行与经典矩阵乘法相同数量的加法/减法?
【发布时间】:2025-12-01 01:20:05
【问题描述】:

分治矩阵乘法是否执行与经典矩阵乘法相同数量的加法/减法?

我知道它们专门用于乘法运算,因为它们都具有相同的 O(n^3) 复杂度...

但是当我尝试在我正在制作的程序中计算它们时,加法/减法会变成不同的数字,我不确定这是否正确。

如果有人知道,请告诉我,谢谢。

【问题讨论】:

  • 互联网搜索会回答这个问题....
  • 这似乎与your question from two hours ago非常相似。
  • 我已经试过了.. 我想我的谷歌技能很烂
  • 似乎 additions 的数量不是很容易用谷歌搜索的,只有操作的数量。

标签: algorithm recursion matrix matrix-multiplication


【解决方案1】:

让我们假设方阵。

如果您计算经典矩阵乘法中的加法次数(没有减法),您会得到 N^3 次加法。有 N^2 个元素,每个元素都是由 N-1 个加法组成的行和列的点积,所以几乎正好是 N^3 次加法。

要计算分治矩阵乘法中的加法次数,我们来看看它是如何工作的:

将 NxN 矩阵拆分为四个 (N/2)x(N/2) 矩阵,然后将其视为 2x2 矩阵并递归执行块乘法。 例如将两个 8x8 矩阵相乘:

┌┌A A A A┐┌B B B B┐┐ ┌┌a a a a┐┌b b b b┐┐
││A A A A││B B B B││ ││a a a a││b b b b││
││A A A A││B B B B││ ││a a a a││b b b b││
│└A A A A┘└B B B B┘│ │└a a a a┘└b b b b┘│
│┌C C C C┐┌D D D D┐│*│┌c c c c┐┌d d d d┐│
││C C C C││D D D D││ ││c c c c││d d d d││
││C C C C││D D D D││ ││c c c c││d d d d││
└└C C C C┘└D D D D┘┘ └└c c c c┘└d d d d┘┘

新矩阵将是:

┌┌       ┐┌       ┐┐
││ Aa+Bc ││ Ab+Bd ││
││       ││       ││
│└       ┘└       ┘│
│┌       ┐┌       ┐│
││ Ca+Dc ││ Cb+Dd ││
││       ││       ││
└└       ┘└       ┘┘
(where for example Aa is a 4x4 matrix multiplication)

[N/2xN/2]*[N/2xN/2] 的每个乘法都是大小为 N/2 的子问题。我们必须做 8 个这样的子问题。这给了我们上面的重复:

additions[N] = 8*additions[N/2] + N^2

也就是说,如果我们付出 N^2 个加法的代价,我们可以将 N 大小的问题分解为 8 个大小为 N/2 的子问题。 我们可以使用主定理(或更一般的 Akra-Bazzi 定理)或通过检查来解决:

additions[N] = 8*(8*(8*(8*(..1..) +(N/8)^2) +(N/4)^2) +(N/2)^2) +N^2

使用Master Theoremadditions[N] = O(N^(log_2(8))) = O(N^3)

既然增长顺序相同,我们为什么要这样做?我们不会。事实证明,为了获得更好的渐近复杂度,你不想这样做,你想使用一种称为 Strassen 方法的代数技巧。请参阅第 4 页的http://www.cs.berkeley.edu/~jordan/courses/170-fall05/notes/dc.pdf。我们的新递归关系来自计算乘法和加法的数量,如该页所示。形成一个 NxN 矩阵需要 18 个 [N/2xN/2] 个矩阵相加。

additions[N] = 7*additions[N/2] + 18*(N/2)^2
             = 7*additions[N/2] + (18/4)*(N/2)^2

如我们所见,我们必须少做一个子问题,但代价是在组合中做更多的工作。主定理说additions[N] = O(N^(log_2(7))) ~= O(N^2.807)

所以渐近地,将有更少的添加,但只是渐近的。当我们模拟这两种递归关系时,真实的故事就会揭开:

#!/usr/bin/python3

n = 1  # NxN matrix

normal = 1
naive = 1
strassen = 1

print('NUMBER OF ADDITIONS')
print('       NxN |   normal     naive  strassen | best')
print('-'*60)
while n < 1000000000:
    n *= 2

    normal = (n-1)*n**2
    naive = 8*naive + n**2
    strassen = 7*strassen + (18/4)*n**2

    print('{:>10} | {:>8.2e}  {:>8.2e}  {:>8.2e} | {}'.format(
        n,
        normal, naive, strassen/normal,
        'strassen' if strassen<n**3 else 'normal'
    ))

结果:

NUMBER OF ADDITIONS
       NxN |   normal     naive  strassen | best
------------------------------------------------------------
         2 | 4.00e+00  1.20e+01  2.50e+01 | normal
         4 | 4.80e+01  1.12e+02  2.47e+02 | normal
         8 | 4.48e+02  9.60e+02  2.02e+03 | normal
        16 | 3.84e+03  7.94e+03  1.53e+04 | normal
        32 | 3.17e+04  6.45e+04  1.12e+05 | normal
        64 | 2.58e+05  5.20e+05  7.99e+05 | normal
       128 | 2.08e+06  4.18e+06  5.67e+06 | normal
       256 | 1.67e+07  3.35e+07  4.00e+07 | normal
       512 | 1.34e+08  2.68e+08  2.81e+08 | normal
      1024 | 1.07e+09  2.15e+09  1.97e+09 | normal
      2048 | 8.59e+09  1.72e+10  1.38e+10 | normal
      4096 | 6.87e+10  1.37e+11  9.68e+10 | normal
      8192 | 5.50e+11  1.10e+12  6.78e+11 | normal
     16384 | 4.40e+12  8.80e+12  4.75e+12 | normal
     32768 | 3.52e+13  7.04e+13  3.32e+13 | strassen
     65536 | 2.81e+14  5.63e+14  2.33e+14 | strassen
    131072 | 2.25e+15  4.50e+15  1.63e+15 | strassen
    262144 | 1.80e+16  3.60e+16  1.14e+16 | strassen
    524288 | 1.44e+17  2.88e+17  7.98e+16 | strassen
   1048576 | 1.15e+18  2.31e+18  5.59e+17 | strassen
   2097152 | 9.22e+18  1.84e+19  3.91e+18 | strassen
   4194304 | 7.38e+19  1.48e+20  2.74e+19 | strassen
   8388608 | 5.90e+20  1.18e+21  1.92e+20 | strassen
  16777216 | 4.72e+21  9.44e+21  1.34e+21 | strassen
  33554432 | 3.78e+22  7.56e+22  9.39e+21 | strassen
  67108864 | 3.02e+23  6.04e+23  6.57e+22 | strassen
 134217728 | 2.42e+24  4.84e+24  4.60e+23 | strassen
 268435456 | 1.93e+25  3.87e+25  3.22e+24 | strassen
 536870912 | 1.55e+26  3.09e+26  2.25e+25 | strassen
1073741824 | 1.24e+27  2.48e+27  1.58e+26 | strassen

正如我们所见,仅就加法而言,Strassen 在加法数量方面优于传统的正常矩阵乘法,但只有当您的矩阵大小超过大约 30000x30000 时。 p>

(另请注意,在加法方面,天真的分治乘法的性能与传统矩阵乘法相同。但是,它的性能仍然“差”了最初的 3 倍,但随着矩阵大小的增加, 渐近地差 2 倍。当然,这并不能告诉我们涉及乘法的真正复杂性,但如果确实如此,如果我们有一个可以利用不同计算的并行算法,我们可能仍然想使用它结构。)

【讨论】:

    【解决方案2】:

    如果谈论的是简单的分治矩阵乘法算法(而不是 Strassens 的方法),那么与普通矩阵乘法相比,操作的数量相同

    This 链接提及:

    在这种情况下,分而治之的方法导致的操作数量与矩阵乘法的“正常”方法完全相同。上面的递归来自这样一个事实,即普通方法在应用于 2×2 矩阵时,需要 8 次乘法和 4 次加法。

    【讨论】:

      最近更新 更多