In [1]:
import numpy as np
In [2]:
def stationary_distribution(P: np.array) -> np.array:
A = P - np.eye(len(P))
A[:, (len(P) - 1)] = np.ones([len(P)])
p_stationary = np.linalg.inv(A)[len(P) - 1, :]
return p_stationary
In [3]:
def check_detailed_balance(transition, pi=None):
if pi is None:
pi = stationary_distribution(transition)
detailed_balance= True
for x in range(4):
for y in range(4):
detailed_balance &= (pi[x] * transition[x, y] == pi[y] * transition[y, x])
return detailed_balance
In [4]:
transition_2 = np.array([[ 0, 1, 0, 0, 0, 0],
[ 1/25, 8/25, 16/25, 0, 0, 0],
[ 0, 4/25, 12/25, 9/25, 0, 0],
[ 0, 0, 9/25, 12/25, 4/25, 0],
[ 0, 0, 0, 16/25, 8/25, 1/25],
[ 0, 0, 0, 0, 1, 0]])
In [5]:
transition_3 = (1/16) * np.array([[ 3, 2, 2, 2, 3, 4],
[ 4, 3, 2, 2, 2, 3],
[ 3, 4, 3, 2, 2, 2],
[ 2, 3, 4, 3, 2, 2],
[ 2, 2, 3, 4, 3, 2],
[ 2, 2, 2, 3, 4, 3]])
In [6]:
transition_7 = np.array([[0.6, 0.4, 0, 0],
[ 0, 0, 0.6, 0.4],
[0.6, 0.4, 0, 0],
[ 0, 0, 0.3, 0.7]])
In [ ]:
In [7]:
transition_10c = np.array([[0.7, 0, 0.3, 0],
[0.2, 0.5, 0.3, 0],
[0.1, 0.2, 0.1, 0.3],
[0, 0.4, 0, 0.6]])
print(stationary_distribution(transition_10c))
In [8]:
print(stationary_distribution(transition_2))
In [9]:
print(stationary_distribution(transition_3))
In [10]:
print(stationary_distribution(transition_7))
In [11]:
transition_12 = np.array([[ 0, 2/3, 0, 1/3],
[1/3, 0, 2/3, 0],
[ 0, 1/6, 0, 5/6],
[2/5, 0, 3/5, 0]])
In [12]:
print(stationary_distribution(transition_12))
In [13]:
transition_13 = np.array([[0.0, 0.0, 0.1, 0.9],
[0.0, 0.0, 0.6, 0.4],
[0.8, 0.2, 0.0, 0.0],
[0.4, 0.6, 0.0, 0.0]])
In [14]:
stationary_distribution(np.linalg.matrix_power(transition_13, 3))
Out[14]:
In [15]:
transition_ruiz = np.array([[0.0, 1.0, 0.0, 0.0, 0.0],
[0.3, 0.0, 0.7, 0.0, 0.0],
[0.3, 0.0, 0.0, 0.7, 0.0],
[0.3, 0.0, 0.0, 0.0, 0.7],
[1.0, 0.0, 0.0, 0.0, 0.0]])
In [16]:
np.linalg.matrix_power(transition_ruiz, 4)
Out[16]:
In [17]:
stationary_distribution(transition_ruiz)
Out[17]:
In [ ]:
In [18]:
transition_19 = np.array([[0.7, 0.3],
[0.1, 0.9]])
In [19]:
transition_19_3 = np.linalg.matrix_power(transition_19, 3)
transition_19_3
Out[19]:
In [20]:
np.array([[0.75, 0.25]]) @ transition_19_3
Out[20]:
In [21]:
stationary_distribution(transition_19)
Out[21]:
In [22]:
transition_20 = np.array([[0.75, 0.25],
[0.08, 0.92]])
v_20_1995 = np.array([[0.7, 0.3]])
In [23]:
transition_20_3 = np.linalg.matrix_power(transition_20, 3)
transition_20_3
Out[23]:
In [24]:
v_20_1995 @ transition_20_3
Out[24]:
In [25]:
transition_20_10 = np.linalg.matrix_power(transition_20, 10)
transition_20_10
Out[25]:
In [26]:
v_20_1995 @ transition_20_10
Out[26]:
In [27]:
stationary_distribution(transition_20)
Out[27]:
In [28]:
transition_36 = np.array([[ 0, 0, 1],
[0.05, 0.95, 0],
[ 0, 0.02, 0.98]])
In [29]:
stationary_distribution(transition_36)
Out[29]:
In [30]:
1 / stationary_distribution(transition_36)
Out[30]:
In [31]:
transition_37 = np.array([[ 1, 0, 0, 0],
[0.2, 0.8, 0, 0],
[ 0, 0.2, 0.8, 0],
[ 0, 0, 0.2, 0.2]])
In [32]:
stationary_distribution(transition_37)
Out[32]:
In [33]:
transition_38 = np.array([[0.5, 0.5, 0, 0],
[2/3, 0, 1/3, 0],
[3/4, 0, 0, 1/4],
[ 1, 0, 0, 0]])
In [34]:
pi_38 = stationary_distribution(transition_38)
In [35]:
check_detailed_balance(transition_38)
Out[35]:
In [36]:
n = 12
transition_48 = np.zeros([n, n])
for i in range(n):
transition_48[i, [(i - 1) % n, (i + 1) % n]] = [0.5] * 2
transition_48
Out[36]:
El resultado será: $$\pi_{i} = 1 / 12 \ \forall i \in {1, 2, ..., 12}$$ Por cumplir la matriz de transición la propiedad de ser doblemente estocástica (tanto filas como columnas suman la unidad).
In [37]:
stationary_distribution(transition_48)
Out[37]:
In [39]:
import numpy as np
def position_to_clock(position: int) -> int:
if (position % 12):
return position % 12
else:
return 12
n = 100000
y = 0
for n_temp in range(1, n + 1):
s = f'{12} '
position = np.random.choice([-1, 1])
s += f'{position_to_clock(position): 2d} '
while(position % 12 != 0):
position += np.random.choice([-1, 1])
s += f'{position_to_clock(position): 2d} '
y += (position != 0)
# print(f'y: {y:3d} s: {s}')
if n_temp % 10000 == 0:
print(f'n = {n_temp}\tp = {y / n_temp:.5f}')
print(f'n = {n}\tp = {y / n:.5f}')