Calcular exatamente uma probabilidade

9

Esta tarefa é sobre escrever código para calcular exatamente uma probabilidade. A saída deve ser uma probabilidade precisa escrita como uma fração em sua forma mais reduzida. Ou seja, nunca deve produzir, 4/8mas sim 1/2.

Para um número inteiro positivo n, considere uma sequência uniformemente aleatória de 1s e -1s de comprimento ne chame-a de A. Agora concatene Aseu primeiro valor. Ou seja, A[1] = A[n+1]se a indexação de 1. Aagora tiver comprimento n+1. Agora considere também uma segunda sequência aleatória de comprimento ncujos primeiros nvalores sejam -1, 0 ou 1 com probabilidade 1 / 4,1 / 2, 1/4 cada e chame-a de B.

Por exemplo, considere n=3. Valores possíveis para Ae Bpoderiam ser A = [-1,1,1,-1]e B=[0,1,-1]. Nesse caso, os dois produtos internos são 0e 2.

Agora considere o produto interno de A[1,...,n]e Be o produto interno de A[2,...,n+1]e B.

Seu código deve gerar a probabilidade de que ambos os produtos internos sejam zero.

Pois n=1essa probabilidade é clara 1/2.

Não me importo como né especificado no código, mas deve ser muito simples e óbvio como alterá-lo.

Línguas e bibliotecas

Você pode usar qualquer idioma e bibliotecas que desejar. Gostaria de executar o seu código, portanto, inclua uma explicação completa de como executar / compilar seu código no linux, se possível.

Martin Ender
fonte
2
Casos de teste para os primeiros nseriam úteis. Talvez também um exemplo explícito de A, B e dos dois produtos internos possa ajudar.
Martin Ender
Se optarmos por codificar o número inteiro, n=4conta como zero, dois ou três bytes? A saída precisa ser exatamente a/b ou seria [a b], por exemplo, permitida?
Dennis
@ Dennis Tem que ser exato. Se você codificar o número inteiro, terei que alterá-lo apenas em um lugar para alterar n? Caso contrário, acho que isso não é permitido.
Sim, meu programa usa o número inteiro apenas uma vez para calcular uma potência cartesiana. Tudo o resto é derivado da matriz resultante.
Dennis

Respostas:

7

Pitão, 48 47 46 44 bytes

K,smlf!|Fms*Vd.>Tk2^,1_1Q^+0tM3Q^8Qj\//RiFKK

Experimente online: Demonstração

A versão online provavelmente não computa n=6. No meu laptop (versão offline), leva cerca de 45 segundos.

Abordagem de força bruta.

Explicação:

