Proofs: HAT-trie
These are the human proofs of HAT-trie, at full length.
The HAT-trie stores each key once and finds it, and bursts and splits keep its invariant full
This proof shows: correctness.
We use the pseudocode, the notation and the invariant (H1) to (H4) of the page. For a node , write for its string, the symbols of the pointers from the root to . An entry stands for the key given by (H2).
Lemma 1 (descent). For a string , DESCEND stops at the node with , where either or the pointer leads to a container . A key can only be stored at in the first case, and only in in the second, under the string if is pure and if is hybrid.
Proof. The loop follows one pointer per symbol while it leads to a trie node, so . A key is stored at a node value when , or in a container under a node whose string is a prefix of , with the pointer by leading to that container, by (H2). Suppose is stored. If for a node , the descent reaches and stops with , since it consumes the symbols of along existing nodes; so . Otherwise the container holding hangs under a node by the pointer ; the descent passes through and stops there, because that pointer leads to a container; so and the container is , and the stored string is the one given by (H2).
GET. By Lemma 1, GET looks at the only place where can be. By (H3) the entry for the string is in the slot of its hash, which FIND scans, and by (H4) it is there at most once. So GET returns the value of if it is a key, and NIL otherwise.
PUT. By Lemma 1 and the same argument, PUT updates the existing entry of if there is one, and else adds one entry, at the place where GET will look. So (H2) and (H4) hold, and (H3) holds except that may have entries.
BURST keeps the keys. Each case of lines L9 to L11 replaces one container under a node and moves its entries; we show that each entry keeps the key it stands for.
- Line L9. is pure under symbol of , so its entry stands for . The new node has . The empty entry becomes , standing for . Each other entry goes into the hybrid container of , which covers all symbols, as the string , and stands for , with in its range.
- Line L10. is hybrid under with range , and its entries stand for . The new containers are hybrid under with ranges that partition , each pointer of the range now leads to the part that contains it, and each entry goes to the part that contains . So still stands for and lies in the container its first symbol points to.
- Line L11. is hybrid with range , so all its entries start with and stand for with . As a pure container under , the entry stands for , the same key.
In each case the moved entries are distinct strings in the new container, because they stood for distinct keys, and each is put in the slot of its hash. So (H2) to (H4) hold except for the size bound of the new containers, which line L12 puts on the work list.
BURST ends. Assume . A container processed at line L9 is pure with more than entries, so it has a nonempty entry , and the new node has , a proper prefix of the key . Node strings are distinct, so line L9 runs at most once for each proper prefix of a stored key, finitely often. Between two runs of line L9, the work list only processes containers under existing nodes. Line L10 replaces a container by parts with strictly smaller ranges, and line L11 turns a container with a range of one symbol into a pure one, which is not split again. For one node, the ranges of its hybrid containers partition its pointers, so at most splits and conversions can happen before the next node is created. Hence the work list empties, and at that point every container has at most entries, so (H3) holds.