마르코프 프로세스의 수렴


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

규칙

  • 표준 허점 적용
  • 당신은 오른쪽 또는 왼쪽 확률 행렬을 원하는지 선택할 수 있습니다
  • 플로트, 유리수, 무한 정밀도 10 진수 등과 같은 합리적인 숫자 유형을 사용할 수 있습니다.
  • 이것은 이므로 각 언어에 대한 가장 짧은 바이트 제출은 해당 언어의 승자로 선언됩니다. 응답이 없습니다

@FryAmTheEggman 이전 주석이 삭제 된 것처럼 보이므로 중복 될 수 있지만 중복 및 주기적 행렬은 이미 "x에 대한 한계가 행렬의 무한대에 접근하는 왼쪽 또는 오른쪽 확률 행렬을 제공합니다. of x는 모든 유한 값을 가진 행렬에 접근합니다. "라고 말하면서 입력이 고유 한 솔루션으로 수렴된다는 것을 읽었습니다. (즉, 입력 매트릭스는 인체 공학적입니다.)
Nathaniel

@Nathaniel 그것은 체인이 환원 가능한 것처럼 당신이 말한 것을 충족시키는 결과를 가질 수 있지만 (체인이 설명하는 체인은 돌이킬 수 없으므로 입력이 보장되지는 않습니다) 사실이 아닙니다. 긍정적 인 반복적이지 않기 때문에 인체 공학적이어야합니다. ergodicity를 보장하는 것이 OP가 원하는 것입니다. 모든 행 값의 추가 제약이 동일하기 때문에 지금 가지고 있다고 생각합니다. Markov 체인에 대한 설명을 추가 할 필요없이 입력을 제한하는 더 좋은 방법을 알고 있다면 HyperNeutrino가이를 인정할 것입니다! :)
FryAmTheEggman

1
@FryAmTheEggman 아, 맞아요, 죄송합니다. 행렬을 거듭 제곱하기보다는 거듭 제곱 반복을 생각하고있었습니다. (따라서 "고유 한 솔루션"이라는 의미는 "반복 프로세스의 시작점과 무관 한 것"을 의미하지만 여기서는 관련이 없습니다.) '모든 행이 동일합니다'조건이 작업을 수행한다는 데 동의합니다. OP가 "마르코프 체인은 인체 공학적임을 보장합니다"라고 말할 수 있다고 생각합니다. 걱정할 것 같은 우리와 같은 사람들을 만족시킬 것입니다!
Nathaniel

실제로 BBA = B 에 대한 해이면 스칼라 상수 c에 대한 cB도 마찬가지 입니다 . 따라서 스케일을 수정하지 않으면 0이 아닌 솔루션 엄격하게 고유 할 수 없습니다 . ( B 가 확률 론적 (stochastic) 인 것을 요구하는 것은 그것을 할 것이다.) 또한, B 의 행 또는 컬럼 이 동일한 지의 여부는 A 가 확률 론적 (stochastic) 인지 왼쪽 인지에 달려있다 .
Ilmari Karonen

2
고등학교 수학 수업 중 행렬에 대해 배운 적이없는 사람이라면 누구나 곱할 수 있습니다 : mathsisfun.com/algebra/matrix-multiplying.html . 나는 무엇이 요청되고 있는지 이해하기 위해 그것을 찾아야했다. 어쩌면 그것은 지구상의 다른 곳에서 일반적인 지식 일 것이다. : :
Kevin 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}작동하지 않는지 궁금 합니다. 종료 조건 트리거를 방해하는 수치 부정확성?
코드 InChaos

@CodesInChaos는 아마도 정확성이 부족할 것입니다. 임의의 정밀 라이브러리로 전환해도 도움이되지 않습니다. 아마도 잘못된 일을하고 있지만 동일한 방식으로 시간 초과 (Rmpfr) 또는 실패 (gmp) 중 하나입니다.
Giuseppe

