[论文解析] Hu-Shing 算法 - 快速求出矩阵链乘积最优解
论文 Part I | 论文 Part II | 论文另版 | 模板
本文中所有图片均来自原论文。
Chpt. 1 简要介绍
Hu-Shing 算法,是一个能够快速解决矩阵链乘积(或矩阵链排序问题,MCOP)的算法。在这项研究成果之前,A. K. Chandra 就已经提出在
下面是对 MCOP 的介绍。
下式将
n - 1 个矩阵相乘,并最终得到一个新的矩阵:M = M_1 \times M_2 \times \cdots \times M_{n-1} 我们假设
M_i 是一个w_{i} \times w_{i + 1} 大小的矩阵。考虑到矩阵乘法满足结合律,那么我们任意改变乘法的顺序,所得到的最终矩阵必然是相同的,但运算次数却不尽相同。该问题的目的是找到一个最优的乘法策略,满足在该策略下进行矩阵乘法所需操作数最少。在这里,我们假设对p \times q 的矩阵和q \times r 的矩阵进行乘法所需的操作数是pqr 。
在接下来的解析中,我们将 Part I 提到的引理、公理和推论加上 "1." 的前缀,而将 Part II 提到的引理、公理和推论加上 2." 的前缀。
Chpt. 2 划分凸多边形
对于一个包含
- 对划分出的每个三角形,不妨假设其连接了权值分别为
x, y, z 的三个节点,那么其代价为xyz 。 - 一个划分的代价就是所有三角形的代价和。
在上面对六边形的划分中,对应的代价就是
我们称一个凸多边形的划分为最优划分,当且仅当这个划分提供了最小的代价。
在上面的例子中,我们将
引理 1.1:对
n-1 个矩阵的链式乘法分配方案都可以对应到n 边形的一个划分。
证明:考察最后一次乘法的位置:
考虑到这一次乘法实际上是将一个
进一步的,为了得到乘法左右的两个矩阵,我们可以继续考虑这两个矩阵进行的最后一次乘法,而这恰好对应三角形左右的两个子多边形(它们的基底也分别对应了我们此时连接的两条边)。我们就可以利用归纳法的思路,继续将这个凸多边形进行等代价的划分,直到剩下的部分无法再划分,矩阵不断退化为初始给出的矩阵为止。
此时,我们就通过乘法的结合方式推出了凸多边形的一种划分。这也就说明了每一种乘法结合方式对应了一种划分。
在链式乘法到划分的转化下,我们可以立马得到另一个引理:
引理 1.2:引入一个大小为
w_n \times w_1 的矩阵M_n ,那么对下面所有的矩阵链式乘法所需的最少操作次数相同:M_1 \times M_2 \times \cdots \times M_{n-1}\\ M_n \times M_1 \times \cdots \times M_{n-2}\\ \vdots\\ M_{2} \times M_{3} \times \cdots \times M_n
证明:对于上述的矩阵链式乘法,在实质上对应的是同一个凸多边形的最优划分代价,那么它们对应的最少操作次数必然相同。
在正式步入划分问题之前,我们需要补充一个事实。对于凸多边形的任何一个划分,我们必然可以逐步将二度点(恰好与两条边相连的点)连带着它所连的边一起删除,并在最后留下基底对应的线段。在这个过程中,我们可以注意到:每一次移除实际上对应了一次矩阵乘法,而每一次移除后剩余的凸多边形,除了基底之外的边都分别对应了当前链式乘法中每个矩阵的对应大小。我们就通过模拟的方式将划分对应到了链式乘法的一种组合方式。
接下来,我们考虑通过一个引理侧面反映上述操作的可行性。
引理 1.3:在
n 边形(n \geq 4 )的任意划分中,必然存在至少两个包含二度点的三角形。
证明:我们通过
那么我们有
由于
至此,我们终于完成了矩阵链式乘法问题到多边形划分的问题,也终于可以将全部精力集中在解决新的图论问题上了。
我们首先补充第一个记号:
引理 1.4:如果
\forall i \in [1, k], w_i \leq w'_i ,那么C(w_1, w_2, \cdots, w_k) \leq C(w'_1, w'_2, \cdots, w'_k)
证明在此略去。
然后,我们继续对图论记号进行扩充。
在后续对图的讨论中,侧边被用来强调凸多边形外部的线段,而弧被用来强调凸多边形内部的线段。
称两个点在凸多边形相邻,当且仅当二者之间连有一条侧边。称两个点在凸多边形相连,当且仅当二者之间连有一条边。
在剩余的篇幅中,我们需要将点重新标记。我们使用
接下来定义
在每个点都被标记之后,我们就可以定义边的顺序了。定义边
据此,我们可以定义:一个划分
接下来,我们将给出一个十分重要的定理。
定理 1.1:对于任何一种排列
V_1, V_2, \cdots, V_n 的方式,我们总能找到一种最优划分,其包含V_1 - V_2 和V_2 - V_3 两条边(可以是侧边或者弧)。
证明:尝试对凸多边形的大小进行归纳。对于三边形和四边形而言,这个结论是正确的。接下来,令
根据引理 1.3,这个凸多边形上必然存在两个二度点,假设为
- 如果
V_i 不是V_1, V_2, V_3 中的一个,那么考虑直接将V_i 所在的三角形移走,那么在剩余的n-1 边形中,V_1, V_2, V_3 依然分别是最小的三个点。根据前提,必然存在V_1 - V_2 和V_2 - V_3 两条边。对V_j 同理。 -
如果
V_i 和V_j 都在V_1, V_2, V_3 中。我们假设V_i < V_j ,那么其对应三种情况:-
-
-
$$ T_{12q} + C(w_2, w_q, \cdots, w_p, w_3) $$ 而如果直接连接 $V_1 - V_3$,代价为 $$ T_{123} + C(w_1, w_q, \cdots, w_p, w_3) $$ 根据定义,$T_{123} \leq T_{12q}$,而根据引理 1.3,$C(w_1, w_q, \cdots, w_p, w_3) \leq C(w_2, w_q, \cdots, w_p, w_3)$。那么连接 $V_1$ 和 $V_3$ 显然是更优的选择。
-
我们就证明了这个定理。
推论 1.1:对于任何一种排列
V_1, V_2, \cdots, V_n 的方式,最小最优划分必然包含V_1 - V_2 和V_1 - V_3 两条边。
证明在此略去。
在这个定理的帮助下,我们可以尝试递归解决原先的问题。对于一个多边形,只要
称一个多边形为基础多边形,当且仅当其包含至少四个点,并且
接下来,我们通过一个定理论述对基础多边形的处理方式。
定理 1.2:在一个基础多边形中,
V_2 - V_3 在一个最优划分中存在的一个必要而不充分的条件是\dfrac 1 {w_1} + \dfrac 1 {w_4} \leq \dfrac 1 {w_2} + \dfrac 1 {w_3} 另外,在最小最优划分中,如果
V_2 - V_3 不存在,那么V_1 - V_4 必然存在。
证明:在最小最优划分中,如果
如果在一个最优划分中,
考虑上图中两种情况的代价。左侧构造的代价是
右侧构造的代价是
首先,根据引理 1.4,我们知道
为了使左侧不劣于右侧,我们可以得到一个更加宽松的不等式
也就是
我们紧接着给出一个引理。这个引理来自最经典的调整思路。
引理 1.5:在一个最优划分中,假设
V_x - V_z 是一条弧,与其相邻的两个三角形分别暴汗了V_y 和V_w (也就是说,V_x - V_y - V_z - V_w 共同形成了一个四边形),那么选择V_x - V_z 而非V_y - V_w 的必要条件是\dfrac 1 {v_x} + \dfrac 1 {v_z} \geq \dfrac 1 {v_y} + \dfrac 1 {v_w}
证明:考虑此四边形,连接
而连接
为了保证前者不劣于后者,我们有
也就是
值得注意的是,如果上述不等式无法取等,那么
如果所有弧都满足上述性质,那么称该划分是稳定的,因为我们无法简单的通过四边形内的调整进行优化。
推论 1.2 最优划分一定是稳定的,而稳定的划分不一定是最优的。
证明:前半部分显然,而对后半部分,可以给出反例。
值得注意的是,引理 1.5 得到的不等式实际上可以进一步弱化,并拆分成两种形式。
称一个弧
称一个弧
推论 1.3:所有的弧要么水平,要么竖直。
证明:不妨假设有一个弧
不难发现,两种情况均违背了引理 1.5 给出的不等式,故这一条弧不可能存在。
在接下来的定理中,我们将目光聚焦在水平弧上。
定理 1.3:对于多边形上任意的两个不相邻的点
V_x, V_z ,不妨假设V_y 是在V_x - V_z 一侧的点中最小的一个,而V_w 是在另一侧的点中最小的一个。方便起见,假设V_x < V_z, V_y < V_w 。那么在最小最优划分中,V_x - V_z 作为水平弧存在的必要条件是w_y < w_x \leq w_z < w_w
证明:利用反证法。如果
假设有
在这个基础多边形中,根据定理 1.2,必然有
根据定理 1.2,我们可以得到该弧存在的必要条件:
由于
推论 1.4:将上述定理进行弱化后,可以得到水平弧在最小最优分划存在的必要条件是:
V_y < V_x < V_z < V_w
证明在此略去。
实际上,上面的推论有一个更加直观的解释。对于一个水平弧,若想让这个弧出现在最小最优分划中,那么该弧一侧的所有点都要同时大于两个端点,而另一侧需要存在一个点同时小于两个端点。我们称前者形成的子多边形为上多边形,而后者为下多边形。
我们称满足上述性质的弧为潜在水平弧。显然,最小最优分划中的所有水平弧只会是潜在水平弧。
我们在此给出一个新的推论。
推论 1.5:对于一个多边形的最大点
V_m ,令V_x, V_z 与这个点相邻,那么如果存在一个V_y 使得V_y < V_x 并且V_y < V_z ,那么V_x - V_z 就是一个潜在水平弧。
证明在此略去。
接下来,我们引入兼容的概念。称两个弧互相兼容,当且仅当二者可以在一个划分中同时出现——换句话说,二者不会在非端点处相交。接下来,我们将会提出论文 Part I 中最为重要,也是最漂亮的定理。
定理 1.4:所有的潜在水平弧两两互相兼容。
证明:利用反证法。假设
根据定义,我们有
至此,Part I 中的全部理论准备都已经证完。根据推论 1.4 和定理 1.4,我们可以给出基于栈实现
我们任意选择一个权重最小的位置作为
假设栈顶元素为
在枚举完成后,如果栈中存在至少四个元素,那么直接把
由于整个过程只需要绕着多边形走一圈,那么称这个算法为“单次扫描算法”。这个算法没有直接对点进行重标号,所以相对编号是比较灵活的,同时也避免了排序的复杂度。
另外,这个算法产生的弧序列实际上只保证包含所有的潜在水平弧,而其中也会包含其余不符合条件的弧(实际上,这些弧恰好是所有和
实际上,原论文给出的算法可以进一步优化,参考后续的示例代码。
Chpt. 3 单调基础多边形
我们终于迈入了该论文的 Part II。这一部分和下一部分将会完整的阐释最终的算法是如何运作的。
在此之前,我们需要解决一个子问题:单调多边形。我们首先扩充一些定义。
定义一个点是局部最大值,当且仅当它大于两个与它相邻的点。同理定义局部最小值。
定义一个多边形是单调多边形,当且仅当其恰好包含一个局部最大值和一个局部最小值。更具体的,我们只需要讨论单调基础多边形的情况。
另外,我们引入一个比较形象的划分形式。我们假设所有和最小的点不相邻的点都和最小的点连一条弧,那么我们就得到了一个类似于扇形的划分。我们将这种划分记作
并称最小点
我们引出 Part II 的第一个引理。
引理 2.1:对于一个不存在潜在水平弧的多边形,最小最优划分必然是扇形划分。
证明:显然,此时的最优划分只能由竖直弧组成。那么扇形划分显然满足竖直弧的性质,并且也是理论上能够达到的最小字典序。
接下来假设有一个更优的划分,其并不是扇形划分。那么必然存在三个点
还记得前面定义的上多边形吗?我们在这里需要借助上多边形定义潜在水平边的层级关系。定义一条潜在水平弧
我们定义
引理 2.2:在集合
P 中,两条潜在水平弧之间不存在互相包含或者互相不包含的关系。
证明:由于两条潜在水平弧不能互相交叉,所以它们的上多边形必然是包含关系。而考虑到在单调基础多边形中,任何一个潜在水平弧的上多边形必然包含唯一的一个局部最大值,则上多边形的交不可能为空。
根据上述性质,我们自然得到了证明。
在上述引理的帮助下,我们就可以大致刻画出潜在水平弧的位置关系。
我们将最大值提到上方,而最小值拉到下方,整体就形成了一个竖直的结构。潜在水平弧横跨竖直结构的左右两侧,并且形成一个层状结构。
进一步的,假如
同时,我们定义
引理 2.3:在单调基础多边形中,任何一个被两条潜在水平弧约束的子多边形必然是一个单调基础多边形。
证明:考虑到单调基础多边形两侧点之间的单调性,可以证明无论两条潜在水平弧的两个端点的大小如何,我们总能确认出恰好一个局部最大值和一个局部最小值。
引理 2.4:在单调基础多边形中,对于任何一个被两条潜在水平弧约束的子多边形,其自身的潜在水平弧在整个多边形中依然是潜在水平弧。
证明:分别考察上多边形和下多边形的性质,可以发现潜在水平弧的上多边形在加入比两个端点大的一系列点,并且在下多边形中加入任意的点,都不会影响潜在水平弧的性质,故该性质可以延续到整个多边形上。
为了方便起见,我们在这里假设最大的点和最小的点等价于两个退化的潜在水平弧,那么我们可以大致清楚最终的最小最优划分的结构:整个多边形被一些潜在水平弧拆分称若干部分,而每一部分都被两个潜在水平弧约束,并且都使用扇形划分。
对于所有可能的潜在水平弧选择方案,我们将它们以包含的潜在水平弧的条数作为关键字分为
对于
对于
对于一个扇形
这里,我们利用
我们假设在
这个式子可以直接用于衡量一个潜在水平弧的贡献能力。在一个多边形中,我们称一个潜在水平弧是正贡献的当且仅当上述不等式成立,否则称其为负贡献的。当然,这个定义也可以迁移到子多边形上,只需要强调
在上述过程中,我们注意到正贡献的判定公式左右已经将子多边形的上边沿和下边沿独立了出来:
- 不等式左侧
\dfrac{C(w_i : w_j)}{(w_i:w_j) - w_i w_j} 的形式只和子多边形的上边沿相关,而且上边沿越高,对应的值也越大; - 不等式右侧
w_1 的形式恰好等于子多边形下边沿的两个端点中较小者的权值,同样的,下边沿越低,对应的值越小。
接下来,我们用
我们将不等式左侧的表达式进行特化,用
接下来论述一个性质。假设
在这个性质的帮助下,我们不妨考虑正贡献的性质能否从外向内延续。
定理 2.1:如果潜在水平弧在某个多边形中为正贡献的,那么它在任意一个包含自身的子多边形中也是正贡献的(前提是不能变成侧边),反之则不然。
证明:仍然选择一条潜在水平弧
而如果我们只考虑一个包含
根据单调基础多边形的性质,我们知道
如图所示,
根据前面提到的性质,我们知道
那么
在这个定理下,我们可以提出一个增量的算法思路。我们在把所有的潜在的水平弧找到后,从上往下进行枚举,并不断算出其上多边形的最小最优划分。在地板不断往下移动的时候,根据前面对支持系数的定义,当前已经确认的潜在水平弧将有可能失效(但不可能重新出现),我们只需要快速完成判断即可。
接下来,为了可以让失效的行为变得更有规律性,我们来为这个算法进行更多的理论补充。
我们首先定义一个潜在水平弧的上限弧。我们从高到低对上限弧进行构造。为统一记号,称
- 首先,令
h_n 的上限弧为h_n 。 - 其次,从高到低考察剩余的潜在上限弧。假设目前考虑的是
h_i ,那么它的上限弧是最低的h_k ,满足S(h_k/h_i) > S(U_k/h_k)
然后我们定义潜在水平弧之间的父子关系。我们称
我们可以注意到一个事实:
另外一个可以注意到的事实是,如果
我们可以证明两个重要定理。
定理 2.2:一条潜在水平弧出现在最小最优划分中可以推出其上限弧也出现在最小最优化分中。
证明:待补充。
定理 2.3:一条潜在水平弧出现在最小最优划分中当且仅当其父弧也出现在最小最优化分中。
证明:待补充。
推论 2.1:一个“祖先弧”和它的所有后代必然在最小最优化分中同时出现或者同时不出现。
证明在此略去。
于此同时,利用支持系数的定义,我们可以导出如下定理:
定理 2.4:对于
h_i, h_j (h_j 在上方),假设被二者约束的多边形的最优划分是一个扇形,那么如果S(U_j / h_j) \geq w_i ,那么h_j 不会在以h_n 为上边沿,低于或等于h_i 的任何潜在水平弧为下边沿约束得来的多边形中起正贡献。
证明:利用反证法可以轻松得到,在此略去。
根据定理 2.3,我们可以从潜在水平弧的“族谱”中的叶子节点作为起点,并一步步向上扩展。当我们在考察
而需要注意的是,根据父子关系的定义,我们可以在从高到低的扫描过程中逐步完善整个父子结构——当我们搜索到一条弧的时候,其上方所有弧的父子关系都会被明确,并且弧自身已经被恰当的压缩或者删除。
我们终于可以给出解决单调基础多边形的最小最优划分的
- 通过前面提到的单次扫描算法,得到所有的潜在水平弧。我们将其从高到低进行排布(而在实际的计算过程中,它们已经被这样排布了)。
- 从高到低枚举所有未被退化的潜在水平弧。令
h_j 为当前处理的潜在水平弧,而h_k 与h_i 分别为仅靠在h_j 上/下方的潜在水平弧。我们此时保证h_j 的上多边形中的最小最优方案已经被动态维护。我们同时获取了未被删除的所有潜在水平弧对应的上限弧。 我们首先确定h_j 的上限弧和子弧。我们不断将S(h_k/h_j) 和S(U_k/h_k) 进行比较。- 如果前者不大于后者,那么其满足子弧的性质,我们就可以清晰的知道
h_k 是h_j 的子弧。我们将h_k 和其所有子孙合并到h_j 下,并借助支持系数的性质直接得到S(U_k/h_j) 。此时,U_k 成为h_j 对应的新的h_k 。我们进行替换后回到 2. 最后的循环。 - 反之,
h_k 就是h_j 的上限弧,我们进入下一步。
- 如果前者不大于后者,那么其满足子弧的性质,我们就可以清晰的知道
- 接下来,我们考察
S(U_j/h_j) 和w_i 的关系。- 如果前者不小于后者,那么
h_j 在今后必然起负贡献,我们直接将h_j 和它的所有后代删除,并将h_j 更新为h_k ,并同时更新h_k 为U_k 。随后回到 3. 对应的循环。 - 反之,
h_j 目前可以起正贡献,我们直接进行下一步。
- 如果前者不小于后者,那么
- 此时,关于
h_j 的信息已经被全部处理完。我们只需要将h_j 替换为h_i ,开启对下一个潜在水平弧的考察。
最后剩余的潜在水平弧直接对应了最小最优划分。其中,这些潜在水平弧将多边形分为若干部分,而每一部分都是扇形划分。我们据此即可直接构造出方案,并进行后续的计算。
这个算法的正确行证明在此省略,而线性复杂度是显然的。
Chpt. 4 普通多边形
我们将上述算法从单调多边形的特例迁移到普通的情况。我们依然固定下全局最小值,那么此时将会存在若干个局部最大值,而由于潜在水平弧并不会交叉,我们可以发现它们形成了一个树状结构(需要注意的是,这个结构只依赖于它们的端点形成的区间对应的包含关系,而不等同于前面提到的父子关系)。我们在这个树状结构上定义一个弧的子树,其和普通树形结构同理。我们也能定义潜在水平弧的上下关系,并且这个上下关系实际上和这个树状结构同步。我们在此省略形式化证明过程。
在这个情况中,一个水平弧对应的下边沿弧实际上还是单一的,而由于其树状结构的特性,其可能包含很多个上限弧,限制住了弧的子树。支持系数的参数也因此产生变化。
定义
在上面给出的图中,
我们重新规范一下上限弧的定义,因为此时的上限弧形成了一个集合。
- 对叶子节点,其上限弧只有本身。
- 否则,对一个水平弧
h_i ,其上限弧h_k 需要满足:-
-
- 上限弧之间不存在包含关系,而只能并列;
- 没有在
h_k 之下且在h_i 之上的弧同时满足上述性质。
-
不过,由于在一条弧下方的所有弧依然是线性排列的,子弧的定义依然适用。
原文中忽略了接下来讨论的细节,并直接指出:支撑算法 1 正确性的定理 2.2,定理 2.3,推论 2.1 和定理 2.4 在普通多边形上依然适用,而区别仅在于将诸如“
接下来,我们照着算法 1 的思路,给出最终的算法,其成功的在
- 通过前面提到的单次扫描算法,得到所有的潜在水平弧。我们在得到的序列上线性构造出弧的树形结构(过程中只需要维护树的一条当前弧即可,参考笛卡尔树的构造流程)。我们顺便将局部最大值插入到树中作为儿子,并视为被退化的潜在水平弧。
- 从儿子到根枚举(或者说后序遍历)所有未被退化的潜在水平弧。令
h_j 为当前处理的潜在水平弧,而X 与h_i 分别为仅靠在h_j 上/下方的潜在水平弧(集合)。我们此时保证h_j 的上多边形中的最小最优方案已经被动态维护。我们同时获取了未被删除的所有潜在水平弧对应的上限弧。我们考察\max_{h_x \in X}S(U_x/h_x) 和w_j 的关系。- 如果前者不小于后者,令
h_k = \argmax_{h_x \in X} S(U_x/h_x) ,那么h_k 在今后必然起负贡献,我们直接将h_k 和它的所有后代删除。同时,我们在X 中删除h_k 并添加h_k 的所有上限弧。然后,我们回到 2. 对应的循环。 - 反之,
X 的所有弧目前可以起正贡献,我们直接进行下一步。
- 如果前者不小于后者,令
- 然后,我们确定
h_j 的上限弧。我们不断将S(U_j/h_j) 和\max_{h_x \in X}S(U_x/h_x) 进行比较。- 如果前者不大于后者,令
h_k = \argmax_{h_x \in X} S(U_x/h_x) ,那么其满足子弧的性质,我们就可以清晰的知道h_k 是h_j 的子弧。我们将h_k 和其所有子孙合并到h_j 下,然后在X 中删去h_k 并加入其所有上限弧。随后,我们借助支持系数的性质直接得到S(X/h_j) 。我们即可回到 2. 最后的循环。 - 反之,
X 就是h_j 的上限弧集合,我们进入下一步。
- 如果前者不大于后者,令
- 此时,关于
h_j 的信息已经被全部处理完。我们只需要根据后序遍历的顺序继续下去即可。
注意到我们交换了两个操作的顺序。这是因为在一开始就把当前考虑的水平弧删除后,需要对其上限弧逐一考虑,有可能会导致复杂度退化。在交换前后顺序并改写判定负贡献的形式后,我们就能保证复杂度。
注意到这个算法的瓶颈是时刻维护一个集合的
另外一个可以注意到的点是,考虑到上限弧在支持系数上的偏序关系,我们把
至此,我们终于可以在