Konvergensi Proses Markov

10

Tantangan

Diberikan matriks stochastic kiri atau kanan di mana batas x mendekati tak terhingga dari matriks ke kekuatan x mendekati matriks dengan semua nilai terbatas, kembalikan matriks yang menjadi titik konvergensi matriks. Pada dasarnya, Anda ingin terus mengalikan matriks dengan sendirinya sampai hasilnya tidak lagi berubah.

Uji Kasus

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

Aturan

  • Celah Standar Berlaku
  • Anda dapat memilih apakah Anda ingin matriks stochastic kanan atau kiri
  • Anda dapat menggunakan jenis angka yang masuk akal, seperti mengapung, rasional, desimal presisi tak terbatas, dll
  • Ini adalah , jadi pengiriman terpendek dalam byte untuk setiap bahasa dinyatakan sebagai pemenang untuk bahasanya. Tidak ada jawaban yang akan diterima
HyperNeutrino
sumber
@FryAmTheEggman sepertinya beberapa komentar sebelumnya telah dihapus, jadi ini mungkin berlebihan, tetapi matriks yang dapat direduksi dan periodik sudah dikecualikan oleh "Diberikan matriks stochastic kiri atau kanan di mana batas x mendekati infinity dari matriks ke daya of x mendekati matriks dengan semua nilai yang terbatas ", yang saya baca mengatakan input dijamin untuk menyatu ke solusi yang unik. (yaitu matriks input dijamin ergodik.)
Nathaniel
@Nathaniel Itu tidak sepenuhnya benar, seolah-olah rantai dapat direduksi Anda dapat memiliki hasil (seperti untuk matriks identitas) yang memenuhi apa yang Anda katakan tetapi rantai yang dijelaskannya tidak dapat direduksi dan oleh karena itu input tidak akan dijamin untuk menjadi ergodik (karena tidak akan berulang positif). Menjamin ergodisitas adalah apa yang diinginkan OP, dan saya pikir mereka memilikinya sekarang, berkat kendala tambahan dari semua nilai baris yang identik. Jika Anda tahu cara yang lebih baik untuk membatasi input tanpa perlu menambahkan penjelasan tentang rantai Markov, saya yakin HyperNeutrino akan menghargainya! :)
FryAmTheEggman
1
@FryAmTheEggman ah, Anda benar, maaf. Saya berpikir tentang iterasi daya daripada menaikkan matriks menjadi kekuatan. (Jadi dengan "solusi unik" yang saya maksudkan adalah "yang tidak tergantung pada titik awal dari proses iterasi", tetapi itu tidak relevan di sini.) Saya setuju bahwa kondisi 'semua baris identik' berfungsi. Saya kira OP hanya bisa mengatakan "rantai Markov dijamin ergodik," yang akan memuaskan orang-orang seperti kita yang cenderung khawatir tentang hal itu!
Nathaniel
Sebenarnya, jika B adalah solusi untuk BA = B , maka cB juga untuk konstanta skalar apa pun c . Jadi solusi bukan nol tidak bisa sepenuhnya unik, kecuali jika Anda entah bagaimana memperbaiki skalanya. (Membutuhkan B untuk menjadi stokastik akan melakukannya.) Juga, jelas, apakah itu baris atau kolom B yang sama akan tergantung pada apakah A adalah stokastik kiri atau kanan.
Ilmari Karonen
2
Untuk siapa pun yang tidak pernah belajar tentang matriks selama kelas Matematika di sekolah menengah dan cara melipatgandakannya: mathsisfun.com/algebra/matrix-multiplying.html . Saya harus mencarinya untuk memahami apa yang ditanyakan .. Mungkin itu adalah pengetahuan umum di tempat lain di Bumi ..: S
Kevin Cruijssen

Jawaban:

7

R ,  44  43 byte

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

Cobalah online!

Teruslah mengalikan hingga menemukan matriks yang diperbaiki. Rupanya X!=(X=X%*%m)melakukan perbandingan, kemudian ditugaskan kembali X, jadi itu rapi.

Terima kasih kepada @Vlo karena telah memangkas satu byte; meskipun dicoret 44 masih tetap 44.

Giuseppe
sumber
1
Saya heran mengapa function(m){ while(any(m!=(m=m%*%m)))0 m}tidak berhasil. Ketidakakuratan numerik mencegah pemutusan kondisi dari memicu?
CodesInChaos
@CodesInChaos kemungkinan besar itu kurang presisi. Beralih ke pustaka presisi arbitrer tidak membantu, baik - mereka baik waktu habis (Rmpfr) atau gagal (gmp) dengan cara yang sama, meskipun saya mungkin melakukan sesuatu yang salah.
Giuseppe
@ Giuseppe Saya kira pendekatan yang disarankan adalah kuadrat ulang sampai tidak ada perubahan lagi? (Saya tidak bisa membaca R)
user202729
@ user202729 ya itu. R menggunakan angka floating point 64-bit dan saya tahu kesalahan menyebar dengan cepat.
Giuseppe
Saya pikir algoritma itu tidak stabil. Jelly juga memiliki masalah yang sama. (TODO buktikan ini dan temukan alternatifnya)
user202729
5

Oktaf ,45 42 35 byte

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

