Calcola esattamente una probabilità


9

Questa attività riguarda la scrittura di codice per calcolare esattamente una probabilità. 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 al Asuo primo valore. Cioè A[1] = A[n+1]se l'indicizzazione da 1. Aora ha lunghezza n+1. 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.

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 due prodotti interni sono 0e 2.

Consideriamo ora il prodotto interno A[1,...,n]e Bed il prodotto interno di A[2,...,n+1]e B.

Il codice deve generare la probabilità che entrambi i prodotti interni siano zero.

Per n=1questa probabilità è chiaramente 1/2.

Non mi importa come nviene specificato nel codice, ma dovrebbe essere molto semplice ed ovvio come modificarlo.

Lingue e biblioteche

Puoi usare qualsiasi lingua e librerie che ti piacciono. Vorrei eseguire il tuo codice, quindi per favore includi una spiegazione completa su come eseguire / compilare il tuo codice in Linux, se possibile.


2
I casi di test per i primi nsarebbero utili. Anche un esempio esplicito di A, B e dei due prodotti interni potrebbe essere d'aiuto.
Martin Ender,

Se scegliamo di codificare il numero intero, n=4conta come zero, due o tre byte? L'output deve essere esattamente a/b o sarebbe [a b], ad esempio, consentito?
Dennis,

@Dennis Deve essere esatto. Se decodifichi il numero intero dovrò cambiarlo in un solo posto per cambiarlo n? Altrimenti, penso che non sia permesso.

Sì, il mio programma usa l'intero solo una volta per calcolare una potenza cartesiana. Tutto il resto deriva dall'array risultante.
Dennis,

Risposte:


7

Pyth, 48 47 46 44 byte

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

Provalo online: dimostrazione

La versione online probabilmente non viene calcolata n=6. Sul mio laptop (versione offline) sono necessari circa 45 secondi.

Approccio a forza bruta.

Spiegazione:

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

dang, dimenticato di gcd, sapeva che c'era qualcosa che mi mancava
Maltysen il

+0r1_2è più corto di /R2r2_2.
Isaacg,

Penso che sia giusto dovrebbe essere la versione 89/512 che conti.

@Lembik Ok Modificato.
Jakube

Devo ammetterlo, non mi è mai venuto in mente che questo potesse essere fatto in 47 caratteri!

8

Mathematica, 159 100 87 86 85 byte

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

Per cambiare nbasta cambiare la definizione della variabile all'inizio.

Dal momento che è una forza bruta è piuttosto lento, ma ecco i primi otto risultati:

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

L'ultimo ha già impiegato 231 secondi e l'autonomia è orribilmente esponenziale.

Spiegazione

Come ho detto è una forza bruta. In sostanza, sto solo elencando tutto il possibile Ae B, calcolo i due prodotti punto per ogni possibile coppia e quindi trovo la frazione di coppie che ha prodotto {0, 0}. Le funzioni combinatorie di Mathematica e algebra lineare sono state molto utili per giocare a golf:

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

Questo genera tutte le n-tuple contenenti 1o -1, cioè, tutte le possibili A. Per n = 3quello è:

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

Per calcolare Bfacciamo quasi lo stesso:

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

Ripetendo 0, dupliciamo ogni tupla per ciascuna 0che contiene, aumentando così il 0doppio di 1o -1. Sempre usando n = 3come esempio:

{{-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}}

Ora, per ogni possibile A, vogliamo che il prodotto scalare di ciascuna di quelle possibili B, entrambi con A[1 .. n]e A[2 .. n+1]. Ad esempio, se la nostra corrente Aè {1, 1, -1}, vogliamo il prodotto punto con entrambi {1, 1, -1}e con {1, -1, 1}. Dal momento che tutte le nostre Bsono già convenientemente le righe di una matrice, vogliamo le due liste secondarie Acome colonne di un'altra matrice, in modo da poter calcolare un semplice prodotto punto tra loro. Ma trasporre {{1, 1, -1}, {1, -1, 1}}dà semplicemente {{1, 1}, {1, -1}, {-1, 1}}quale è solo un elenco di tutte le liste secondarie cicliche a 2 elementi di A. Questo è ciò che fa:

