Algorithm Search⌘K

Proofs: Jacobson's rank structure

These are the human proofs of Jacobson's rank structure, at full length.

Jacobson's rank structure returns rank and select correctly full

This proof shows: correctness.

We use the pseudocode and the notation of the page: bb is the block length, ss the number of blocks in a superblock, L=sbL = sb, K=⌊n/b⌋K = \lfloor n/b \rfloor, and B[p]=0B[p] = 0 for p≥np \ge n by convention. Write R(i)=rank1(i)=∣{p<i:B[p]=1}∣R(i) = \text{rank}_1(i) = |\{p < i : B[p] = 1\}|. With the convention, R(i)R(i) is defined for each i≥0i \ge 0 and equals R(n)=mR(n) = m for i≥ni \ge n.

Lemma 1 (the table). After line L2, T[x][r]=∣{t<r:bit t of x is 1}∣T[x][r] = |\{t < r : \text{bit } t \text{ of } x \text{ is } 1\}| for 0≤x<2b0 \le x < 2^b and 0≤r≤b0 \le r \le b.

Proof. Line L2 sets each entry to this value by its definition. □\square

Lemma 2 (BUILD). After BUILD, for 0≤k≤K0 \le k \le K: bit tt of X[k]X[k] is B[kb+t]B[kb + t] for 0≤t<b0 \le t < b; RS[q]=R(qL)RS[q] = R(qL) for 0≤q≤⌊K/s⌋0 \le q \le \lfloor K/s \rfloor; and RB[k]=R(kb)−RS[⌊k/s⌋]RB[k] = R(kb) - RS[\lfloor k/s \rfloor].

Proof. We show the invariant c=R(kb)c = R(kb) at the top of each step kk of the loop of line L4, and that after step kk the entries X[k]X[k], RB[k]RB[k] and, if s∣ks \mid k, RS[k/s]RS[k/s] hold their stated values.

Initialization. Line L3 sets c=0=R(0)c = 0 = R(0) before step k=0k = 0.

Maintenance. Assume c=R(kb)c = R(kb) at the top of step kk. If s∣ks \mid k, line L5 sets RS[k/s]=c=R(kb)=R((k/s)L)RS[k/s] = c = R(kb) = R((k/s) L). Otherwise q=⌊k/s⌋q = \lfloor k/s \rfloor satisfies qs<kqs < k, so RS[q]RS[q] was set at step qsqs, which came earlier. In both cases RS[⌊k/s⌋]RS[\lfloor k/s \rfloor] exists when line L6 runs, and line L6 sets RB[k]=R(kb)−RS[⌊k/s⌋]RB[k] = R(kb) - RS[\lfloor k/s \rfloor]. Line L7 sets bit tt of X[k]X[k] to B[kb+t]B[kb + t]. By Lemma 1 with r=br = b, line L8 adds the number of 1s among B[kb],…,B[kb+b−1]B[kb], \ldots, B[kb + b - 1], which is R(kb+b)−R(kb)R(kb + b) - R(kb). So c=R((k+1)b)c = R((k+1) b) at the top of step k+1k + 1.

Termination. The loop runs for k=0,…,Kk = 0, \ldots, K, so each entry is set. The superblock indices k/sk/s for s∣k≤Ks \mid k \le K are exactly 0,…,⌊K/s⌋0, \ldots, \lfloor K/s \rfloor. □\square

Lemma 3 (RANK1). For 0≤i≤n0 \le i \le n, RANK1(i)(i) returns R(i)R(i).

Proof. Let k=⌊i/b⌋k = \lfloor i/b \rfloor, r=i mod br = i \bmod b and q=⌊k/s⌋q = \lfloor k/s \rfloor. Since i≤ni \le n, k≤⌊n/b⌋=Kk \le \lfloor n/b \rfloor = K, so all three reads of line L10 are defined. We have qL=qsb≤kb≤i=kb+rqL = qsb \le kb \le i = kb + r. By Lemma 2, RS[q]+RB[k]=R(kb)RS[q] + RB[k] = R(kb). The positions pp with kb≤p<ikb \le p < i are kb+tkb + t for 0≤t<r0 \le t < r, and by Lemma 2 their bits are bits 00 to r−1r - 1 of X[k]X[k]. By Lemma 1, T[X[k]][r]T[X[k]][r] is their number of 1s, which is R(i)−R(kb)R(i) - R(kb). The sum is R(i)R(i). □\square

Lemma 4 (SELECT1). For 1≤j≤m1 \le j \le m, SELECT1(j)(j) returns p∗=min⁡{p:R(p+1)≥j}p^* = \min\{p : R(p + 1) \ge j\}, which is the position of the jj-th 1.

Proof. First, p∗p^* is the position of the jj-th 1. The function RR does not decrease, R(0)=0<jR(0) = 0 < j and R(n)=m≥jR(n) = m \ge j, so p∗p^* exists and 0≤p∗≤n−10 \le p^* \le n - 1. By minimality, R(p∗)<j≤R(p∗+1)R(p^*) < j \le R(p^* + 1). Since R(p∗+1)−R(p∗)≤1R(p^* + 1) - R(p^*) \le 1, this gives R(p∗)=j−1R(p^*) = j - 1 and B[p∗]=1B[p^*] = 1, which is the definition of select1(j)\text{select}_1(j).

For the search we use the invariant (I): lo≤p∗≤hilo \le p^* \le hi. Line L11 makes it true, since 0≤p∗≤n−10 \le p^* \le n - 1. In an iteration, lo≤mid<hilo \le mid < hi. If R(mid+1)≥jR(mid + 1) \ge j, then p∗≤midp^* \le mid by the definition of p∗p^*, and hi←midhi \leftarrow mid keeps (I). Otherwise R(mid+1)<jR(mid + 1) < j, and since RR does not decrease, R(p+1)<jR(p + 1) < j for each p≤midp \le mid, so p∗≥mid+1p^* \ge mid + 1 and lo←mid+1lo \leftarrow mid + 1 keeps (I). Lemma 3 gives the value R(mid+1)R(mid + 1), since mid+1≤nmid + 1 \le n. Each iteration makes hi−lohi - lo smaller by at least ⌈(hi−lo)/2⌉≥1\lceil (hi - lo)/2 \rceil \ge 1, so the loop stops after at most ⌈lg⁡n⌉\lceil \lg n \rceil iterations, with lo=hilo = hi. By (I), lo=p∗lo = p^*. ■\blacksquare

Back to Jacobson's rank structure