Probabilità: quanto in alto puoi andare?


10

In precedenza avevo posto una domanda su come calcolare una probabilità in modo rapido e preciso. Tuttavia, evidentemente è stato troppo facile dato che è stata data una soluzione a forma chiusa! Ecco una versione più difficile.

Questa attività riguarda la scrittura di codice per calcolare una probabilità esattamente e rapidamente . L'output dovrebbe essere una probabilità precisa scritta come una frazione nella sua forma più ridotta. Cioè non dovrebbe mai essere prodotto 4/8ma piuttosto 1/2.

Per alcuni numeri interi positivi n, considera una stringa uniformemente casuale di 1 e -1 secondi di lunghezza ne chiamala A. Ora concatena Auna copia di se stessa. Cioè A[1] = A[n+1]se l'indicizzazione da 1 A[2] = A[n+2]e così via. Aora ha lunghezza 2n. Ora considera anche una seconda stringa casuale di lunghezza i ncui primi nvalori sono -1, 0 o 1 con probabilità 1 / 4,1 / 2, 1/4 ciascuno e chiamalo B.

Ora considera il prodotto interno di Bwith A[1+j,...,n+j]for different j =0,1,2,....

Ad esempio, considera n=3. I valori possibili per Ae Bpotrebbero essere A = [-1,1,1,-1,...]e B=[0,1,-1]. In questo caso i primi due prodotti interni sono 0e 2.

Compito

Per ciascuno j, a partire da j=1, il codice dovrebbe generare la probabilità che tutti i primi j+1prodotti interni siano zero per ciascuno n=j,...,50.

Copiando la tabella prodotta da Martin Büttner per j=1abbiamo i seguenti risultati di esempio.

n   P(n)
1   1/2
2   3/8
3   7/32
4   89/512
5   269/2048
6   903/8192
7   3035/32768
8   169801/2097152

Punto

Il tuo punteggio è il più grande che il jtuo codice completa in 1 minuto sul mio computer. Per chiarire un po ', ognuno ha jun minuto. Si noti che il codice di programmazione dinamica nella domanda collegata precedente lo farà facilmente per j=1.

Tie breaker

Se due voci ottengono lo stesso jpunteggio, quella vincente sarà quella che raggiungerà il massimo nin un minuto sulla mia macchina per quello j. Se anche le due migliori iscrizioni sono uguali su questo criterio, il vincitore sarà la risposta inviata per prima.

Lingue e biblioteche

Puoi usare qualsiasi linguaggio e librerie liberamente disponibili che ti piacciono. Devo essere in grado di eseguire il tuo codice, quindi per favore includi una spiegazione completa su come eseguire / compilare il tuo codice in Linux, se possibile.

La mia macchina I tempi verranno eseguiti sulla mia macchina. Questa è un'installazione ubuntu standard su un processore a otto core AMD FX-8350. Questo significa anche che devo essere in grado di eseguire il tuo codice.

Voci vincenti

  • j=2in Python di Mitch Schwartz.
  • j=2in Python di feersum. Attualmente la voce più veloce.

Se la domanda non è chiara in alcun modo, per favore fatemi sapere in modo da poterlo risolvere rapidamente.

2
Sei di gran lunga la mia domanda preferita. Poi di nuovo, ho una cosa per calcolare i valori esattamente e rapidamente .
primo

@primo Grazie! Questo significa che possiamo aspettarci una risposta in RPython? :)

Potresti mettere la differenza tra questa domanda e l'altra?
Kirbyfan64sos,

@ kirbyfan64sos L'altro è essenzialmente la stessa domanda solo per `j = 1`.

Risposte:


3

Python 2, j = 2

Ho provato a trovare una sorta di 'forma chiusa' per j = 2. Forse potrei farne un'immagine MathJax, anche se sarebbe davvero brutta con tutto l'indice che armeggia. Ho scritto questo codice non ottimizzato solo per testare la formula. Il completamento richiede circa 1 secondo. I risultati corrispondono al codice di Mitch Schwartz.

ch = lambda n, k: n>=k>=0 and fac[n]/fac[k]/fac[n-k]
W = lambda l, d: ch(2*l, l+d)
P = lambda n, p: n==0 or ch(n-1, p-1)
ir = lambda a,b: xrange(a,b+1)

N = 50
fac = [1]
for i in ir(1,4*N): fac += [i * fac[-1]]

for n in ir(2, N):
    s = 0
    for i in ir(0,n+1):
     for j in ir(0,min(i,n+1-i)):
      for k in ir(0,n+i%2-i-j):
       t=(2-(k==0))*W(n+i%2-i-j,k)*W(i-(j+i%2),k)*W(j,k)**2*P(i,j+i%2)*P(n+1-i,j+1-i%2)
       s+=t
    denp = 3 * n - 1
    while denp and not s&1: denp -= 1; s>>=1
    print n, '%d/%d'%(s,1<<denp)

