Streaming Model
假设我们会依次接收到一个正整数序列a1,a2,⋯,保证序列长度不超过m。但我们只有有限的内存位来存放它们,序列的长度可能会远大于内存的大小。一个简单的问题是,最少需要几位内存bit才能回答“实际输入的序列长度n是多少”这个问题呢?一个简单直接的方法就是把内存当作一个二进制计数器来用,每接收到一个数据就增加1。这样⌈log2m⌉位内存就已经足够了。
能不能设计一个更好的算法呢?对于确定性的算法,这是不可能的:由于确定性的算法在接收完每个输入数据流后都会在内存上留下一个确定的状态。设内存大小为M,那么不同的状态个数最多只有2M个。假设M<⌈log2m⌉,那么2M<m,可见势必有两个不同长度的输入数据流最后会对应同样的内存状态,所以这显然不是一个正确的算法。
尽管不存在一个更好的确定性算法,但在许多应用场景下,我们并不要求知道输入数据流的精确长度,而是只需要给出一个对数据流长度的一个估计。如果允许输出包含一点小的误差,会不会能节省大量的空间呢?换言之,我们希望能找到一个算法给出一个数据流长度的估计n^,并且所需的内存大小尽量小。这是concentration的第一个例子,我们希望算法的近似输出能“concentrate”在标准输出附近。
Morris' Algorithm
我们考虑采用带有随机性的算法。一个构造巧妙的算法(Morris' algorithm)是这样做的:初始时令X=0,每接收到一个输入ai时,以2−X的概率令X增加1,1−2−X的概率令X保持不变,输出n^=2X−1。因为X是O(logm)级别的,所以储存X只需要O(loglogm)的内存,大大优化了内存空间。
我们能证明,这个算法在期望意义下是准确的,也即E[n^]=n。考虑对输入数据流的长度n归纳,当n=1时,X以20=1的概率增加1,所以输出一定为21−1=1,满足;假设输入流长度<n时成立,对于长度为n的输入,令随机变量Xi表示输入第i个数以后X的值,那么E[n^]=E[2Xn]−1,由全概率公式E[2Xn]=x=0∑nPr[Xn=x]⋅2x。根据算法,Pr[Xn=x]=(1−2−x)Pr[Xn−1=x]+2−(x−1)Pr[Xn−1=x−1],带入可得E[2Xn]=x=0∑n2x[(1−2−x)Pr[Xn−1=x]+2−(x−1)Pr[Xn−1=x−1]] =x=0∑n(2xPr[Xn−1=x]−Pr[Xn−1=x]+2Pr[Xn−1=x−1]) =x=0∑n−12xPr[Xn−1=x]−x=0∑n−1Pr[Xn−1=x]+2x=0∑nPr[Xn−1=x−1] =E[2Xn−1]+1,由归纳假设得E[2Xn]=n+1,也即E[n^]=n,证毕。
以上分析说明,Morris算法满足了最基本的concentration要求:算法估计在期望意义下准确,也即算法的输出的分布的中心点和标准答案重合。期望意义下准确并不代表输出以很高的概率集中在期望附近,相反假设输出在期望两侧很远的位置以对称的概率分布,也可能导致期望准确。换言之,我们能不能给出更高阶moment(期望是一阶moment)的concentration的要求:算法估计以很高概率分布在期望附近?
利用Concentration不等式,我们可以对Morris算法给出的估计进行更精确的分析。根据Chebyshev不等式,Pr[∣n^−n∣≥ε]≤ε2Var(n^)。其中Var(n^)=E[(n^−n)2] =E[n^2]−n2。而E[n^2]=E[(2Xn−1)2] =E[(2Xn)2]−2E[2Xn]+1 =E[(2Xn)2]−2(n+1)+1。所以只需求解E[(2Xn)2]。
我们发现E[(2Xn)2]=23n2+23n+1。归纳法,当n=1时X1=1,E[22]=4=23+23+1,成立;假设<n时已经成立,由全概率公式E[(2Xn)2]=x=0∑nPr[Xn=x]⋅22x。再一次,Pr[Xn=x]=(1−2−x)Pr[Xn−1=x]+2−(x−1)Pr[Xn−1=x−1],代入得E[(2Xn)2]=x=0∑n22x[(1−2−x)Pr[Xn−1=x]+2−(x−1)Pr[Xn−1=x−1]] =x=0∑n((22x−2x)Pr[Xn−1=x]+2x+1Pr[Xn−1=x−1]) =x=0∑n−1(22x−2x)Pr[Xn−1=x]+x=0∑n−12x+2Pr[Xn−1=x] =x=0∑n−1(22x+3⋅2x)Pr[Xn−1=x],由归纳假设和一阶的结论得到=E[(2Xn−1)2]+3E[2Xn−1] =23(n−1)2+23(n−1)+1+3n=23n2+23n+1。
综上,Var(n^)=23n2+23n+1−2(n+1)+1−n2 =21n2−21n≤2n2。代入Chebyshev不等式,取a=εn,则Pr[∣n^−n∣≥εn]≤2ε21。然而这还不是一个非常好的Concentration,因为当ε→0时2ε21→∞。为了避免这个问题,我们可以对算法做一点修改,从而获得更好的Concentration。
The Averaging Trick
Chebyshev不等式是用方差来做估计的。我们从小就知道,减小方差的基本方法就是“多次测量取平均”。于是我们可以独立重复运行k次Morris算法,对每次得到的结果n^i取平均,输出n^∗=ki=1∑kn^i。那么Pr[∣n^∗−n∣≥εn]≤ε2n2Var(n^∗) =ε2n2k2i=1∑kVar(n^i)≤ε2k2n2i=1∑k21n2 =2ε2k1。那么取k≥2ε2δ1,就有Pr[∣n^∗−n∣≥εn]≤δ。
这个多次求值取平均的技巧称为The Averaging Trick。通过以上分析可知,此时Pr[∣n^∗−n∣≥εn]能被常数bound住,是一个好的Concentration。新算法的内存占用情况如何呢?由于每次都需要保存在之前的结果,如果我们并行地为每一次都分配新的内存,那么需要的内存就是O(k⋅loglogn)。能否每一次把前一次的结果存下来然后利用重复的空间呢?如果那样,那么我们需要保存2X的值,那么需要一块大小为logn的内存,还不如并行。所以最优的内存分配方案就是O(k⋅loglogn),当k≥2ε2δ1时,内存为O(ε2δloglogn)。
The Median Trick
和“多次测量取平均”类似,我们还可以“多次测量取中位数”来减少误差。在上面取平均的例子中,我们需要重复O(ε2δ1)次才能用一个任意小的常数δ来bound。为了说明取中位数的方法,我们首先采用The Averaging Trick用一个常数δ=31来bound(重复k=2ε23取平均),也即Pr[∣n^∗−n∣≥εn]≤31。重复以上过程s次,得到s个估计n^1∗,⋯,n^s∗。取这s个数的中位数作为输出n^∗∗。
我们来分析Pr[∣n^∗∗−n∣≥εn]。中位数落在区间[n−εn,n+εn]外这一事件发生能推出至少有一半的n^i∗落在了区间外。 定义Yi=1[∣n^i∗−n∣≥εn],Y=i=1∑sYi,那么Pr[∣n^∗∗−n∣≥εn]≤Pr[Y≥s/2]。现在Yi以概率p=Pr[∣n^∗−n∣≥εn]≤31满足伯努利分布,根据Chernoff Bound,Pr[Y≥(1+δ)μ]≤e−31δ2μ。现在μ=p⋅s≤3s,所以取δ=21可得Pr[Y≥s/2]≤Pr[Y≥23μ]≤e−12μ≤e−36s。
综上,Pr[∣n^∗∗−n∣≥εn]≤e−36s。取s=O(logδ1),可得Pr[∣n^∗∗−n∣≥εn]≤δ。我们同样为这s次计算单独分配新内存,那么总内存为O(s⋅k⋅loglogn) =O(ε21⋅logδ1⋅loglogn),在相同Concentration的情况下我们把δ1优化为了logδ1。