Giovanni's Diary > Subjects > Programming > Notes > Algoritmi >
Probabilistic Algorithms
Negli algoritmi probabilistici, il calcolo delle probabilità e' applicato non ai dati di input, ma ai dati di output.
In questo capitolo discuteremo algoritmi la cui correttezza e' probabilistica (Montecarlo) e algoritmi corretti il cui tempo di funzionamento e' probabilistico (Las Vegas).
Algoritmi Montecarlo
Test di primalità
Vogliamo trovare un algoritmo per determinare se un numero in input \(n\) e' primo. Una soluzione inefficiente testa tutti gli interi fra \(2\) e \(\sqrt{n}\).
boolean isPrimeNaif(int n) for i=1 to sqrt(n) do if n/i == floor(n/i) then return false return true
Per migliorare l'algoritmo possiamo ricordare il piccolo teorema di Fermat che dimostra che se \(n\) e' primo, allora:
\[\forall b,2\le b < n:\ b^{n-1}mod\ n=1\]
Allora:
boolean isPrime1(int n) b = random(2, n-1) if b^{n-1} mod n != 1 then return false return true
Tuttavia esistono dei numeri composti che non sono primi ma rispettano la condizione. Infatti il piccolo teorema di Fermat non e' un se e solo se: se il numero e' primo allora la condizione vale, ma non il contrario. Dobbiamo sfruttare un altro risultato teorico per migliorare l'algoritmo.
Miller-Rabin: Se \(n\) e' primo, allora per ogni intero \(b\), con \(2\le b < n\) valgono entrambe le seguenti condizioni:
- \(mcd(n, b)=1\)
- \(b^m\ mod\ n = 1\lor \exists i, 0\le i < v:b^{m2^i}mod\ = n-1\)
con \(n-1=m2^v\), \(m\) dispari.
Contrapposizione: Se esiste un intero \(b\) con \(w\le b < n\) tale che almeno una delle seguenti condizione e' vera:
- \(mcd(n, b)\neq 1\)
- \(b^m\ mod\ n\ne 1 \land \forall i, 0\le i
allora \(n\) e' composto.
boolean isPrime(int n) for i =1 to k do b=random(2, n-1) if isComposize(n, b) then return false return true
Complessità: \(O(klog^2(n)log(log(n))log(log(log(n))))\). Rabin ha dimostrato che se \(n\) e' composto allora ci sono almeno \((n-1)^{3/4}\) testimoni in \([2, ..., n-1]\). Il test di compostezza ha una probabilità inferiore a \(1/4\) di rispondere erroneamente.
Espressione polinomiale nulla
Data un'espressione algebrica polinomiale \(p(x_1, ..., x_n)\) in \(n\) variabili, determinare se \(p\) e' identicamente nulla oppure no. Una funzione polinomiale è identicamente nulla se è uguale a zero per ogni valore della variabile indipendente, \(p(x)=0\ \forall x\in D\).
Algoritmo:
- Si genera una $n$-pila di valori \(v_1, ..., v_n\)
- Si calcola \(x=p(v1, ..., v_n)\)
- Se \(x\neq 0\), \(p\) non e' identicamente nulla
- Se \(x=0\), \(p\) potrebbe essere identicamente nulla
- Se ogni \(v_i\) e' un valore intero casuale compreso fra \(1\) e \(2d\) dove \(d\) e' il grado del polinomio, allora la probabilita' di errore non supera \(\frac{1}{2}\).
- Si ripete \(k\) volte, riducente la probabilita' di errore a \((\frac{1}{2})^k\).
Strutture dati probabilistiche
Alcune strutture dati utili viste in precedenza sono:
- Bit set: si usa un solo bit per oggetto ma bisogna avere una elenco prefissato di oggetti
- Tabelle hash: struttura dinamica ma alta occupazione di memoria
Introduciamo ora i Bloom filters, struttura dinamica con bassa occupazione di memoria, ma elementi non possono essere cancellati e non si ha memorizzazione con una risposta probabilistica.
Le funzioni che possiamo chiamare sono:
- \(insert(key)\): Inserisce l'elemento \(key\) nel bloom filter
- \(boolean\ contains(key)\): se restituisce false allora l'elemento \(key\) e' sicuramente non presente nell'insieme. Se restituisce true l'elemento \(key\) può essere presente oppure no (falsi positivi).
Sia \(\epsilon\) la probabilità di falso positivo. I bloom filter richiedono \(1.44log_2(\frac{1}{\epsilon})\) bit per elemento inserito.
Implementazione: si ha un vettore booleano \(A\) si \(m\) bit, inizializzato a false e \(k\) funzioni hash \(h_1, h_2, ..., h_k:U\rightarrow [0, m-1]\).
insert(key) for i=1 to k do A[h_i(key)]=true boolean contains(key) for i=1 to k do if A[h_i(key)]==false then return false return true
Qualche formula ora senza dimostrazione:
- Dati \(n\) oggetti, \(m\) bit, \(k\) funzioni hash, la probabilità di un falso positivo e' pari a \(\epsilon (1-e^{\frac{-kn}{m}})^k\)
- Dati \(n\) oggetti e \(m\) bit, il valore ottimale per \(k\) e' pari a \(k=\frac{m}{n}\ln2\)
- Dati \(n\) oggetti e una probabilità di falsi positivi \(\epsilon\), il numero di bit \(m\) richiesti e' pari a \(m=-\frac{n\ln\epsilon}{(\ln2)^2}\)
Algoritmi Las Vegas
Agli algoritmi statistici sui vettore estraggono alcune caratteristiche statisticamente rilevanti da un vettore numerico, come la media, la varianza o la moda.
Problema della selezione
Dato un array \(A\) contenente \(n\) valore e un valore \(1\le k \le n\), trovare l'elemento che occuperebbe la posizione \(k\) se il vettore fosse ordinato.
Da notare che il problema di trovare la mediana e' equivalente al problema della selezione con \(k=\frac{n}{2}\)
Ovviamente possiamo ordinare il vettore e prendere il valore in posizione \(k\), con costo \(O(nlogn)\). Per piccoli valori di \(k\) si potrebbe invece create un heap e poppare il min finché non arriviamo al $k$-appesimo min.
Un'approccio potrebbe essere utilizzare il quick sort assumendo che la probabilità di scegliere un numero come pivot sia la stessa tra tutti i numeri del vettore. A questo punto si può dimostrare che il tempo medio e' \(O(n)\).
Item selection(Item[] A, int start, int end, int k) if start==end then return A[start] else int j = pivot(A, start, end) int q = j-start+1 if k==q then return A[j] else if k < q then return selection(A, start, j-1, k) else return selection(A, j+1, end, k-q)