import numpy as np
import random
import numpy.random as npr
import matplotlib.pyplot as plt
# Simulation d'un processus de Poisson de paramètre "lambd"
def Simu_Poisson(t,lambd):
T = 0
Z = 0
Time_list = [T]
Ech_list = [Z]
while T < t:
T += -np.log(npr.rand())/lambd # ~Exp(lambd)
if T < t:
Time_list.append(T)
Z += 1
Ech_list.append(Z)
else:
Time_list.append(t)
Ech_list.append(Z)
return(Time_list,Ech_list)
T,Z = Simu_Poisson(10,1/2)
plt.step(T,Z,'--P', where='post')
plt.show()
lamba_caché = 14
t = 100
T,Z = Simu_Poisson(t,lamba_caché)
#Z[-2]/T[-2] # estimateur de lambda : X_t/t
# autre estimateur (on supprime T[0]=0 de la liste)
# np.mean((np.array(Z[1:])/np.array(T[1:])))
# Simulation d'une CMTC de générateur infinitesimal Q et de mesure initiale mu sur un espace d'états E
def Simu_init(mu):
i = random.choices(range(len(mu)), mu)[0]
return(E[i])
def Simu_CMTC(t,Q,mu):
N = len(Q[0]) # taille de E
T = 0
Time_list = [T]
Z = Simu_init(mu)
Ech_list = [Z]
lambd = -np.diag(Q) # paramètres des exponentielles entre deux sauts
P = (Q.T/lambd).T + np.identity(N) # matrice de transition de la chaîne de Markov incluse
while T < t:
i = E.index(Z)
T += -np.log(npr.rand())/lambd[i]
if T < t:
Time_list.append(T)
j = random.choices(range(N),P[i])[0]
Z = E[j]
Ech_list.append(Z)
else:
Time_list.append(t)
Ech_list.append(Z)
return(Time_list,Ech_list)
# EXEMPLE
E = [0,1.5,3,7]
mu0 = np.ones(4)*0.25
Q = np.array(
[[-5, 3, 1, 1],
[1, -1, 0, 0],
[2, 1, -4, 1],
[0, 2, 2, -4]])
# Tests :
# np.diag(Q)<0
# np.sum(Q,axis=1)==0
# Q2 = np.array(
# [[-1, 0.3, 0.7, 0],
# [1, -2, 0.5, 0.5],
# [1, 1, -3, 1],
# [0.1, 0.1, 0.3, -0.5]])
T,Z = Simu_CMTC(100,Q,mu0)
plt.step(T,Z,'--P', where='post')
plt.show()
# Mesure d'équilibre
def Mesure_invariante(Q):
N = len(Q[0])
A = np.append(Q.T,[np.ones(N)],axis=0)
b = np.zeros(N+1)
b[-1] = 1
pi = np.linalg.solve(np.dot(A.T,A),np.dot(A.T,b))
return(pi)
#Test :
#np.dot(Mesure_invariante(Q),Q)
Mesure_invariante(Q) # NB : calcul exact = [14/83, 58/83, 6/83, 5/83]
Ainsi, pour toute fonction $f : E \to \mathbb R$, on a $$ \lim_{t\to\infty}\frac1t\int_0^t f(X_s) d s = \sum_{x\in E}f(x)\pi_x $$ Par exemple, pour $f(x)=x^2$ on obtient que la moyenne temporelle de la variante de $X_t$ c'est la variance d'une variable de loi $\pi$, donnée ici par :
Var_Pi = np.dot(np.array(E)**2,Mesure_invariante(Q))-np.dot(np.array(E),Mesure_invariante(Q))**2
Var_Pi
Retrouvons à l'aide de ce résultat la mesure invariante (en prenant $f(x)=\boldsymbol 1_{x=y}$ pour $y\in E$)
# Temps moyen passé par état
def frequences_moyennes(t,Q,mu):
T,Z = Simu_CMTC(t,Q,mu)
N = len(Q[0])
Njumps = len(T)
frequences = np.zeros(N)
for i in range(Njumps):
j = E.index(Z[i])
if i==0:
frequences[j] += T[1] # on rappelle que T[0]=0
elif i<Njumps-1:
frequences[j] += T[i+1]-T[i]
else:
frequences[j] += t-T[-1]
return(frequences/t)
frequences_moyennes(int(1e4),Q,mu0)
Le generateur $Q$ d'une file d'attente $M/M/K$ de loi d'arrivées $\mathcal(\lambda)$ et de loi de durée de traitement $\mathcal E(\mu)$ est donné par $Q_{0,0}=-Q_{0,1}=-\lambda$ puis, pour $n\geq 1$, $$ Q_{x,x-1}=\min(n,K)\mu,\quad Q_{x,x}=-(\lambda+\min(n,K)\mu),\quad Q_{x,x+1}=\lambda $$ et $Q_{x,y}=0$ autrement. Autrement dit, les taux de saut sont $\lambda(n)=\lambda+\min(n,K)\mu$ pour tout $n\in\mathbb N$ et, la matrice de transition de la chaîne incluse est $P_{0,1}=1$ puis, pour tout $n\geq 1$, $$ P_{n,n-1}=\mu\min(n,K)/(\lambda+\min(n,K)\mu),\qquad P_{n,n+1}=\lambda/(\lambda+\min(n,K)\mu) $$
def MM(K,lambd,mu,t): # inter-arrivées ~ Exp(lambd), temps de traitement ~ Exp(mu), K guichets.
T = 0
Time_list = [T]
Z = 0
Ech_list = [Z]
while T < t:
T += -np.log(npr.rand())/(lambd+min(Z,K)*mu)
if T < t:
Time_list.append(T)
if npr.rand()<lambd/(lambd+min(Z,K)*mu):
Z += 1
else:
Z -= 1
Ech_list.append(Z)
else:
Time_list.append(t)
Ech_list.append(Z)
return(Time_list,Ech_list)
# Taille moyenne empirique de la file
def moyEst(T,Z):
Tm = T[:-1] # on supprime T[-1]=t
Tp = T[1:] # on supprime T[0]=0
Tdiff = np.array(Tp)-np.array(Tm)
t = T[-1]
Zp = Z[:-1] # on supprime Z[-1] (qui est égal à Z[-2])
return(Tdiff.dot(Zp)/t)
# Guichet M/M/1, lambd=1, mu=20
t = int(1e4)
T,Z = MM(1,1,20,t)
plt.step(T,Z,'--P', where='post')
plt.show()
moyEst(T,Z)
# Guichet M/M/2, lambd=1, mu=10
t = int(1e5)
T,Z = MM(2,1,10,t)
plt.step(T,Z,'--P', where='post')
plt.show()
moyEst(T,Z)