概览
本节介绍了由 Volker Strassen 于 1969 年发表的突破性Strassen 算法,该算法通过巧妙的子矩阵线性组合,将分治矩阵乘法中的递归乘法次数从 8 次减少到 7 次,从而将时间复杂度从 降低到 。算法分为四步:分区、构造 10 个中间矩阵 、递归计算 7 个乘积 、通过 的加减组合恢复结果矩阵 。本节详细展示了 的定义、 的恢复过程及其正确性验证,并建立了递归关系式 。
- Strassen 算法将递归子矩阵乘法从 8 次减少到 7 次,以常数次额外加减法为代价
- 递归关系式 的解为 ,渐近优于
- 算法通过 10 个中间矩阵 (子矩阵的和与差)和 7 个乘积矩阵 实现乘法次数的减少
- 的四个子矩阵通过 的加减组合恢复,共需 12 次子矩阵加减法
- 核心洞察:减少一次递归乘法( 级别)所换取的额外加减法( 级别)在渐近意义上是值得的
知识结构总览
graph TB A["4.2 Strassen算法"] --> B["算法动机与直觉"] A --> C["算法四步骤"] A --> D["7个乘积矩阵 P1-P7"] A --> E["结果矩阵的恢复"] A --> F["递归关系式分析"] A --> G["正确性验证"] B --> B1["8次乘法→7次乘法"] B --> B2["x²-y² 的代数技巧"] B --> B3["乘法代价 vs 加法代价"] C --> C1["步骤1:基准情况与分区"] C --> C2["步骤2:构造 S1-S10"] C --> C3["步骤3:递归计算 P1-P7"] C --> C4["步骤4:恢复 C11-C22"] D --> D1["P1 = A11·S1"] D --> D2["P2 = S2·B22"] D --> D3["P3 = S3·B11"] D --> D4["P4 = A22·S4"] D --> D5["P5 = S5·S6"] D --> D6["P6 = S7·S8"] D --> D7["P7 = S9·S10"] E --> E1["C11 = P5+P4-P2+P6"] E --> E2["C12 = P1+P2"] E --> E3["C21 = P3+P4"] E --> E4["C22 = P5+P1-P3-P7"] F --> F1["T(n) = 7T(n/2) + Θ(n²)"] F --> F2["解为 Θ(n^lg7) ≈ Θ(n^2.81)"] F --> F3["与 Θ(n³) 的对比"] G --> G1["C11 的展开验证"] G --> G2["C12 的展开验证"] G --> G3["C21 的展开验证"] G --> G4["C22 的展开验证"]
核心思想
核心思想
Strassen 算法的核心思想是:在 4.1 矩阵乘法 的分治框架基础上,通过预先构造子矩阵的线性组合,将递归乘法次数从 8 次减少到 7 次。虽然这需要额外执行 10 次子矩阵加法(构造 )和 12 次子矩阵加减法(恢复 ),但这些加减法的代价是 ,而减少一次乘法节省的是 级别的递归代价。在递归展开后,这一”用加减法换乘法”的策略使得总运行时间从 降低到 ,这是矩阵乘法算法历史上的第一次渐近突破。
1. 算法动机与直觉
减少乘法次数的代数直觉:
考虑计算 :
- 朴素方法: 计算 和 ,然后相减——需要 2 次乘法和 1 次减法
- 代数技巧: 利用恒等式 ——只需 1 次乘法和 2 次加减法
当 和 是标量时,两种方法都需要 3 次标量运算,没有区别。但当 和 是大矩阵时,乘法的代价远高于加法(矩阵乘法 vs 矩阵加法 ),此时第二种方法显著优于第一种。
Strassen 算法正是将这一思想推广到矩阵乘法:通过精心设计的线性组合,在不同的子矩阵乘积之间”共享”计算结果,从而减少总的乘法次数。
2. Strassen 算法的四步骤
Strassen 算法
Strassen 算法计算 ,其中 、、 均为 矩阵, 为 2 的幂。算法分为四步:
步骤 1:基准情况与分区
- 若 ,执行一次标量乘法和一次标量加法,耗时 ,返回
- 否则,通过索引计算将 、、 各划分为四个 子矩阵(与 4.1 矩阵乘法 相同),耗时
步骤 2:构造 10 个中间矩阵
- 创建 ,每个是两个子矩阵的和或差
- 创建并初始化 7 个 矩阵
- 共 17 个矩阵的创建和初始化,耗时
步骤 3:递归计算 7 个乘积
- 使用步骤 1 的子矩阵和步骤 2 的 ,递归计算
- 7 次递归调用,耗时
步骤 4:恢复结果矩阵
- 通过 的加减组合更新
- 共 12 次子矩阵加减法,耗时
3. 10 个中间矩阵 S1-S10
中间矩阵
步骤 2 创建以下 10 个 矩阵,每个是两个子矩阵的和或差:
矩阵 定义 含义 右列的差 上行的和 下行的和 左列的差 对角线的和 对角线的和 右列的差 下行的和 左列的差 上行的和 这些中间矩阵的设计是 Strassen 算法的核心——它们使得后续的 7 次乘法能够”覆盖”原来 8 次乘法的所有信息。
4. 7 个乘积矩阵 P1-P7
乘积矩阵
步骤 3 递归计算以下 7 个 矩阵乘积。算法只执行中间列的乘法,右列仅为展开说明,算法中不会显式计算:
乘积 算法执行的计算 展开为原始子矩阵 注意 是一个”全交叉”乘积,包含了 和 的所有对角线子矩阵组合。 和 则包含”交叉”和”反对角”组合。
5. 结果矩阵的恢复
从 恢复
步骤 4 通过 的加减组合恢复结果矩阵的四个子矩阵:
步骤 4 共执行 12 次子矩阵加减法( 需要 4 次, 需要 2 次, 需要 2 次, 需要 4 次),耗时 。
的正确性验证
展开 ,逐项代入 的展开式并垂直对齐可消去的项:
消去后剩余:
这正是 ,与标准矩阵乘法定义一致。
、、 的正确性验证
:
:
:
6. 递归关系式分析
Strassen 算法的递归关系式
综合四步分析,Strassen 算法的运行时间递归关系式为:
其中:
- 步骤 1(基准情况):
- 步骤 1(分区)+ 步骤 2(构造 和初始化 )+ 步骤 4(恢复 ):
- 步骤 3(7 次递归乘法):
使用主定理求解(第 4.5 节预告):
- ,,
- 比较 与 :(取 ),属于主定理情形 1
- 因此
由于 ,Strassen 算法渐近优于 4.1 矩阵乘法 的 方法。
Strassen 算法的代价权衡
Strassen 算法的核心权衡是:
- 减少的代价: 1 次递归子矩阵乘法(每次递归节省 ,累积效果巨大)
- 增加的代价: 10 次子矩阵加法(步骤 2)+ 12 次子矩阵加减法(步骤 4)= 22 次 的操作
在递归的每一层,增加的代价为 ,而减少的代价体现在递归树的结构变化上——从 8 叉树变为 7 叉树。虽然递归树仍然”茂密”,但叶子数量从 减少到 ,这是一个显著的渐近改进。
代价统计: Strassen 算法总共使用 7 次子矩阵乘法和 18 次子矩阵加法(10 次构造 + 12 次恢复 ,但其中 的构造与恢复 的某些操作可以共享,净增 18 次)。
补充理解与拓展
Strassen 算法的历史意义与后续发展
Volker Strassen 于 1969 年发表的这篇论文 “Gaussian elimination is not optimal” 是计算复杂性理论中最具影响力的成果之一。在 Strassen 之前,数学界普遍认为 是矩阵乘法的最优复杂度——毕竟标准定义本身就涉及 次标量乘法。Strassen 的工作打破了这一”直觉障碍”,证明算法可以超越定义的表面复杂度。此后,矩阵乘法的指数不断被降低:Coppersmith-Winograd(1987)达到 ,Stothers(2010)降至 ,Virginia Vassilevska Williams(2012)改进至 ,Alman-Williams(2021)进一步降至 ,最新结果由 Duan-Wu-Zhou(2023)取得 。然而,Strassen 算法因其相对简洁的实现,至今在实际应用中仍被广泛使用(例如在 BLAS 库中)。
来源:V. Strassen, “Gaussian elimination is not optimal”, Numerische Mathematik, 13(4):354-356, 1969; T. H. Cormen et al., Introduction to Algorithms, 4th ed., MIT Press, 2022, Section 4.2.
Strassen 算法的实际应用与常数因子
虽然 Strassen 算法的渐近复杂度优于朴素方法,但在实际应用中需要考虑常数因子。Strassen 算法的常数因子较大(更多的矩阵加减法、更复杂的内存访问模式),因此对于较小的矩阵,朴素方法实际上更快。实践中通常采用混合策略:当递归到某个阈值 (通常在 之间)时切换到朴素方法。此外,Strassen 算法的数值稳定性也略差于朴素方法——由于中间矩阵涉及减法,当矩阵元素大小差异悬殊时可能出现精度损失。Laderman(1976)证明了存在使用 7 次乘法但不需要减法的算法,但实现更为复杂。
来源:T. H. Cormen et al., Introduction to Algorithms, 4th ed., MIT Press, 2022, Section 4.2; J. Laderman, “A noncommutative algorithm for multiplying 3×3 matrices using 23 multiplications”, Bulletin of the AMS, 1976.
易混淆点与辨析
"Strassen 算法减少了乘法次数所以更快"的片面理解
初学者可能简单地认为”7 次乘法比 8 次乘法少,所以更快”,而忽略了算法的整体代价分析。
- ❌ “Strassen 算法快是因为 7 < 8,乘法次数少了”
- ✅ “Strassen 算法快是因为减少 1 次递归乘法所节省的代价(体现在递归树从 8 叉变为 7 叉,叶子数量从 减少到 )远超增加的 18 次子矩阵加减法的代价(每次 )。关键在于乘法的递归代价是 级别,而加减法只是 级别。在递归展开后,这一差异被指数放大”
直觉理解:想象每次递归节省 1/8 的乘法代价,但只增加了固定比例的加减法代价。经过 层递归后,乘法节省的总量呈指数增长,而加减法的额外代价只是线性增长。
"Strassen 算法适用于所有矩阵乘法场景"的误解
初学者可能认为 Strassen 算法在所有情况下都优于朴素方法。
- ❌ “Strassen 算法的时间复杂度更低,应该始终使用它”
- ✅ “Strassen 算法的渐近优势在 足够大时才体现。对于小规模矩阵,其较大的常数因子(更多的加减法、更复杂的内存访问模式)使它反而更慢。实践中通常设置递归阈值 ,当 时使用 Strassen,否则切换到朴素方法。此外,Strassen 算法的数值稳定性略差,对精度要求极高的场景需谨慎使用”
实践原则:渐近复杂度描述的是 时的行为。对于有限规模的输入,常数因子、内存层次结构、并行性等因素都可能影响实际性能。
习题精选
| 题号 | 核心考点 | 难度 |
|---|---|---|
| 4.2-1 | Strassen 算法的手动计算 | ⭐⭐⭐ |
| 4.2-2 | Strassen 算法的伪代码 | ⭐⭐ |
| 4.2-3 | 3×3 矩阵乘法的乘法次数下界 | ⭐⭐⭐ |
| 4.2-4 | Pan 的矩阵乘法算法对比 | ⭐⭐⭐ |
| 4.2-5 | 复数乘法与 Strassen 思想的联系 | ⭐⭐ |
4.2-1 使用 Strassen 算法计算矩阵乘积 ,展示你的计算过程。
思路提示: 对 矩阵,,直接应用 Strassen 的公式。
解答:
令 ,。
子矩阵(此时为标量):,。
步骤 2:计算 :
步骤 3:计算 :
步骤 4:恢复 :
验证:
直接计算验证: ✓, ✓, ✓, ✓
4.2-2 编写 Strassen 算法的伪代码。
思路提示: 按照四步骤结构组织伪代码,注意矩阵分区的索引计算。
解答:
STRASSEN-MATRIX-MULTIPLY(A, B, C, n) 1 if n == 1 2 c_11 = c_11 + a_11 · b_11 3 return 4 partition A, B, C into n/2 × n/2 submatrices 5 A_11, A_12, A_21, A_22 6 B_11, B_12, B_21, B_22 7 C_11, C_12, C_21, C_22 8 // 步骤 2:构造 S1-S10 9 S_1 = B_12 - B_22 10 S_2 = A_11 + A_12 11 S_3 = A_21 + A_22 12 S_4 = B_21 - B_11 13 S_5 = A_11 + A_22 14 S_6 = B_11 + B_22 15 S_7 = A_12 - A_22 16 S_8 = B_21 + B_22 17 S_9 = A_11 - A_21 18 S_10 = B_11 + B_12 19 // 步骤 3:递归计算 P1-P7 20 STRASSEN-MATRIX-MULTIPLY(A_11, S_1, P_1, n/2) 21 STRASSEN-MATRIX-MULTIPLY(S_2, B_22, P_2, n/2) 22 STRASSEN-MATRIX-MULTIPLY(S_3, B_11, P_3, n/2) 23 STRASSEN-MATRIX-MULTIPLY(A_22, S_4, P_4, n/2) 24 STRASSEN-MATRIX-MULTIPLY(S_5, S_6, P_5, n/2) 25 STRASSEN-MATRIX-MULTIPLY(S_7, S_8, P_6, n/2) 26 STRASSEN-MATRIX-MULTIPLY(S_9, S_10, P_7, n/2) 27 // 步骤 4:恢复 C 28 C_11 = C_11 + P_5 + P_4 - P_2 + P_6 29 C_12 = C_12 + P_1 + P_2 30 C_21 = C_21 + P_3 + P_4 31 C_22 = C_22 + P_5 + P_1 - P_3 - P_7
4.2-3 如果你能用 次乘法(不假设乘法可交换)来乘以 矩阵,那么你能用 时间乘以 矩阵的最大 是多少?这个算法的运行时间是多少?
思路提示: 将 矩阵递归地划分为 块矩阵(每块为 ),建立递归关系式 ,然后求使解小于 的最大 。
解答:
递归关系式为 。
由主定理,解为 (当 多项式大于 时)。
要求 ,即 。
因此最大整数 。当 时,。
注意到 ,不满足 。
重新计算:。。
需要 ,即 。
因此 。但 ,所以 也不满足严格小于。
实际上需要 。。。所以 时 ✓。
答案: 最大 。运行时间为 ,确实为 。
4.2-4 V. Pan 发现了使用 132,464 次乘法乘以 矩阵、使用 143,640 次乘法乘以 矩阵、使用 155,424 次乘法乘以 矩阵的方法。哪种方法在分治矩阵乘法中产生最好的渐近运行时间?与 Strassen 算法相比如何?
思路提示: 对每种方法建立递归关系式 ,其中 是矩阵大小, 是乘法次数。比较 的大小。
解答:
方法 渐近复杂度 Pan 68×68 68 132,464 Pan 70×70 70 143,640 Pan 72×72 72 155,424 Strassen 2 7 三种 Pan 方法给出几乎相同的指数(约 2.795),均略优于 Strassen 的 。其中 方法给出最小的指数 ,是三者中最好的。然而,这些方法的优势仅体现在极大的矩阵规模上,且实现复杂度远高于 Strassen 算法。
4.2-5 展示如何仅用 3 次实数乘法来乘以复数 和 。算法应以 为输入,分别产生实部分量 和虚部分量 。
思路提示: 复数乘法 天然需要 4 次实数乘法。利用类似 Strassen 的代数技巧,可以减少到 3 次。
解答:
计算:
则:
- 实部
- 虚部
仅需 3 次乘法()和 5 次加减法(计算 、、、),替代了原来的 4 次乘法和 2 次加减法。这与 Strassen 算法的思想完全一致——用加减法换乘法。
视频学习指南
| 资源 | 链接 | 对应内容 | 备注 |
|---|---|---|---|
| MIT 6.006 Lecture 9: Matrix Multiplication | https://www.youtube.com/watch?v=O4V6IlxiWp8 | Strassen 算法详解 | Erik Demaine 教授 |
| Abdul Bari - Strassen’s Matrix Multiplication | https://www.youtube.com/watch?v=e8j7dzY2S6I | Strassen 算法逐步演示 | 直观的动画讲解 |
| Stanford CS161 Lecture 5: Strassen | https://www.youtube.com/watch?v=aChF5aM9RgI | Strassen 算法与主定理 | Mary Wootters 教授 |
| 河南大学《算法导论》中文字幕版 | https://www.bilibili.com/video/BV1H4411B7FY | 4.2 Strassen 算法 | 中文授课,适合入门 |
教材原文
教材原文摘录
“You might find it hard to imagine that any matrix multiplication algorithm could take less than time, since the natural definition of matrix multiplication requires scalar multiplications. Indeed, many mathematicians presumed that it was not possible to multiply matrices in time until 1969, when V. Strassen published a remarkable recursive algorithm for multiplying matrices.”
“The key to Strassen’s method is to use the divide-and-conquer idea from the MATRIX-MULTIPLY-RECURSIVE procedure, but make the recursion tree less bushy. We’ll actually increase the work for each divide and combine step by a constant factor, but the reduction in bushiness will pay off.”
“Strassen’s strategy for reducing the number of matrix multiplications at the expense of more matrix additions is not at all obvious—perhaps the biggest understatement in this book!”
“We can see that Strassen’s remarkable algorithm, comprising steps 1-4, produces the correct matrix product using 7 submatrix multiplications and 18 submatrix additions.”