Convergenza di un processo di Markov


10

Sfida

Data una matrice stocastica sinistra o destra in cui il limite come x si avvicina all'infinito della matrice alla potenza di x si avvicina a una matrice con tutti i valori finiti, restituire la matrice a cui converge la matrice. Fondamentalmente, si desidera continuare a moltiplicare la matrice da sola fino a quando il risultato non cambia più.

Casi test

[[7/10, 4/10], [3/10, 6/10]] -> [[4/7, 4/7], [3/7, 3/7]]
[[2/5, 4/5], [3/5, 1/5]] -> [[4/7, 4/7], [3/7, 3/7]]
[[1/2, 1/2], [1/2, 1/2]] -> [[1/2, 1/2], [1/2, 1/2]]
[[1/3, 2/3], [2/3, 1/3]] -> [[1/2, 1/2], [1/2, 1/2]]
[[1/10, 2/10, 3/10], [4/10, 5/10, 6/10], [5/10, 3/10, 1/10]] -> [[27/130, 27/130, 27/130], [66/130, 66/130, 66/130], [37/130, 37/130, 37/130]]
[[1/7, 2/7, 4/7], [2/7, 4/7, 1/7], [4/7, 1/7, 2/7]] -> [[1/3, 1/3, 1/3], [1/3, 1/3, 1/3], [1/3, 1/3, 1/3]]

Regole

  • Si applicano scappatoie standard
  • Puoi scegliere se vuoi una matrice destra o sinistra stocastica
  • È possibile utilizzare qualsiasi tipo di numero ragionevole, come float, razionali, decimali di precisione infinita, ecc
  • Questo è , quindi l'invio più breve in byte per ogni lingua è dichiarato il vincitore per la sua lingua. Nessuna risposta sarà accettata

@FryAmTheEggman sembra che alcuni commenti precedenti siano stati eliminati, quindi questo potrebbe essere ridondante, ma le matrici riducibili e periodiche sono già escluse da "Dato una matrice sinistra o destra stocastica in cui il limite come x si avvicina all'infinito della matrice alla potenza di x si avvicina a una matrice con tutti i valori finiti ", che leggo dicendo che l'input è garantito per convergere in una soluzione unica. (vale a dire che la matrice di input è garantita per essere ergodica.)
Nathaniel

@Nathaniel Questo non è del tutto vero, poiché se la catena è riducibile puoi avere un risultato (come per la matrice identità) che soddisfa ciò che hai detto ma la catena che descrive non è irriducibile e quindi l'input non sarebbe garantito essere ergodico (poiché non sarà ricorrente ricorrente). Garantire ergodicità è ciò che l'OP vuole, e penso che lo abbiano ora, grazie al vincolo aggiuntivo di tutti i valori di riga identici. Se conosci un modo migliore per limitare l'input senza dover aggiungere una spiegazione delle catene di Markov, sono sicuro che HyperNeutrino lo apprezzerebbe! :)
FryAmTheEggman

1
@FryAmTheEggman ah, hai ragione, scusa. Stavo pensando all'iterazione del potere piuttosto che elevare la matrice a un potere. (Quindi per "soluzione unica" intendevo "uno indipendente dal punto di partenza del processo di iterazione", ma qui non è rilevante.) Concordo sul fatto che la condizione 'tutte le righe sono identiche' fa il lavoro. Suppongo che l'OP potrebbe semplicemente dire "la catena Markov è garantita per essere ergodica", il che soddisferebbe le persone come noi che probabilmente si preoccuperanno!
Nathaniel

In realtà, se B è una soluzione a BA = B , allora lo è anche cB per qualsiasi costante scalare c . Quindi una soluzione diversa da zero non può essere strettamente unica, a meno che non si risolva in qualche modo la scala. (Richiedere che B sia stocastico lo farebbe.) Inoltre, ovviamente, se le sue file o le colonne di B sono uguali dipenderà dal fatto che A sia stocastico di sinistra o di destra.
Ilmari Karonen l'

2
Per chiunque non abbia mai imparato a conoscere le matrici durante le lezioni di matematica al liceo e come moltiplicarle: mathsisfun.com/algebra/matrix-multiplying.html . Ho dovuto cercare per capire cosa mi veniva chiesto .. Forse è conoscenza comune altrove sulla Terra ..: S
Kevin Cruijssen

Risposte:


7

R ,  44  43 byte

function(m){X=m
while(any(X-(X=X%*%m)))0
X}

