矩阵乘法是种极其耗时的运算。以
式(4.8)包含一个
这是一个很可怕的数字,当
分治法
Strassen算法基于分治的思想,因此我们首先考虑一个简单的分治策略。
每个
于是
展开得
每个等式需要计算两次矩阵乘法和一次矩阵加法。用
其中,
我们可以用上篇文章递归式求解——代入法、递归树与主定理中介绍的递归树法或主方法计算式(4.16)的解。结果是
Strassen算法
1969年,Volker Strassen发表文章提出一种渐进快于平凡算法的矩阵相乘算法,引起巨大轰动。在此之前,很少人敢设想一个算法能渐近快于平凡算法。矩阵乘法的渐近上界自此被改进了。
让我们回头观察前面使用分治策略的时候为什么无法提高速度。
因为分解后的问题包含了8次矩阵相乘和4次矩阵相加,就是这8次矩阵相乘导致了速度不能提升。于是我们想到能不能减少矩阵相乘的次数,哪怕代价是更多的矩阵相加。Strassen正是利用了这一点。
现在,我们来看一下Strassen算法的原理。
仍然把每个矩阵分割为4份,然后创建如下10个中间矩阵。
接着,计算7次矩阵乘法。
最后,根据这7个结果就可以计算出
是不是很神奇呢?话说我第一次看到这个算法的时候真的是惊呆了,10个
我们可以把
同样地,我们可以写出Strassen算法的递推公式。
使用递归树或主方法得到解为
下图展示了平凡算法和Strassen算法的性能差异,
![69de7d51a8db9ef9e973075c28858d5d.png](https://i-blog.csdnimg.cn/blog_migrate/b49571d5a30f06e55e26e17a9abe09f4.jpeg)
代码与实验
为了实际检验Strassen算法的性能,我分别实现了矩阵乘法的平凡算法和Strassen算法,完整代码见PlainMultiplier.java和StrassenMultiplier.java。实现并不复杂,不再赘述。但在实现的过程中,我发现当数据规模
在实践中还有一点需要注意,Strassen算法只适合用于
对Strassen的一些好奇
我猜很多人像我一样,会比较好奇Strassen当年是怎么想出这个算法的。这个疑问困扰了我很久,在网上很少能查到相关的资料,甚至Strassen当年的论文中也没有提到他的思路。
后来有人提到,Gauss曾经发现一个技巧,计算复数乘积
看似需要4次乘法,但其实换种计算方式
就只需要3次乘法,代价是加法从2次增加到5次。Strassen受到这一算法的启发,认为矩阵乘法也可以通过类似的方式实现。但Strassen的研究涉及到更高级的理论,我看过后就放弃了,目前还没法完全理解。我会把相关资料放在文章末尾,感兴趣的同学可以前往阅读。
最后,值得一提的是,研究者们经过多年努力,到目前为止,已经把矩阵乘法的时间复杂度降到了
参考资料
Gaussian Elimination is not Optimal Strassen
Strassen's Algorithm Made (Somewhat) More Natural: A Pedagogical Remark Ann Q. Gates, Vladik Kreinovich
How did Strassen come up with his matrix multiplication method? StackExchange
Toward an Optimal Algorithm for Matrix Multiplication Sara Robinson
Multiplying matrices in O(n^2.373) time Virginia Vassilevska Williams