Esiste un algoritmo di "ordinamento" che restituisce una permutazione casuale quando si utilizza un comparatore a gettoni?


9

Ispirato da questa domanda in cui chi chiede sapere se il tempo di esecuzione cambia quando il comparatore utilizzato in un algoritmo di ricerca standard viene sostituito da un discreto lancio di monete, e anche dall'incapacità di Microsoft di scrivere un generatore di permutazione uniforme, la mia domanda è quindi :

Esiste un algoritmo di ordinamento basato sul confronto che, a seconda della nostra implementazione del comparatore:

  1. restituisce gli elementi in ordine ordinato quando si utilizza un comparatore reale (ovvero, il confronto fa quello che ci aspettiamo in un algoritmo di ordinamento standard)
  2. restituisce una permutazione uniformemente casuale degli elementi quando il comparatore viene sostituito da un lancio di moneta equo (ovvero, restituisce x < y = truecon probabilità 1/2, indipendentemente dal valore di xe y)

Il codice per l'algoritmo di ordinamento deve essere lo stesso. È solo il codice all'interno del confronto "scatola nera" che può cambiare.


Vedi anche questa domanda .
Raffaello

2
Vedi anche la seguente domanda interessante: cstheory.stackexchange.com/questions/5321/… .
Yuval Filmus,

1
Vuoi che il tuo comparatore casuale sia ben educato? Ecco due modi possibili. (1) Una volta che il comparatore ha deciso che , quindi x < y sempre e anche y > x . (2) stessa, ma se inoltre il comparatore decide che x < y e y < z , allora impegna a x < z (e z > x ). In entrambi i casi, ogni query non vincolata è ancora completamente casuale. x<yx<yy>xx<yy<zx<zz>x
Yuval Filmus,

@YuvalFilmus Voglio essenzialmente ciò che viene richiesto nella tua domanda collegata, tranne che lo stesso circuito dovrebbe anche ordinare se sostituiamo il gate casuale con un gate di scambio-confronto che ordina la coppia di elementi.
Joe

1
Vedi qui per belle visualizzazioni.
Raffaello

Risposte:


3

Il seguente algoritmo deterministico (senza il comparatore) funziona per una tupla di input :(a1,,an)

  1. Do la Fisher-Yates Shuffle usare il comparatore con una certa coppia statica (ad esempio ) (campionamento per accettazione-rifiuto facendo) come un coin flip. Se il comparatore emette 1 la prima volta, utilizzarlo invertito per evitare un loop di rifiuto infinito nel caso deterministico.a1<a21
  2. (speedup opzionale: prova una singola coppia volte, dove n è la lunghezza o il tuo input. Se una qualsiasi delle due uscite differisce, restituisci la permutazione ottenuta in (1))nn
  3. Ordina il tuo array usando unisci ordinamento.

Data una relazione di ordine deterministico come comparatore, questo algoritmo ordina un array nel tempo poiché il shuffle Fisher-Yates viene eseguito in O ( n ) usando i "bit casuali" non casuali di O ( log n ) (ad es. Chiamate al comparatore ) in ogni passaggio e unisci l'ordinamento ha la stessa complessità asintotica. Il risultato di (1) è totalmente inutile in questo caso, ma poiché è seguito da un tipo reale, questo non fa male.O(nlogn)O(n)O(logn)

Dato un vero lancio della moneta come comparatore (1) consente l'array con uguale probabilità per ogni permutazione e se davvero devi fare (3) (hai lasciato fuori (2) o (2) non è riuscito a determinare la casualità), questo non è danno perché la distribuzione del suo risultato dipende solo dall'ordine del suo input che è uniformemente distribuito tra tutte le permutazioni a causa di (1), quindi anche il risultato dell'intero algoritmo è distribuito uniformemente. Il numero di volte in cui ogni campionamento di accettazione-rifiuto deve essere ripetuto viene distribuito geometricamente (respingi con probabilità ) e quindi ha un valore atteso<2. Ogni ripetizione utilizza al massimolognbit, quindi l'analisi di runtime è quasi la stessa del caso deterministico, ma otteniamo solo unruntime previstodiO(nlogn), con possibilità di non termine (termina soloquasi sicuramente).<12<2lognO(nlogn)