Provalo online!

Continua a moltiplicarsi fino a quando non trova una matrice fissa. Apparentemente X!=(X=X%*%m)fa il confronto, quindi riassegna X, quindi è pulito.

Grazie a @Vlo per la rasatura di un byte; anche se barrato 44 è ancora regolare 44.


1
Mi chiedo perché function(m){ while(any(m!=(m=m%*%m)))0 m}non funzioni. Inesattezze numeriche che impediscono l'attivazione della condizione di risoluzione?
Codici A Caos

@CodesInChaos molto probabilmente è una mancanza di precisione. Il passaggio a una libreria di precisione arbitraria non aiuta, neanche - vanno in timeout (Rmpfr) o falliscono (gmp) allo stesso modo, anche se probabilmente sto facendo qualcosa di sbagliato.
Giuseppe

@Giuseppe Immagino che l'approccio suggerito venga ripetuto a quadratura fino a quando non cambia più? (Non riesco a leggere R)
user202729

@ user202729 sì, lo è. R utilizza numeri in virgola mobile a 64 bit e so che gli errori si propagano abbastanza rapidamente.
Giuseppe

Penso che l'algoritmo sia instabile. Anche la gelatina ha lo stesso problema. (TODO lo dimostra e trova un'alternativa)
user202729

5

Ottava ,45 42 35 byte

@(A)([v,~]=eigs(A,1))/sum(v)*any(A)

Provalo online!

Salvato 3 byte grazie a Giuseppe e altri 7 grazie a Luis Mendo!

Questo utilizza che l'autovettore corrispondente all'autovalore 1 (anche l'autovalore massimo) è il vettore di colonna che si ripete per ciascun valore della matrice limitante. Dobbiamo normalizzare il vettore per avere la somma 1 affinché sia ​​stocastico, quindi semplicemente lo ripetiamo per riempire la matrice. Non sono molto esperto nel golf Octave, ma non sono stato in grado di trovare un modo funzionale per fare ripetute moltiplicazioni, e un programma completo sembra che sarà sempre più lungo di così.

Possiamo usare any(A)poiché dalle restrizioni sappiamo che la matrice deve descrivere una catena irriducibile di Markov, e quindi ogni stato deve essere raggiungibile dagli altri stati. Pertanto almeno un valore in ogni colonna deve essere diverso da zero.


Come eigsrestituisce sempre l'autovettore corrispondente 1? Il mio ricordo delle catene markov è un po 'confuso.
Giuseppe


@Giuseppe Poiché la matrice è stocastica, e un paio di altre cose, il suo autovalore massimo è 1 e eigsritorna a partire dall'autovalore più grande. Inoltre, grazie per il golf!
FryAmTheEggman

Ah giusto. Le catene di Markov sono al mio prossimo esame, ma poiché è per attuari, alcuni dettagli mancano del tutto.
Giuseppe



3

APL (Dyalog) , 18 6 byte

12 byte salvati grazie a @ H.PWiz

+.×⍨⍣≡

Provalo online!


+.×⍨⍣≡per 6 byte. Cioè, piazza fino a quando non cambia nulla
H.Piz,

@ H.PWiz Credo di si. Non ho idea del perché non l'ho fatto in primo luogo. Grazie!
Uriel

3

k / q, 10 byte

k / q perché il programma è identico in entrambe le lingue. Il codice è davvero solo idiomatico k / q.

{$[x]/[x]}

Spiegazione

{..}è fuori la sintassi lambda, con xcome parametro implicito

$[x] ha $ come operatore di moltiplicazione della matrice binaria, fornendo solo un parametro crea un operatore unario che ha lasciato moltiplicare per la matrice di Markov

/[x] applica la moltiplicazione sinistra fino alla convergenza, iniziando con x stessa.


3

C (gcc) , 207 192 190 181 181 byte + 2 byte di bandiera-lm

  • Risparmiato quindici diciassette ventidue byte grazie a plafoniera .
  • Salvataggio di nove byte; rimozione return A;.
float*f(A,l,k,j)float*A;{for(float B[l*l],S,M=0,m=1;fabs(m-M)>1e-7;wmemcpy(A,B,l*l))for(M=m,m=0,k=l*l;k--;)for(S=j=0;j<l;)m=fmax(m,fdim(A[k],B[k]=S+=A[k/l*l+j]*A[k%l+j++*l]));}

Provalo online!


@ceilingcat Contando i byte flag del compilatore, si ottiene nuovamente 192. Incluso comunque il tuo suggerimento.
Jonathan Frech,

@ceilingcat Grazie.
Jonathan Frech,

2

Python 3 , 75 61 byte

f=lambda n:n if allclose(n@n,n)else f(n@n)
from numpy import*

Provalo online!

Nei casi di test ci sono imprecisioni del float, quindi i valori possono differire di un po 'dalle frazioni esatte.

PS. numpy.allclose()viene utilizzato perché numpy.array_equal()è più lungo e soggetto a fluttuare inesattezze.

-14 byte Grazie HyperNeutrino;) Oh sì, ho dimenticato l'operatore @; P


