Algorithm Search⌘K

Proofs: Semi-persistent array

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

The semi-persistent array gives each valid version its contents full

This proof shows: correctness.

Setting. A state is a shared array AA of nn slots together with version records. The abstract model gives each version vv ever made a fixed sequence cont(v)\text{cont}(v) of nn values: the first version has the initial contents, and the version returned by SET(v,i,x)(v, i, x) has cont(v)\text{cont}(v) with slot ii set to xx. The state is good if there are versions v0,…,vkv_0, \ldots, v_k such that:

  • (I1) vkv_k has kind arr, and each vjv_j with j<kj < k has kind diff(ij,xj,vj+1)\text{diff}(i_j, x_j, v_{j+1});
  • (I2) A=cont(vk)A = \text{cont}(v_k), and for j<kj < k, cont(vj)\text{cont}(v_j) equals cont(vj+1)\text{cont}(v_{j+1}) with slot iji_j set to xjx_j;
  • (I3) every other version made so far has kind dead.

The valid versions are v0,…,vkv_0, \ldots, v_k.

Lemma 1 (get). In a good state, GET(vj,i)(v_j, i) returns slot ii of cont(vj)\text{cont}(v_j), and changes nothing.

Proof. GET visits vj,vj+1,…v_j, v_{j+1}, \ldots in order. Let l≥jl \ge j be the first index with l<kl < k and il=ii_l = i, if there is one. For j≤p<lj \le p < l, (I2) gives slot ii of cont(vp)\text{cont}(v_p) equal to slot ii of cont(vp+1)\text{cont}(v_{p+1}), since ip≠ii_p \ne i. So slot ii of cont(vj)\text{cont}(v_j) equals slot ii of cont(vl)\text{cont}(v_l), which is xlx_l by (I2), and that is what line L4 returns. If there is no such ll, the same argument up to vkv_k gives slot ii of cont(vk)=A[i]\text{cont}(v_k) = A[i], which line L6 returns. GET writes nothing. □\square

Lemma 2 (reroot). In a good state, REROOT(vj)(v_j) leaves a good state with valid versions v0,…,vjv_0, \ldots, v_j.

Proof. Line L12 collects tp=vj+pt_p = v_{j + p} for p=0,…,mp = 0, \ldots, m with m=k−jm = k - j, by (I1). We claim that after line L13 has processed tm−1,…,tlt_{m-1}, \ldots, t_l, the array is cont(vj+l)\text{cont}(v_{j + l}). Before the loop it is cont(vk)\text{cont}(v_k) by (I2). The step for tlt_{l} sets A[ij+l]←xj+lA[i_{j+l}] \gets x_{j+l}, which turns cont(vj+l+1)\text{cont}(v_{j+l+1}) into cont(vj+l)\text{cont}(v_{j+l}) by (I2). After the loop, A=cont(vj)A = \text{cont}(v_j). Line L14 marks vj+1,…,vkv_{j+1}, \ldots, v_k dead, and line L15 makes vjv_j of kind arr. Now (I1) holds for v0,…,vjv_0, \ldots, v_j (the diffs of v0,…,vj−1v_0, \ldots, v_{j-1} are untouched), (I2) holds because A=cont(vj)A = \text{cont}(v_j) and the earlier diffs are unchanged, and (I3) holds because the versions removed from the path are dead. □\square

Lemma 3 (set). In a good state, SET(vj,i,x)(v_j, i, x) returns a new version ww with cont(w)\text{cont}(w) equal to cont(vj)\text{cont}(v_j) with slot ii set to xx, and leaves a good state with valid versions v0,…,vj,wv_0, \ldots, v_j, w.

Proof. By Lemma 2, after line L7 the state is good with vjv_j newest and A=cont(vj)A = \text{cont}(v_j). Line L8 makes ww of kind arr. Line L9 sets vjv_j to diff(i,A[i],w)\text{diff}(i, A[i], w), with A[i]A[i] read before the write, and line L10 sets A[i]←xA[i] \gets x. Now A=cont(w)A = \text{cont}(w), and cont(vj)\text{cont}(v_j) equals cont(w)\text{cont}(w) with slot ii set to the old A[i]A[i], which is (I2) for the pair vj,wv_j, w. (I1) and (I3) are clear. □\square

Theorem. After any sequence of operations, the state is good; each GET or TO-LIST on a valid version returns its contents in the model; each operation on a version that is not valid is rejected; and the contents of a valid version never change.

Proof. The first version alone is a good state with k=0k = 0. By Lemmas 1 to 3 every operation keeps the state good and returns the right answer. TO-LIST copies A=cont(vk)A = \text{cont}(v_k) and applies the diffs from vk−1v_{k-1} back to vjv_j, which yields cont(vj)\text{cont}(v_j) by the argument of Lemma 2 applied to a copy. A version that is not valid has kind dead by (I3), and lines L1 and L11 reject it. Finally, cont\text{cont} of a version is fixed by the model, and the good state represents it exactly for each valid version, so a valid version is never seen to change. ■\blacksquare

Back to Semi-persistent array