마르코프 프로세스의 수렴


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

실제로 B 가 BA = 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.