Proofs: Cache-oblivious B-tree
These are the human proofs of Cache-oblivious B-tree, at full length.
The index stays exact after every update, and the search finds the predecessor full
This proof shows: correctness, termination.
We use the pseudocode of the page. The PMA has segments of cells. The index is a complete binary tree with levels; the node at depth with path has the segments to below it. Its position in the index array is , which is a bijection onto by the proof on the van Emde Boas layout page, so distinct nodes have distinct cells. The PMA keeps its key sequence strictly increasing and equal to the stored set, and every operation of the PMA ends; both facts are proved on the packed memory array page. We write (C1) for this, and (C2), (C3) for the conditions on the index from the page. For a node , let be the set of keys in the segments below .
Lemma 1. If (C1), (C2) and (C3) hold, then for every node , is the smallest element of , or none if is empty.
Proof. By induction on the height of . For a leaf, this is (C2) with (C1): the first key of a segment is its smallest key. For an internal node, , and by (C1) every key of the left part is smaller than every key of the right part, since the left segments come first. So the smallest element of is that of the left part if it is not empty, and that of the right part otherwise, which is (C3) with the induction hypothesis.
Lemma 2 (UPDATE). Suppose (C2) and (C3) held, and then the PMA changed only the cells of segments to . After UPDATE, (C2) and (C3) hold.
Proof. Call a node changed if one of the segments is below it. A node that is not changed has the same segments below it with the same contents, and its children are not changed either; its value was right before and still is, since (C2) and (C3) for it refer only to unchanged things. Line L11 sets every changed leaf by (C2). The changed nodes at depth are exactly those with from to , which is the range of line L13. Lines L12 and L13 go from depth up to 0, so when a node at depth is set, both its children, at depth , already have their final values: they were set in the pass before, or at line L11, or they are not changed. So (C3) holds at each changed node after it is set, and later passes do not change it again.
Lemma 3 (BUILD). After BUILD, (C2) and (C3) hold.
Proof. Line L14 calls UPDATE on all segments, so every node is changed and set, leaves first and then by increasing height, as in Lemma 2.
Lemma 4 (SEARCH). If (C1), (C2) and (C3) hold, SEARCH returns the position of the largest key at most , or none if there is none.
Proof. If no key is at most , the scan of line L4 finds no key at most in any segment, so SEARCH returns none, which is right. Otherwise let be the largest key at most . We show the invariant at the start of each pass of line L2: . At the root, holds all keys.
Consider a pass at node with . If none and , then by Lemma 1 the right part has a key at most , and every key of the left part is smaller than it by (C1); so , the largest key at most , is not in the left part, and . Otherwise, by Lemma 1, the right part is empty or all its keys exceed , so is not in it, and . In both cases line L3 moves to the child that holds .
The loop ends after passes, since each moves one level down. At the leaf, is in the segment, whose keys are in order by (C1), and no key after in it is at most . So the scan of line L4 returns the position of .
Lemma 5 (INSERT and DELETE). If (C1) to (C3) hold before an update, they hold after it, and the set changes as specified.
Proof. By Lemma 4, line L5 or L9 finds the predecessor of , which is the position that the PMA insert and delete use; so by the proof of the PMA, (C1) holds after the PMA step and the set changes as specified. If the PMA resized, the index is built again, and Lemma 3 gives (C2) and (C3). Otherwise, the PMA changed only the cells of the window , which is a run of whole segments; for a delete without a rebalance, is the segment of the deleted cell. Lines L8 and L10 call UPDATE on exactly these segments, and Lemma 2 gives (C2) and (C3).
Termination. SEARCH makes passes and scans cells. UPDATE runs over finite ranges. The PMA steps end, by the proof of the PMA. So every operation ends.
The empty structure is built by BUILD, so (C1) to (C3) hold at the start. By Lemma 5 they hold after every update, and by Lemma 4 every predecessor query is right; contains and range follow from it and from (C1), as for the PMA.