关于 FWT 的一些理解
本文作者为 JustinRochester ,转载本文请先与作者本人联系,并注明本文原作者。凡未经允许,私自转载且不注明作者的人,均构成侵权
规定 \(\otimes\) 为任一位运算,给定数组 \(a_n,b_n\) ,求数组 \(\displaystyle c_n=\sum_{i\otimes j=n}a_ib_j\)
我们假设将数组 \(a_n,b_n,c_n\) 分别看成一个向量,并对该三个向量进行线性变换。
\(c_n\) 的线性变换可逆
设线性变换分别为 \(T_A,T_B,T_C\) ,且线性变换后,新数组 \(a'_n,b'_n,c'_n\) 满足 \(c'_n=a'_n\cdot b'_n\)
则 \(\vec {i'}=T_i\cdot \vec i\)
故 \(\vec c=T_C^{-1}\vec {c'}=T_C^{-1}(\vec {a'}\cdot \vec {b'})=T_C^{-1}[(T_A\vec a)\cdot (T_B\vec b)]\)
这里的 \(\vec a\cdot \vec b\) 代表对应位相乘
将满足的等式代入线性变换得 \(\displaystyle \sum_i T_{C(n,i)}c_i=c'_n=a'_n\cdot b'_n=\sum_p T_{A(n,p)}a_p\sum_q T_{B(n,q)}b_q\)
代入 \(\displaystyle c_n=\sum_{i\otimes j=n}a_ib_j\) 得
\(\displaystyle \sum_i T_{C(n,i)}\sum_{p\otimes q}a_pb_q=\sum_p \sum_q T_{B(n,q)} T_{A(n,p)}a_pb_q\)
\(\displaystyle \sum_p\sum_q T_{C(n,p\otimes q)}a_pb_q=\sum_p \sum_q T_{B(n,q)} T_{A(n,p)}a_pb_q\)
约除相同项,我们得到 \(\displaystyle T_{C(n,p\otimes q)}=T_{B(n,q)} T_{A(n,p)}\)
由于位运算的可按位拆解性,我们得到,对于每一位 \(b\) ,都有 \(\displaystyle T_C(n_b,p_b\otimes_b q_b)=T_B(n_b,q_b) T_A(n_b,p_b)\)
又由于二进制每位的取值只有 \(0\) 或 \(1\) ,我们对于 \(T_i\) 只需要构造矩阵 \( \left( \begin{matrix} T_i(0, 0)&T_i(0, 1) \\ T_i(1, 0)&T_i(1, 1) \end{matrix} \right) \) ,并且满足上述条件即可
当然 \(T_C\) 必须可逆,即 \(T_C\) 满秩,行列式 \(T_C(0, 0)T_C(1, 1)-T_C(0, 1)T_C(1, 0)\neq 0\)
当对矩阵中仅有第 \(i\) 位不同的两个值 \(v_l,v_r(v_l<v_r)\) 进行计算时,有:
\(\left( \begin{matrix} v'_l \\ v'_r \end{matrix} \right)= \left( \begin{matrix} T_i(0, 0)&T_i(0, 1) \\ T_i(1, 0)&T_i(1, 1) \end{matrix} \right)\cdot \left( \begin{matrix} v_l \\ v_r \end{matrix} \right)= \left( \begin{matrix} T_i(0, 0)v_l+T_i(0, 1)v_r \\ T_i(1, 0)v_l+T_i(1, 1)v_r \end{matrix} \right)\)
当 \(\otimes\) 为按位或时:构造矩阵 \(T_A=T_B=T_C= \left( \begin{matrix} 1&0 \\ 1&1 \end{matrix} \right) \)
则 \(q_b=p_b=0\) 时 \(T_C(n_b, q_b\vee p_b)=T_C(n_b, 0)=1=1\cdot 1=T_A(n_b,0)\cdot T_B(n_b, 0)=T_A(n_b,q_b)\cdot T_B(n_b,p_b)\)
否则 \(T_C(n_b,q_b\vee p_b)=T_C(n_b, 1)=n_b=T_A(n_b,q_b)\cdot T_A(n_b,p_b)\)
由于 \(\text{det }T_C=0-1\neq 0\) ,故存在 \(T_C^{-1}= \left( \begin{matrix} 1&0 \\ -1&1 \end{matrix} \right)\)
所以进行 FWT 时,代码如下:
for(int b=0;1<<b<len;++b) for(int i=0;i<len;++i) if (~i>>b&1) {
int j=i^(1<<b);
a[j]=add(a[j],a[i]);
}
而进行逆变换 UFWT 时,代码如下:
for(int b=0;1<<b<len;++b) for(int i=0;i<len;++i) if (~i>>b&1) {
int j=i^(1<<b);
a[j]=dis(a[j],a[i]);
}
当 \(\otimes\) 为按位与时:构造矩阵 \(T_A=T_B=T_C= \left( \begin{matrix} 1&1 \\ 0&1 \end{matrix} \right) \)
当 \(\otimes\) 为按位异或时:构造矩阵 \(T_A=T_B=T_C= \left( \begin{matrix} 1&1 \\ 1&-1 \end{matrix} \right) \)
当 \(\otimes\) 为按位同或时:构造矩阵 \(T_A=T_B=T_C= \left( \begin{matrix} -1&1 \\ 1&1 \end{matrix} \right) \)
当然,我们知道,单个位的位运算是一个 \(\{0, 1\}\times\{0, 1\}\to\{0, 1\}\) 的二元函数 \(f(x,y)\)
因此,函数的个数应为 \(|\{0, 1\}^{\{0, 1\}\times\{0, 1\}}|=|\{0, 1\}|^{|\{0, 1\}\times\{0, 1\}|}=2^{2\times 2}=16\) 种
因此,我们如果能求出这 \(16\) 种的位运算计算方法,理论上能求解所有的奇葩位运算
\(S\) | \(1\otimes 1\) | \(1\otimes 0\) | \(0\otimes 1\) | \(0\otimes 0\) | \(T_A\) | \(T_B\) | \(T_C\) | \(T_C^{-1}\) |
---|---|---|---|---|---|---|---|---|
\(0\) | \(0\) | \(0\) | \(0\) | \(0\) | \(\left(\begin{matrix}1&1 \\ 0&0\end{matrix}\right)\) | \(\left(\begin{matrix}1&1 \\ 0&0\end{matrix}\right)\) | \(\left(\begin{matrix}1&0 \\ 0&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&0 \\ 0&1\end{matrix}\right)\) |
\(1\) | \(0\) | \(0\) | \(0\) | \(1\) | \(\left(\begin{matrix}1&1 \\ 0&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&1 \\ 0&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&1 \\ 0&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&-1 \\ 0&1\end{matrix}\right)\) |
\(2\) | \(0\) | \(0\) | \(1\) | \(0\) | \(\left(\begin{matrix}1&1 \\ 0&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&1 \\ 1&0\end{matrix}\right)\) | \(\left(\begin{matrix}1&1 \\ 0&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&-1 \\ 0&1\end{matrix}\right)\) |
\(3\) | \(0\) | \(0\) | \(1\) | \(1\) | \(\left(\begin{matrix}1&0 \\ 0&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&1 \\ 1&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&0 \\ 0&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&0 \\ 0&1\end{matrix}\right)\) |
\(4\) | \(0\) | \(1\) | \(0\) | \(0\) | \(\left(\begin{matrix}1&1 \\ 1&0\end{matrix}\right)\) | \(\left(\begin{matrix}1&1 \\ 0&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&1 \\ 0&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&-1 \\ 0&1\end{matrix}\right)\) |
\(5\) | \(0\) | \(1\) | \(0\) | \(1\) | \(\left(\begin{matrix}1&1 \\ 1&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&0 \\ 0&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&0 \\ 0&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&0 \\ 0&1\end{matrix}\right)\) |
\(6\) | \(0\) | \(1\) | \(1\) | \(0\) | \(\left(\begin{matrix}1&1 \\ 1&-1\end{matrix}\right)\) | \(\left(\begin{matrix}1&1 \\ 1&-1\end{matrix}\right)\) | \(\left(\begin{matrix}1&1 \\ 1&-1\end{matrix}\right)\) | \(\left(\begin{matrix}{1\over 2}&{1\over 2} \\ {1\over 2}&-{1\over 2}\end{matrix}\right)\) |
\(7\) | \(0\) | \(1\) | \(1\) | \(1\) | \(\left(\begin{matrix}1&0 \\ 1&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&0 \\ 1&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&0 \\ 1&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&0 \\ -1&1\end{matrix}\right)\) |
\(8\) | \(1\) | \(0\) | \(0\) | \(0\) | \(\left(\begin{matrix}1&1 \\ 1&0\end{matrix}\right)\) | \(\left(\begin{matrix}1&1 \\ 1&0\end{matrix}\right)\) | \(\left(\begin{matrix}1&1 \\ 0&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&-1 \\ 0&1\end{matrix}\right)\) |
\(9\) | \(1\) | \(0\) | \(0\) | \(1\) | \(\left(\begin{matrix}1&-1 \\ 1&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&-1 \\ 1&1\end{matrix}\right)\) | \(\left(\begin{matrix}-1&1 \\ 1&1\end{matrix}\right)\) | \(\left(\begin{matrix}-{1\over 2}&{1\over 2} \\ {1\over 2}&{1\over 2}\end{matrix}\right)\) |
\(10\) | \(1\) | \(0\) | \(1\) | \(0\) | \(\left(\begin{matrix}1&1 \\ 1&1\end{matrix}\right)\) | \(\left(\begin{matrix}0&1 \\ 1&0\end{matrix}\right)\) | \(\left(\begin{matrix}1&0 \\ 0&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&0 \\ 0&1\end{matrix}\right)\) |
\(11\) | \(1\) | \(0\) | \(1\) | \(1\) | \(\left(\begin{matrix}1&0 \\ 1&1\end{matrix}\right)\) | \(\left(\begin{matrix}0&1 \\ 1&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&0 \\ 1&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&0 \\ -1&1\end{matrix}\right)\) |
\(12\) | \(1\) | \(1\) | \(0\) | \(0\) | \(\left(\begin{matrix}0&1 \\ 1&0\end{matrix}\right)\) | \(\left(\begin{matrix}1&1 \\ 1&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&0 \\ 0&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&0 \\ 0&1\end{matrix}\right)\) |
\(13\) | \(1\) | \(1\) | \(0\) | \(1\) | \(\left(\begin{matrix}0&1 \\ 1&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&0 \\ 1&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&0 \\ 1&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&0 \\ -1&1\end{matrix}\right)\) |
\(14\) | \(1\) | \(1\) | \(1\) | \(0\) | \(\left(\begin{matrix}0&1 \\ 1&1\end{matrix}\right)\) | \(\left(\begin{matrix}0&1 \\ 1&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&0 \\ 1&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&0 \\ -1&1\end{matrix}\right)\) |
\(15\) | \(1\) | \(1\) | \(1\) | \(1\) | \(\left(\begin{matrix}0&0 \\ 1&1\end{matrix}\right)\) | \(\left(\begin{matrix}0&0 \\ 1&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&0 \\ 0&1\end{matrix}\right)\) | \(\left(\begin{matrix}1&0 \\ 0&1\end{matrix}\right)\) |
采用卡诺图化简法得到:
\(T_A=\left( \begin{matrix} \overline{S_3\wedge S_2}&(\overline{S_1\wedge S_0})\cdot (-1)^{[S=9]} \\ S_3\vee S_2&(S_1\vee S_0)\cdot (-1)^{[S=6]} \end{matrix} \right)\)
\(T_B=\left( \begin{matrix} \overline{S_3\wedge S_1}&(\overline{S_2\wedge S_0})\cdot (-1)^{[S=9]} \\ S_3\vee S_1&(S_2\vee S_0)\cdot (-1)^{[S=6]} \end{matrix} \right)\)
\(T_C=\left( \begin{matrix} (-1)^{[S=9]}&(S_2\vee S_1)\oplus(S_3\vee S_0) \\ (S_2\wedge S_1)\oplus(S_3\wedge S_0)&(-1)^{[S=6]} \end{matrix} \right)\)
\(\displaystyle T_C^{-1}={1\over \text{det }T_C} \left( \begin{matrix} T_{1, 1}&-T_{0, 1} \\ -T_{1, 0}&T_{0, 0} \end{matrix} \right) =(-{1\over 2})^{[S=6\vee S=9]}\left( \begin{matrix} (-1)^{[S=6]}&-(S_2\vee S_1)\oplus(S_3\vee S_0) \\ -(S_2\wedge S_1)\oplus(S_3\wedge S_0)&(-1)^{[S=9]} \end{matrix} \right)\)
inline void updl(ll &a0,ll &a1,int S){
bool S0=(S&1),S1=(S>>1&1),S2=(S>>2&1),S3=(S>>3&1);
__int128 A0=a0,A1=a1;
a0=(S3&S2?0:A0) + (S1&S0?0:A1)*(S==9?-1:1);
a1=(S3|S2?A0:0) + (S1|S0?A1:0)*(S==6?-1:1);
}
inline void updr(ll &a0,ll &a1,int S){
bool S0=(S&1),S1=(S>>1&1),S2=(S>>2&1),S3=(S>>3&1);
__int128 A0=a0,A1=a1;
a0=(S3&S1?0:A0) + (S2&S0?0:A1)*(S==9?-1:1);
a1=(S3|S1?A0:0) + (S2|S0?A1:0)*(S==6?-1:1);
}
inline void updi(ll &a0,ll &a1,int S){
bool S0=(S&1),S1=(S>>1&1),S2=(S>>2&1),S3=(S>>3&1);
__int128 A0=a0,A1=a1;
a0=( (S==6?-A0:A0)-( ((S2|S1)^(S3|S0))?A1:0 ) )*(S==6|S==9?-1:1)>>(S==6|S==9);
a1=( ( ((S2&S1)^(S3&S0))?-A0:0 )+(S==9?-A1:A1) )*(S==6|S==9?-1:1)>>(S==6|S==9);
}
inline void FWT(ll *a,int n,void (*upd)(ll&,ll&,int) ){
for(int i=1;i<n;i<<=1) for(int S=0;S<n;++S)
if( (~S)&i )
upd(a[S],a[S|i],Sta[__builtin_ctz(i)]);
}