smlf!|Fms*Vd.>Tk2^,1_1Q^+0tM3Q   implicit: Q = input number
                          tM3    the list [-1, 0, 1]
                        +0       add zero, results in [0, -1, 0, 1]
                       ^     Q   all possible lists of length Q using these elements
 m                               map each list d (B in Lembik's notation) to:
                  ,1_1              the list [1, -1]
                 ^    Q             all possible lists of length Q
   f                                filter for lists T (A in Lembik's notation),
                                    which satisfy:
       m        2                      map each k in [0, 1] to:
        s*Vd.>Tk                          scalar-product d*(shifted T by k)
    !|F                                not or (True if both scalar-products are 0)      
  l                                 determine the length                
s                                add all possibilities at the end

K,...^8QQj\//RiFKK   
 ,...^8Q             the list [result of above, 8^Q]
K                    store it in K
              iFK    determine the gcd of the numbers in K
            /R   K   divide the numbers in K by the gcd
         j\/         join the two numbers by "/" and print
Jakube
fonte
Dang, esqueceu mdc, sabia que havia algo que eu perdi
Maltysen
+0r1_2é mais curto que /R2r2_2.
Isaacg
Eu acho que para ser justo, deve ser a versão 89/512 que você conta.
@Lembik Ok Alterou.
Jakube 8/15
Devo admitir que nunca me ocorreu que isso pudesse ser feito em 47 caracteres!
8

Mathematica, 159 100 87 86 85 bytes

n=3;1-Mean@Sign[##&@@Norm/@({1,0,0,-1}~t~n.Partition[#,2,1,1])&/@{1,-1}~(t=Tuples)~n]

Para mudar nbasta alterar a definição da variável no início.

Como a força bruta é bastante lenta, mas aqui estão os oito primeiros resultados:

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

O último já levou 231 segundos e o tempo de execução é terrivelmente exponencial.

Explicação

Como eu disse, é força bruta. Basicamente, estou apenas enumerando tudo possível Ae Bcalcule os dois produtos de ponto para cada par possível e, em seguida, encontre a fração de pares que produziu {0, 0}. As funções combinatória e de álgebra linear do Mathematica foram bastante úteis no golfe:

{1,-1}~(t=Tuples)~n

Isso gera todas as n-tuplas que contêm 1ou -1, ou seja, tudo possível A. Pois n = 3isso é:

{{1, 1, 1}, 
 {1, 1, -1}, 
 {1, -1, 1}, 
 {1, -1, -1}, 
 {-1, 1, 1}, 
 {-1, 1, -1}, 
 {-1, -1, 1}, 
 {-1, -1, -1}}

Para calcular B, fazemos quase o mesmo:

{1,0,0,-1}~t~n

Repetindo 0, duplicamos cada tupla para cada um 0que contém, aumentando assim a 0probabilidade de duas vezes 1ou -1. Novamente usando n = 3como exemplo:

{{-1, -1, -1},
 {-1, -1, 0}, {-1, -1, 0},
 {-1, -1, 1},
 {-1, 0, -1}, {-1, 0, -1},
 {-1, 0, 0}, {-1, 0, 0}, {-1, 0, 0}, {-1, 0, 0},
 {-1, 0, 1}, {-1, 0, 1},
 {-1, 1, -1},
 {-1, 1, 0}, {-1, 1, 0},
 {-1, 1, 1},
 {0, -1, -1}, {0, -1, -1},
 {0, -1, 0}, {0, -1, 0}, {0, -1, 0}, {0, -1, 0},
 {0, -1, 1}, {0, -1, 1},
 {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
 {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
 {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, {0, 0, 1},
 {0, 1, -1}, {0, 1, -1},
 {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0},
 {0, 1, 1}, {0, 1, 1},
 {1, -1, -1},
 {1, -1, 0}, {1, -1, 0},
 {1, -1, 1},
 {1, 0, -1}, {1, 0, -1},
 {1, 0, 0}, {1, 0, 0}, {1, 0, 0}, {1, 0, 0},
 {1, 0, 1}, {1, 0, 1},
 {1, 1, -1},
 {1, 1, 0}, {1, 1, 0},
 {1, 1, 1}}

Agora, para cada possível A, queremos o produto escalar de cada uma delas possível B, com A[1 .. n]e A[2 .. n+1]. Por exemplo, se nossa atual Aé {1, 1, -1}, queremos o produto escalar com ambos {1, 1, -1}e com {1, -1, 1}. Como todas as nossas Bjá são convenientemente as linhas de uma matriz, queremos as duas sublistas Acomo colunas de outra matriz, para que possamos calcular um simples produto de ponto entre elas. Mas a transposição {{1, 1, -1}, {1, -1, 1}}simplesmente fornece {{1, 1}, {1, -1}, {-1, 1}}qual é apenas uma lista de todas as sublistas cíclicas de 2 elementos A. É o que isso faz:

Partition[#,2,1,1]

Então calculamos isso e pegamos o produto escalar com nossa lista de B. Como agora obtemos uma lista aninhada (uma vez que cada possível Agera um vetor separado), as aplainamos ##&@@.

Para saber se um par {x, y}é {0, 0}calculamos Sign[Norm[{x,y}]] onde Norm√(x²+y²). Isso dá 0ou 1.

Finalmente, uma vez que agora só quero saber as frações de 1s em uma lista de 0s e 1s toda necessidade que é a média aritmética da lista. No entanto, isso gera a probabilidade de que pelo menos um produto de ponto seja diferente de zero, então subtraímos 1para obter o resultado desejado.

Martin Ender
fonte
6

Pitão - 65 55 bytes

Corrigido o erro com redução de fração ao custo de um byte.

Usa a abordagem de força bruta e pode jogar muito golfe, mas só queria obter algo por aí. Muito devagar

*F-KP/Jmms*Vked,thdPhd*makhk^,1_1Q^[1ZZ_1)Q,ZZ2/lJ^2/K2

Ele usa produtos cartesianos para gerar ambos Ae B, fazendo as probabilidades variáveis, fazendo 0aparecer duas vezes na lista de fontes e, em seguida, conta como zero o produto interno. O produto interno é facilitado pelo Vaçúcar sintático da ectorização. Simplificar a fração estava me assustando inicialmente, mas era bastante fácil com a Pfunção de fatoração de rime e a percepção de que só precisamos reduzir por potências de 2.

Experimente online aqui .

Maltysen
fonte
Como eu mudo n?
@Lembik O programa Pyth solicita uma entrada do usuário, especificada na segunda caixa de texto (se você usar o compilador online).
Jakube 7/07
@Jakube Oh thanks! E ele realmente parece funcionar também :)
6

CJam, 58 57 54 51 46 bytes

WX]m*Zm*_{~.+2,@fm<\f.*::+0-!},,__~)&:T/'/@,T/

Para executá-lo, insira o número inteiro desejado entre WX]e m*.

Obrigado a @ jimmy23013 pela mágica dos bits e por jogar fora 5 bytes!

Experimente on-line no intérprete CJam .

Idéia

A maioria das partes dessas respostas é direta, mas usa dois truques:

  • Em vez de emparelhar todos os vetores de {-1, 1} n com todos os vetores de {-1, 0, 1} n com as probabilidades desejadas, considera-se contar o número de trigêmeos de vetores em {-1, 1} n que satisfazem uma certa condição.

    Se adicionarmos os dois últimos vetores de um trigêmeo, o resultado será um vetor de {-2, 0, 2} n .

    Desde (-1) + 1 = 0 = 1 + (-1) , 0 s ocorrerá duas vezes tão frequentemente quanto -2 s e 2 s.

    Dividir cada componente por 2 produziria um vetor de {-1, 0, 1} n com as probabilidades desejadas.

    Como estamos interessados ​​apenas se o produto escalar for 0 ou não, podemos pular a divisão por 2 .

  • Depois de contar todos os trigêmeos que satisfazem a condição da pergunta e o número total de trigêmeos, temos que reduzir a fração resultante.

    Em vez de calcular o MDC de ambos os números, como o denominador sempre terá uma potência de 2, basta dividir os dois números pela potência mais alta de 2 que divide o numerador.

    Para obter a potência mais alta de 2 que divide x , podemos tomar o AND bit a bit de x e ~ x + 1 .

    ~ x inverte todos os bits de X , então todos os arrasto 0 s tornam-se 1 s. Ao adicionar 1 a ~ x , esses 1 s voltarão a 0 se o último 1 em ~ x + 1 corresponderá ao último 1 em x .

    Todos os outros bits são 0 de distintos, portanto, AND bit a bit retorna o número inteiro que consiste no último 1 de x e em todos os 0 s que o seguem. Esta é a potência mais alta de 2 que divide x .

Código

WX]    e# Push the array [-1 1].
       e# Insert N here.
m*     e# Cartesian product: Push the array of all vectors of {-1,1}^N.
Zm*    e# Cartesian product: Push the array of all triplets of these vectors.
_      e# Copy the array.
{      e# Filter; for each triplet of vectors U, V and W in {-1,1}^N:
  ~    e#   Dump U, V and W on the stack.
  .+   e#   Compute X := V + W, a vector of {-2,0,2}^N, where each component is
       e#   zero with probability 1/2.
  2,@  e#   Push [0 1]. Rotate U on top of it.
  fm<  e#   Push [U U'], where U' is U rotated one dimension to the left.
  \f.* e#   Push [U*X and U'*X], where * denotes the vectorized product.
  ::+  e#   Add the components of both products.
  0-   e#   Remove zeroes.
       e#   Push the logical NOT of the array.
},     e#   If the array was empty, keep the triplet.
,      e# Push X, the length of the filtered array.
__~)&  e# Push X & ~X + 1.
:T     e# Save the result in T and divide X by T.
'/     e# Push a slash.
@,T/   e# Dividet he length of the unfiltered array by T.
Dennis
fonte
WX]m*Zm*_{~.+2,@fm<\f.*::+0-!},,__W*&:T/'/@,T/.
jimmy23013
@ jimmy23013: Isso é um pouco impressionante de mágica. Obrigado!
Dennis