マルコフ過程の収束


10

チャレンジ

xの行列がxの累乗に無限大に近づくときの制限がすべての有限値の行列に近づくような、左または右確率行列が与えられた場合、行列が収束する行列を返します。基本的には、結果が変化しなくなるまで、マトリックスを単独で乗算し続けます。

テストケース

[[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]]

ルール

  • 標準抜け穴が適用されます
  • 確率的行列が右か左かを選択できます
  • float、有理数、無限精度の小数など、適切な数値型を使用できます。
  • これはなので、各言語のバイト単位での最短の送信がその言語の勝者として宣言されます。回答は受け付けられません

@FryAmTheEggman以前のコメントがいくつか削除されているようです。これは冗長になる可能性がありますが、還元可能で周期的な行列は、「xが行列の無限大に近づくにつれて、限界が左または右確率行列である場合、のxは、すべて有限の値を持つ行列に近づきます」と書いてあります。(つまり、入力行列は
ナサニエル

@Nathanielそれはまったく真実ではありません。チェーンが還元可能である場合、あなたが言ったことに一致する結果(恒等行列など)を得ることができますが、それが記述するチェーンは還元不可能ではないため、入力は保証されません。エルゴード的であること(ポジティブな再発にはならないため)。エルゴード性を保証することはOPが望んでいることであり、すべての行の値が同一であるという追加の制約のおかげで、OPには今それがあると思います。マルコフ連鎖の説明を追加する必要なしに入力を制限するためのより良い方法を知っているなら、HyperNeutrinoがそれを高く評価すると確信しています!:)
FryAmTheEggman 2018年

1
@FryAmTheEggmanああ、あなたは正しい、ごめんなさい。マトリックスを累乗するのではなく、累乗反復を考えていました。(つまり、「一意のソリューション」とは、「反復プロセスの開始点に依存しないソリューション」を意味しましたが、ここでは関係ありません。)「すべての行が同一」条件が機能することに同意します。OPは、「マルコフ連鎖はエルゴディックであることが保証されている」とだけ言うことができると思います。これは、心配する可能性がある私たちのような人々を満足させるでしょう!
ナサニエル

実際、BBA = Bの解であれば、スカラー定数cのcBもそうです。したがって、何らかの方法でスケールを修正しない限り、ゼロ以外のソリューション厳密に一意にすることはできません。(Bが確率的である必要があります。)また、Bの行または列が等しいかどうかは、Aが確率的であるか左であるかに依存します。
Ilmari Karonen

2
高校の数学の授業中に行列について決して知らなかった他の人とそれらを乗算する方法:mathsisfun.com/algebra/matrix-multiplying.html。私は...頼まれていたかを理解するためにそれをルックアップするために持っていた...多分それは他の場所で、地球上の常識です:S
ケビンCruijssen

回答:


7

R 44  43バイト

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

オンラインでお試しください!

固定行列が見つかるまで乗算を続けます。どうやらX!=(X=X%*%m)比較を行ってからを再割り当てXしているので、それはきちんとしている。

バイトを削ってくれた@Vloに感謝します。取り消し線を引かれた44は依然として通常の44です。


1
なぜfunction(m){ while(any(m!=(m=m%*%m)))0 m}動かないのかしら。終了条件のトリガーを妨げる数値の誤り?
CodesInChaos 2018年

@CodesInChaosはおそらく精度の欠如です。任意の精度のライブラリに切り替えることも助けにはなりません-それらは同じようにタイムアウト(Rmpfr)または失敗(gmp)しますが、おそらく私は何か間違っているのでしょう。
ジュゼッペ

@Giuseppe私は提案されたアプローチがもはや変化しなくなるまで二乗を繰り返すと思いますか?(Rを読み込めません)
user202729

@ user202729そうです。Rは64ビットの浮動小数点数を使用しており、エラーがすぐに伝播することを知っています。
ジュゼッペ

アルゴリズムは不安定だと思います。ゼリーにも同じ問題があります。(TODOがこれを証明し、代替案を見つける)
user202729

