简介
Strassen矩阵乘法是典型的分而治之算法。我们已经见过诸如归并排序,Karatsuba大数乘法的分而治之的算法。让我们再次领略一下分而治之的含义。
与动态编程的“分散”得到子解决方案是为了得到最终的解决方案不同。在这里,我们更多的是谈论如何把子方案拼接起来。一般问题的子问题的解决方案是平等的,以某种方式定义它们的合并。
归并排序算法就是一个典型的例子。归并排序中,有两个有序表,想要把合并为一个有序表。当然,归并排序中最棘手的问题就是合并本身。通过2个有序表A和B,把A,B中的每个子序列合并。说的有点偏离话题了,但是这就是归并排序的弱点,尽管归并排序最坏的时间复杂度是O(n,log(n)),快速排序通常是首选,因为它没有合并。快速排序只是连接两个子数组。注意,在快序排序中子序列的长度是一般情况下是不同的。尽管它的最坏的时间复杂度是O(n ^ 2),通常优于归并排序。
上面这个简单的例子向我们说明了,有时候合并两个子问题的解决方案实际上并不是一项简单的任务。因此在使用任何分而治之方法时,必须小心。
历史
施特拉森,出生于1936年,德国数学家。他有关概率的作品很知名,但是在计算机科学和算法领域中也很知名,因为他的矩阵算法。他的矩阵算法仍然是优于一般矩阵乘法算法主要方法。
1969,拉森第一次公开了这个算法并证明了n ^ 3算法并不是最优的。实际上拉森给出的解决方案只是稍微好一些。但他的贡献是巨大的,因为这引发了更多的关于矩阵乘法的研究,产生了更快的方法,即Coppersmith-Winograd算法,时间复杂度为O(n ^ 2,3737)。
综述
通常情况下,两个矩阵A[NxN]和B[NxN]相乘的算法是相当简单的。尽管这要比两个数相乘难一些,尽管它是不可交换的,但仍然非常简单,,只是算起来缓慢。
我们先来定义一个矩阵 A[NxN]。 当我们谈及NxN的矩阵时,通常认为是一个N行乘N列的正方形网格。在每一个A[i][j]中填入值。
当然,作为开发者,我们可以把矩阵作为二维数组。
// PHP two-dimensional array
$a = array(
0 => array($v1, $v2, $v3, $v4),
1 => array($v5, $v6, $v7, $v8),
2 => array($v9, $v10, $v11, $v12),
);
不要忘记NxN矩阵仅是一个矩阵的例子。同样我们可以建立其他任何大小的矩阵NxM(N < > M)。
然而矩阵相乘中,矩阵的大小是至关重要。为什么呢?
正如我上面所说的矩阵相乘与数字相乘不同。首先,矩阵乘法中两个矩阵是不能交换的。
其次,是矩阵A乘矩阵B的方式
这仅适用于 NxN的矩阵,看一下矩形矩阵相乘的问题。事实上,这是不可能发生,除非矩阵A的第二维度不相等矩阵B的第一个维度。
希望我们现在谈的是平方矩阵都有完全相同的维度。
我们已经知道两个平方矩阵(具有相同维度NxN)如何相乘了,现在让我们评估时间复杂度的通用算法。
仅当如下情况,AB = C:
C[i][j] = sum(A[i][k] * B[k][j]) for k = 0 .. n
有n ^ 3的操作。让我们试着找出一个分而治之的方法。
事实上,在矩阵下,这并不困难,因为我们知道矩阵可以分为较小的子矩阵。
得到如下结果:
再一次,同样的复杂性——我们得到了8个产出和4个和。
当然,为了获得更快的解决方案,我们看一下1969年Strassen所做的。他定义了P1,P2,P3,P4,P5,P6和P7如下图。
复杂度
Strassen的算法比一般矩阵乘法算法稍微快一些。一般的算法的时间复杂度是O(n ^ 3),而Strassen的算法的复杂度是O(n ^ 2.80)。
你可以看到在下面的图表速度只是稍微快一些,即使对于大的n。
应用
尽管比计算机科学,这个算法似乎更接近纯数学。无论在哪使用NxN的数组,我们都可以从矩阵乘法中受益。
另一方面Strassen的算法并不比一般的n ^ 3矩阵乘法算法快多少。维度对于小n(通常是n < 45)的问题,一般算法是更好的选择。然而从图中可以看出,当n > 100以上是,差别还是非常大的。
当我们谈论邻接矩阵图| V | = n时,通常使用NxN数组,一些图表的算法实际上取决于矩阵乘法。
作者:Stoimen