Algorithm Search⌘K

Proofs: SD-array

These are the human proofs of SD-array, at full length.

The rank, select and access of the SD-array are correct full

This proof shows: correctness.

Let BB have length nn and its 1s at p0<⋯<pm−1p_0 < \cdots < p_{m-1}, with m≥1m \ge 1, and let ℓ\ell, LoLo and HH be the Elias-Fano code of this sequence with universe nn. Write hj=⌊pj/2ℓ⌋h_j = \lfloor p_j / 2^\ell \rfloor, so pj=hj2ℓ+Lo[j]p_j = h_j 2^\ell + Lo[j]. We use two facts proved on the Elias-Fano page: the (j+1)(j+1)-th 1 of HH is at hj+jh_j + j (fact A), and for 0≤h≤⌊(n−1)/2ℓ⌋0 \le h \le \lfloor (n-1)/2^\ell \rfloor, with P(h)=0P(h) = 0 for h=0h = 0 and P(h)=SELECT0H(h)+1P(h) = \text{SELECT0}_H(h) + 1 otherwise, P(h)−h=∣{j:hj<h}∣P(h) - h = |\{j : h_j < h\}| (fact B).

Select1 (line L1). By fact A, SELECT1H(j)−(j−1)=hj−1_H(j) - (j - 1) = h_{j-1}, so line L1 returns hj−12ℓ+Lo[j−1]=pj−1h_{j-1} 2^\ell + Lo[j-1] = p_{j-1}, the position of the jj-th 1.

Rank1 (lines L2 to L7). If i=ni = n, every 1 is before ii and line L2 returns mm. Let 0≤i<n0 \le i < n, h=⌊i/2ℓ⌋h = \lfloor i / 2^\ell \rfloor and l=i mod 2ℓl = i \bmod 2^\ell, so 0≤h≤⌊(n−1)/2ℓ⌋0 \le h \le \lfloor (n-1)/2^\ell \rfloor. Let J<={j:hj<h}J_{<} = \{j : h_j < h\}, J=={j:hj=h}J_= = \{j : h_j = h\} and J>={j:hj>h}J_> = \{j : h_j > h\}. Since the hjh_j are nondecreasing, these are consecutive ranges of indices in this order. By fact B with hh, line L6 sets r=P(h)−h=∣J<∣r = P(h) - h = |J_<|. By fact B with h+1h + 1, P(h+1)−(h+1)=∣J<∣+∣J=∣P(h+1) - (h+1) = |J_<| + |J_=|, and line L5 sets s=P(h+1)−1−P(h)=∣J=∣s = P(h+1) - 1 - P(h) = |J_=|. So the indices of bucket hh are J=={r,…,r+s−1}J_= = \{r, \ldots, r + s - 1\}. Fact B applies to h+1h + 1 when h+1≤⌊(n−1)/2ℓ⌋+1h + 1 \le \lfloor (n-1)/2^\ell \rfloor + 1, which holds, because HH has ⌊(n−1)/2ℓ⌋+1\lfloor (n-1)/2^\ell \rfloor + 1 zeros. Now:

  • for j∈J<j \in J_<, pj<(hj+1)2ℓ≤h2ℓ≤ip_j < (h_j + 1) 2^\ell \le h 2^\ell \le i, so each such 1 is before ii;
  • for j∈J>j \in J_>, pj≥(h+1)2ℓ>ip_j \ge (h+1) 2^\ell > i, so none is before ii;
  • for j∈J=j \in J_=, pj=h2ℓ+Lo[j]<h2ℓ+l=ip_j = h 2^\ell + Lo[j] < h 2^\ell + l = i if and only if Lo[j]<lLo[j] < l.

So rank1(i)=r+∣{t<s:Lo[r+t]<l}∣\text{rank}_1(i) = r + |\{t < s : Lo[r + t] < l\}|, which line L7 returns. The positions in J=J_= are strictly increasing with the same high part, so Lo[r],…,Lo[r+s−1]Lo[r], \ldots, Lo[r + s - 1] are strictly increasing, and the binary search for the first tt with Lo[r+t]≥lLo[r + t] \ge l computes this count.

Access (lines L8, L9). Let r=rank1(i)r = \text{rank}_1(i), the number of 1s before ii. If B[i]=1B[i] = 1, then i=pri = p_r, so r<mr < m and SELECT1(r+1)=pr=i(r + 1) = p_r = i. If B[i]=0B[i] = 0, then either r=mr = m, or the next 1 after the first rr ones is pr>ip_r > i, so SELECT1(r+1)≠i(r + 1) \ne i. Line L9 returns B[i]B[i] in both cases.

Select0 (line L10). The function f(q)=(q+1)−rank1(q+1)=rank0(q+1)f(q) = (q + 1) - \text{rank}_1(q + 1) = \text{rank}_0(q + 1) is nondecreasing in qq and increases by one exactly at the positions qq with B[q]=0B[q] = 0. For 1≤j≤n−m1 \le j \le n - m, the least qq with f(q)≥jf(q) \ge j is therefore the position of the jj-th 0, and f(n−1)=n−m≥jf(n - 1) = n - m \ge j ensures that it lies in [0,n−1][0, n-1], the range of the binary search.

The case m=0m = 0. Then ℓ=0\ell = 0, HH has only zeros, every rank is 00 by fact B, and access returns 0 by line L9. ■\blacksquare

Back to SD-array