Algorithm Search⌘K

Proofs: Binary random-access list

These are the human proofs of Binary random-access list, at full length.

The binary random-access list keeps its invariant and implements a persistent list full

This proof shows: correctness, termination.

We use the pseudocode and the invariant (B1) to (B3) of the page. For a leaf tree tt, seq(t)\text{seq}(t) is the sequence of the items of its leaves from left to right, and size(t)=∣seq(t)∣\text{size}(t) = |\text{seq}(t)|. For a digit list L=d0,…,dℓ−1L = d_0, \ldots, d_{\ell-1}, seq(L)\text{seq}(L) is the concatenation of seq(t)\text{seq}(t) over the One digits dk=One td_k = \text{One } t in increasing order of kk. We say that a digit list LL is valid from rank jj if each dk=One td_k = \text{One } t of LL has tt complete of rank j+kj + k, and its last digit, if any, is a One. A list is valid when it is valid from rank 0; this is (B1) and (B2), and (B3) is the definition of seq(L)\text{seq}(L).

The facts about trees that we use: if t1t_1 and t2t_2 are complete of rank kk, then LINK(t1,t2)(t_1, t_2) is complete of rank k+1k + 1 and has sequence seq(t1)⋅seq(t2)\text{seq}(t_1) \cdot \text{seq}(t_2); and a complete tree node(w,t1,t2)\text{node}(w, t_1, t_2) of rank k+1≥1k + 1 \ge 1 has children complete of rank kk, with w=2k+1w = 2^{k+1} and seq=seq(t1)⋅seq(t2)\text{seq} = \text{seq}(t_1) \cdot \text{seq}(t_2). Both follow from the definitions.

Lemma 1 (CONS-TREE). If LL is valid from rank jj and tt is complete of rank jj, then CONS-TREE(t,L)(t, L) terminates and returns a list L′L' that is valid from rank jj with seq(L′)=seq(t)⋅seq(L)\text{seq}(L') = \text{seq}(t) \cdot \text{seq}(L).

