Конвергенція процесу Маркова


10

Виклик

З огляду на ліво- або право-стохастичну матрицю, де межа, коли х наближається до нескінченності матриці, до сили 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 наближається до матриці з усіма кінцевими значеннями ", яку я читав, кажучи, що вхід гарантовано сходиться до унікального рішення. (тобто матриця вводу гарантовано буде ергодичною.)
Натаніел

@Nathaniel Це не зовсім правда, так як якщо ланцюжок є скорочуваною, ви можете отримати результат (як для матриці ідентичності), який відповідає тому, що ви сказали, але ланцюг, яку він описує, не є невідводимим, і тому вхід не гарантується бути ергодичним (оскільки це не буде позитивним повторюванням). Гарантувати ергодичність - це те, що хоче ОП, і я думаю, що вони цього мають, завдяки додатковому обмеженню, що всі значення рядків однакові. Якщо ви знаєте кращий спосіб обмежити вхід без необхідності додавати пояснення ланцюгів Маркова, я впевнений, що HyperNeutrino оцінить це! :)
FryAmTheEggman

1
@FryAmTheEggman ах, ти маєш рацію, вибач. Я думав про ітерацію потужності, а не про підвищення матриці до влади. (Отже, під "унікальним рішенням" я мав на увазі "таке, яке не залежить від початкової точки процесу ітерації", але це не актуально.) Я погоджуюся, що умова "всі рядки однакові" виконує цю роботу. Я думаю, що ОП могла просто сказати, що "ланцюг Маркова гарантовано буде ергодичним", що задовольнило б таких людей, як ми, які, швидше за все, турбуються про це!
Натаніел

Власне, якщо B є рішенням BA = B , то так є cB для будь-якої скалярної постійної c . Тож ненульове рішення не може бути строго унікальним, якщо ви якимось чином не зафіксуєте шкалу. (Якщо вимога B буде стохастичною, це зробить.) Також очевидно, чи рівні її рядки або стовпці B будуть залежати від того, стоїть лівий чи правий стохастичний A.
Ільмарі Каронен

2
Для всіх, хто ніколи не дізнавався про матриці під час уроку математики у середній школі та як їх примножувати: mathsisfun.com/algebra/matrix-multiplying.html . Мені довелося роздивитись, щоб зрозуміти, про що питають .. Можливо, це загальновідомі відомості в інших місцях на Землі ..: S
Кевін Кройсейсен

Відповіді:


7

R ,  44  43 байт

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

Спробуйте в Інтернеті!

Просто продовжує множитися, поки не знайде фіксовану матрицю. Мабуть X!=(X=X%*%m), порівняння, потім переназначення X, тож це акуратно.

Дякуємо @Vlo за те, що поголив байт; незважаючи на те, що перекреслений 44 все ще є регулярним.


1
Цікаво, чому function(m){ while(any(m!=(m=m%*%m)))0 m}це не працює. Числові неточності, що запобігають виникненню умови припинення?
CodesInChaos

@CodesInChaos, швидше за все, це недостатня точність. Перехід до довільної бібліотеки точності також не допомагає - вони або вимкнено (Rmpfr), або виходять з ладу (gmp) таким же чином, хоча я, мабуть, щось не так.
Джузеппе

@Giuseppe Я здогадуюсь, що запропонований підхід повторюється в квадраті, поки більше не зміниться? (Я не можу прочитати R)
користувач202729

@ user202729 так. R використовує 64-бітні числа з плаваючою комою, і я знаю, що помилки пропонують досить швидко.
Джузеппе

Я думаю, що алгоритм нестабільний. У желе теж є та ж проблема. (TODO доведіть це і знайдіть альтернативу)
user202729

5

Октава ,45 42 35 байт

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

Спробуйте в Інтернеті!

Збережено 3 байти завдяки Джузеппе та ще 7 завдяки Луїсу Мендо!

При цьому використовується те, що власний вектор, що відповідає власній величині 1 (також максимальне власне значення), є стовпчиковим вектором, який повторюється для кожного значення обмежуючої матриці. Ми повинні нормалізувати вектор, щоб мати суму 1, щоб він був стохастичним, тоді ми просто повторюємо його, щоб заповнити матрицю. Я не дуже добре розбираюся в гольф Octave, але мені не вдалося знайти функціональний спосіб зробити повторне множення, і повна програма, схоже, завжди буде довшою, ніж ця.

Ми можемо використовувати, any(A)оскільки з обмежень ми знаємо, що матриця повинна описувати непридатний ланцюг Маркова, і тому кожен стан повинен бути доступний для інших станів. Тому принаймні одне значення в кожному стовпці повинно бути не нульовим.


Як eigsзавжди повертає власний вектор, відповідний 1? Моя пам’ять про ланцюги Маркова трохи нечітка.
Джузеппе


@Giuseppe Оскільки матриця є стохастичною та ще кількома речами, її максимальне власне значення дорівнює 1, і eigsповертається, починаючи з найбільшого власного значення. Також дякую за гольф!
FryAmTheEggman

Ага, правильно. Ланцюжки Маркова є на моєму наступному іспиті, але оскільки це для актуарників, деякі деталі повністю відсутні.
Джузеппе




3

k / q, 10 байт

k / q, оскільки програма однакова в обох мовах. Код насправді просто ідіоматичний k / q.

{$[x]/[x]}

Пояснення

{..}- це лямбда-синтаксис, xв якості неявного параметра

$[x] має $ як оператор множення двійкової матриці, забезпечуючи лише один параметр створює одинарний оператор, який залишився множитися на матрицю Маркова

/[x] застосовує ліве множення до зближення, починаючи з самого x.


3

C (gcc) , 207 192 190 181 176 байт + 2 байта прапора-lm

  • Збережено п’ятнадцять сімнадцять двадцяти двох байтів завдяки стельовій коті .
  • Збережено дев'ять байтів; видалення 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

Власне, візьміть нумерові масиви як вхідні дані і виконайте x=n@n: P tio.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

Чому основна функція настільки багатослівна?
користувач202729

@ user202729 Оскільки float/ doubleне мають належної точності з плаваючою точкою, java.math.BigDecimalслід використовувати це замість. І замість того , щоб просто +-*/, BigDecimals використовувати .add(...), .subtract(...), .multiply(...), .divide(...). Так щось просто, як 7/10стає new BigDecimal(7).divide(new BigDecimal(10)). Крім того, знаки " ,scale,RoundingModein" divideнеобхідні для значень з "нескінченними" десятковими значеннями (як, наприклад 1/3, " 0.333...). Основним методом, звичайно, може бути гольф, але я не турбувався, коли робив пошук і заміну, щоб перетворити поплавці на BigDecimals.
Кевін Кройсейсен

@ceilingcat Дякую!
Кевін Круїссен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.