Considera una sequenza in cui il membro ith è ese A [i] == A [i + 1] o nse A [i]! = A [i + 1]. inel programma è il numero di ns. Se iè pari, la sequenza deve iniziare e terminare con e. Se iè dispari, la sequenza deve iniziare e terminare con n. Le sequenze sono ulteriormente classificati in base al numero di corse di consecutivi es o ns. Ci sono j+ 1 dell'uno e jdell'altro.

Quando l'idea random walk è estesa a 3 dimensioni, c'è un problema sfavorevole che ci sono 4 possibili direzioni di camminare in (uno per ciascuno dei ee, en, neo nn) che significa che non sono linearmente dipendenti. Quindi l' kindice somma il numero di passi effettuati in una delle direzioni (1, 1, 1). Quindi ci sarà un numero esatto di passaggi che devono essere eseguiti nelle altre 3 direzioni per annullarlo.

P (n, p) indica il numero di partizioni ordinate di n oggetti in p parti. W (l, d) indica il numero di modi in cui una camminata casuale di lpassi percorre esattamente una distanza d. Come prima c'è 1 possibilità di spostarsi a sinistra, 1 possibilità di spostarsi a destra e 2 per rimanere fermi.


Grazie! Un'immagine della formula sarebbe davvero fantastica.

Grazie per la spiegazione. Lo fai sembrare semplice! Ho appena visto il tuo commento per il quale potresti trovare una soluzione j=3. Sarebbe fantastico!

3

Python, j = 2

L'approccio di programmazione dinamica per la j = 1mia risposta alla domanda precedente non ha bisogno di molte modifiche per funzionare a livelli più alti j, ma rallenta rapidamente. Tabella di riferimento:

n   p(n)

2   3/8
3   11/64
4   71/512
5   323/4096
6   501/8192
7   2927/65536
8   76519/2097152
9   490655/16777216
10  207313/8388608

E il codice:

from time import*
from fractions import*
from collections import*

def main():
    N_MAX=50

    T=time()

    n=2
    Y=defaultdict(lambda:0)
    numer=0

    for a1 in [1]:
        for b1 in (1,0):
            for a2 in (1,-1):
                for b2 in (1,0,0,-1):
                    if not a1*b1+a2*b2 and not a2*b1+a1*b2:
                        numer+=1
                    Y[(a1,a2,b1,b2,a1*b1+a2*b2,a2*b1,0)]+=1

    thresh=N_MAX-1

    while time() <= T+60:
        print('%d %s'%(n,Fraction(numer,8**n/4)))

        if thresh<2:
            print('reached N_MAX with %.2f seconds remaining'%(T+60-time()))
            return

        n+=1
        X=Y
        Y=defaultdict(lambda:0)
        numer=0

        for a1,a2,b1,b2,s,t,u in X:
            if not ( abs(s)<thresh and abs(t)<thresh+1 and abs(u)<thresh+2 ):
                continue

            c=X[(a1,a2,b1,b2,s,t,u)]

            # 1,1

            if not s+1 and not t+b2+a1 and not u+b1+a1*b2+a2: numer+=c
            Y[(a1,a2,b2,1,s+1,t+b2,u+b1)]+=c

            # -1,1

            if not s-1 and not t-b2+a1 and not u-b1+a1*b2+a2: numer+=c
            Y[(a1,a2,b2,1,s-1,t-b2,u-b1)]+=c

            # 1,-1

            if not s-1 and not t+b2-a1 and not u+b1+a1*b2-a2: numer+=c
            Y[(a1,a2,b2,-1,s-1,t+b2,u+b1)]+=c

            # -1,-1

            if not s+1 and not t-b2-a1 and not u-b1+a1*b2-a2: numer+=c
            Y[(a1,a2,b2,-1,s+1,t-b2,u-b1)]+=c

            # 1,0

            c+=c

            if not s and not t+b2 and not u+b1+a1*b2: numer+=c
            Y[(a1,a2,b2,0,s,t+b2,u+b1)]+=c

            # -1,0

            if not s and not t-b2 and not u-b1+a1*b2: numer+=c
            Y[(a1,a2,b2,0,s,t-b2,u-b1)]+=c

        thresh-=1

main()

Qui stiamo mantenendo traccia dei primi due elementi A, gli ultimi due elementi B(dove b2è l'ultimo elemento), ed i prodotti interni di (A[:n], B), (A[1:n], B[:-1])e (A[2:n], B[:-2]).


.... ha raggiunto N_MAX con 21.20 secondi rimanenti
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.