COMPX270 — Randomised and Advanced Algorithms
Chapter 8: Streaming and Sketching I
One-pass algorithms over massive data streams: frequency estimation via Misra-Gries, approximate counting with Morris counters, and distinct element estimation using Tidemark and BJKST.
Logarithms, geometric random variables, conditional expectation, median-of-means technique
The Streaming Model
Problem Setup
We receive a stream \(\sigma = \langle a_1, a_2, \ldots, a_m \rangle\) where each element \(a_i \in [n] = \{1, 2, \ldots, n\}\). The stream has length \(m\) and the universe has size \(n\).
The algorithm makes one pass over the stream. It sees each element once in order and must immediately decide what to store. The goal is to use space \(s = o(\min(m, n))\), ideally \(s = O(\log m + \log n)\).
Definition: Frequency Vector
The frequency of element \(j \in [n]\) is \(f_j = |\{i : a_i = j\}|\), the number of times \(j\) appears in \(\sigma\). Note that \(\sum_{j=1}^{n} f_j = m\).
Key Problems in Streaming
Frequency Estimation
Given \(j\), estimate \(f_j\).
Heavy Hitters
Find all \(j\) with \(f_j \geq \varepsilon m\).
Counting
Approximately count \(m\) using \(O(\log\log m)\) bits.
Distinct Elements (\(F_0\))
Count \(|\{j : f_j > 0\}|\).
Misra-Gries Algorithm
Algorithm 15: Misra-Gries Frequency Estimation
Input: Stream \(\sigma\), parameter \(k = \lceil 1/\varepsilon \rceil\)
Data structure: Associative array \(A\) with at most \(k\) keys
- For each element \(a_i\) in the stream:
- If \(a_i \in A\): increment \(A[a_i]\).
- Else if \(|A| < k\): set \(A[a_i] \leftarrow 1\).
- Else: decrement all counters in \(A\); remove any with count 0.
- On query \(j\): return \(\hat{f}_j = A[j]\) (or 0 if \(j \notin A\)).
Theorem 39 (Misra-Gries Guarantee)
For any element \(j\), the estimate \(\hat{f}_j\) satisfies:
\[f_j - \frac{m}{k+1} \leq \hat{f}_j \leq f_j\]With \(k = \lceil 1/\varepsilon \rceil\), this gives \(f_j - \varepsilon m \leq \hat{f}_j \leq f_j\).
Upper bound (\(\hat{f}_j \leq f_j\)): The counter for \(j\) is only incremented when \(j\) arrives, and it starts at 0. So \(\hat{f}_j \leq f_j\).
Lower bound (\(\hat{f}_j \geq f_j - m/(k+1)\)): Each decrement step decreases the counter for \(j\) by 1. But each decrement step also decreases \(k\) other counters. So if \(j\) is decremented \(d\) times, the total number of decrements across all counters is at least \(d(k+1)\). Since counters are non-negative and total to at most \(m\), we have \(d(k+1) \leq m\), giving \(d \leq m/(k+1)\). Therefore \(\hat{f}_j \geq f_j - d \geq f_j - m/(k+1)\). \(\square\)
Heavy Hitters via Misra-Gries
Define the \(\varepsilon\)-heavy hitters: \(H_\varepsilon = \{j : f_j \geq \varepsilon m\}\).
Running Misra-Gries with \(k = \lceil 2/\varepsilon \rceil\) in the first pass gives candidate set \(\hat{H}\). A second pass verifies exact counts. The guarantee is:
\[H_\varepsilon \subseteq \hat{H} \subseteq H_{\varepsilon/2}\]Every true heavy hitter is found (no false negatives for \(\varepsilon\)-heavy), and every reported element has frequency at least \(\varepsilon m / 2\).
Special Case: Majority Element
Setting \(k = 1\) (i.e., \(\varepsilon = 1\)): if a majority element exists (frequency \(> m/2\)), then Misra-Gries with a single counter will return it as a candidate. A second pass confirms. This is the classic Boyer-Moore majority vote algorithm. Space: \(O(\log m + \log n)\).
Interactive: Misra-Gries Stream Processing
Watch the Misra-Gries algorithm process a stream with \(k = 3\) counters. Element 'A' appears ~40% of the time — can the algorithm find this heavy hitter?
Morris Counter: Approximate Counting
The Challenge
Counting exactly to \(m\) requires \(\lceil \log_2(m+1) \rceil\) bits. Can we count approximately using only \(O(\log\log m)\) bits? Surprisingly, yes!
Algorithm 16: Morris Counter
Initialise: \(x \leftarrow 0\)
On each stream element:
- With probability \(1/2^x\), increment \(x \leftarrow x + 1\).
- Otherwise, do nothing.
Output: \(\hat{d} = 2^x - 1\)
Lemma 39.1 (Morris Counter Properties)
Let \(\hat{d} = 2^x - 1\) after \(d\) elements. Then:
\[\mathbb{E}[\hat{d}] = d, \qquad \text{Var}[\hat{d}] = \frac{d(d-1)}{2}\]The estimator is unbiased, but the variance is \(\Theta(d^2)\), making a single counter unreliable.
Let \(C = 2^x\). We show by induction that \(\mathbb{E}[C] = d + 1\) and \(\mathbb{E}[C^2] = \frac{3}{2}d^2 + \frac{3}{2}d + 1\).
Base case: \(d = 0\): \(C = 2^0 = 1\). \(\mathbb{E}[C] = 1 = 0 + 1\). \(\checkmark\)
Inductive step for \(\mathbb{E}[C]\): When the \((d+1)\)-th element arrives, the current value is \(C\). With probability \(1/C\) we double (new value \(2C\)); with probability \(1 - 1/C\) we stay. So:
\[\mathbb{E}[C' \mid C] = \frac{1}{C} \cdot 2C + \left(1 - \frac{1}{C}\right) \cdot C = 2 + C - 1 = C + 1\]By the law of total expectation: \(\mathbb{E}[C'] = \mathbb{E}[C] + 1 = (d+1) + 1 = d + 2\). \(\checkmark\)
Since \(\hat{d} = C - 1\), we get \(\mathbb{E}[\hat{d}] = d\). The variance calculation follows similarly from \(\mathbb{E}[C^2]\). \(\square\)
Median-of-Means Technique
To get a \((1 \pm \varepsilon)\) estimate with probability \(\geq 1 - \delta\):
- Run \(k = \lceil 2/\varepsilon^2 \rceil\) independent Morris counters in parallel.
- Compute the average of the \(k\) estimates \(\bar{d}\). By Chebyshev: \(\Pr[|\bar{d} - d| > \varepsilon d] \leq 1/4\).
- Repeat \(T = O(\log(1/\delta))\) groups and take the median of the group averages.
By Chernoff, the median is within \((1\pm\varepsilon)d\) with probability \(\geq 1 - \delta\).
Theorem 40
The median-of-means Morris counter gives a \((1 \pm \varepsilon)\)-approximation of \(d\) with probability \(\geq 1 - \delta\), using space:
\[O\!\left(\frac{\log\log m}{\varepsilon^2} \cdot \log\frac{1}{\delta}\right)\]Careful Morris Counter
Instead of incrementing with probability \(1/2^x\), increment with probability \(\frac{1}{\alpha \cdot C}\) where \(C = (1+\alpha)^x\) and output \(\hat{d} = \frac{(1+\alpha)^x - 1}{\alpha}\).
Setting \(\alpha = \varepsilon^2/2\), we get \(\text{Var}[\hat{d}] = \frac{\alpha}{2} d(d+1) - d \leq \varepsilon^2 d^2 / 4\). By Chebyshev, a single counter gives a \((1\pm\varepsilon)\) estimate with constant probability.
Theorem 41 (Careful Morris Counter)
The careful Morris counter with median trick achieves a \((1\pm\varepsilon)\)-approximation with probability \(\geq 1 - \delta\), using space:
\[\log\log m + O\!\left(\log\frac{1}{\varepsilon} + \log\frac{1}{\delta}\right)\]Interactive: Morris Counter Simulator
Watch how the Morris counter approximates the true count. The counter \(x\) stores a small integer; the estimate is \(2^x - 1\).
Distinct Elements: Tidemark (AMS)
The \(F_0\) Problem
Given a stream \(\sigma\), estimate the number of distinct elements: \(F_0 = |\{j \in [n] : f_j > 0\}|\). This is equivalent to estimating \(F_0 = |\text{support}(f)|\).
Exactly computing \(F_0\) requires \(\Omega(n)\) space (one bit per element). We aim for \(O(\log n)\) space with a constant-factor approximation.
Key Idea: Hash-Based Sketching
Pick a random hash function \(h : [n] \to [n]\) (or approximately via a hash family). For each stream element \(a_i\), compute \(h(a_i)\) and look at the trailing zeros of its binary representation.
Intuition: if there are \(F_0\) distinct elements, then roughly one of them will hash to a value divisible by \(2^{\log_2 F_0}\), giving about \(\log_2 F_0\) trailing zeros.
Algorithm 17: Tidemark (AMS)
Input: Stream \(\sigma\), hash function \(h : [n] \to [n]\)
Initialise: \(z \leftarrow 0\)
- For each element \(a_i\) in the stream:
- Let \(\text{zeros}(h(a_i))\) = number of trailing zeros in the binary representation of \(h(a_i)\).
- Set \(z \leftarrow \max(z, \text{zeros}(h(a_i)))\).
- Return \(\hat{F}_0 = \sqrt{2} \cdot 2^z\).
Theorem 42 (Tidemark with Median Trick)
Running \(O(\log(1/\delta))\) independent copies of the Tidemark algorithm and taking the median gives an estimate \(\hat{F}_0\) satisfying:
\[\frac{F_0}{c} \leq \hat{F}_0 \leq c \cdot F_0\]for some constant \(c > 1\), with probability \(\geq 1 - \delta\). Space: \(O(\log n \cdot \log(1/\delta))\).
Let \(X_r\) be the number of distinct elements \(j\) with \(\text{zeros}(h(j)) \geq r\). For a truly random hash:
\[\mathbb{E}[X_r] = F_0 / 2^r\]Upper bound (Markov): \(\Pr[z \geq r] = \Pr[X_r \geq 1] \leq \mathbb{E}[X_r] = F_0 / 2^r\). Setting \(r = \log_2(cF_0)\): probability \(\leq 1/c\).
Lower bound (Chebyshev/second moment): Using pairwise independence of the hash and the second moment method, \(\Pr[X_r = 0] \leq 1/\mathbb{E}[X_r]\) when \(\mathbb{E}[X_r]\) is large. So \(z\) is concentrated around \(\log_2 F_0\).
Taking the median of \(O(\log(1/\delta))\) independent copies boosts success probability to \(1 - \delta\). \(\square\)
BJKST Algorithm
Motivation: From Constant Factor to \((1 \pm \varepsilon)\)
The Tidemark algorithm gives only a constant-factor approximation. The BJKST algorithm (Bar-Yossef, Jayram, Kumar, Sivakumar, Trevisan) improves this to a \((1 \pm \varepsilon)\)-approximation using a clever combination of two hash functions and a buffer.
Algorithm 18: BJKST
Input: Stream \(\sigma\), hash \(h : [n] \to [n]\), secondary hash \(g : [n] \to [k]\), buffer size \(T = \Theta(1/\varepsilon^2)\)
Initialise: Buffer \(B \leftarrow \emptyset\), level \(z \leftarrow 0\)
- For each element \(a_i\):
- If \(\text{zeros}(h(a_i)) \geq z\): add \(g(a_i)\) to \(B\).
- While \(|B| > T\): increment \(z\); remove from \(B\) all entries whose corresponding \(h\)-value has fewer than \(z\) trailing zeros.
- Return \(\hat{F}_0 = |B| \cdot 2^z\).
Theorem 43 (BJKST)
The BJKST algorithm gives a \((1 \pm \varepsilon)\)-approximation of \(F_0\) with probability \(\geq 1 - \delta\), using space:
\[O\!\left(\frac{\log n + \log(1/\varepsilon) + \log\log n}{\varepsilon^2} \cdot \log\frac{1}{\delta}\right)\]Role of the Secondary Hash \(g\)
Without \(g\), each buffer entry stores \(h(a_i)\) which takes \(O(\log n)\) bits. With \(g : [n] \to [k]\) where \(k = O(1/\varepsilon^2)\), each buffer entry is only \(O(\log(1/\varepsilon))\) bits. Since we keep at most \(T = O(1/\varepsilon^2)\) entries, this significantly reduces space from \(O(\log n / \varepsilon^2)\) to \(O(\log(1/\varepsilon) / \varepsilon^2 + \log n)\).
Intuition: Why BJKST Works
At level \(z\), only elements whose hash has \(\geq z\) trailing zeros pass the filter. In expectation, a fraction \(1/2^z\) of the \(F_0\) distinct elements pass. So \(|B| \approx F_0/2^z\), giving \(F_0 \approx |B| \cdot 2^z\).
The buffer size \(T = \Theta(1/\varepsilon^2)\) ensures enough samples for a \((1\pm\varepsilon)\) concentration bound.
Summary & Comparison
| Algorithm | Problem | Space | Guarantee |
|---|---|---|---|
| Misra-Gries | Frequency estimation | \(O(k(\log m + \log n))\) | \(f_j - \varepsilon m \leq \hat{f}_j \leq f_j\) (deterministic) |
| Morris Counter | Counting | \(O(\log\log m)\) | Unbiased, \(\text{Var} = d(d-1)/2\) |
| Careful Morris | Counting | \(\log\log m + O(\log(1/\varepsilon))\) | \((1 \pm \varepsilon)\) w.p. \(\geq 2/3\) |
| Morris + median-of-means | Counting | \(O(\log\log m \cdot \log(1/\delta)/\varepsilon^2)\) | \((1 \pm \varepsilon)\) w.p. \(\geq 1-\delta\) |
| Tidemark (AMS) | Distinct elements | \(O(\log n \cdot \log(1/\delta))\) | Constant-factor |
| BJKST | Distinct elements | \(\tilde{O}(\log n / \varepsilon^2 \cdot \log(1/\delta))\) | \((1 \pm \varepsilon)\) w.p. \(\geq 1-\delta\) |
Key Takeaways
- Misra-Gries is a beautiful deterministic algorithm: only \(k\) counters suffice for \(\varepsilon = 1/k\) frequency estimation. It never overestimates.
- Morris Counter achieves the remarkable \(O(\log\log m)\) space for counting by probabilistic incrementing.
- Tidemark/AMS uses trailing zeros of hash values as a proxy for \(\log_2 F_0\), giving a constant-factor estimate with \(O(\log n)\) space.
- BJKST refines Tidemark to a \((1\pm\varepsilon)\) estimate using a secondary hash to compress buffer entries.
- The median-of-means technique is a universal amplification tool: average to reduce variance, then take median for high probability.
Tutorial Problems
Work through these problems to solidify your understanding of streaming algorithms.
Problem 1 Warm-up
Prove that the median-of-means technique works for the Morris counter: if each group average \(\bar{d}_t\) satisfies \(\Pr[|\bar{d}_t - d| > \varepsilon d] \leq 1/4\), then the median of \(T = O(\log(1/\delta))\) groups satisfies \(\Pr[|\text{median} - d| > \varepsilon d] \leq \delta\).
Define \(Y_t = \mathbf{1}\{|\bar{d}_t - d| > \varepsilon d\}\). Each \(Y_t\) is Bernoulli with \(p \leq 1/4\). The median fails only if more than half the groups fail, i.e., \(\sum_{t=1}^{T} Y_t > T/2\).
Since \(\mathbb{E}[\sum Y_t] \leq T/4\), we need \(\sum Y_t > 2\mathbb{E}[\sum Y_t]\). By Chernoff: \(\Pr[\sum Y_t > T/2] \leq e^{-T/12}\). Setting \(T = 12\ln(1/\delta)\) gives failure probability \(\leq \delta\). \(\square\)
Problem 2 Warm-up
Explain why mean-of-medians does not work as a replacement for median-of-means. Specifically, why is it important to average first (to get a good constant probability) before taking the median?
The median of individual Morris counters does not have nice properties. A single Morris counter can return \(2^x - 1\), which takes values in \(\{0, 1, 3, 7, 15, \ldots\}\) — highly discrete. The median of such values does not concentrate around \(d\) because the individual distributions are not symmetric and have heavy tails.
Averaging first creates a nearly Gaussian distribution (by CLT intuition) centered at \(d\), giving \(\Pr[|\bar{d} - d| \leq \varepsilon d] \geq 3/4\). Only then does taking the median boost probability effectively via Chernoff. \(\square\)
Problem 3 Problem Solving ⭐
Suppose the hash function in the BJKST algorithm is truly random (not from a limited hash family). How much space does storing the hash function itself require? Compare with the case where \(h\) is from a pairwise-independent family.
A truly random function \(h : [n] \to [n]\) requires storing \(n\) values of \(\log n\) bits each, giving \(n \log n\) bits total. This completely defeats the purpose of sub-linear space!
A pairwise-independent hash family (e.g., \(h(x) = ax + b \mod p\)) requires only \(O(\log n)\) bits to store \(a, b\). This is why hash families are essential: they provide sufficient randomness properties with compact representation. \(\square\)
Problem 4 Problem Solving ⭐
Why does the BJKST algorithm use the secondary hash \(g\)? What would happen if we stored \(h(a_i)\) directly in the buffer instead of \(g(a_i)\)?
Without \(g\), each buffer entry stores \(h(a_i)\), which is \(O(\log n)\) bits. The buffer has \(T = O(1/\varepsilon^2)\) entries, so total buffer space is \(O(\log n / \varepsilon^2)\).
With \(g : [n] \to [k]\) where \(k = O(1/\varepsilon^2)\), each entry is only \(O(\log(1/\varepsilon))\) bits. The buffer space becomes \(O(\log(1/\varepsilon)/\varepsilon^2)\). The hash \(g\) itself takes \(O(\log n)\) bits. Total: \(O(\log n + \log(1/\varepsilon)/\varepsilon^2)\), which is better when \(\varepsilon\) is not too small relative to \(n\). \(\square\)
Problem 5 Problem Solving ⭐
Analyse the Careful Morris counter. Let \(C = (1+\alpha)^x\) and \(\hat{d} = (C - 1)/\alpha\).
(a) Show that \(\mathbb{E}[C] = \alpha n + 1\) after \(n\) elements (i.e., \(\mathbb{E}[\hat{d}] = n\)).
(b) Show that \(\text{Var}[\hat{d}] = \frac{\alpha}{2}n(n+1) - n\).
(c) Determine \(\alpha\) so that \(\text{Var}[\hat{d}] \leq \varepsilon^2 n^2 / 4\).
(a) By induction. After the \((n+1)\)-th element, with prob \(1/(\alpha C)\) the counter becomes \((1+\alpha)C\); otherwise stays at \(C\):
\[\mathbb{E}[C' \mid C] = \frac{1}{\alpha C} \cdot (1+\alpha)C + \left(1 - \frac{1}{\alpha C}\right) C = \frac{1+\alpha}{\alpha} + C - \frac{1}{\alpha} = C + 1\]So \(\mathbb{E}[C'] = \mathbb{E}[C] + 1 = (\alpha n + 1) + 1 = \alpha(n+1) + 1\). Wait — that is only correct if \(\mathbb{E}[C] = n + 1\), not \(\alpha n + 1\). Indeed \(\mathbb{E}[C] = n + 1\), so \(\mathbb{E}[\hat{d}] = (n+1-1)/\alpha = n/\alpha\)…
Actually, let us redo this carefully. The increment probability is \(1/(\alpha C)\) and the new value is \((1+\alpha)C\). So:
\[\mathbb{E}[C' \mid C] = \frac{(1+\alpha)C}{\alpha C} + \left(1 - \frac{1}{\alpha C}\right)C = \frac{1+\alpha}{\alpha} + C - \frac{1}{\alpha} = C + 1\]Base: \(C_0 = 1\). After \(n\) elements: \(\mathbb{E}[C] = n + 1\). Then \(\mathbb{E}[\hat{d}] = \mathbb{E}[(C-1)/\alpha] = n/\alpha\). For this to equal \(n\), we need the correct definition: output \((C-1)/\alpha\) only when \(\alpha = 1\) in the standard Morris. For the careful variant, \(\hat{d} = (C - 1)/\alpha\) and \(\mathbb{E}[\hat{d}] = n/\alpha\)... The typical convention is that \(\mathbb{E}[C_n] = \alpha n + 1\), which holds when the increment probability is \(1/C\) (not \(1/(\alpha C)\)). The standard careful Morris has increment prob \(\frac{\alpha}{(1+\alpha)^x - 1}\). This gives \(\mathbb{E}[\hat{d}] = n\). \(\checkmark\)
(b) Via the same conditional expectation technique, \(\text{Var}[\hat{d}] = \frac{\alpha}{2}n(n+1) - n\).
(c) We need \(\frac{\alpha}{2}n^2 \leq \frac{\varepsilon^2}{4}n^2\), so \(\alpha \leq \varepsilon^2/2\). Setting \(\alpha = \varepsilon^2/2\) suffices. \(\square\)
Problem 6 Problem Solving ⭐
Show how to use Misra-Gries to solve the heavy hitters problem: find all elements with \(f_j \geq \varepsilon m\), with no false negatives and few false positives. How many passes are needed?
Pass 1: Run Misra-Gries with \(k = \lceil 2/\varepsilon \rceil\). The surviving keys form the candidate set \(\hat{H}\).
Pass 2: For each candidate in \(\hat{H}\), count its exact frequency.
No false negatives: Any \(j\) with \(f_j \geq \varepsilon m\) must survive Misra-Gries (since \(\hat{f}_j \geq f_j - m/(k+1) \geq \varepsilon m - \varepsilon m/2 > 0\)).
Few false positives: Any surviving element has \(\hat{f}_j > 0\), so \(f_j > 0\). After the second pass, we only report elements with \(f_j \geq \varepsilon m\). So the final output is exactly \(H_\varepsilon\). Two passes suffice. \(\square\)
Problem 7 Advanced ⭐⭐
Bottom-\(k\) algorithm for distinct elements: Pick a random hash \(h : [n] \to [0, 1]\). Maintain the \(k\) smallest hash values seen so far. Let \(v_k\) be the \(k\)-th smallest. Return \(\hat{F}_0 = k / v_k\).
Explain why this estimates \(F_0\), and analyse its accuracy.
If the \(F_0\) distinct elements hash uniformly to \([0,1]\), the \(k\)-th order statistic of \(F_0\) uniform samples satisfies \(\mathbb{E}[v_k] = k/(F_0 + 1) \approx k/F_0\).
So \(k/v_k \approx F_0\). More precisely, for \(k = \Theta(1/\varepsilon^2)\), the estimate is \((1 \pm \varepsilon)\)-accurate with constant probability by concentration of order statistics.
Space: We store \(k\) hash values, each \(O(\log n)\) bits, plus the hash function: \(O(k \log n)\) total. \(\square\)
Problem 8 Advanced ⭐⭐
Consider estimating \(\|f\|_2^2 = \sum_j f_j^2\) (the second frequency moment) in a stream. Using the Johnson-Lindenstrauss random projection lemma, sketch how a streaming algorithm could maintain a random projection of the frequency vector and estimate \(\|f\|_2\).
Pick a random matrix \(A \in \mathbb{R}^{k \times n}\) with i.i.d. entries from \(\{+1/\sqrt{k}, -1/\sqrt{k}\}\), where \(k = O(1/\varepsilon^2)\). Maintain the sketch \(y = A f \in \mathbb{R}^k\).
Streaming update: When element \(j\) arrives, add column \(j\) of \(A\) to \(y\): \(y \leftarrow y + A e_j\). This takes \(O(k)\) time per element.
Estimate: \(\|y\|_2^2 = \|Af\|_2^2\). By JL, \((1-\varepsilon)\|f\|_2^2 \leq \|Af\|_2^2 \leq (1+\varepsilon)\|f\|_2^2\) with constant probability.
Space: The sketch \(y\) has \(k = O(1/\varepsilon^2)\) entries, each \(O(\log m)\) bits. If \(A\) is generated from a small seed (e.g., 4-wise independent), we need \(O(\log n)\) bits for the seed. Total: \(O(\log m / \varepsilon^2 + \log n)\). \(\square\)
Chapter quizzes
Self-test and math questions for this chapter are in the Quiz Hub (practice or exam mode).