马尔可夫过程的收敛


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

规则

  • 适用标准漏洞
  • 您可以选择是否需要右随机矩阵或左随机矩阵
  • 您可以使用任何合理的数字类型,例如浮点数,有理数,无限精度小数等
  • 这是,因此每种语言的最短提交(以字节为单位)被宣布为其语言的赢家。没有答案将被接受

@FryAmTheEggman似乎已删除了一些较早的注释,因此这可能是多余的,但是可归约和周期性矩阵已被“给出一个左或右随机矩阵,其中x的极限接近于幂的矩阵无穷大” x表示具有所有有限值的矩阵”,我的意思是保证输入收敛到唯一解。(即确保输入矩阵是遍历的。)
Nathaniel

@Nathaniel并非如此,好像链条是可约的,您可以得到一个满足您所说内容的结果(如恒等矩阵),但它描述的链条是不可约的,因此不能保证输入遍历(因为它不会是阳性复发)。确保遍历性是OP想要的,由于所有行值都相同的附加约束,我想他们现在已经做到了。如果您知道一种更好的约束输入的方法而无需添加马尔可夫链的说明,那么我相信HyperNeutrino将不胜感激!:)
FryAmTheEggman

1
@FryAmTheEggman啊,你是对的,对不起。我在考虑幂次迭代,而不是将矩阵提高到幂次。(因此,“唯一解决方案”的意思是“一个与迭代过程的起点无关的变量”,但这在这里并不重要。)我同意“所有行都相同”的条件可以完成这项工作。我想OP只能说“保证马尔可夫链是遍历的”,这将使像我们这样担心的人满意!
纳撒尼尔(Nathaniel)'18

实际上,如果BBA = B的解,那么对于任何标量常数c,cB也是。因此,除非您以某种方式确定规模,否则非零解决方案不可能严格唯一。(要求B是随机的。)显然,B的行或列是否相等将取决于A是左随机还是右随机。
Ilmari Karonen

2
对于在高中数学班期间从未学习过矩阵以及如何进行乘法运算的其他人,请访问:mathsisfun.com/algebra/matrix-multiplying.html。我不得不看它了解当时被问..也许这是常识在地球上其他地方..:S
凯文Cruijssen

Answers:


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

@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)因为从这些限制中我们知道矩阵必须描述一个不可约的马尔可夫链,因此每个状态都必须可以从其他状态到达。因此,每列中至少有一个值必须为非零。


如何eigs始终返回与对应的特征向量1?我对马尔可夫链的记忆有些模糊。
朱塞佩


@Giuseppe因为矩阵是随机的,还有其他一些事情,所以其最大特征值是1,并且eigs从最大特征值开始返回。另外,感谢您的高尔夫!
FryAmTheEggman,

嗯对 马尔可夫链条正在我的下一次考试中,但是由于它是针对精算师的,因此其中的一些细节完全丢失了。
朱塞佩




3

k / q,10个字节

k / q,因为程序在两种语言中都是相同的。该代码实际上只是惯用的k / q。

{$[x]/[x]}

说明

{..} 超出了lambda语法, x隐式参数

$[x] 将$作为二进制矩阵乘法运算符,仅提供一个参数即可创建一元运算符,该运算符与Markov矩阵相乘

/[x] 从x本身开始应用左乘法直到收敛。


3

C(GCC) 207个 192 190 181 176字节+2字节标志-lm

  • 多亏了ceilingcat,节省了15个 17个 22个字节
  • 保存九个字节;去除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。尽管如此,还是包含了您的建议。
乔纳森·弗雷希

@ceilingcat谢谢。
乔纳森·弗雷希

2

Python 3中75 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


使用dot代替matmul:D
HyperNeutrino

实际上,将numpy数组作为输入并执行x=n@nPtio.run/…–
HyperNeutrino,


将其添加回f=前面,因为它被递归调用;)
Shieru Asakoto

哦,是的,你是对的:)好电话!
HyperNeutrino

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

-17个字节感谢@ceilingcat

绝对不是正确的语言..该死的浮点精度..

说明:

在线尝试。

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应该改用/。而不是简单地+-*/,BigDecimals的使用.add(...).subtract(...).multiply(...).divide(...)。因此,事情7/10变得如此简单new BigDecimal(7).divide(new BigDecimal(10))。此外,,scale,RoundingModedivide所需要的值以“无限”小数值(例如1/30.333...)。主要方法当然可以打高尔夫球,但是当我执行搜索和替换以将花车转换为BigDecimals时,我并不在意。
凯文·克鲁伊森

@ceilingcat谢谢!
凯文·克鲁伊森
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.