Partition[#,2,1,1]

Quindi lo calcoliamo e prendiamo il prodotto punto con il nostro elenco di B. Dato che ora otteniamo un elenco nidificato (poiché ogni possibile Aproduce un vettore separato), li appiattiamo con ##&@@.

Per scoprire se una coppia {x, y}è {0, 0}calcoliamo Sign[Norm[{x,y}]] dove Norm√(x²+y²). Questo dà 0o 1.

Infine, dal momento che ora vogliamo solo sapere le frazioni di 1s in un elenco di 0s e 1s tutti abbiamo bisogno è la media aritmetica della lista. Tuttavia, questo produce la probabilità che entrambi i prodotti con almeno un punto siano diversi da zero, quindi lo sottraggiamo 1per ottenere il risultato desiderato.


6

Pyth - 65 55 byte

Bug risolto con riduzione della frazione al costo di un byte.

Utilizza un approccio a forza bruta e può essere giocato a golf enormemente, ma volevo solo ottenere qualcosa là fuori. Molto lento

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

Utilizza i prodotti cartesiani per generare entrambi Ae B, facendo le probabilità variabili facendo 0apparire due volte nell'elenco delle fonti e quindi conta a zero quelli del prodotto interno. Il prodotto interno è facilitato dallo Vzucchero sintattico ectorization. Semplificare la frazione mi spaventava inizialmente, ma era abbastanza facile con la Pfunzione di fattorizzazione della brina e la realizzazione che dobbiamo ridurre solo con potenze di 2.

Provalo online qui .


Come cambio n?

@Lembik Il programma Pyth richiede un input dell'utente, che è specificato nella seconda casella di testo (se si utilizza il compilatore online).
Jakube,

@Jakube Oh grazie! E in realtà sembra funzionare anche :)

6

CJam, 58 57 54 51 46 byte

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

Per eseguirlo, inserire il numero intero desiderato tra WX]e m*.

Grazie a @ jimmy23013 per la magia e per giocare a golf a 5 byte!

Provalo online nell'interprete CJam .

Idea

Molte parti di queste risposte sono semplici, ma utilizza due trucchi accurati:

  • Invece di associare tutti i vettori di {-1, 1} n con tutti i vettori di {-1, 0, 1} n con le probabilità desiderate, considera il numero di terzine di vettori in {-1, 1} n che soddisfano una certa condizione.

    Se aggiungiamo gli ultimi due vettori di una tripletta, il risultato sarà un vettore di {-2, 0, 2} n .

    Poiché (-1) + 1 = 0 = 1 + (-1) , 0 s si verificano due volte più spesso -2 s e 2 s.

    Dividendo ciascun componente per 2 si otterrebbe un vettore di {-1, 0, 1} n con le probabilità desiderate.

    Poiché siamo interessati solo se il prodotto scalare è 0 o no, possiamo saltare la divisione per 2 .

  • Dopo aver contato tutte le terzine che soddisfano le condizioni della domanda e il numero totale di terzine, dobbiamo ridurre la frazione risultante.

    Invece di calcolare il GCD di entrambi i numeri, poiché il denominatore sarà sempre una potenza di 2, è sufficiente dividere entrambi i numeri per la massima potenza di 2 che divide il numeratore.

    Per ottenere la massima potenza di 2 che divide x , possiamo prendere AND bit a bit di x e ~ x + 1 .

    ~ x inverte tutti i bit di x , quindi tutti gli 0 finali che diventano 1 s. Aggiungendo 1 a ~ x , questi 1 s torneranno a 0 se l'ultimo 1 in ~ x + 1 corrisponderà all'ultimo 1 in x .

    Tutti gli altri bit sono entrambi 0 di distinti, quindi il bit bit AND restituisce l'intero composto dall'ultimo 1 di xe da tutti gli 0 s che lo seguono. Questa è la massima potenza di 2 che divide x .

Codice

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.

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

@Jimmy23013: è un po 'di magia impressionante. Grazie!
Dennis,
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.