Proof. By induction on the length of LL. If LL is empty (line L2), L′=⟨One t⟩L' = \langle \text{One } t \rangle, valid from rank jj, with sequence seq(t)\text{seq}(t). If d0=Zerod_0 = \text{Zero} (line L3), L′L' replaces it by One tt, of rank jj; the other digits and the last digit are unchanged (the last digit is not d0d_0, since a valid list does not end in Zero), and the new first tree comes before all others, so seq(L′)=seq(t)⋅seq(L)\text{seq}(L') = \text{seq}(t) \cdot \text{seq}(L). If d0=One ud_0 = \text{One } u (lines L4 and L5), uu has rank jj, so LINK(t,u)(t, u) is complete of rank j+1j + 1 with sequence seq(t)⋅seq(u)\text{seq}(t) \cdot \text{seq}(u). The rest of LL is valid from rank j+1j + 1 (it is empty or ends in a One) and is shorter, so by the hypothesis the recursive call returns L′′L'' valid from rank j+1j + 1 with seq(L′′)=seq(t)⋅seq(u)⋅seq(rest(L))\text{seq}(L'') = \text{seq}(t) \cdot \text{seq}(u) \cdot \text{seq}(\text{rest}(L)). Then L′=Zero::L′′L' = \text{Zero} :: L'' is valid from rank jj, since L′′L'' is non-empty and ends in a One, and seq(L′)=seq(L′′)=seq(t)⋅seq(L)\text{seq}(L') = \text{seq}(L'') = \text{seq}(t) \cdot \text{seq}(L). □\square

Lemma 2 (UNCONS-TREE). If LL is non-empty and valid from rank jj, then UNCONS-TREE(L)(L) terminates and returns (t,L′)(t, L') where tt is complete of rank jj, L′L' is valid from rank jj, and seq(t)⋅seq(L′)=seq(L)\text{seq}(t) \cdot \text{seq}(L') = \text{seq}(L).

Proof. By induction on the length of LL. If L=⟨One t⟩L = \langle \text{One } t \rangle (line L7), tt has rank jj and L′=⟨⟩L' = \langle\rangle. If d0=One td_0 = \text{One } t and LL has more digits (line L8), then L′=Zero::rest(L)L' = \text{Zero} :: \text{rest}(L), whose last digit is the last digit of LL, a One; so L′L' is valid from rank jj, and seq(t)⋅seq(L′)=seq(L)\text{seq}(t) \cdot \text{seq}(L') = \text{seq}(L). If d0=Zerod_0 = \text{Zero} (line L9), then rest(L)\text{rest}(L) is non-empty, because a valid list does not end in Zero, and it is valid from rank j+1j + 1. By the hypothesis, the call returns a tree uu complete of rank j+1≥1j + 1 \ge 1, so u=node(w,t1,t2)u = \text{node}(w, t_1, t_2) with t1t_1 and t2t_2 complete of rank jj, and a list L′′L'' valid from rank j+1j + 1 with seq(u)⋅seq(L′′)=seq(rest(L))=seq(L)\text{seq}(u) \cdot \text{seq}(L'') = \text{seq}(\text{rest}(L)) = \text{seq}(L). Line L10 returns t1t_1 and L′=One t2::L′′L' = \text{One } t_2 :: L'', which is valid from rank jj (if L′′L'' is empty its last digit is One t2t_2), and seq(t1)⋅seq(L′)=seq(t1)⋅seq(t2)⋅seq(L′′)=seq(L)\text{seq}(t_1) \cdot \text{seq}(L') = \text{seq}(t_1) \cdot \text{seq}(t_2) \cdot \text{seq}(L'') = \text{seq}(L). □\square

Lemma 3 (CONS, HEAD, TAIL). Let LL be valid with seq(L)=⟨x0,…,xn−1⟩\text{seq}(L) = \langle x_0, \ldots, x_{n-1} \rangle. CONS(x,L)(x, L) is valid with sequence ⟨x,x0,…,xn−1⟩\langle x, x_0, \ldots, x_{n-1} \rangle. If n≥1n \ge 1, HEAD(L)=x0(L) = x_0 and TAIL(L)(L) is valid with sequence ⟨x1,…,xn−1⟩\langle x_1, \ldots, x_{n-1} \rangle. If n=0n = 0, both report an error.

Proof. A leaf is complete of rank 0, so Lemma 1 with j=0j = 0 gives the claim for CONS. A valid list is empty exactly when n=0n = 0, since every One digit holds at least one item; then line L6 reports the error. Otherwise, by Lemma 2 with j=0j = 0, UNCONS-TREE returns a tree of rank 0, which is a leaf leaf(y)\text{leaf}(y), and a valid L′L' with ⟨y⟩⋅seq(L′)=seq(L)\langle y \rangle \cdot \text{seq}(L') = \text{seq}(L). So y=x0y = x_0 and seq(L′)=⟨x1,…,xn−1⟩\text{seq}(L') = \langle x_1, \ldots, x_{n-1} \rangle. □\square

Lemma 4 (LOOKUP). If LL is valid with seq(L)=⟨x0,…,xn−1⟩\text{seq}(L) = \langle x_0, \ldots, x_{n-1} \rangle, then LOOKUP(i,L)(i, L) returns xix_i for 0≤i<n0 \le i < n and reports an error for i≥ni \ge n.

Proof. Let the One digits of LL hold the trees u1,u2,…,uru_1, u_2, \ldots, u_r in digit order, and let sq=∑p<qsize(up)s_q = \sum_{p < q} \text{size}(u_p). The loop of line L13 keeps this invariant: before the digits of uqu_q are examined, the variable ii equals i0−sqi_0 - s_q, where i0i_0 is the input index, and i0≥sqi_0 \ge s_q. It holds at the start (s1=0s_1 = 0). Zero digits change nothing. At the digit of uqu_q, if i<size(uq)i < \text{size}(u_q), then sq≤i0<sq+1s_q \le i_0 < s_{q+1}, so xi0x_{i_0} is the item of index ii in seq(uq)\text{seq}(u_q), and the descent starts. Otherwise line L19 subtracts size(uq)\text{size}(u_q), which gives i0−sq+1i_0 - s_{q+1} with i0≥sq+1i_0 \ge s_{q+1}, and the invariant holds for uq+1u_{q+1}. If the loop ends, i0≥sr+1=ni_0 \ge s_{r+1} = n, and line L20 reports the error correctly.

The descent of lines L16 to L18 keeps the invariant "the wanted item is the item of index ii in seq(t)\text{seq}(t), and 0≤i<size(t)0 \le i < \text{size}(t)". At a node node(w,t1,t2)\text{node}(w, t_1, t_2) with size(t1)=w/2\text{size}(t_1) = w/2, the item of index ii is in t1t_1 at index ii if i<w/2i < w/2, and in t2t_2 at index i−w/2i - w/2 otherwise, which is line L17. Each step goes one level down, so the loop stops after at most the rank of the tree, at a leaf with i=0i = 0, whose item is the wanted one. □\square

Lemma 5 (UPDATE). If LL is valid with seq(L)=⟨x0,…,xn−1⟩\text{seq}(L) = \langle x_0, \ldots, x_{n-1} \rangle and 0≤i<n0 \le i < n, then UPDATE(i,y,L)(i, y, L) returns a valid list whose sequence is that of LL with xix_i replaced by yy.

Proof. UPDATE-TREE(i,y,t)(i, y, t), for tt complete and 0≤i<size(t)0 \le i < \text{size}(t), returns a tree of the same shape with the item of index ii replaced by yy: by induction on the rank, a leaf has i=0i = 0 (line L25), and at a node the same case split as in Lemma 4 sends the change to the correct child and keeps the other child and ww (lines L27 and L28). UPDATE then follows the same walk over the digits as LOOKUP, with the same invariant on ii, and rebuilds the digit cells before the changed tree with the same digits (lines L21 and L24) and the changed tree in the same place (line L23). Ranks, the last digit and the order of the trees do not change, so the result is valid, and its sequence differs only at position ii. The precondition i<ni < n means that line L23 is reached before the list ends. □\square

Persistence. No line assigns to a field of an existing digit cell or tree node: lines L2, L3, L5, L7, L8, L10, L21, L23, L24, L27 and L28 build new cells and nodes, and share old ones only as children. So every list built earlier keeps its digits, trees and sequence.

Theorem. Every list built from the empty list by CONS, TAIL and UPDATE, applied to any earlier versions, is valid, and each operation returns the result that the persistent list type specifies. Each operation terminates.

Proof. The empty list is valid. By persistence, an earlier version is still valid when it is used again. Lemmas 3, 4 and 5 give the results and the validity of the new versions. Termination: CONS-TREE and UNCONS-TREE recurse on a shorter digit list, the loops of LOOKUP run over a finite digit list and down a finite tree, and UPDATE and UPDATE-TREE recurse on a shorter digit list or a lower rank. ■\blacksquare

Back to Binary random-access list