转置原理
序
如果一个算法的输入是一个向量 \(\bm a\),输出是另一个向量 \(\bm b\),且这个算法是一个线性变换,那么可以写成如下形式:
其中 \(M\) 为这个算法的线性变换所代表的矩阵。
由于 \((AB)^T=B^TA^T\),所以上式可以变形为:
这个式子的意义是,考虑另外一个算法,其输入是一个向量 \(\bm a^T\),输出是另一个向量 \(\bm b^T\),且这个算法的线性变换所代表的矩阵为 \(M^T\)。称这个算法为原算法的转置算法。不难看出,一个算法的转置的转置是他本身。
那么如果有一个运行时间为 \(O(T(n))\) 的算法,就存在一个运行时间与原算法同样的转置算法,反之依然。
为什么呢?考虑这个算法的每一步操作都相当于一个线性变换,假如这个算法运行 \(t\) 步,第 \(i\) 步所代表的线性变换为 \(M_i\),那么有:
要算 \(M^T\),根据公式,只需要将每个 \(M_i\) 转置后翻转整个序列,即:
这样,如果能原操作耗费同样时间进行所有操作的转置操作,那么就能与原算法耗费同样的时间完成其转置算法。
这里为了证明,考虑将 \(M\) 分解为三种初等矩阵的乘积,即对换、倍乘、倍加。而且向量乘初等矩阵复杂度是 \(O(1)\) 的,如果能证明初等矩阵的转置操作复杂度仍然是 \(O(1)\),就证明了上述命题。显然,初等矩阵的转置还是初等矩阵,所以上述命题得证。
那么具体地该如何求出一个算法的转置算法呢?还是考虑分解成初等矩阵的乘积,然后讨论这三种初等矩阵的转置是什么:
- 对于对换操作,如果是交换了 \(a_i\) 和 \(a_j\),有 \(\begin{bmatrix}0&1\\1&0\end{bmatrix}\times\begin{bmatrix}a_i\\a_j\end{bmatrix}=\begin{bmatrix}a_j\\ a_i\end{bmatrix}\),转置后矩阵不变,含义还是交换元素。
- 对于倍乘操作,分析与上面相似,含义不变。
- 对于倍加操作,如果是给 \(a_i\) 倍加上 \(a_j\) 的 \(c\) 倍,有 \(\begin{bmatrix}1&c\\0&1\end{bmatrix}\times\begin{bmatrix}a_i\\a_j\end{bmatrix}=\begin{bmatrix}a_i+ca_j\\ a_j\end{bmatrix}\),转置后得到 \(\begin{bmatrix}1&0\\c&1\end{bmatrix}\times\begin{bmatrix}a_i\\a_j\end{bmatrix}=\begin{bmatrix}a_i\\ a_j+ca_i\end{bmatrix}\),含义是给 \(a_j\) 倍加上 \(a_i\) 的 \(c\) 倍。
所以就可以求出一个算法的转置算法了。
转置原理优化加法卷积
(暂时默认下标从 \(0\) 开始)
考虑 FFT 这个算法是啥,输入是一个 \(n\) 维向量 \(\bm a\),输出的也是一个 \(n\) 维向量 \(\bm b\),进行的变换就是傅里叶矩阵:
简要地说,\(\operatorname{FFT}_{i,j}=\omega_n^{i,j}\)。
不难观察到 \(\operatorname{FFT}=\operatorname{FFT}^T\),所以说 FFT 的转置算法还是 FFT。
考虑 FFT 算法是如何实现的。对于一个输入向量,我们先对其交换位反转的位置对,然后进行一个线性变换 \(P\),可以写成如下形式:
对于 IFFT,交换操作是同样的,线性变换不同,设为 \(Q\),于是有:
假如说要求 \(\bm a\) 和 \(\bm b\) 的加法卷积,那么就是要求:
其中点号代表逐项相乘。
因为 \(\operatorname{FFT}=\operatorname{FFT}^T\),所以:
注意这个式子,相当于是我们先求出 \(\bm a\times P^T\) 和 \(\bm b\times P^T\),然后将其分别 bitrev,乘起来,再 bitrev 回去,最后乘上 \(Q\)。那这个 bitrev 其实可以扔掉,仍然能达到相同的效果。于是要求即为:
现在只需要算 \(P^T\) 就好了。还记得上面讲的求一个算法的转置吗?那么就完成了。现在不需要预处理位反转了。这只是一个常数优化但是不失为一个例子。

浙公网安备 33010602011771号