Sự hội tụ của một quá trình Markov


10

Thử thách

Đưa ra một ma trận ngẫu nhiên trái hoặc phải trong đó giới hạn khi x tiếp cận vô hạn của ma trận với sức mạnh của x tiếp cận một ma trận với tất cả các giá trị hữu hạn, trả về ma trận mà ma trận hội tụ. Về cơ bản, bạn muốn tiếp tục nhân ma trận cho đến khi kết quả không còn thay đổi.

Các trường hợp thử nghiệm

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

Quy tắc

  • Áp dụng sơ hở tiêu chuẩn
  • Bạn có thể chọn xem bạn muốn một ma trận ngẫu nhiên phải hay trái
  • Bạn có thể sử dụng bất kỳ loại số hợp lý nào, chẳng hạn như số float, số hữu tỷ, số thập phân chính xác vô hạn, v.v.
  • Đây là , vì vậy việc gửi byte ngắn nhất cho mỗi ngôn ngữ được tuyên bố là người chiến thắng cho ngôn ngữ của nó. Không có câu trả lời sẽ được chấp nhận

@FryAmTheEggman có vẻ như một số bình luận trước đó đã bị xóa, do đó, điều này có thể là dư thừa, nhưng ma trận có thể rút gọn và định kỳ đã bị loại trừ bởi "Đưa ra ma trận ngẫu nhiên trái hoặc phải trong đó giới hạn khi x tiếp cận vô hạn của ma trận với sức mạnh của x tiếp cận một ma trận với tất cả các giá trị hữu hạn ", mà tôi đọc như nói rằng đầu vào được đảm bảo để hội tụ đến một giải pháp duy nhất. (tức là ma trận đầu vào được đảm bảo là ergodic.)
Nathaniel

@Nathaniel Điều đó không hoàn toàn đúng, vì nếu chuỗi có thể rút gọn, bạn có thể có kết quả (như đối với ma trận danh tính) đáp ứng những gì bạn nói nhưng chuỗi mà nó mô tả là không thể giảm được và do đó đầu vào sẽ không được đảm bảo là ergodic (vì nó sẽ không tái phát tích cực). Đảm bảo tính linh hoạt là những gì OP muốn, và tôi nghĩ rằng họ có điều đó ngay bây giờ, nhờ vào sự ràng buộc bổ sung của tất cả các giá trị hàng giống hệt nhau. Nếu bạn biết một cách tốt hơn để hạn chế đầu vào mà không cần thêm lời giải thích về chuỗi Markov, tôi chắc chắn HyperNeutrino sẽ đánh giá cao điều đó! :)
FryAmTheEggman

1
@FryAmTheEggman ah, bạn nói đúng, xin lỗi. Tôi đã nghĩ về việc lặp lại sức mạnh hơn là nâng ma trận lên một sức mạnh. (Vì vậy, theo "giải pháp duy nhất" tôi có nghĩa là "một giải pháp độc lập với điểm bắt đầu của quá trình lặp", nhưng điều đó không liên quan ở đây.) Tôi đồng ý rằng điều kiện 'tất cả các hàng đều giống hệt nhau'. Tôi cho rằng OP chỉ có thể nói "chuỗi Markov được đảm bảo là công thái học", điều này sẽ làm hài lòng những người như chúng tôi, những người có khả năng lo lắng về điều đó!
Nathaniel

Trên thực tế, nếu B là một giải pháp cho BA = B , thì cB cho bất kỳ hằng số vô hướng c . Vì vậy, một giải pháp khác không có thể là hoàn toàn độc đáo, trừ khi bạn bằng cách nào đó sửa chữa thang đo. (Yêu cầu B là stochastic sẽ làm điều đó.) Ngoài ra, rõ ràng, việc các hàng của nó hoặc các cột của B bằng nhau sẽ phụ thuộc vào việc A là ngẫu nhiên trái hay phải.
Ilmari Karonen

2
Đối với bất kỳ ai khác chưa bao giờ học về ma trận trong lớp Toán ở trường trung học và cách nhân chúng: mathsisfun.com/acheebra/matrix-multipelling.html . Tôi đã phải tìm kiếm nó để hiểu những gì đang được hỏi .. Có lẽ đó là kiến ​​thức phổ biến ở những nơi khác trên Trái đất ..: S
Kevin Cruijssen

Câu trả lời:


7

R ,  44  43 byte

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

Hãy thử trực tuyến!

Chỉ cần tiếp tục nhân cho đến khi nó tìm thấy một ma trận cố định. Rõ ràng X!=(X=X%*%m)là so sánh, sau đó gán lại X, vì vậy đó là gọn gàng.

Cảm ơn @Vlo đã cạo sạch một byte; mặc dù gạch bỏ 44 vẫn là 44 thường xuyên.


1
Tôi tự hỏi tại sao function(m){ while(any(m!=(m=m%*%m)))0 m}không làm việc. Không chính xác số ngăn chặn điều kiện chấm dứt kích hoạt?
CodeInChaos

@CodesInChaos rất có thể đó là sự thiếu chính xác. Chuyển sang một thư viện chính xác tùy ý cũng không giúp được gì - họ hết thời gian (Rmpfr) hoặc thất bại (gmp) theo cách tương tự, mặc dù tôi có thể làm sai điều gì đó.
Giuseppe

@Giuseppe Tôi đoán cách tiếp cận được đề xuất được lặp lại bình phương cho đến khi không còn thay đổi? (Tôi không thể đọc R)
user202729

@ user202729 vâng đúng vậy. R sử dụng số dấu phẩy động 64 bit và tôi biết lỗi phát sinh khá nhanh.
Giuseppe