Utilizzare dotinvece di matmul: D
HyperNeutrino

In realtà, prendi array intorpiditi come input e fai x=n@n: P tio.run/…
HyperNeutrino


Aggiunto f=in primo piano perché viene chiamato in modo ricorsivo;)
Shieru Asakoto

Oh sì hai ragione :) buona chiamata!
HyperNeutrino

2

Java 8, 356 339 byte

import java.math.*;m->{BigDecimal t[][],q;RoundingMode x=null;for(int l=m.length,f=1,i,k;f>0;m=t.clone()){for(t=new BigDecimal[l][l],i=l*l;i-->0;)for(f=k=0;k<l;t[i/l][i%l]=(q!=null?q:q.ZERO).add(m[i/l][k].multiply(m[k++][i%l])))q=t[i/l][i%l];for(;++i<l*l;)f=t[i/l][i%l].setScale(9,x.UP).equals(m[i/l][i%l].setScale(9,x.UP))?f:1;}return m;}

-17 byte grazie a @ceilingcat .

Sicuramente non la lingua giusta .. Accidenti precisione in virgola mobile ..

Spiegazione:

Provalo online.

import java.math.*;     // Required import for BigDecimal and RoundingMode
m->{                    // Method with BigDecimal-matrix as both parameter and return-type
  BigDecimal t[][],q;   //  Temp BigDecimal-matrix
  RoundingMode x=null;  //  Static RoundingMode value to reduce bytes
  for(int l=m.length,   //  The size of the input-matrix
          f=1,          //  Flag-integer, starting at 1
          i,k;          //  Index-integers
      f>0;              //  Loop as long as the flag-integer is still 1
      m=t.clone()){     //    After every iteration: replace matrix `m` with `t`
    for(t=new BigDecimal[l][l],
                        //   Reset matrix `t`
        i=l*l;i-->0;)   //   Inner loop over the rows and columns
      for(f=k=0;        //    Set the flag-integer to 0
          k<l           //    Inner loop to multiply
          ;             //      After every iteration:
           t[i/l][i%l]=(q!=null?q:q.ZERO).add(
                        //       Sum the value at the current cell in matrix `t` with:
             m[i/l][k]  //        the same row, but column `k` of matrix `m`,
             .multiply(m[k++][i%l])))
                        //        multiplied with the same column, but row `k` of matrix `m`
        q=t[i/l][i%l];  //     Set temp `q` to the value of the current cell of `t`
    for(;++i<l*l;)      //   Loop over the rows and columns again
      f=t[i/l][i%l].setScale(9,x.UP).equals(m[i/l][i%l].setScale(9,x.UP))?
                        //    If any value in matrices `t` and `m` are the same:
         f              //     Leave the flag-integer unchanged
        :               //    Else (they aren't the same):
         1;}            //     Set the flag-integer to 1 again
  return m;}            //  Return the modified input-matrix `m` as our result

Perché la funzione principale è così dettagliata?
user202729

@ user202729 Perché float/ doublenon avere la corretta precisione in virgola mobile, java.math.BigDecimaldovrebbe essere usato invece. E invece di semplicemente +-*/, BigDecimals usano .add(...), .subtract(...), .multiply(...), .divide(...). Quindi qualcosa semplicemente come 7/10diventa new BigDecimal(7).divide(new BigDecimal(10)). Inoltre, i valori ,scale,RoundingModein dividesono richiesti per valori con valori decimali "infiniti" (come 1/3essere 0.333...). Il metodo principale può ovviamente essere giocato a golf, ma non mi sono preoccupato quando ho fatto una ricerca e sostituzione per convertire i galleggianti in BigDecimals.
Kevin Cruijssen l'

@ceilingcat Grazie!
Kevin Cruijssen,
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.