Salta al contenuto
Note per Studenti Esercizio - Contatore di Morris - distribuzione esatta, varianza e numero di contatori

Esercizio - Contatore di Morris - distribuzione esatta, varianza e numero di contatori

Teoria: Algoritmi di streaming - campionamento di riserva e conteggio degli elementi distintiModello a flusso (un passaggio, memoria molto minore di n); campionamento di riserva (reservoir sampling) con dimostrazione per induzione; contatore di Morris (stima non distorta 2^X-1, varianza n(n-1)/2); elementi distinti: idea di Flajolet-Martin e stima del k-esimo minimo (k-1)/v_k; Count-Min sketch con garanzia (epsilon, delta) e dimensionamento w=e/epsilon, d=ln(1/delta).Algoritmi di streaming - campionamento di riserva e conteggio degli elementi distinti → (contatore di Morris), Momenti e deviazioni - Markov, Chebyshev e mediana randomizzataVar(ΣX_i) = ΣVar + 2ΣCov, e basta l'indipendenza a coppie perché la varianza si sommi. Chebyshev dà code polinomiali (collezionista: P(T ≥ nH_n + cn) ≤ π²/(6c²)); il metodo del secondo momento dà P(X=0) ≤ Var(X)/E[X]². Algoritmo della mediana: campione di n^(3/4) elementi, due estremi d e u a ±√n, ordinamento dei soli elementi tra d e u; fallisce con probabilità ≤ n^(-1/4) ed è Las Vegas con 2n + o(n) confronti.Momenti e deviazioni - Markov, Chebyshev e mediana randomizzata → (Chebyshev).

Testo. Il contatore di Morris tiene un intero XX, inizialmente 00; a ogni evento incrementa XX con probabilità 2−X2^{-X}; la stima è n~=2X−1\tilde n=2^X-1.

  1. Calcolare la distribuzione esatta di XX dopo n=3n=3 e n=4n=4 eventi. Verificare E[n~]=nE[\tilde n]=n e Var(n~)=n(n−1)2\text{Var}(\tilde n)=\frac{n(n-1)}2.
  2. Dimostrare entrambe le formule per ogni nn.
  3. Con n=1000n=1000 la deviazione standard è circa 707707. Quanti contatori indipendenti, mediati, servono perché l'errore relativo sia ≤10%\le10\% con probabilità ≥90%\ge90\% (Chebyshev)? Verificare con una simulazione.
  4. Variante con base 1+a1+a: incremento con probabilità (1+a)−X(1+a)^{-X}, stima (1+a)X−1a\frac{(1+a)^X-1}a, Var=a n(n−1)2\text{Var}=\frac{a\,n(n-1)}2. Che aa garantisce, con un solo contatore, errore ≤10%\le10\% con probabilità ≥90%\ge90\%? Quanti bit servono per contare fino a 10610^6, contro il conteggio esatto?

Soluzione

1. Distribuzioni esatte. Se X=xX=x l'incremento ha probabilità 2−x2^{-x}. Dopo 11 evento X=1X=1 con probabilità 11 (da X=0X=0 si incrementa con probabilità 20=12^0=1).

  • n=2n=2: da X=1X=1: X=2X=2 con 12\frac12, X=1X=1 con 12\frac12.
  • n=3n=3: da X=1X=1 (peso 12\frac12): sale a 22 con 12\frac12 e resta con 12\frac12; da X=2X=2 (peso 12\frac12): sale a 33 con 14\frac14 e resta con 34\frac34. Quindi P(X=1)=14P(X=1)=\frac14, P(X=2)=14+38=58P(X=2)=\frac14+\frac38=\frac58, P(X=3)=18P(X=3)=\frac18. Stime 2X−1=1,3,72^X-1=1,3,7: E=14+158+78=3E=\frac14+\frac{15}8+\frac78=3; E[n~2]=14+458+498=12E[\tilde n^2]=\frac14+\frac{45}8+\frac{49}8=12, Var=12−9=3=3⋅22\text{Var}=12-9=3=\frac{3\cdot2}2.
  • n=4n=4: P(X=1)=18P(X=1)=\frac18, P(X=2)=1932P(X=2)=\frac{19}{32}, P(X=3)=1764P(X=3)=\frac{17}{64}, P(X=4)=164P(X=4)=\frac1{64} (si ottengono dalla distribuzione di n=3n=3: X=1X=1 resta con 12\frac12, X=2X=2 viene da 14⋅12+58⋅34=1932\frac14\cdot\frac12+\frac58\cdot\frac34=\frac{19}{32}, ecc.). Stime 1,3,7,151,3,7,15: E=18+5732+11964+1564=4E=\frac18+\frac{57}{32}+\frac{119}{64}+\frac{15}{64}=4; Var=n(n−1)2=6\text{Var}=\frac{n(n-1)}2=6 (verificato con frazioni esatte per n=1,…,30n=1,\dots,30).