Cobalah online!

Disimpan 3 byte berkat Giuseppe, dan 7 lagi berkat Luis Mendo!

Ini menggunakan vektor eigen yang sesuai dengan nilai eigen 1 (juga nilai eigen maksimum) adalah vektor kolom yang diulang untuk setiap nilai matriks pembatas. Kita harus menormalkan vektor untuk memiliki jumlah 1 agar stochastic, maka kita cukup mengulanginya untuk mengisi matriks. Saya tidak terlalu pandai bermain golf Oktaf, tapi saya belum bisa menemukan cara fungsional untuk melakukan perkalian berulang, dan program lengkap sepertinya akan selalu lebih lama dari ini.

Kita dapat menggunakan any(A)karena dari pembatasan kita tahu bahwa matriks harus menggambarkan rantai Markov yang tidak dapat direduksi, sehingga setiap negara bagian harus dapat dijangkau dari negara bagian lain. Oleh karena itu setidaknya satu nilai di setiap kolom harus bukan nol.

FryAmTheEggman
sumber
Bagaimana eigsselalu mengembalikan vektor eigen sesuai dengan 1? Ingatan saya tentang rantai markov agak kabur.
Giuseppe
42 byte
Giuseppe
@ Giuseppe Karena matriksnya stokastik, dan beberapa hal lainnya, nilai eigen maksimumnya adalah 1, dan eigskembali mulai dari nilai eigen terbesar. Juga, terima kasih untuk golfnya!
FryAmTheEggman
Ah benar Rantai Markov sedang dalam ujian saya berikutnya tetapi karena itu untuk aktuaris, beberapa detail sepenuhnya hilang.
Giuseppe
3

Jelly , 6 byte

æ׳$ÐL

Ini adalah program lengkap.

Cobalah online!

Dennis
sumber
3

APL (Dyalog) , 18 6 byte

12 byte disimpan berkat @ H.PWiz

+.×⍨⍣≡

Cobalah online!

Uriel
sumber
+.×⍨⍣≡untuk 6 byte. Artinya,
jujur
@ H.Piz aku percaya itu. Saya tidak tahu mengapa saya tidak melakukannya sejak awal. Terima kasih!
Uriel
3

k / q, 10 byte

k / q karena program ini identik dalam kedua bahasa. Kode ini benar-benar hanya idiomatis k / q.

{$[x]/[x]}

Penjelasan

{..}keluar sintaks lambda, dengan xsebagai parameter implisit

$[x] memiliki $ sebagai operator perkalian matriks biner, menyediakan hanya satu parameter yang menciptakan operator unary yang meninggalkan dikalikan oleh Markov Matrix

/[x] menerapkan perkalian kiri hingga konvergensi, dimulai dengan x itu sendiri.

ulucs
sumber
3

C (gcc) , 207 192 190 181 176 bytes + 2 flag bytes-lm

  • Disimpan lima belas tujuh belas dua puluh dua byte berkat ceilingcat .
  • Disimpan sembilan byte; menghapus 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]));}

Cobalah online!

Jonathan Frech
sumber
@ceilingcat Menghitung byte flag compiler, ini menghasilkan 192 lagi. Termasuk saran Anda.
Jonathan Frech
@ceilingcat Terima kasih.
Jonathan Frech
2

Python 3 , 75 61 byte

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

Cobalah online!

Dalam kasus uji ada ketidaktepatan float, sehingga nilai mungkin berbeda sedikit dari fraksi yang tepat.

PS. numpy.allclose()digunakan karena numpy.array_equal()lebih panjang dan rawan melayang ketidaktepatan.

-14 byte Terima kasih HyperNeutrino;) Oh ya saya lupa operator @; P

Shieru Asakoto
sumber
Gunakan dotsebagai ganti matmul: D
HyperNeutrino
Sebenarnya, ambil array numpy sebagai input dan lakukan x=n@n: P tio.run/…
HyperNeutrino
59 byte
HyperNeutrino
Ditambahkan kembali f=di depan karena secara rekursif disebut;)
Shieru Asakoto
Oh ya kau benar :) panggilan bagus!
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 terima kasih kepada @ceilingcat .

Jelas bukan bahasa yang tepat .. Presisi titik apung sialan ..

Penjelasan:

Cobalah 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
Kevin Cruijssen
sumber
Mengapa fungsi utamanya begitu bertele-tele?
user202729
@ user202729 Karena float/ doubletidak memiliki presisi floating point yang tepat, java.math.BigDecimalharus digunakan sebagai gantinya. Dan bukan hanya +-*/, BigDecimals menggunakan .add(...), .subtract(...), .multiply(...), .divide(...). Jadi sesuatu sesederhana 7/10menjadi new BigDecimal(7).divide(new BigDecimal(10)). Selain itu, ,scale,RoundingModedalam dividediperlukan untuk nilai-nilai dengan nilai desimal 'tak terbatas' (seperti 1/3sedang 0.333...). Metode utama tentu saja bisa golf, tapi saya tidak repot-repot ketika saya melakukan pencarian & ganti untuk mengubah floats ke BigDecimals.
Kevin Cruijssen
@ceilingcat Terima kasih!
Kevin Cruijssen