Сходимость марковского процесса


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

@Nathaniel Это не совсем верно, так как если цепочка сводима, у вас может быть результат (например, для матрицы тождеств), который соответствует тому, что вы сказали, но цепочка, которую он описывает, не является неприводимой, и поэтому входные данные не гарантируются быть эргодичным (так как это не будет положительно повторяющимся). Гарантировать эргодичность - это то, чего хочет OP, и я думаю, что теперь они это имеют, благодаря дополнительному ограничению на то, что все значения строк идентичны. Если вы знаете лучший способ ограничения ввода без добавления объяснения цепей Маркова, я уверен, что 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 все еще регулярно 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 байта, а еще Луиса Мендо - еще 7!

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

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


Как eigsвсегда вернуть собственный вектор, соответствующий 1? Моя память о цепях Маркова немного размыта.
Джузеппе


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

Ах, верно. Цепи Маркова на моем следующем экзамене, но так как это для актуариев, некоторые детали полностью отсутствуют.
Джузеппе




3

к / кв, 10 байт

k / q потому что программа идентична на обоих языках. Код действительно просто идиоматический к / к.

{$[x]/[x]}

объяснение

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

$[x] имеет $ как оператор умножения двоичной матрицы, при условии, что только один параметр создает унарный оператор, который умножается на матрицу Маркова

/[x] применяет левое умножение до сходимости, начиная с самого x.


3

C (gcc) , 207 192 190 181 176 байт + 2 байта флага-lm

  • Сохранено пятнадцать, семнадцать, двадцать два байта, благодаря floorcat .
  • Сохранено девять байтов; удаление 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

На самом деле, возьмите numy массивы в качестве входных данных и сделайте x=n@n: P tio.run/…
HyperNeutrino


Добавил обратно f=на фронт, потому что это рекурсивно называется;)
Шиеру Асакото

Ах да, ты прав :) хороший звонок!
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,RoundingModein divideнеобходимы для значений с «бесконечными» десятичными значениями (например, 1/3быть 0.333...). Основной метод, конечно, можно использовать в гольфе, но я не стал беспокоиться, когда выполнил поиск и замену, чтобы преобразовать поплавки в BigDecimals.
Кевин Круйссен

@ceilingcat Спасибо!
Кевин Круйссен
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.