算法导论4-2
读书笔记
本章主要讲述了用于矩阵乘法的Strassen算法;
首先使用暴力算法给出了矩阵乘法的一个解,由于使用了三重循环,所以时间复杂度为\(\theta(n^3)\);
然后使用分治法给出一个解,但是时间复杂度并没有优于暴力算法,仍然是\(\theta(n^3)\);
最后引出了Strassen算法,能在\(\theta(n^{\lg{7}})\)的时间复杂度内,完成对矩阵的乘法;
在本章中,如何使用Strassen算法讲的很清楚,但是为什么能够奏效讲的不够清楚。
- 将输入矩阵\(A, B\)和输出矩阵\(C\)分解为\(\frac{n}{2}\ast\frac{n}{2}\)的子矩阵。采用下标计算方式;
- 创建10个\(\frac{n}{2}\ast\frac{n}{2}\)的矩阵\(S_1\)..\(S_{10}\),并且按照下方规则进行赋值:
- 然后根据上述所创建的10个矩阵,进行7次递归计算,形成7个新的矩阵
- 最后根据上述生成的7个矩阵,生成输出矩阵\(C\):
在章节4-5中会详细讲解算法原理。
课后练习
4.2-1
使用Strassen算法计算如下矩阵乘法
\[\begin{bmatrix} 1 & 3 \\ 7 & 5 \end{bmatrix} \begin{bmatrix} 6 & 8 \\ 4 & 2 \end{bmatrix} \]
首先使用常规算法算出结果以验证Strassen算法的正确性;
使用Strassen算法的过程:
- 分割输入矩阵\(A, B\)
- 生成10个中间矩阵
- 进行7次递归运算,生成7个性的矩阵
- 生成输出矩阵\(C\)
所以结果矩阵为
与常规解法结果相同,所以结果正确;
为Strassen算法编写伪代码
这里我直接引用了大峰子的伪代码
square-Matrix-Strassen (A, B)
n = A.row
let C be a new n*n matrix
if n == 1 //base case
C11 = A11 • B11
else //recursive case
partition A, B, and C as in equations 4.9
let S1, S2, S3, S4, S5, S6, S7, S8, S9, S10 be new n/2 * n/2 matrixs
S1 = B12 - B22
S2 = A11 + A12
S3 = A21 + A22
S4 = B21 - B11
S5 = A11 + A22
S6 = B11 + B22
S7 = A12 - A22
S8 = B21 + B22
S9 = A11 - A21
S10 = B11 + B12
P1 = square-Matrix-Strassen (A11, S1)
P2 = square-Matrix-Strassen (S2, B22)
P3 = square-Matrix-Strassen (S3, B11)
P4 = square-Matrix-Strassen (A22, S4)
P5 = square-Matrix-Strassen (S5, S6)
P6 = square-Matrix-Strassen (S7, S8)
P7 = square-Matrix-Strassen (S9, S10)
C11 = P5 + P4 - P2 + P6
C12 = P1 + P2
C21 = P3 + P4
C22 = P5 + P1 - P3 - P7
return C
4.2-2
如何修改Strassen算法,使之适应矩阵规模不是2的幂的情况?并且证明算法的运行时间为\(\theta{n^{lg{7}}}\)
对于第一小问,添加额外的行或列使之成为2的幂的方阵,添加的行或列均为0即可。
对于第二小问,//todo
4.2-3
如果可以用\(k\)次乘法操作(假定乘法交换律不成立)完成3*3矩阵相乘,那么你可以在\(o(n^{\lg{7}})\)时间内完成\(n\ast {n}\)矩阵相乘,满足这一条件的最大的\(k\)是多少? 此算法的运行时间是怎样的?
\(3\ast{3}\)并不满足Strassen算法的条件,所以先将其补全为\(4\ast{4}\),因此\(k=4^{\log_2^7}=49\)。
运行时间应该大于49,因为还有许多的加法;
4.2-4
V.Pan 发现一种方法,可以用132464次乘法操作完成\(68\ast{68}\)的矩阵相乘,发现另一种方法,可以用143640次乘法操作完成\(70\ast{70}\)的矩阵相乘,还发现一种方法,可以用155424次乘法操作完成\(72\ast{72}\)的矩阵相乘。但用于矩阵现成的分治算法时,上述哪种方法会得到最佳的渐近运行时间?与Strassen算法相比,性能如何?
\(72\ast{72}\)的方法会得到最佳的渐进运行时间,因为72最接近128;
通过计算,Strassen算法对应的次数为823543,823543,823543;所以V.Pan的方法会更优;
4.2-5
用Strassen算法作为子进程来进行一个\(kn\ast{n}\)矩阵和一个\(n\ast{kn}\)矩阵相乘,最快需要花费多长时间?对两个输入矩阵规模互换的情况,回答相同的问题。
先将两个举证补全为\(kn\ast{kn}\),然后再补全为二次幂;规模互换,解法不变;花费时间其实说不好,在于\(k\)作为系数到底有多大,还有\(kn\)距离右侧的二次幂有多远。
4.2-6
设计算法,仅使用三次实数算法即可完成复数\(a+bi\)和\(c+di\)相乘。算法需接收\(a,b,c,d\)作为输入,分别生成实部\(ac-bd\)和虚部\(ad+bc\)
算法如下