Algorithm Search⌘K

Proofs: RRR bit vector

These are the human proofs of RRR bit vector, at full length.

The RRR bit vector is correct and its offsets fit in lg C(n, m) + n/b + 1 bits full

This proof shows: correctness, space.

Write C(j,c)=(jc)C(j, c) = \binom{j}{c}, with C(j,c)=0C(j, c) = 0 for c>jc > j. A block is a word xx of bb bits; its class is $c = $ the number of 1s of xx, and if its 1s are at p1<⋯<pcp_1 < \cdots < p_c, its offset is o(x)=∑i=1cC(pi,i)o(x) = \sum_{i=1}^{c} C(p_i, i). Lines L1 to L4 compute exactly this sum: when the loop meets the ii-th 1, at j=pij = p_i, the counter cc has just become ii.

Lemma 1 (range). For a block of class cc, 0≤o(x)<C(b,c)0 \le o(x) < C(b, c). More precisely, if all 1s are below position hh, then o(x)<C(h,c)o(x) < C(h, c).

Proof. By induction on cc. For c=0c = 0, o=0<1=C(h,0)o = 0 < 1 = C(h, 0). For c≥1c \ge 1, pc≤h−1p_c \le h - 1, and the first c−1c - 1 ones lie below pcp_c, so by induction their sum is less than C(pc,c−1)C(p_c, c-1), that is at most C(pc,c−1)−1C(p_c, c-1) - 1. Then o(x)≤C(pc,c−1)−1+C(pc,c)=C(pc+1,c)−1≤C(h,c)−1o(x) \le C(p_c, c-1) - 1 + C(p_c, c) = C(p_c + 1, c) - 1 \le C(h, c) - 1 by Pascal's rule and the monotonicity of C(⋅,c)C(\cdot, c). □\square

Lemma 2 (decode). For each block xx of class cc, DECODE(c,o(x))=x(c, o(x)) = x.

Proof. DECODE scans jj from b−1b - 1 down. Let the invariant be: before step jj, the bits above jj of the output are those of xx, the remaining counter c′c' is the number of 1s of xx at positions ≤j\le j, and the remaining value o′o' is ∑i=1c′C(pi,i)\sum_{i=1}^{c'} C(p_i, i) for those 1s. It holds at j=b−1j = b - 1. At step jj, if xx has a 1 at jj, then j=pc′j = p_{c'} and o′≥C(j,c′)o' \ge C(j, c'), so line L7 sets the bit and lines L8 restore the invariant. If xx has no 1 at jj, then all of the c′c' ones are below jj, and Lemma 1 with h=jh = j gives o′<C(j,c′)o' < C(j, c'), or c′=0c' = 0; so line L7 does not set the bit. After j=0j = 0 the output equals xx. □\square

By Lemmas 1 and 2, ENCODE maps the C(b,c)C(b, c) blocks of class cc injectively into {0,…,C(b,c)−1}\{0, \ldots, C(b,c) - 1\}, so it is a bijection, and each offset fits in L[c]=⌈lg⁡C(b,c)⌉L[c] = \lceil \lg C(b, c) \rceil bits.

The pointers. BUILD appends the offsets of blocks 0,1,…0, 1, \ldots to the stream in order, with lengths L[K[t]]L[K[t]]. So the offset of block tt starts at ∑t′<tL[K[t′]]\sum_{t' < t} L[K[t']], which is P[q]+PB[t]P[q] + PB[t] by the definitions of the samples, with q=⌊t/k⌋q = \lfloor t/k \rfloor. In the same way R[q]+RB[t]=∑t′<tK[t′]=rank1(tb)R[q] + RB[t] = \sum_{t' < t} K[t'] = \text{rank}_1(t b). Hence line L14 (and L11, L18) rebuilds block tt exactly, by Lemma 2.

Access and rank. Position ii is bit i mod bi \bmod b of block t=⌊i/b⌋t = \lfloor i/b \rfloor, so line L11 is correct. For rank, $\text{rank}_1(i) = \text{rank}_1(t b) + $ the number of 1s of block tt at positions below i mod bi \bmod b. If i mod b=0i \bmod b = 0 the second term is 0, which is line L13; otherwise it is the POPCOUNT of line L15.

Select. Let j≤mj \le m. The number of 1s before superblock qq, R[q]R[q], is nondecreasing in qq and R[0]=0<jR[0] = 0 < j, so the last qq with R[q]<jR[q] < j exists, and the jj-th 1 is not in a later superblock, because those start with at least jj ones before them. In the same way, the binary search of line L17 finds the block tt of superblock qq that holds the jj-th 1: the last block with rank1(tb)<j\text{rank}_1(tb) < j. The jj-th 1 of BB is then the (j−rank1(tb))(j - \text{rank}_1(tb))-th 1 of block tt, which line L19 returns. For select0\text{select}_0 the same argument holds with the counts of 0s, tb−rank1(tb)t b - \text{rank}_1(t b); the bits of the last block word above b′b' are not part of BB and lie after the last real 0, so they are never reached when j≤n−mj \le n - m.

Space of the offsets. Let btb_t be the length of block tt: bb for each block but the last, and b′=n−(⌈n/b⌉−1)bb' = n - (\lceil n/b \rceil - 1) b for the last. Let ctc_t be the class of block tt, and let Lt=⌈lg⁡C(bt,ct)⌉L_t = \lceil \lg C(b_t, c_t) \rceil be the length of its offset, which suffices by Lemma 1 with h=bth = b_t. Cutting a vector into its blocks is a bijection between the bit vectors of length nn and the tuples of blocks of lengths (bt)(b_t). It maps the vectors whose blocks have the classes (ct)(c_t) onto the tuples whose block tt has class ctc_t, and there are ∏tC(bt,ct)\prod_t C(b_t, c_t) of these. Each such vector has ∑tct=m\sum_t c_t = m ones, so it is one of the C(n,m)C(n, m) vectors with mm ones, and ∏tC(bt,ct)≤C(n,m)\prod_t C(b_t, c_t) \le C(n, m). Hence

∑tLt≤∑t(lg⁡C(bt,ct)+1)≤lg⁡C(n,m)+⌈n/b⌉≤lg⁡C(n,m)+nb+1.\sum_t L_t \le \sum_t \left(\lg C(b_t, c_t) + 1\right) \le \lg C(n, m) + \lceil n / b \rceil \le \lg C(n, m) + \frac{n}{b} + 1.

■\blacksquare

Back to RRR bit vector