关于 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)]);
}
posted @ 2021-03-28 19:48  JustinRochester  阅读(271)  评论(0编辑  收藏  举报