Probabilidades: ¿qué tan alto puedes llegar?

10

Anteriormente hice una pregunta sobre cómo calcular una probabilidad de forma rápida y precisa. Sin embargo, evidentemente fue demasiado fácil ya que se le dio una solución de forma cerrada. Aquí hay una versión más difícil.

Esta tarea consiste en escribir código para calcular una probabilidad de manera exacta y rápida . El resultado debe ser una probabilidad precisa escrita como una fracción en su forma más reducida. Es decir, nunca debería salir, 4/8sino más bien 1/2.

Para algún número entero positivo n, considere una cadena uniformemente aleatoria de 1s y -1s de longitud ny llámela A. Ahora concatene a Auna copia de sí mismo. Eso es A[1] = A[n+1]si indexa desde 1, A[2] = A[n+2]y así sucesivamente. AAhora tiene longitud 2n. Ahora también considere una segunda cadena aleatoria de longitud ncuyos primeros nvalores son -1, 0 o 1 con probabilidad 1 / 4,1 / 2, 1/4 cada uno y llámelo B.

Ahora considere el producto interno de Bcon A[1+j,...,n+j]para diferente j =0,1,2,....

Por ejemplo, considere n=3. Los posibles valores de Ay Bpodrían ser A = [-1,1,1,-1,...]y B=[0,1,-1]. En este caso, los dos primeros productos internos son 0y 2.

Tarea

Para cada uno j, comenzando j=1, su código debería generar la probabilidad de que todos los primeros j+1productos internos sean cero para cada uno n=j,...,50.

Copiando la tabla producida por Martin Büttner para obtener j=1los siguientes resultados de muestra.

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

Puntuación

Su puntaje es el más grande que jsu código completa en 1 minuto en mi computadora. Para aclarar un poco, cada juno tiene un minuto. Tenga en cuenta que el código de programación dinámica en la pregunta vinculada anterior lo hará fácilmente j=1.

Desempate

Si dos entradas obtienen el mismo jpuntaje, la entrada ganadora será la que obtenga la mayor puntuación nen un minuto en mi máquina para eso j. Si las dos mejores entradas son iguales en este criterio también, entonces el ganador será la respuesta presentada primero.

Idiomas y bibliotecas

Puede utilizar cualquier idioma y bibliotecas disponibles gratuitamente que desee. Debo poder ejecutar su código, así que incluya una explicación completa sobre cómo ejecutar / compilar su código en Linux si es posible.

Mi máquina Los tiempos se ejecutarán en mi máquina. Esta es una instalación estándar de ubuntu en un procesador AMD FX-8350 de ocho núcleos. Esto también significa que necesito poder ejecutar su código.

Entradas ganadoras

  • j=2en Python por Mitch Schwartz.
  • j=2en Python por feersum. Actualmente la entrada más rápida.
Comunidad
fuente
Si la pregunta no está clara de alguna manera, hágamelo saber para que pueda solucionarlo rápidamente.
2
Eres, con mucho, mi pregunta favorita. Por otra parte, sí tengo algo para calcular valores de manera exacta y rápida .
primo
@primo Gracias! ¿Esto significa que podemos esperar una respuesta en RPython? :)
¿Podría poner la diferencia entre esta pregunta y la otra?
kirbyfan64sos
@ kirbyfan64sos La otra es esencialmente la misma pregunta para `j = 1` solamente.

Respuestas:

3

Pitón 2, j = 2

Traté de encontrar una especie de 'forma cerrada' para j = 2. Tal vez podría hacer una imagen de MathJax, aunque sería realmente feo con todo el violín del índice. Escribí este código no optimizado solo para probar la fórmula. Tarda aproximadamente 1 segundo en completarse. Los resultados coinciden con el código de 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)

Considere una secuencia donde el miembro i-ésimo es esi A [i] == A [i + 1] o nsi A [i]! = A [i + 1]. ien el programa es el número de ns. Si ies par, la secuencia debe comenzar y terminar con e. Si ies impar, la secuencia debe comenzar y terminar con n. Las secuencias se clasifican además por el número de corridas de so es consecutivas n. Hay j+ 1 de uno y jdel otro.

Cuando la idea paseo aleatorio se extiende a 3 dimensiones, existe un problema desafortunado que hay 4 posibles direcciones para caminar en (uno para cada uno de ee, en, ne, o nn) que significa que no son linealmente dependientes. Entonces, el kíndice suma el número de pasos dados en una de las direcciones (1, 1, 1). Luego habrá un número exacto de pasos que se deben seguir en las otras 3 direcciones para cancelarlo.

P (n, p) da el número de particiones ordenadas de n objetos en p partes. W (l, d) da el número de formas para que una caminata aleatoria de lpasos recorra una distancia de exactamente d. Como antes, hay 1 posibilidad de moverse hacia la izquierda, 1 oportunidad de moverse hacia la derecha y 2 para quedarse.

Feersum
fuente
¡Gracias! Una imagen de la fórmula sería realmente genial.
Gracias por la explicación. ¡Lo haces parecer simple! Acabo de ver tu comentario para el que podrías hacer una solución j=3. ¡Eso sería sorprendente!
3

Python, j = 2

El enfoque de programación dinámica para j = 1mi respuesta a la pregunta anterior no necesita muchas modificaciones para funcionar en niveles superiores j, pero se ralentiza rápidamente. Tabla de referencia:

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

Y el código:

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()

Aquí estamos hacer el seguimiento de los dos primeros elementos de A, los dos últimos elementos de B(donde b2es el último elemento), y los productos internos de (A[:n], B), (A[1:n], B[:-1]), y (A[2:n], B[:-2]).

Mitch Schwartz
fuente
.... alcanzó N_MAX con 21.20 segundos restantes