5

オクターブ45 42 35バイト

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

オンラインでお試しください!

Giuseppeのおかげで3バイト節約でき、Luis Mendoのおかげでさらに7バイト節約できました。

これは、固有値1(最大固有値でもある)に対応する固有ベクトルが、制限行列の各値に対して繰り返される列ベクトルであることを使用します。確率的になるように、ベクトルを正規化して合計1にし、行列を埋めるために単純に繰り返します。私はOctaveのゴルフに精通していませんが、乗算を繰り返すための機能的な方法を見つけることができず、完全なプログラムは常にこれより長くなるようです。

any(A)制限から、行列は既約マルコフ連鎖を記述しなければならず、各状態は他の状態から到達可能でなければならないことがわかっているため、使用できます。したがって、各列の少なくとも1つの値はゼロ以外でなければなりません。


eigs常に対応する固有ベクトルをどのように返すの1ですか?マルコフ連鎖の私の記憶は少しあいまいです。
ジュゼッペ


@Giuseppe行列は確率的であり、他にもいくつかあるため、その最大固有値は1でありeigs、最大の固有値から開始して戻ります。また、ゴルフありがとうございます!
FryAmTheEggman 2018年

ああ、そうです。マルコフ連鎖は私の次の試験にありますが、アクチュアリー用なので、詳細の一部が完全に欠けています。
ジュゼッペ




3

k / q、10バイト

プログラムは両方の言語で同一であるため、k / q。コードは実際には慣用的なk / qです。

{$[x]/[x]}

説明

{..}x暗黙のパラメータとしてのラムダ構文です

$[x] バイナリマトリックス乗算演算子として$があり、1つのパラメーターのみを指定すると、マルコフマトリックスを乗算する左単項演算子が作成されます

/[x] x自体から始まり、収束するまで左乗算を適用します。


3

C(GCC) 207 192 190 181 176バイト+ 2つのフラグバイト-lm

  • 保存された15 17二十-二人はおかげバイトceilingcatを
  • 9バイトを節約。削除する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]));}

オンラインでお試しください!


@ceilingcatコンパイラフラグバイトを数えると、再び192になります。それにもかかわらず、あなたの提案を含めました。
Jonathan Frech

@ceilingcatありがとうございます。
Jonathan Frech

2

Pythonの375の 61バイト

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

オンラインでお試しください!

テストケースでは浮動小数点数の誤差があるため、値は正確な分数とは少し異なる場合があります。

PS。numpy.allclose()が使用されるのは、numpy.array_equal()が長く、フロートが不正確になる傾向があるためです。

-14バイトHyperNeutrinoに感謝;)ああ、はい@演算子を忘れました; P


:Dのdot代わりに使用matmul
HyperNeutrino 2018年

実際には、入力としてnumpyの配列を取得してくださいx=n@n:Pのtio.run/...
HyperNeutrino


f=再帰的に呼び出されるため、前にバックを追加しました;)
浅子しげる2018年

ああ、そうだね:)いい電話だ!
HyperNeutrino 2018年

2

Javaの8、356の 339バイト

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

@ceilingcatのおかげで-17バイト。

間違いなく正しい言語ではありません。

説明:

オンラインでお試しください。

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

なぜメイン関数はとても冗長なのですか?
user202729

@ user202729 float/にdoubleは適切な浮動小数点精度がないため、java.math.BigDecimal代わりに使用する必要があります。そして、代わりに、単に+-*/、のBigDecimalを使用し.add(...).subtract(...).multiply(...).divide(...)。だから、できるだけ単純に7/10なるものnew BigDecimal(7).divide(new BigDecimal(10))。また、,scale,RoundingMode中にはdivide(のような「無限」小数点値と値のために必要とされ1/3ています0.333...)。メインの方法はもちろんゴルフにも使用できますが、フロートをBigDecimalsに変換するために検索と置換を行っても、気になりませんでした。
Kevin Cruijssen

@ceilingcatありがとう!
Kevin Cruijssen
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.