2. Dimostrazione. Sia Zn=2XnZ_n=2^{X_n}. Dato Xn=xX_n=x: E[Zn+1∣Xn=x]=2x+1⋅2−x+2x(1−2−x)=2+2x−1=Zn+1,E[Z_{n+1}\mid X_n=x]=2^{x+1}\cdot2^{-x}+2^x(1-2^{-x})=2+2^x-1=Z_n+1, E[Zn+12∣Xn=x]=4x+1⋅2−x+4x(1−2−x)=4⋅2x+4x−2x=Zn2+3Zn.E[Z_{n+1}^2\mid X_n=x]=4^{x+1}\cdot2^{-x}+4^x(1-2^{-x})=4\cdot2^x+4^x-2^x=Z_n^2+3Z_n. Quindi E[Zn+1]=E[Zn]+1E[Z_{n+1}]=E[Z_n]+1 e, con Z0=1Z_0=1, E[Zn]=n+1E[Z_n]=n+1: E[n~]=nE[\tilde n]=n. Inoltre E[Zn+12]=E[Zn2]+3(n+1)E[Z_{n+1}^2]=E[Z_n^2]+3(n+1), da cui E[Zn2]=1+3∑i=1ni=1+3n(n+1)2E[Z_n^2]=1+3\sum_{i=1}^ni=1+\frac{3n(n+1)}2 e Var(Zn)=1+3n(n+1)2−(n+1)2=n2−n2\text{Var}(Z_n)=1+\frac{3n(n+1)}2-(n+1)^2=\frac{n^2-n}2. Controllo con n=3n=3: 1+18−16=31+18-16=3 ✓.

3. Numero di contatori. La media di ss contatori indipendenti ha varianza n(n−1)2s\frac{n(n-1)}{2s}. Chebyshev: P(∣nˉ−n∣≥0,1n)≤n(n−1)/(2s)0,01n2<10,02s≤0,1  ⟺  s≥500.P(|\bar n-n|\ge0{,}1n)\le\frac{n(n-1)/(2s)}{0{,}01n^2}<\frac1{0{,}02s}\le0{,}1\iff s\ge\boxed{500}. Simulazione (n=1000n=1000). Un solo contatore (50005000 prove): media 989989, deviazione standard 679679 (teoria 707707; la media ha errore standard ≈10\approx10). Media di 500500 contatori (100100 prove): media 1001,81001{,}8, deviazione standard 30,930{,}9 (teoria 31,631{,}6), e l'errore supera il 10%10\% in 11 prova su 100100: ben sotto il 10%10\% massimo garantito da Chebyshev, che è un limite largo.

4. Base 1+a1+a. Per un solo contatore, Chebyshev: P(∣n~−n∣≥εn)≤a n(n−1)/2ε2n2<a2ε2P(|\tilde n-n|\ge\varepsilon n)\le\frac{a\,n(n-1)/2}{\varepsilon^2n^2}<\frac a{2\varepsilon^2}. Si impone ≤δ\le\delta: a=2ε2δ=2⋅0,01⋅0,1=0,002a=2\varepsilon^2\delta=2\cdot0{,}01\cdot0{,}1=\boxed{0{,}002}. Il contatore arriva a X≈log⁡1+a(a n)X\approx\log_{1+a}(a\,n): per n=106n=10^6, ln⁡(0,002⋅106)ln⁡1,002=7,600,001998=3804\frac{\ln(0{,}002\cdot10^6)}{\ln1{,}002}=\frac{7{,}60}{0{,}001998}=3804, cioè ⌈log⁡23804⌉=12\lceil\log_23804\rceil=12 bit, contro ⌈log⁡2106⌉=20\lceil\log_210^6\rceil=20 bit del conteggio esatto. Simulazione per n=1000n=1000, a=0,002a=0{,}002 (30003000 prove): media 1000,81000{,}8, deviazione standard 32,132{,}1 (teoria 31,631{,}6) e l'errore supera il 10%10\% nello 0,13%0{,}13\% dei casi. Con a=1a=1 (ε\varepsilon non controllato) servono log⁡2log⁡2n\log_2\log_2n bit: ≈5\approx5 bit per n=109n=10^9, ma con deviazione standard ≈0,7n\approx0{,}7n.

Codice di verifica

python
import random
from fractions import Fraction
from statistics import mean, pstdev

def distribuzione(n):
    d = {0: Fraction(1)}
    for _ in range(n):
        nuovo = {}
        for x, p in d.items():
            q = Fraction(1, 2 ** x)                           # probabilità di incremento
            nuovo[x + 1] = nuovo.get(x + 1, 0) + p * q
            nuovo[x] = nuovo.get(x, 0) + p * (1 - q)
        d = nuovo
    return d

for n in (3, 4):
    d = distribuzione(n)
    m = sum(p * (2 ** x - 1) for x, p in d.items())
    v = sum(p * (2 ** x - 1) ** 2 for x, p in d.items()) - m * m
    print(n, {x: str(p) for x, p in sorted(d.items()) if p}, m, v)

def morris(n, a=1.0):
    X = 0
    for _ in range(n):
        if random.random() < (1 + a) ** -X:
            X += 1
    return ((1 + a) ** X - 1) / a

random.seed(2)
uno = [morris(1000) for _ in range(5000)]
print(mean(uno), pstdev(uno))
m500 = [mean(morris(1000) for _ in range(500)) for _ in range(100)]
print(mean(m500), pstdev(m500), mean(abs(v - 1000) > 100 for v in m500))
v = [morris(1000, 0.002) for _ in range(3000)]
print(mean(v), pstdev(v), mean(abs(x - 1000) > 100 for x in v))

Risultato: per n=3n=3 e n=4n=4 le distribuzioni del punto 1 con media 3 e varianza 3, poi media 4 e varianza 6; poi tre righe di simulazione: 989.39 678.68 (un contatore), 1001.77 30.88 0.01 (media di 500500 contatori) e 1000.76 32.07 0.00133 (base 1,0021{,}002), cioè media, deviazione standard e frazione di errori oltre il 10%10\% citate nei punti 3 e 4.

Versione ripasso

Teoria collegata