Proofs: CHD perfect hashing
These are the human proofs of CHD perfect hashing, at full length.
CHD evaluates in O(1) time, uses O(n) words, and builds in O(n) expected time in an idealized model sketch
This proof shows: time.expected, space.extra.
The model is the word RAM, with keys and hash values of words. Let be the average bucket size and the load.
Claim 1 (evaluation). CHD-EVAL takes time in the worst case.
Proof. Lines L12 and L13 compute , and once each, read , and do one division, one multiplication, two additions and one reduction. With stored as a plain array, the read is one memory access.
Claim 2 (plain space). The function takes words: the array of entries, each less than , and the descriptions of , and . For a constant this is words. The build uses more words for the buckets and the marks of the slots.
Lemma 3 (cost of one attempt). One attempt of lines L2 to L9 takes time, where is the number of indices that line L7 tests for bucket .
Proof. Line L3 takes time. Line L4 takes . The order of line L5 is a sort of sizes between 0 and , which counting sort does in . One test of line L7 computes slots, and checks that they are free and distinct in time: it puts a temporary mark on each slot, stops at a slot that is used or already marked, and then removes the temporary marks. Line L9 takes . Summing over the buckets gives the claim.
Lemma 4 (expected trials, idealized model). Assume that is fully random, and that for each bucket the slot vectors for are independent, each with independent uniform entries in , and independent of everything that happens before the bucket is placed. Let for a constant , and ignore the cap . Then , where .
Proof. Consider bucket with keys, and let be the number of used slots when it is placed. The buckets not yet placed hold at least the keys of , so . A test succeeds when independent uniform slots are distinct and free, which has probability
since each factor is at least . The tests are independent, so is geometric and . So . For fully random , each is binomial with trials and success probability , and for such a , . Summing over the buckets gives .
For constant and , Lemmas 3 and 4 give expected time for one attempt in the idealized model. An attempt fails only if some bucket needs more than tests, which by Markov's inequality has probability at most , less than once is large enough. Then the expected number of attempts is at most 2, and the expected build time is .
What is a sketch here. Three steps are not proved on this page.
- The idealized model. The real slot vectors for different are built from the same values and , so they are not independent: the indices with the same are cyclic shifts of each other. The analysis of Belazzougui, Botelho and Dietzfelbinger (ESA 2009, LNCS 5757, pages 682 to 693) treats the hash functions as fully random and analyzes the scheme with its own assumptions; we do not reproduce it. The bound of Lemma 4 also grows like and does not use the order of line L5; the paper's analysis of the placement in order of decreasing size gives much better constants.
- The compressed space. The statement that the compressed takes about 2 bits for each key, close to the lower bound for perfect hash functions, is from the same paper (its abstract gives about 1.4 bits for each key for and about 1.98 bits for ), together with the access time of its compressed code.
- The minimal case . Lemma 4 needs . With , the last buckets are placed in a table with very few free slots; a bucket of one key still always fits within tests, by the index for a free slot , but no bound for buckets of two or more keys is proved here.
CHD-BUILD returns a perfect hash function, minimal when m = n, and ends with probability 1 for fully random hash functions full
This proof shows: correctness, termination.
Let be a set of distinct keys, let , and let . For an index write . Then CHD-EVAL, by lines L12 and L13.
Lemma 1 (invariant of the placement loop). Fix one attempt, that is, one pass of lines L2 to L9 with fixed , and . After each bucket that line L9 places, the following holds. Let be the set of buckets placed so far. The slots , for and , are pairwise distinct, and the used slots are exactly these slots.
Proof. By induction on the buckets in the order of line L5. Before the first one, is empty and line L4 marks all slots free. Suppose the claim holds for , and line L9 places bucket with index . The loop of line L7 stopped at (otherwise line L8 would have left the loop), so its condition was false: the slots , , are pairwise distinct and none of them is used. By the hypothesis, the used slots are those of the keys of , so the new slots are also distinct from all of these. Line L9 sets and marks exactly the new slots, so the claim holds for . An empty bucket is placed with and adds no slot.
Theorem 1 (the output is perfect). If CHD-BUILD returns, then CHD-EVAL maps into , is one to one on , and, when , maps onto .
Proof. Each value is reduced mod , so it is in . CHD-BUILD returns only after an attempt in which line L8 never set ok to false, so every bucket was placed. The buckets partition , since each key lies in exactly the bucket . By Lemma 1 with , the slots for are pairwise distinct, and these are the values of CHD-EVAL. So CHD-EVAL is one to one on . If , its distinct values on lie in a set of elements, so they are all of .
Lemma 2 (a sufficient condition). If is one to one on , the attempt succeeds.
Proof. We show that every bucket is placed with , the first index that line L7 tests. For , . When bucket comes, the values for are pairwise distinct. By Lemma 1 the used slots are the values of the keys of the buckets already placed, all different from the keys of , so none of them equals any , . So the condition of line L7 is false at .
Theorem 2 (termination). If each attempt draws uniformly from all functions , independently of the earlier attempts, then CHD-BUILD ends with probability 1, after at most attempts in expectation.
Proof. Each attempt runs at most buckets with at most values of each, so it ends. By Lemma 2, it succeeds when is one to one on , which happens with probability since . The attempts are independent, so the number of attempts is at most a geometric random variable with mean , which is finite.
The bound of Theorem 2 is very weak; it only shows that the restart loop cannot run forever. The expected number of attempts in practice is close to 1, see the complexity proof. For the polynomials of degree 2 of the Python version, Theorem 1 still holds, since it does not depend on how the functions are chosen, but Theorem 2 is not proved.