【杂谈】01矩阵乘法

23 篇文章 0 订阅
13 篇文章 0 订阅
本文探讨了优化01矩阵乘法的一种一维分块方法,通过在模2意义下进行计算,利用bitset优化,实现了比传统二维分块更优的复杂度O(n³/ωlogn)。代码实现简洁,尤其适用于大块大小。通过在kk方向进行分块,减少了计算量,达到优于二维分块的效果。
摘要由CSDN通过智能技术生成

前言

前几天看了一下 2017 2017 2017 年论文《非常规大小分块算法初探》,里面有一节讲到了 01 01 01 矩阵乘法,介绍了一种 O ( n 3 ω log ⁡ n ) \mathcal O({n^3\over\omega\sqrt{\log n}}) O(ωlogn n3) 的分块做法。然而其代码实现难度高,复杂度优化效果小,我曾向 R a i n y b u n n y \sf Rainybunny Rainybunny 说,不会真的有人写这玩意儿骗分吧!

结果我还是写了分块 01 01 01 矩阵乘法来骗分。但是并不是上面的方法。是我无意中想到的一个分块方法。为什么要写出来呢?可能也是为了留作纪念吧……

概述

这里的 01 01 01 矩阵是,在模 2 2 2 意义下(在域 G F ( 2 ) \Bbb{GF}(2) GF(2) 内)进行所有操作,包括答案矩阵也要对 2 2 2 取模。

二维分块

这是论文中的方法,先简单讲讲。不妨设要计算 A × B A\times B A×B,将两个矩形都划分成若干 S × S S\times S S×S 大小的子矩形。花费 O ( 4 S 2 S 3 ω ) \mathcal O(4^{S^2}{S^3\over \omega}) O(4S2ωS3) 的时间,预处理每一种不同的情况对应的结果。然后用 O [ ( n S ) 3 S 2 ω ] = O ( n 3 S ω ) \mathcal O[({n\over S})^3{S^2\over\omega}]=\mathcal O({n^3\over S\omega}) O[(Sn)3ωS2]=O(Sωn3) 的复杂度合并结果。取 S = log ⁡ 4 n 2 S=\sqrt{{\log_4 n}\over 2} S=2log4n 时,有最优复杂度 O ( n 3 ω log ⁡ n ) \mathcal O({n^3\over{\omega \sqrt{\log n}}}) O(ωlogn n3)

一维分块

为什么上面的方法不优呢?因为 S ⩽ ω S\leqslant\omega Sω,所以 b i t s e t \tt bitset bitset 的效用发挥不出来了。 b i t s e t \tt bitset bitset 才是最强的分块者!

考虑 ω \omega ω S S S 的分块效果同时存在。回到原式 C i , j = ∑ k A i , k B k , j C_{i,j}=\sum_k A_{i,k}B_{k,j} Ci,j=kAi,kBk,j 上,不妨设 i i i 是未分块的一维。能不能对 j j j S S S 分块呢?相当于矩阵 A A A 的某个行向量,要点乘 S S S 个列向量。似乎并没有冗余计算。估计行不通。

所以考虑对 k k k S S S 分块。也就是 A A A 的行向量的一部分,长度仅为 S S S,代表 B B B 的某些行向量是否被选择,然后异或到第 i i i 行上。长度仅为 S S S,这提示我们 Method of four Russians \text{Method of four Russians} Method of four Russians,即讨论 2 S 2^S 2S 种不同的 A i , k    ( k ∈ [ l , r ] ) A_{i,k}\;(k\in[l,r]) Ai,k(k[l,r]) 的情况,并直接计算出对第 i i i 行的贡献。

那么 B B B 中每 S S S 行就要暴力计算一次,这是 O ( n S ⋅ 2 S ⋅ n ω ) \mathcal O({n\over S}\cdot 2^S\cdot{n\over\omega}) O(Sn2Sωn) 的,而 A A A 中只需要 O ( n 2 S ) \mathcal O({n^2\over S}) O(Sn2) 次行向量操作,是 O ( n 3 ω S ) \mathcal O({n^3\over \omega S}) O(ωSn3) 的,取 S = log ⁡ n S=\log n S=logn 有最优复杂度 O ( n 3 ω log ⁡ n ) \mathcal O({n^3\over \omega\log n}) O(ωlognn3),且代码实现极其简单。

代码实现

n n n 是矩阵大小, s t e p step step 是块的大小,已在主函数内求出。

const int MAXN = 2000;
const int LOGN = 10;
bitset<MAXN> dp[1<<LOGN];
int lowbit[1<<LOGN], n, step;
struct Matrix{
	bitset<MAXN> a[MAXN];
	inline void clear(){
		for(int i=0; i!=n; ++i)
			a[i].reset();
	}
	Matrix operator * (const Matrix &b) const {
		Matrix c; c.clear();
		for(int l=0,r=step; l!=n; l=r,r+=step){
			if(__builtin_expect(r > n, false))
				r = n; // not to exceed n
			for(int S=1; S!=(1<<step); ++S){
				const int &id = lowbit[S];
				dp[S] = dp[S^(1<<id)]^b.a[l+id];
			}
			for(int i=0,now=0; i!=n; ++i,now=0){
				for(int j=l; j!=r; ++j)
					now ^= (a[i].test(j))<<(j-l);
				c.a[i] ^= dp[now]; // find in table
			}
		}
		return c;
	}
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值