USO DI CONCETTI PROBABILISTICI NEL PROGETTO E NELL’ANALISI DI ALGORITMI - Analisi probabilistica di algoritmi deterministici: si assume una distribuzione di probabilità delle istanze e si calcola il tempo di esecuzione atteso. In casi di distribuzioni semplici (es. nel sorting si assume che ogni permutazione sia equiprobabile) si può calcolare il tempo medio di esecuzione. - Progetto di algoritmi probabilistici: si assume che un algoritmo in alcuni casi ‘getti una moneta’ (utilizzi un generatore di bit casuali) e si valuta quale è il risultato atteso e quale è il tempo di esecuzione atteso. 1 ALGORITMI PROBABILISTICI • Utili in molte circostanze per ottenere soluzioni efficienti e semplici di problemi a vario livello di complessità. • Possono commettere errori • Lo studio della loro complessità richiede l’introduzione di classi di complessità probabilistiche. 2 L’utilizzazione della randomizzazione fa parte delle tecniche fondamentali di progetto di algoritmi già note. ESEMPI Hashing: nelle strutture dati (tabelle o alberi) per la gestione di dizionari, funzioni di randomizzazione delle chiavi (funzioni hash) consentono di distribuire in maniera uniforme le stringhe appartenenti ad un determinato insieme (identificatori contenuti in un programma, chiavi di un database ecc.) e quindi ottenere con buona probabilità tempi di accesso molto rapidi. naturalmente può accadere che due chiavi diverse abbiano lo stesso valoredella funzione hash dando luogo a conflitti che si risolvono con vari metodi. 3 Quicksort: dato un vettore di n interi, l’algoritmo di ordinamento quicksort ha un costo worst case O(n2) ma, nella sua versione probabilistica, in cui la scelta del perno è casuale, ha un costo atteso O(n log n) (algoritmo Random Quicksort). 4 L’algoritmo è del tipo ‘divide et impera’. Gli algoritmi di questo tipo hanno un comportamento efficiente se riescono a scomporre la soluzione del problema dato in due o più sottoproblemi bilanciati, cioè di taglia sostanzialmente simile. Nella sua versione deterministica il quicksort non effettua una suddivisione bilanciata (o meglio può effettuarla solo scegliendo come perno il mediano, ma questo passo è abbastanza costoso). Nella versione randomizzata il fatto di scegliere il perno in modo casuale consente invece di avere con buona probabilità una suddivisione bilanciata e di ottenere così un costo di esecuzione atteso molto migliore. Il bilanciamento dei sottoproblemi ci da la relazione di ricorrenza T(n) = 2 T(n/2) + cn che ha come soluzione T(n) = n log n. 5 Per ottenere una soluzione del tipo n log n non è necessario decomporre esattamente in due parti uguali il problema ma anche un rapporto 1/4 – 3/4 tra i due sottoproblemi è accettabile. In questo caso la probabilità di estrarre un perno valido è molto più alta perché ci sono n/2 elementi che sono compresi tra l’elemento di posizione n/4 e quello di posizione 3n/4. La relazione di ricorrenza diventa: T(n) = cn + T(n/4) + T(3n/4) Si verifica immediatamente che T(n) = O(n log n) soddisfa la relazione. Una dimostrazione più formale si ottiene calcolando esattamente quale è il numero atteso di confronti che vengono effettuati dall’algoritmo Random Quicksort. 6 Si noti che già questi due primi esempi mostrano che gli algoritmi randomizzati possono avere due comportamenti molto diversi: - nel caso dell’hashing abbiamo che una possibilità di errore (unilaterale) se il valore della funzione hash di due chiavi è diversa le chiavi sono sicuramente diverse ma se il valore è uguale le chiavi possono essere uguali o diverse (algoritmo sempre veloce e con buona probabilità corretto, ma a volte scorretto – ALGORITMI ‘MONTECARLO’); - nel caso del random quicksort la randomizzazione incide solo sul costo dell’algoritmo ma la soluzione è comunque sempre corretta (algoritmo sempre corretto e con buona probabilità veloce, ma a volte lento – ALGORITMI ‘LAS VEGAS’). 7 PARADIGMI - Randomizzazione dell’input. Per evitare le istanze più sfavorevoli un algoritmo probabilistico può ‘rimescolare’ l’input in modo casuale e poi risolvere il problema con un procedimento più ‘semplice’. In molti problemi le istanze sfavorevoli sono molto rare e un riordinamento casuale può raramente creare una istanza difficile. - Abbondanza di testimoni. In molti problemi, una proprietà dell’input (grafo, stringa, numero intero) è attestata da ‘testimoni’. Spesso cercarli deterministicamente può costare molto tempo ma se ce ne sono molti può essere facile trovarli in modo probabilistico. - Campionamento casuale. Se scelto correttamente un campione casuale può essere rappresentativo di una intera popolazione (sondaggi). 8 - Riduzione dello spazio delle istanze. In molti problemi abbiamo a che fare con un ‘piccolo’ insieme di dati appartenenti a un ‘grande’ universo. In questi casi possiamo usare la randomizzazione per mappare i dati su un piccolo universo. Esempi: - Hashing: citato precedentemente - Fingerprinting: date due stringhe x, y di n bit (es.: n=220) per decidere se x=y in modo deterministico dobbiamo controllare carattere per carattere mentre in modo probabilistico possiamo confrontare sottostringhe molto più corte. 9 Al fine di illustrare alcuni algoritmi probabilistici introduciamo l’istruzione random (n, m) che restituisce come valore un numero intero a caso tra n ed m, con probabilità uniforme 1/(m-n+1). Nota bene. Il fatto che l’istruzione ‘random’ fornisca un numero a caso tra n ed m con probabilità uniforme è una assunzione teorica che ci consente di analizzare il comportamento di un algoritmo probabilistico. In pratica l’istruzione farà ricorso a un generatore di numeri pseudocasuali. Anche una moneta avrà sempre una leggera polarizzazione che non garantisce che la probabilità di avere testa o croce sia esattamente 1/2. La possibilità di disporre in pratica di sorgenti realmente casuali è uno dei problemi fondamentali della teoria degli algoritmi probabilistici. 10 TEST DI PRIMALITA’ Il ‘piccolo’ teorema di Fermat afferma che per ogni primo p ed ogni a ∈ [2,…, p-1]: ap-1 mod p = 1. In particolare tale risultato vale per a = 2. Ciò consente di definire il seguente algoritmo per il test di primalità ALGORITMO PSEUDOPRIMI Se 2n-1 mod n ≠ 1 allora restituisci ‘n è composto’ altrimenti restituisci ‘n è primo’ Questo algoritmo presenta una certa probabilità di errore perché esistono numeri composti n che soddisfano l’equazione 2n-1 mod n = 1 e quindi possono essere dichiarati erroneamente ‘primi’. 11 Esistono anche numeri composti n (numeri di Carmichael) tali che l’equazione an-1 mod n = 1 è soddisfatta per ogni a ∈ [2,…, n-1]. E’ necessario un test più raffinato. 12 TEST DI COMPOSTEZZA DI RABIN E MILLER Un intero a∈[2,…, n-1] è un testimone della compostezza di n se: 1) an-1 mod n ≠ 1, oppure se: 2) esiste un intero t ≥ 1 tale che n-1 = m 2t (la rappresentazione binaria di n-1 è uguale alla rappresentazione binaria del numero dispari m seguito da t zeri) e il MCD tra am – 1 ed n appartiene a [2,…, n-1]. 13 Se a testimonia che n è composto, n è effettivamente composto. Infatti se vale la 1, n non soddisfa il teorema di Fermat e se vale la 2, n deve ammettere un divisore proprio. NOTA BENE. Utilizzando risultati della teoria dei numeri si può dimostrare che se n è composto esistono in [2, …, n-1] almeno 3(n-1)/4 numeri interi che testimoniano la sua ‘compostezza’. 14 ALGORITMO RANDOM TEST DI COMPOSTEZZA input: n a ← random (2, n-1) se a testimonia la compostezza di n allora accetta, altrimenti rifiuta L’algoritmo ha un costo di esecuzione polinomiale perché la verifica che a testimonia la compostezza può essere fatta in tempo polinomiale. Poiché, come si è detto, se n è composto esistono 3(n – 1)/4 testimoni tra 2 ed n-1, abbiamo che la probabilità che se n è composto non venga estratto un numero che non è un testimone di compostezza è al più 1/4. Quindi se n composto → l’algoritmo accetta con probabilità ≥ 3/4 se n primo → l’algoritmo rifiuta 15 Per migliorare l’affidabilità dell’algoritmo possiamo ripeterne l’applicazione estraendo ogni volta in modo indipendente dalle estrazioni precedenti un valore a. In tal modo, in k passi la probabilità di errore si riduce ad 1/4k e diventa rapidamente inferire alla possibilità che si verifichi un errore a livello hardware. Si noti che l’algoritmo può commettere errori ‘da un solo lato’, infatti • se n è primo viene sicuramente rifiutato (rifiutato con probabilità 1) • se n è composto viene accettato con probabilità 3/4 e rifiutato con probabilità 1/4. 16 Un algoritmo probabilistico che può errare nell’accettazione e/o nel rifiuto viene detto un algoritmo di tipo ‘Monte Carlo’. In generale un algoritmo probabilistico può commettere errori - unilaterali - bilaterali. Un algoritmo di tipo ‘Las Vegas’ è invece un algoritmo probabilistico che, se risponde, dà risposte corrette ma a volte potrebbe non rispondere (o potrebbe rispondere ma solo dopo un numero sufficiente di iterazioni e quindi impiegando un tempo eccessivamente lungo). 17 Si noti che gli algoritmi probabilistici trovano le loro più valide applicazioni nella risoluzione di problemi di costo polinomiale o di problemi che sono in NP-P ma non NP-completi. Infatti si può dimostrare che se per un problema NP-completo potessimo trovare un algoritmo polinomiale la cui probabilità di errore possa essere resa arbitrariamente piccola, allora esisterebbero algoritmi di tale tipo per qualunque problema in NP, un fatto che si ritiene inverosimile. 18 PRODOTTO DI MATRICI (Algoritmo di Freivald) Il problema consiste nel determinare, date tre matrici, A, B, C se A×B = C. Nessun algoritmo è in grado di risolvere questo problema in modo deterministico in un tempo inferiore a O(n2.4), il miglior tempo noto per il prodotto di matrici. Il seguente algoritmo risolve il problema in tempo O(n2) con un errore ≤ 1/2. ALGORITMO RANDOM PRODOTTO DI MATRICI input: A, B, C per i che va da 1 a n ripeti x[i] ← random (0, 1) se A(Bx) = Cx allora accetta, altrimenti rifiuta. 19 DIMOSTRAZIONE Chiaramente se l’algoritmo rifiuta esso si comporta correttamente mentre quando accetta potrebbe errare, infatti potrebbe accettare anche se A×B ≠ C. Però possiamo dimostrare che ciò accade al più per metà dei 2n vettori x in (0,1)n, cioè almeno 2n-1 vettori testimoniano correttamente che A×B ≠ C (in altre parole A (B x)) ≠ C x). Poiché se A×B ≠ C la matrice D = A×B – C non è nulla, è sufficiente mostrare che per 2n-1 vettori x il prodotto Dx = δ = (δ1, δ2, ... δn) non è nullo. Supponiamo che la riga di in D non sia nulla e che dis1, … disk siano i suoi elementi non nulli (k≥1). 20 Dobbiamo dimostrare che δi = Σj dij xj = Σh dish xsh ≠ 0 per almeno 2n-1 vettori x. Infatti se fosse δi = 0 avremmo xs1 = - 1/ dis1 Σ dish xsh per 2 ≤ h ≤ n e quindi il valore xs1 sarebbe fissato univocamente e resterebbero liberi solo (al più) i restanti n-1 elementi. In altre parole, se x annulla una riga non nulla di D, almeno una delle sue componenti resta fissata e quindi non ci possono essere più di 2n-1 vettori che annullano una riga non nulla. QED 21 TEST DI NULLITA’ DI UN POLINOMIO Il problema consiste nel decidere se un polinomio Q nelle variabili x1, ..., xn, fornito in una forma algebrica generale, è identicamente nullo. NOTA BENE. Se il polinomio venisse fornito come somma di monomi la verifica sarebbe banale ma se viene fornito con una espressione algebrica generale gli algoritmi di semplificazione necessari per metterlo sotto forma di somma di monomi sarebbero di costo troppo elevato. 22 Supponiamo che g(Q) sia il grado del polinomio (o un upper bound di esso). Si può dimostrare che se Q NON è identicamente nullo, allora, per ogni costante c > 1, e per ogni insieme I di interi con |I| ≥ cg(Q), il numero di elementi y=(y1, ..., yn) ∈ In per cui Q(y1, ..., yn) = 0 è al più |I|n /c. A partire da questo risultato è possibile definire il seguente algoritmo probabilistico in cui si assume I = {1,2, ..., 2g(Q)}. ALGORITMO RANDOM TEST POLINOMIO NULLO input: Q per i che va da 1 a n ripeti y[i] ← random (1, 2g(Q)) se Q(y[1], ..., y[n]) ≠ 0 allora rifiuta, altrimenti accetta. 23 DIMOSTRAZIONE Avendo assunto c=2 abbiamo che al più 1/2 dei vettori y=(y1, ..., yn) generati a caso potrà dare Q(y) = 0. Quindi - se Q è nullo viene sicuramente accettato - se Q non è nullo abbiamo una probabilità 1/2 che sia rifiutato e una probabilità 1/2 che sia accettato. Anche in questo caso abbiamo un errore unilaterale. QED Un risultato strettamente legato al precedente consente di realizzare un algoritmo probabilistico per determinare se due polinomi sono distinti. Sia dato un campo F di cardinalità q. Due diversi polinomi Q1 e Q2 con k variabili e di grado massimo g possono concordare al più su gqk-1 elementi di Fk. 24 CLASSI DI COMPLESSITA’ PROBABILISTICHE Per formalizzare le computazioni probabilistiche e studiare le relative classi di complessità dobbiamo innanzitutto introdurre le macchine di Turing probabilistiche. Per far ciò partiamo da macchine di Turing non deterministiche per le quali facciamo le seguenti assunzioni semplificatrici. - Il grado di non determinismo è 2. - Ogni passo è non deterministico. - Ogni computazione si svolge in tempo polinomiale. - Tutte le computazioni hanno la stessa durata. 25 Se ora interpretiamo i rami di una computazione non deterministica come risultati di una sequenza di t scelte casuali indipendenti tra due alternative (scelte ogni volta con probabilità 1/2) abbiamo che ogni computazione ha la probabilità 1/2t di realizzarsi. Assumendo che ogni computazione abbia tre possibili esiti: 1, 0, ?, abbiamo che il risultato di una computazione M(x) con input x è una variabile casuale e quindi siamo interessati a valutare Prob {M(x) = z} dove z ∈ (1,0,?). Definiamo: α(M, x): Prob {M(x) = 1} β(M, x): Prob {M(x) = 0} 26 MACCHINE DI TURING PP (PROBABILISTIC POLYNOMIAL-TIME) CLASSE PP Una macchina di Turing probabilistica M è di tipo PP se: - M ha due stati finali, uno di accettazione ed uno di rifiuto, - M accetta x se α(M, x) > 1/2 (x∈L M accetta con Prob>1/2) - M rifiuta x se β(M, x) ≥ 1/2 (x∉L M accetta con Prob≤1/2) ESEMPIO Supponiamo di voler decidere se, data una formula Booleana w, w è soddisfatta da più della metà delle assegnazioni di valori di verità. Chiaramente tale problema ammette una macchina di tipo PP che lo risolve; il problema è dunque nella classe PP. 27 NOTA BENE Le macchine PP possono commettere errore bilaterale. La classe PP non è molto utilizzata perché per ridurre significativamente la probabilità di errore può essere necessario un numero esponenziale di iterazioni (si pensi ad esempio al caso in cui l’errore è 1/2 - 1/2p(n) ). 28 MACCHINE DI TURING BPP (BOUNDED PP) CLASSE BPP Una macchina di Turing probabilistica M è di tipo BPP se esiste una costante ε ∈ (0, 1/2) (estremi esclusi) tale che: - M ha due stati finali, uno di accettazione ed uno di rifiuto, - M accetta x se α(M, x) >1/2+ε (x∈L M accetta con Prob>1/2+ε) - M rifiuta x se β(M, x) >1/2+ε (x∉L M rifiuta con Prob>1/2+ε) - per ogni x o α(M, x) >1/2+ε o β(M, x) >1/2+ε. Nel caso delle macchine BPP un numero polinomiale di iterazioni consente di rendere l’errore piccolo a piacere. Ciò è possibile qualunque sia la costante ε, purché diversa da 0. Anche le macchine BPP commettono errore bilaterale. 29 TEOREMA Sia M una macchina di tipo BPP e sia q un polinomio. Allora esiste una macchina di Turing probabilistica M’ tale che, per ogni x, con |x|=n, x∈L M accetta con Prob α(M’, x) >1 – 1/2q(n) x∉L M rifiuta con Prob β(M’, x) >1 – 1/2q(n) Alla luce del precedente teorema una definizione equivalente della classe BPP è la seguente: x∈L M accetta con Prob>3/4 x∉L M accetta con Prob<1/4 NOTA BENE Le macchine BPP possono commettere errore bilaterale. 30 MACCHINE DI TURING RP (RANDOM P) CLASSE RP Una macchina di Turing probabilistica M è di tipo RP se: - M ha due stati finali, uno di accettazione ed uno di rifiuto, - M accetta x se α(M, x) >1/2 (x∈L M accetta con Prob>1/2) - M rifiuta x se β(M, x) =1 (x∉L M rifiuta con Prob=1) - per ogni x o α(M, x) >1/2 o β(M, x) =1. Le macchine di tipo RP commettono errore unilaterale. Anche nelle macchine di tipo RP l’errore può essere reso piccolo a piacere. ESEMPI L’insieme dei numeri composti appartiene a RP. I problemi dell’uguaglianza di matrici (AB=C) e del polinomio nullo appartengono a co-RP 31 NOTA BENE Nella definizione dell’accettazione di una macchina RP non abbiamo richiesto (come nel caso BPP) che fosse α(M, x) >1/2 + ε. Ciò è dovuto al fatto che si può dimostrare che RP ⊆ BPP. 32 MACCHINE DI TURING ZPP (ZERO ERROR) CLASSE ZPP Una macchina di Turing probabilistica M è di tipo ZPP se: - M ha tre stati finali, uno di accettazione, uno di rifiuto, ed uno di incertezza - M accetta x se α(M, x) >1/2 e β(M, x) =0 - M rifiuta x se β(M, x) > 1/2 e α(M, x) = 0 - per ogni x o α(M, x) >1/2 e β(M, x) =0 o β(M, x) >1/2 e α(M, x) =0. Le macchine di tipo ZPP corrispondono agli algoritmi di tipo Las Vegas: una macchina di tipo ZPP non commette errori. Un algoritmo di tipo Las Vegas per il problema della primalità si può trovare nel testo di Bovet e Crescenzi, Teoria della complessità computazionale. 33 CLASSI DI COMPLESSITA’ PROBABILISTICHE TEOREMA Le classi PP, BPP, ZPP sono chiuse rispetto al complemento. DIMOSTRAZIONE Le definizioni delle classi presentano simmetria rispetto ad accettazione e rifiuto. QED TEOREMA Le classi BPP, RP e ZPP sono chiuse rispetto ad unione ed intersezione. DIMOSTRAZIONE Dimostriamo che BPP è chiuso rispetto all’unione (analogo per RP e ZPP). 34 Siano L1 ed L2 due linguaggi in BPP. In base alle proprietà viste per le macchine di tipo BPP possiamo asserire che esistono due macchine M1ed M2 tali che, per i=1,2, x∈Li implica che α(Mi, x) > 1 – ε x∉Li implica che β(Mi, x) > 1 – ε ove ε ∈ (0, 1/2). Consideriamo dunque una macchina M di tipo BPP che simula una dopo l’altra M1 ed M2 e accetta se e solo se una delle due macchine ha accettato. Se x ∈ L1 ∪ L2 allora α(M, x) > 1 – ε, se x ∉ L1 ∪ L2 allora β(M, x) > (1 – ε)2. 35 Se garantiamo che ε sia tale che (1 – ε)2>1/2 (ad esempio ε=1/4) e definiamo ε’= 1 – (1 – ε)2 abbiamo che se x ∈ L1 ∪ L2 allora α(M, x) > 1 – ε > (1 – ε)2 = 1 – ε’ se x ∉ L1 ∪ L2 allora β(M, x) > 1 – ε’ Quindi M accetta L1 ∪ L2 e quindi L1 ∪ L2 ∈ BPP. QED 36 Tra le classi probabilistiche valgono le seguenti relazioni di inclusione. TEOREMA P ⊆ ZPP DIMOSTRAZIONE Se L è in P allora poniamo tutte le computazioni della macchina probabilistica uguali alla computazione deterministica che decide L ed otteniamo che se x∈L allora α(M, x) =1 se x∉L allora β(M, x) =1. QED 37 TEOREMA ZPP = RP ∩ co-RP DIMOSTRAZIONE Mostriamo innanzitutto che ZPP ⊆ RP e che ZPP ⊆ co-RP, e quindi ZPP ⊆ RP ∩ co-RP. Per mostrare che ZPP ⊆ RP è sufficiente trasformare una macchina di tipo ZPP in una macchina di tipo RP e a tal fine possiamo trasformare una computazione che termina in uno stato di incertezza in una computazione rifiutante. Per mostrare che ZPP ⊆ co-RP è sufficiente ricordare che ZPP è chiuso rispetto alla complementazione. Per mostrare che RP ∩ co-RP⊆ ZPP consideriamo un linguaggio L in RP ∩ co-RP. Allora esistono due macchine di tipo RP M1 ed M2 che accettano rispettivamente L ed il suo complemento. 38 Possiamo scrivere per il linguaggio L il seguente algoritmo di tipo ZPP. input: x simula M1(x) se M1 accetta allora accetta simula M2(x) se M2 accetta allora rifiuta altrimenti termina nello stato di incertezza. Poiché M1 ed M2 sono macchine di tipo RP allora è facile verificare che se x∈L allora α(M, x) > 1/2 e β(M, x) = 0 se x∉L allora α(M, x) = 0 e β(M, x) > 1/2. QED 39 TEOREMA RP ⊆ NP; co-RP ⊆ co-NP DIMOSTRAZIONE Consideriamo la macchina di Turing di tipo RP come una macchina non deterministica. Se L∈RP allora abbiamo che: - se x∈L allora α(M, x) > 1/2 e quindi esiste almeno una computazione accettante - se x∉L allora β(M, x) = 1 e quindi tutte le computazioni rifiutano. QED 40 TEOREMA RP ∪ co-RP ⊆ BPP DIMOSTRAZIONE Dimostriamo che RP ⊆ BPP. Poiché BPP è chiuso rispetto alla complementazione, vale anche co-RP ⊆ BPP e quindi vale l’enunciato del teorema. Sia M una macchina di tipo RP; se M accetta x allora β(M, x) < 1/2. Definiamo una macchina BPP M’ che simula due volte M e accetta x se almeno una delle due computazioni della M accetta. Quindi se M’ accetta α(M’, x) > 1 - 1/4; assumendo ε = 1/4 abbiamo α(M’, x) > 1/2 + ε. Se M’ rifiuta β(M’, x) = 1 > 1/2 + ε. QED 41 TEOREMA NP ∪ co-NP ⊆ PP DIMOSTRAZIONE Dimostriamo che NP ⊆ PP. Poiché PP è chiuso rispetto alla complementazione è chiaro che abbiamo anche co-NP ⊆ PP. Sia data una macchina non deterministica M che accetta un linguaggio L ∈ NP Realizziamo una semplice macchina probabilistica M’ che opera nel seguente modo: su input x al primo passo si dirama in due sottoalberi. Quello di sinistra corrisponde alla computazione non deterministica della macchina M (di profondità p(n)) e quello di destra è un albero completo di computazioni deterministiche di profondità p(n) che accettano sempre. Se x∈L allora almeno la metà più uno delle computazioni accetta e quindi x viene accettata con probabilità α(M,x)>1/2. 42 Altrimenti esattamente la metà delle computazioni accettano e quindi la stringa viene rifiutata con probabilità β(M,x)=1/2. QED TEOREMA BPP ⊆ PP Questo risultato deriva banalmente dalla definizione dei due tipi di macchina. 43 TEOREMA PP ⊆ PSPACE DIMOSTRAZIONE Se un linguaggio L è deciso da una macchina probabilistica di tipo PP in tempo p(n) possiamo mostrare che L può essere deciso dal seguente algoritmo deterministico che usa spazio polinomiale: For i= 1 to 2p(n) do if l’iesima computazione deterministica accetta then cont = cont + 1 end if cont > 2(p(n) – 1) then accetta else rifiuta 44 Problemi aperti: - RP = co-RP? (conseguenza: RP ⊆ NP∩co-NP) - BPP ⊆ NP? 45