Algorithm Search⌘K

Proofs: Cuckoo filter

These are the human proofs of Cuckoo filter, at full length.

The false positive rate of a cuckoo filter full

This proof shows: complexity.

Model. Assume ideal hashing: for a key x∉Sx \notin S, the pair (ϕ(x),i1(x))(\phi(x), i_1(x)) is uniform on {1,…,2f−1}×{0,…,m−1}\{1, \ldots, 2^f - 1\} \times \{0, \ldots, m-1\} and independent of the table TT and of the victim, which depend only on the hashes of other keys, on gg and on the random choices of the inserts. Fix TT, the victim and gg. Write q=2f−1q = 2^f - 1.

Theorem. Pr⁡[QUERY(x)=true]≤(b+bˉ+1)/q≤(2b+1)/q\Pr[\text{QUERY}(x) = \text{true}] \le (b + \bar{b} + 1)/q \le (2b+1)/q, where bˉ≤b\bar{b} \le b is the mean number of entries in a bucket.

Proof. QUERY(x)(x) returns true only if ϕ(x)\phi(x) is in T[i1]T[i_1], in T[alt(i1,ϕ(x))]T[\mathrm{alt}(i_1, \phi(x))] or in the victim slot. By the union bound it is enough to bound the three probabilities.

First bucket. Fix i1i_1. The bucket T[i1]T[i_1] holds at most bb fingerprints, so at most bb values of ϕ(x)\phi(x) match one of them. Each has probability 1/q1/q, so the probability is at most b/qb/q.

Second bucket. For a fingerprint value ϕ\phi and a stored entry (j,ψ)(j, \psi), the entry is in bucket alt(i1,ϕ)\mathrm{alt}(i_1, \phi) and matches only if ψ=ϕ\psi = \phi and j=alt(i1,ϕ)j = \mathrm{alt}(i_1, \phi), that is i1=alt(j,ψ)i_1 = \mathrm{alt}(j, \psi) by the involution. So the expected number of matching entries is

∑(j,ψ)Pr⁡[ϕ(x)=ψ]Pr⁡[i1(x)=alt(j,ψ)]=Nqm=bˉq,\sum_{(j, \psi)} \Pr[\phi(x) = \psi] \Pr[i_1(x) = \mathrm{alt}(j, \psi)] = \frac{N}{q m} = \frac{\bar b}{q},

where the sum is over the NN stored entries, and the two events are independent. The probability of at least one match is at most this.

Victim. The victim has one fingerprint, matched with probability at most 1/q1/q. □\square

Fingerprint size. For the rate to be at most ε\varepsilon it suffices that (2b+1)/(2f−1)≤ε(2b+1)/(2^f - 1) \le \varepsilon, which holds for f≥log⁡2((2b+1)/ε+1)f \ge \log_2((2b + 1)/\varepsilon + 1), and for b=4b = 4 this is about log⁡2(1/ε)+3.2\log_2(1/\varepsilon) + 3.2. The paper uses the simpler estimate 2b/2f2b/2^f.

Time. QUERY reads two buckets of bb slots and the victim, so it takes Θ(b)\Theta(b) time in the worst case on the word RAM. DELETE does the same and may run one insert of the victim. An insert takes O(b)O(b) time when line L4 succeeds and O(b⋅MaxKicks)O(b \cdot \text{MaxKicks}) in the worst case. ■\blacksquare

A cuckoo filter has no false negatives full

This proof shows: correctness, invariant, termination.

Let τ(j,ϕ)=(ϕ,{j,alt(j,ϕ)})\tau(j, \phi) = (\phi, \{j, \mathrm{alt}(j, \phi)\}) be the token of a fingerprint ϕ\phi stored in bucket jj or in the victim slot with bucket jj, and τ(x)=(ϕ(x),{i1(x),i2(x)})\tau(x) = (\phi(x), \{i_1(x), i_2(x)\}) the token of a key xx. Let T\mathcal{T} be the multiset of tokens of the stored entries and K\mathcal{K} the multiset of tokens of the copies of keys in SS. Assume that each DELETE(x)(x) is applied only when xx has a copy in SS.

Lemma 1 (alt is an involution). For each ii and ϕ\phi, alt(alt(i,ϕ),ϕ)=i\mathrm{alt}(\mathrm{alt}(i, \phi), \phi) = i, and so τ(alt(j,ϕ),ϕ)=τ(j,ϕ)\tau(\mathrm{alt}(j, \phi), \phi) = \tau(j, \phi). Also τ(i1(x),ϕ(x))=τ(i2(x),ϕ(x))=τ(x)\tau(i_1(x), \phi(x)) = \tau(i_2(x), \phi(x)) = \tau(x).