Tôi nghĩ rằng thuật toán là không ổn định. Jelly cũng có vấn đề tương tự. (TODO chứng minh điều này và tìm một giải pháp thay thế)
user202729

5

Octave ,45 42 35 byte

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

Hãy thử trực tuyến!

Đã lưu 3 byte nhờ Giuseppe và 7 byte nữa nhờ Luis Mendo!

Điều này sử dụng rằng hàm riêng tương ứng với giá trị riêng 1 (cũng là giá trị riêng tối đa) là vectơ cột được lặp lại cho mỗi giá trị của ma trận giới hạn. Chúng ta phải chuẩn hóa vectơ để có tổng 1 cho nó là ngẫu nhiên, sau đó chúng ta chỉ cần lặp lại nó để điền vào ma trận. Tôi không rành về chơi golf Octave, nhưng tôi chưa thể tìm ra một cách chức năng để thực hiện phép nhân lặp lại, và một chương trình đầy đủ có vẻ như sẽ luôn dài hơn thế này.

Chúng ta có thể sử dụng any(A)từ các hạn chế mà chúng ta biết rằng ma trận phải mô tả chuỗi Markov không thể sửa chữa và do đó mỗi trạng thái phải có thể truy cập được từ các trạng thái khác. Do đó, ít nhất một giá trị trong mỗi cột phải khác không.


Làm thế nào để eigsluôn trả về eigenvector tương ứng với 1? Bộ nhớ của tôi về chuỗi markov là một chút mờ.
Giuseppe


@Giuseppe Bởi vì ma trận là ngẫu nhiên, và một vài thứ khác, giá trị riêng tối đa của nó là 1 và eigstrả về bắt đầu từ giá trị riêng lớn nhất. Ngoài ra, cảm ơn vì đã chơi golf!
FryAmTheEggman

À, đúng rồi. Chuỗi Markov đang trong kỳ thi tiếp theo của tôi nhưng vì nó dành cho chuyên gia tính toán, nên một số chi tiết hoàn toàn bị thiếu.
Giuseppe



3

APL (Dyalog) , 18 6 byte

12 byte được lưu nhờ @ H.PWiz

+.×⍨⍣≡

Hãy thử trực tuyến!


+.×⍨⍣≡cho 6 byte. Đó là, hình vuông cho đến khi không có gì thay đổi
H.PWiz

@ H.PWiz Tôi tin là như vậy. Tôi không biết tại sao tôi đã không làm điều đó ngay từ đầu. Cảm ơn!
Uriel

3

k / q, 10 byte

k / q vì chương trình giống hệt nhau ở cả hai ngôn ngữ. Mã này thực sự chỉ là thành ngữ k / q.

{$[x]/[x]}

Giải trình

{..}là cú pháp lambda, với xmột tham số ngầm định

$[x] có $ là toán tử nhân ma trận nhị phân, chỉ cung cấp một tham số sẽ tạo ra một toán tử đơn nguyên còn lại nhân với Ma trận Markov

/[x] áp dụng phép nhân trái cho đến khi hội tụ, bắt đầu bằng chính x.


3

C (gcc) , 207 192 190 181 176 byte + 2 byte cờ-lm

  • Đã lưu mười lăm mười hai hai mươi hai byte nhờ trần .
  • Đã lưu chín byte; loại bỏ 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]));}

Hãy thử trực tuyến!


@ceilingcat Đếm các byte cờ của trình biên dịch, kết quả này lại là 192. Bao gồm đề nghị của bạn dù sao.
Jonathan Frech

@ceilingcat Cảm ơn bạn.
Jonathan Frech

2

Python 3 , 75 61 byte

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

Hãy thử trực tuyến!

Trong các trường hợp thử nghiệm có sự không chính xác nổi, vì vậy các giá trị có thể khác nhau một chút so với các phân số chính xác.

Tái bút numpy.allclose()được sử dụng vì numpy.array_equal()dài hơn và dễ nổi không chính xác.

-14 byte Cảm ơn HyperNeutrino;) Ồ vâng, tôi đã quên toán tử @; P


Sử dụng dotthay vì matmul: D
HyperNeutrino

Trên thực tế, hãy lấy các mảng numpy làm đầu vào và làm x=n@n: P tio.run/ Kẻ
HyperNeutrino


Đã thêm lại f=ở phía trước vì nó được gọi đệ quy;)
Shieru Asakoto

Oh yeah bạn nói đúng :) cuộc gọi tốt!
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 nhờ @ceilingcat .

Chắc chắn không phải ngôn ngữ phù hợp .. Độ chính xác điểm nổi chết tiệt ..

Giải trình:

Hãy thử trực tuyến.

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

Tại sao chức năng chính quá dài dòng?
dùng202729

@ user202729 Vì float/ doublekhông có độ chính xác dấu phẩy động thích hợp, java.math.BigDecimalnên được sử dụng thay thế. Và thay vì chỉ đơn giản +-*/, BigDecimals sử dụng .add(...), .subtract(...), .multiply(...), .divide(...). Vì vậy, một cái gì đó đơn giản như 7/10trở thành new BigDecimal(7).divide(new BigDecimal(10)). Ngoài ra, phần ,scale,RoundingModetrong divideđược yêu cầu cho các giá trị có giá trị thập phân 'vô hạn' (giống như 1/3hiện hữu 0.333...). Phương pháp chính tất nhiên có thể là chơi gôn, nhưng tôi không bận tâm khi tôi thực hiện tìm kiếm & thay thế để chuyển đổi các phao thành BigDecimals.
Kevin Cruijssen

@ceilingcat Cảm ơn!
Kevin Cruijssen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.