Convergence d'un processus de Markov

10

Défi

Étant donné une matrice stochastique gauche ou droite où la limite lorsque x s'approche de l'infini de la matrice à la puissance de x s'approche d'une matrice avec toutes les valeurs finies, retournez la matrice vers laquelle la matrice converge. Fondamentalement, vous souhaitez continuer à multiplier la matrice par elle-même jusqu'à ce que le résultat ne change plus.

Cas de 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]]

Règles

  • Les échappatoires standard s'appliquent
  • Vous pouvez choisir si vous voulez une matrice stochastique droite ou gauche
  • Vous pouvez utiliser n'importe quel type de nombre raisonnable, comme les flottants, les rationnels, les décimales de précision infinie, etc.
  • Il s'agit de , donc la soumission la plus courte en octets pour chaque langue est déclarée gagnante pour sa langue. Aucune réponse ne sera acceptée
HyperNeutrino
la source
@FryAmTheEggman il semble que certains commentaires antérieurs aient été supprimés, donc cela pourrait être redondant, mais les matrices réductibles et périodiques sont déjà exclues par "Étant donné une matrice stochastique gauche ou droite où la limite lorsque x s'approche de l'infini de la matrice à la puissance de x se rapproche d'une matrice avec toutes les valeurs finies ", que j'ai lu comme disant que l'entrée est garantie de converger vers une solution unique. (c'est-à-dire que la matrice d'entrée est garantie d'être ergodique.)
Nathaniel
@Nathaniel Ce n'est pas tout à fait vrai, comme si la chaîne est réductible, vous pouvez avoir un résultat (comme pour la matrice d'identité) qui correspond à ce que vous avez dit mais la chaîne qu'elle décrit n'est pas irréductible et donc l'entrée ne serait pas garantie de être ergodique (car il ne sera pas récurrent positif). Garantir l'ergodicité est ce que souhaite l'OP, et je pense qu'ils l'ont maintenant, grâce à la contrainte supplémentaire de toutes les valeurs de ligne étant identiques. Si vous connaissez une meilleure façon de contraindre l'entrée sans avoir besoin d'ajouter une explication des chaînes de Markov, je suis sûr que HyperNeutrino l'apprécierait! :)
FryAmTheEggman
1
@FryAmTheEggman ah, vous avez raison, désolé. Je pensais à l'itération de puissance plutôt qu'à élever la matrice à une puissance. (Donc, par «solution unique», j'entendais «une solution indépendante du point de départ du processus d'itération», mais ce n'est pas pertinent ici.) Je suis d'accord que la condition «toutes les lignes sont identiques» fait l'affaire. Je suppose que l'OP pourrait simplement dire "la chaîne Markov est garantie d'être ergodique", ce qui satisferait des gens comme nous qui sont susceptibles de s'en inquiéter!
Nathaniel
En fait, si B est une solution à BA = B , alors cB l' est aussi pour toute constante scalaire c . Une solution non nulle ne peut donc pas être strictement unique, à moins que vous ne corrigiez l'échelle d'une manière ou d'une autre. (Exiger que B soit stochastique le ferait.) De plus, évidemment, que ce soit les lignes ou les colonnes de B qui soient égales dépendra de si A est gauche ou droit stochastique.
Ilmari Karonen
2
Pour tous ceux qui n'ont jamais entendu parler des matrices pendant les cours de mathématiques au lycée et comment les multiplier: mathsisfun.com/algebra/matrix-multiplying.html . J'ai dû chercher pour comprendre ce qui était demandé .. C'est peut-être une connaissance commune ailleurs sur Terre ..: S
Kevin Cruijssen

Réponses:

7

R ,  44  43 octets

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

Essayez-le en ligne!

Continue de multiplier jusqu'à ce qu'il trouve une matrice fixe. Apparemment, X!=(X=X%*%m)fait la comparaison, puis réaffecte X, donc c'est bien.

Merci à @Vlo d'avoir rasé un octet; même si barré 44 est toujours régulier 44.

Giuseppe
la source
1
Je me demande pourquoi function(m){ while(any(m!=(m=m%*%m)))0 m}ça ne marche pas. Des inexactitudes numériques empêchant la condition de terminaison de se déclencher?
CodesInChaos
@CodesInChaos est très probablement un manque de précision. Passer à une bibliothèque de précision arbitraire n'aide pas non plus - ils expirent (Rmpfr) ou échouent (gmp) de la même manière, bien que je fasse probablement quelque chose de mal.
Giuseppe
@ Giuseppe Je suppose que l'approche suggérée est répétée au carré jusqu'à ce qu'elle ne change plus? (Je ne peux pas lire R)
user202729
@ user202729 oui c'est ça. R utilise des nombres à virgule flottante 64 bits et je sais que les erreurs se propagent assez rapidement.
Giuseppe
Je pense que cet algorithme est instable. Jelly a aussi le même problème. (TODO le prouve et trouve une alternative)
user202729
5

Octave ,45 42 35 octets

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

Essayez-le en ligne!

Enregistré 3 octets grâce à Giuseppe et 7 autres grâce à Luis Mendo!

Cela utilise que le vecteur propre correspondant à la valeur propre 1 (également la valeur propre maximale) est le vecteur de colonne qui est répété pour chaque valeur de la matrice limite. Nous devons normaliser le vecteur pour avoir la somme 1 pour qu'il soit stochastique, puis nous le répétons simplement pour remplir la matrice. Je ne connais pas très bien le golf d'Octave, mais je n'ai pas réussi à trouver un moyen fonctionnel de faire des multiplications répétées, et un programme complet semble être toujours plus long que cela.

Nous pouvons utiliser any(A)car des restrictions nous savons que la matrice doit décrire une chaîne de Markov irréductible, et donc chaque état doit être accessible à partir des autres états. Par conséquent, au moins une valeur dans chaque colonne doit être différente de zéro.

FryAmTheEggman
la source
Comment eigsrenvoie toujours le vecteur propre correspondant 1? Ma mémoire des chaînes de Markov est un peu floue.
Giuseppe
42 octets
Giuseppe
@Giuseppe Parce que la matrice est stochastique, et quelques autres choses, sa valeur propre maximale est 1 et eigsretourne à partir de la plus grande valeur propre. Merci aussi pour le golf!
FryAmTheEggman
Ah, c'est vrai. Les chaînes de Markov sont à mon prochain examen, mais comme c'est pour les actuaires, certains détails manquent complètement.
Giuseppe
3

APL (Dyalog) , 18 6 octets

12 octets enregistrés grâce à @ H.PWiz

+.×⍨⍣≡

Essayez-le en ligne!

Uriel
la source
+.×⍨⍣≡pour 6 octets. Autrement dit, carré jusqu'à ce que rien ne change
H.PWiz
@ H.PWiz Je crois que oui. Je ne sais pas pourquoi je ne l'avais pas fait en premier lieu. Merci!
Uriel
3

k / q, 10 octets

k / q car le programme est identique dans les deux langues. Le code est vraiment juste idiomatique k / q.

{$[x]/[x]}

Explication

{..}est hors syntaxe lambda, avec xcomme paramètre implicite

$[x] a $ comme opérateur de multiplication de matrice binaire, fournir un seul paramètre crée un opérateur unaire qui a laissé des multiplications par la matrice de Markov

/[x] applique la multiplication gauche jusqu'à la convergence, en commençant par x lui-même.

ulucs
la source
3

C (gcc) , 207 192 190 181 176 octets + 2 octets d'indicateur-lm

  • Économisé quinze dix - sept vingt-deux octets grâce au plafond .
  • Enregistré neuf octets; suppression 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]));}