Proof. With d=g(ϕ) mod md = g(\phi) \bmod m, (i⊕d)⊕d=i(i \oplus d) \oplus d = i. Since mm is a power of two and i,d<mi, d < m, the value i⊕di \oplus d is also below mm. The token of (alt(j,ϕ),ϕ)(\mathrm{alt}(j, \phi), \phi) has the set {alt(j,ϕ),j}\{\mathrm{alt}(j, \phi), j\}, the same as for (j,ϕ)(j, \phi). For a key, i2(x)=alt(i1(x),ϕ(x))i_2(x) = \mathrm{alt}(i_1(x), \phi(x)) by definition. □\square

Lemma 2 (invariant (T)). After each operation, T=K\mathcal{T} = \mathcal{K}.

Proof. By induction. Line L1 makes both empty. A QUERY changes nothing.

INSERT(x)(x) that returns false at line L2 changes nothing.

INSERT(x)(x) otherwise. K\mathcal{K} gains τ(x)\tau(x). Call the fingerprint in hand, with the bucket ii that it is meant for, the carried entry. At line L3 the carried entry is (i1(x),ϕ(x))(i_1(x), \phi(x)), whose token is τ(x)\tau(x) by Lemma 1. We claim that, during the insert, the stored entries together with the carried entry have token multiset Told+{τ(x)}\mathcal{T}_{\text{old}} + \{\tau(x)\}. Line L4 or L9 stores the carried entry at ii or alt(i,ϕ)\mathrm{alt}(i, \phi), which keeps its token by Lemma 1. Line L5 changes ii to ii or alt(i,ϕ)\mathrm{alt}(i, \phi), which keeps the token. Line L7 swaps the carried entry with a stored entry (i,ψ)(i, \psi) of T[i]T[i]: the stored part now has (i,ϕ)(i, \phi) and the carried entry is (i,ψ)(i, \psi). The carried entry before the swap had token τ(i,ϕ)\tau(i, \phi), which is now stored, and the stored entry τ(i,ψ)\tau(i, \psi) is now carried, so the multiset is unchanged. Line L8 changes ii to alt(i,ψ)\mathrm{alt}(i, \psi), which keeps the token. Line L10 stores the carried entry in the victim slot with its bucket. So at the end T=Told+{τ(x)}=K\mathcal{T} = \mathcal{T}_{\text{old}} + \{\tau(x)\} = \mathcal{K}. Line L10 is reached only when the victim slot is empty, because line L2 returned otherwise, so no victim is overwritten.

DELETE(x)(x). K\mathcal{K} loses one copy of τ(x)\tau(x). If line L14 removes ϕ(x)\phi(x) from T[i1(x)]T[i_1(x)] or T[i2(x)]T[i_2(x)], the removed token is τ(x)\tau(x) by Lemma 1. Line L15 then empties the victim slot and runs lines L4 to L10 on its entry, which keeps the token multiset by the argument for INSERT; the victim slot is empty when line L10 can run, so it is not overwritten. If line L16 clears a victim (j,ϕ(x))(j, \phi(x)) with j∈{i1(x),i2(x)}j \in \{i_1(x), i_2(x)\}, its token is τ(x)\tau(x) by Lemma 1. In each case T\mathcal{T} loses one copy of τ(x)\tau(x). Line L17 is not reached: τ(x)∈K=T\tau(x) \in \mathcal{K} = \mathcal{T}, so some entry has token τ(x)\tau(x). Its fingerprint is ϕ(x)\phi(x) and its bucket jj satisfies {j,alt(j,ϕ(x))}={i1(x),i2(x)}\{j, \mathrm{alt}(j, \phi(x))\} = \{i_1(x), i_2(x)\}, so j∈{i1(x),i2(x)}j \in \{i_1(x), i_2(x)\}, and line L14 or L16 finds it. □\square

Theorem. After any sequence of operations that respects the precondition of DELETE, QUERY(x)(x) returns true for each xx with a copy in SS, and each operation ends.

Proof. If xx has a copy in SS, then τ(x)∈K=T\tau(x) \in \mathcal{K} = \mathcal{T} by Lemma 2. As at the end of the proof of Lemma 2, the entry with this token has fingerprint ϕ(x)\phi(x) and bucket i1(x)i_1(x) or i2(x)i_2(x), in the table or in the victim slot. Line L12 checks exactly these places, so it returns true. Each loop of INSERT runs at most MaxKicks rounds, and DELETE runs at most one such insert, so each operation ends. ■\blacksquare

Back to Cuckoo filter