4.1. Updates and Queries
Cslib.DataStructure.CountMin.Table d w is a vector of d rows, each with w
natural-number counters. A hash bank h : Fin d → X → Fin w selects one bucket per row for each
item. An update adds its weight to those buckets. Cslib.DataStructure.CountMin.run folds
the update function over the stream,
starting from zero. A query takes the minimum of its addressed counters, so queries require
at least one row.
Here two rows hash the low and high bits of four possible items. Item 3 is absent from the
stream, and the other three items have different weights.
def exampleHash (r : Fin 2) (x : Fin 4) : Fin 2 :=
if r = 0 then ⟨x.val % 2, Nat.mod_lt _ (r:Fin 2x:Fin 4⊢ 0 < 2 All goals completed! 🐙)⟩
else ⟨x.val / 2, r:Fin 2x:Fin 4⊢ ↑x / 2 < 2 All goals completed! 🐙⟩
def exampleStream : List (Fin 4 × ℕ) := [(0, 2), (1, 3), (2, 5)]
example : (run exampleHash exampleStream).toList.map Vector.toList =
[[7, 3], [5, 5]] := ⊢ List.map Vector.toList (Vector.toList (run exampleHash exampleStream)) = [[7, 3], [5, 5]]
All goals completed! 🐙
example : List.ofFn (fun x : Fin 4 =>
estimate exampleHash (run exampleHash exampleStream) x) =
[5, 3, 5, 3] := ⊢ (List.ofFn fun x => estimate exampleHash (run exampleHash exampleStream) x) = [5, 3, 5, 3]
All goals completed! 🐙
The true frequencies are 2, 3, 5, 0. Collisions increase the estimates for items 0 and 3.
An absent item can therefore have a positive estimate. The deterministic guarantee is
Cslib.DataStructure.CountMin.frequency_le_estimate_run:
example (x : Fin 4) : frequency exampleStream x ≤
estimate exampleHash (run exampleHash exampleStream) x :=
frequency_le_estimate_run exampleHash exampleStream x