Essayez-le en ligne!

Jonathan Frech
la source
@ceilingcat En comptant les octets d'indicateur du compilateur, cela se traduit à nouveau par 192. Inclus néanmoins votre suggestion.
Jonathan Frech
@ceilingcat Merci.
Jonathan Frech
2

Python 3 , 75 61 octets

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

Essayez-le en ligne!

Dans les cas de test, il existe des inexactitudes flottantes, de sorte que les valeurs peuvent différer légèrement des fractions exactes.

PS. numpy.allclose()est utilisé parce qu'il numpy.array_equal()est plus long et sujet à des inexactitudes flottantes.

-14 octets Merci HyperNeutrino;) Oh oui j'ai oublié l'opérateur @; P

Shieru Asakoto
la source
Utiliser dotau lieu de matmul: D
HyperNeutrino
En fait, prenez les tableaux numpy en entrée et faites x=n@n: P tio.run/…
HyperNeutrino
59 octets
HyperNeutrino
Ajouté à l'arrière f=car il est appelé récursivement;)
Shieru Asakoto
Oh ouais tu as raison :) bon appel!
HyperNeutrino
2

Java 8, 356 339 octets

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 octets grâce à @ceilingcat .

Certainement pas la bonne langue .. Maudite précision en virgule flottante ..

Explication:

Essayez-le en ligne.

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
Kevin Cruijssen
la source
Pourquoi la fonction principale est-elle si verbeuse?
user202729
@ user202729 Parce que float/double n'a pas la bonne précision en virgule flottante, java.math.BigDecimaldoit être utilisé à la place. Et au lieu de simplement +-*/, BigDecimals utiliser .add(...), .subtract(...), .multiply(...), .divide(...). Donc, quelque chose d'aussi simple que cela 7/10devient new BigDecimal(7).divide(new BigDecimal(10)). De plus, les ,scale,RoundingModedans dividesont obligatoires pour les valeurs avec des valeurs décimales «infinies» (comme l' 1/3être 0.333...). La méthode principale peut bien sûr être utilisée, mais je n'ai pas pris la peine quand j'ai fait une recherche et un remplacement pour convertir les flotteurs en BigDecimals.
Kevin Cruijssen
@ceilingcat Merci!
Kevin Cruijssen