Come ha sottolineato Joe: se non ti piace il test per il primo bit in (1), fai (3) quindi (1) e usa che è sempre 0 , poiché l'array è già ordinato nel caso deterministico. Inoltre, devi sottrarre il tuo numero casuale dal limite superiore dell'intervallo nel loop, poiché il limite superiore per il numero casuale produce la permutazione identica. Ma tieni presente che (2) è proibito allora, perché devi sempre fare la riproduzione casuale nel caso del riscatto.an<a10


Puoi anche usare le stesse chiamate al tuo comparatore per (1) e (3), ma poi dimostrare che il risultato è distribuito uniformemente è almeno molto più difficile, se possibile affatto.


Il seguente algoritmo non ha fasi distinte per la riproduzione casuale e l'ordinamento, ma è asintoticamente più lento. È essenzialmente un ordinamento per inserzione con ricerca binaria . Userò per indicare l'input e b k = ( b k , 1 , , b k , k ) per indicare il risultato dopo il k -esimo giro:a=(a1,,an)bk=(bk,1,,bk,k)k

  1. Impostare b1,1=a1
  2. Se allora b 2 = ( a 2 , a 1 ) e ( c , d ) : = ( 2 , 1 ) altrimenti b 2 = ( a 1 , a 2 ) e ( c , d ) : = ( 1 , 2 ) . In entrambi i casi a d <a2<a1b2=(a2,a1)(c,d):=(2,1)b2=(a1,a2)(c,d):=(1,2) sarà sempre 0 (ovvero falso) per un comparatore non casuale.ad<ac0
  3. Per ottenere per k 3, ottenere prima b k - 1 .bkk3bk1
  4. Sia e k = 2 l , ovvero k è la potenza minima di 2 non inferiore a k .l=log2kk=2lk2k
  5. Lasciate . Per ogni j { 1 , , l } let i j = { i j - 1 + 2 l - j i j - 1 + 2 l - j > k - 1 a d < a c i j - 1 i j - 1 + 2 l -i0=0j{1,,l}
    ij={ij1+2ljij1+2lj>k1ad<acij1ij1+2lj>k1¬(ad<ac)ij1+2ljij1+2ljk1bk1,ij1+2lj<akij1ij1+2ljk1¬(bk1,ij1+2lj<ak)
  6. il>kbk=(bk1,1,,bk1,il1,ak,bk1,il,,bk1,k1)
  7. bn

k1k

Si noti che questo algoritmo è inefficiente in entrambe le modalità rispetto allo shuffle Fisher-Yates e unisci l'ordinamento poiché l'inserimento di un elemento in una posizione arbitraria è costoso se l'utilizzo di un array e la ricerca binaria richiedono tempo lineare se si utilizza un elenco. Ma forse una modifica dell'ordinamento heap o dell'albero in un modo simile potrebbe portare a un algoritmo più veloce.


@Joe puoi mettere tutti i tuoi punti ancora validi per il post nella forma corrente in un commento ed eliminare il resto?
frafl

Speravo in un algoritmo che non eseguisse passaggi diversi a seconda del comparatore utilizzato. Riesci a evitare un loop di rifiuto infinito senza sondare il comparatore? Penso che potresti evitare il rifiuto eseguendo prima il passaggio (3) ...
Joe

i

Primo commento: nota che non butto via quel primo bit di esempio, è "dual use". Ho pensato di invertire ogni secondo bit, ma ciò non avrebbe impedito il loop infinito. In effetti è necessario un modello irregolare e può persino rifiutare molte più voci. Ovviamente potrei XOR i due bit più recenti invece del primo e del più recente, ma non è molto diverso.
frafl

ian<a10

4

n2A/2B1/n!n>21/n!A/2B


1
Ma questo vale solo se abbiamo bisogno di un limite deterministico sul runtime, che non è stato richiesto nella domanda. Se richiediamo solo che il runtime previsto sia limitato, questo non dovrebbe essere un problema.
frafl

1
Sei a conoscenza di un algoritmo di ordinamento ragionevole che non termina in tempi polinomiali?
Yuval Filmus,

2
Mescoli il caso deterministico e casuale. L'algoritmo può terminare in tempo polinomico deterministico se chiamato con una relazione di ordine deterministico e in tempo polinomiale atteso se chiamato con una moneta come comparatore.
frafl

2k

kA/2k
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.