Jacobson's rank structure returns rank and select correctly full
This proof shows: correctness.
We use the pseudocode and the notation of the page: b is the block length, s the number of blocks in a superblock, L=sb, K=⌊n/b⌋, and B[p]=0 for p≥n by convention. Write R(i)=rank1(i)=∣{p<i:B[p]=1}∣. With the convention, R(i) is defined for each i≥0 and equals R(n)=m for i≥n.
Lemma 1 (the table). After line L2, T[x][r]=∣{t<r:bit t of x is 1}∣ for 0≤x<2b and 0≤r≤b.
Proof. Line L2 sets each entry to this value by its definition. □
Lemma 2 (BUILD). After BUILD, for 0≤k≤K: bit t of X[k] is B[kb+t] for 0≤t<b; RS[q]=R(qL) for 0≤q≤⌊K/s⌋; and RB[k]=R(kb)−RS[⌊k/s⌋].
Proof. We show the invariant c=R(kb) at the top of each step k of the loop of line L4, and that after step k the entries X[k], RB[k] and, if s∣k, RS[k/s] hold their stated values.
Initialization. Line L3 sets c=0=R(0) before step k=0.
Maintenance. Assume c=R(kb) at the top of step k. If s∣k, line L5 sets RS[k/s]=c=R(kb)=R((k/s)L). Otherwise q=⌊k/s⌋ satisfies qs<k, so RS[q] was set at step qs, which came earlier. In both cases RS[⌊k/s⌋] exists when line L6 runs, and line L6 sets RB[k]=R(kb)−RS[⌊k/s⌋]. Line L7 sets bit t of X[k] to B[kb+t]. By Lemma 1 with r=b, line L8 adds the number of 1s among B[kb],…,B[kb+b−1], which is R(kb+b)−R(kb). So c=R((k+1)b) at the top of step k+1.
Termination. The loop runs for k=0,…,K, so each entry is set. The superblock indices k/s for s∣k≤K are exactly 0,…,⌊K/s⌋. □
Lemma 3 (RANK1). For 0≤i≤n, RANK1(i) returns R(i).
Proof. Let k=⌊i/b⌋, r=imodb and q=⌊k/s⌋. Since i≤n, k≤⌊n/b⌋=K, so all three reads of line L10 are defined. We have qL=qsb≤kb≤i=kb+r. By Lemma 2, RS[q]+RB[k]=R(kb). The positions p with kb≤p<i are kb+t for 0≤t<r, and by Lemma 2 their bits are bits 0 to r−1 of X[k]. By Lemma 1, T[X[k]][r] is their number of 1s, which is R(i)−R(kb). The sum is R(i). □
Lemma 4 (SELECT1). For 1≤j≤m, SELECT1(j) returns p∗=min{p:R(p+1)≥j}, which is the position of the j-th 1.
Proof. First, p∗ is the position of the j-th 1. The function R does not decrease, R(0)=0<j and R(n)=m≥j, so p∗ exists and 0≤p∗≤n−1. By minimality, R(p∗)<j≤R(p∗+1). Since R(p∗+1)−R(p∗)≤1, this gives R(p∗)=j−1 and B[p∗]=1, which is the definition of select1(j).
For the search we use the invariant (I): lo≤p∗≤hi. Line L11 makes it true, since 0≤p∗≤n−1. In an iteration, lo≤mid<hi. If R(mid+1)≥j, then p∗≤mid by the definition of p∗, and hi←mid keeps (I). Otherwise R(mid+1)<j, and since R does not decrease, R(p+1)<j for each p≤mid, so p∗≥mid+1 and lo←mid+1 keeps (I). Lemma 3 gives the value R(mid+1), since mid+1≤n. Each iteration makes hi−lo smaller by at least ⌈(hi−lo)/2⌉≥1, so the loop stops after at most ⌈lgn⌉ iterations, with lo=hi. By (I), lo=p∗. ■