@ 주세페 나는 제안 된 접근법이 더 이상 변경되지 않을 때까지 제곱을 반복한다고 생각합니까? (R을 읽을 수 없음)
user202729

예, 그렇습니다. R은 64 비트 부동 소수점 숫자를 사용하며 오류가 매우 빨리 전파된다는 것을 알고 있습니다.
Giuseppe

알고리즘이 불안정하다고 생각합니다. 젤리도 같은 문제가 있습니다. (TODO에서 이것을 증명하고 대안을 찾으십시오)
user202729

5

옥타브 ,45 42 35 바이트

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

온라인으로 사용해보십시오!

Giuseppe 덕분에 3 바이트를 절약했으며 Luis Mendo 덕분에 7 바이트를 더 절약했습니다!

이는 고유 값 1 (최대 고유 값)에 해당하는 고유 벡터가 제한 행렬의 각 값에 대해 반복되는 열 벡터임을 사용합니다. 확률을 갖기 위해 합계 1을 갖도록 벡터를 정규화 한 다음 행렬을 채우기 위해 반복합니다. 나는 골프 옥타브에 정통하지는 않지만 반복적 인 곱셈을 수행하는 기능적인 방법을 찾지 못했으며 전체 프로그램은 항상 이보다 길 것 같습니다.

우리는 any(A)매트릭스가 돌이킬 수없는 마르코프 체인을 설명해야한다는 것을 알고 있기 때문에 사용할 수 있으므로 각 상태는 다른 상태에서 도달 할 수 있어야합니다. 따라서 각 열에서 하나 이상의 값이 0이 아니어야합니다.


eigs항상 고유 벡터를 어떻게 반환 1합니까? 마르코프 체인에 대한 나의 기억은 약간 희미합니다.
Giuseppe


@Giuseppe 행렬이 확률 론적이며 몇 가지 다른 것 때문에 최대 고유 값은 1이고 최대 고유 값 eigs부터 시작하여 반환합니다. 또한 골프 주셔서 감사합니다!
FryAmTheEggman

아 맞아 Markov 체인은 다음 시험에 있지만 보험 계리사 용이므로 세부 사항 중 일부가 완전히 누락되었습니다.
Giuseppe




3

k / q, 10 바이트

프로그램이 두 언어에서 동일하기 때문에 k / q. 코드는 실제로 관용적 인 k / q입니다.

{$[x]/[x]}

설명

{..}x암시 적 매개 변수로 람다 구문이 없습니다.

$[x] 이진 행렬 곱셈 연산자로 $가 있으며, 하나의 매개 변수 만 제공하면 Markov Matrix에 곱한 단항 연산자가 생성됩니다.

/[x] x 자체부터 시작하여 수렴까지 왼쪽 곱셈을 적용합니다.


3

C (GCC) , 207 (192) 190 (181) 176 바이트 + 2 바이트 플래그-lm

  • 저장된 15 17 에 20-두 바이트 덕분 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 2016 년

@ceilingcat 감사합니다.
Jonathan Frech

2

파이썬 3 , 75 61 바이트

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

온라인으로 사용해보십시오!

테스트 사례에서는 부동 소수점이 부정확하므로 값이 정확한 분수와 약간 다를 수 있습니다.

추신. numpy.allclose()numpy.array_equal()길고 부정확 한 플로트가 발생하기 때문에 사용됩니다 .

-14 bytes Thanks HyperNeutrino;) 아 맞다 @ 연산자를 잊었다;


: D dot대신 사용matmul
HyperNeutrino

실제로, numpy 배열을 입력으로 사용하여 다음을 수행하십시오 x=n@n. –P tio.run/…
HyperNeutrino


f=그것은 재귀 적으로 호출되기 때문에 앞에 다시 추가 ;)
Shieru Asakoto

아 그래, 맞아 :) 좋은 전화!
HyperNeutrino

2

자바 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.