Modélisez un processus de naissance et de mort
Dans une file d’attente, les clients arrivent un par un et repartent un par un. Dans un atelier, les machines tombent en panne une à une et sont réparées une à une. Dans une population, les individus naissent et meurent un à la fois. Tous ces systèmes ont un point commun : l’état est un nombre, et il ne bouge que de plus un ou de moins un.
Cette structure très particulière rend les calculs remarquablement simples : le régime stationnaire s’obtient par une formule explicite, sans résoudre de système. Ce chapitre vous la donne, et elle servira de moteur à toute la partie 3 sur les files d’attente. Notre fil rouge : un petit atelier de trois machines et un seul réparateur.
Le fil rouge : trois machines, un réparateur
Section intitulée « Le fil rouge : trois machines, un réparateur »Un atelier de fabrication possède trois machines identiques. Chacune, quand elle fonctionne, tombe en panne au taux par heure (10 heures de fonctionnement en moyenne). Un seul technicien les répare, une à la fois, en une durée exponentielle de taux par heure (2 heures en moyenne). Les durées sont indépendantes.
On note le nombre de machines en panne à l’instant (qu’elles soient en réparation ou en attente). Les états possibles sont 0, 1, 2 et 3. Que peut-il se passer à partir de l’état ?
- Une panne fait passer de à . Il y a machines en marche, chacune avec une horloge exponentielle de taux ; la première panne survient au taux (les taux s’additionnent, chapitre 5).
- Une réparation fait passer de à , au taux dès qu’au moins une machine est en panne (le technicien ne répare qu’une machine à la fois).
Deux événements simultanés ont une probabilité négligeable : l’état ne saute jamais de deux unités d’un coup.
Définition et générateur
Section intitulée « Définition et générateur »Un processus de naissance et de mort est une chaîne de Markov à temps continu à valeurs dans (ou dans ) dont les seules transitions sont et . Sur un petit intervalle de durée :
- est le taux de naissance dans l’état (arrivée d’un client, panne d’une machine) ;
- est le taux de mort dans l’état (départ d’un client, fin d’une réparation), avec puisqu’on ne peut pas descendre sous zéro.
Le graphe des taux est une simple ligne :
λ0 λ1 λ2 λ(n-1) λn 0 ─────► 1 ─────► 2 ─────► 3 ··· n-1 ───────► n ───────► n+1 ··· ◄───── ◄───── ◄───── ◄─────── ◄─────── μ1 μ2 μ3 μn μ(n+1)et le générateur est tridiagonal : sur la ligne , on trouve juste avant la diagonale, juste après, et sur la diagonale.
Pour l’atelier : , , , (plus aucune machine ne peut tomber en panne) et .
Le régime transitoire : des équations en chaîne
Section intitulée « Le régime transitoire : des équations en chaîne »L’équation de Kolmogorov prend ici une forme très lisible :
La probabilité d’être en augmente grâce aux naissances depuis et aux morts depuis , et diminue de tout ce qui quitte . Pour un espace infini, c’est un système infini d’équations différentielles couplées ; sauf cas particuliers (comme le processus de Poisson du chapitre suivant), on ne sait pas le résoudre à la main. En pratique, on le résout numériquement sur un espace tronqué, ou on se contente du régime stationnaire, beaucoup plus simple.
La balance locale et la formule du régime stationnaire
Section intitulée « La balance locale et la formule du régime stationnaire »Écrivons la balance globale (flux sortant = flux entrant) de l’état 0 : on ne sort de 0 que par une naissance, on n’y entre que par une mort depuis 1.
Pour l’état 1, la balance globale s’écrit . En y retranchant l’égalité précédente, il reste . Par récurrence, on obtient pour tout :
C’est l’équation de balance locale. Elle a une interprétation géométrique simple : coupez le graphe entre et . Le seul moyen de franchir la coupure vers la droite est une naissance depuis , et le seul moyen de la franchir vers la gauche est une mort depuis . En régime stationnaire, il passe autant de flux dans chaque sens.
En déroulant la balance locale, , d’où la formule générale :
- est le produit des taux de naissance de 0 à , divisé par le produit des taux de mort de 1 à ;
- vient de la normalisation .
Et quand l’espace d’états est infini ? Tout dépend de la convergence de . Deux cas fondamentaux, que vous retrouverez dans la partie 3 :
- Taux constants , : alors avec . La série géométrique converge si et seulement si , et alors . C’est la file M/M/1. Si , il n’y a pas de régime stationnaire : la file grossit indéfiniment (ou erre sans jamais se stabiliser).
- Morts proportionnelles , : alors avec , la série converge toujours (vers ), et est une loi de Poisson. C’est la file M/M/∞.
Voici une fonction générique, qui accepte les taux sous forme de fonctions de et tronque l’espace si nécessaire :
import numpy as np
def stationnaire_nm(taux_naissance, taux_mort, n_max): """Régime stationnaire d'un processus de naissance et de mort sur {0, ..., n_max}. taux_naissance(n) = lambda_n, taux_mort(n) = mu_n (pour n >= 1).""" gamma = np.ones(n_max + 1) for n in range(1, n_max + 1): gamma[n] = gamma[n - 1] * taux_naissance(n - 1) / taux_mort(n) # balance locale return gamma / gamma.sum()
lam, mu = 0.1, 0.5pi = stationnaire_nm(lambda n: (3 - n) * lam, lambda n: mu, n_max=3)print(np.round(pi, 3)) # [0.53 0.318 0.127 0.025]print((np.arange(4) * pi).sum()) # nombre moyen de machines en panne ≈ 0.648
# M/M/1 tronquée : si rho < 1, la troncature a un effet négligeablepi_mm1 = stationnaire_nm(lambda n: 8.0, lambda n: 10.0, n_max=200)print(pi_mm1[:3]) # ≈ [0.2 0.16 0.128] = (1 - rho) rho^nEn résumé
Section intitulée « En résumé »- Un processus de naissance et de mort est une chaîne à temps continu sur les entiers qui ne saute que de (taux ) ou de (taux , avec ).
- Son générateur est tridiagonal ; les équations du régime transitoire couplent chaque à ses deux voisins et sont en général difficiles à résoudre.
- En régime stationnaire, la balance locale exprime l’égalité des flux à travers la coupure entre et .
- Formule générale : , , , si la série converge.
- Taux constants : loi géométrique si . Morts proportionnelles à : loi de Poisson de paramètre .
Exercices
Section intitulée « Exercices »Exercice · Un calcul direct
facileUn processus de naissance et de mort sur a pour taux , , , . Écrivez son générateur et calculez sa loi stationnaire.
Voir la solution
(chaque ligne somme à 0). On a et . Donc et . On vérifie la balance locale : et .
En code
import numpy as np
A = np.array([[-2, 2, 0], [1, -2, 1], [0, 2, -2]], dtype=float)print(A.sum(axis=1)) # [0. 0. 0.]
# Formule produit : gamma_n = (lambda_0 ... lambda_{n-1}) / (mu_1 ... mu_n)lam = [2, 1]mu = [1, 2]gamma = np.cumprod([1] + [l / m for l, m in zip(lam, mu)])pi = gamma / gamma.sum()print(pi) # [0.25 0.5 0.25]print(pi @ A) # [0. 0. 0.] : Pi A = 0A <- matrix(c(-2, 2, 0, 1, -2, 1, 0, 2, -2), nrow = 3, byrow = TRUE)rowSums(A) # 0 0 0
# Formule produit : gamma_n = (lambda_0 ... lambda_{n-1}) / (mu_1 ... mu_n)lam <- c(2, 1); mu <- c(1, 2)gamma <- cumprod(c(1, lam / mu))pi_ <- gamma / sum(gamma)pi_ # 0.25 0.50 0.25pi_ %*% A # 0 0 0 : Pi A = 0Exercice · Embaucher un second technicien ?
moyenDans l’atelier du chapitre, on envisage d’embaucher un second technicien : deux machines peuvent alors être réparées en même temps.
- Quels taux changent ? Donnez les nouveaux .
- Calculez la nouvelle loi stationnaire et le nombre moyen de machines en panne.
- Le gain vous paraît-il justifier l’embauche ?
Voir la solution
- Les taux de panne ne changent pas. Les réparations se font au taux : , .
- ; ; . Donc et
Le nombre moyen de machines en panne vaut , contre 0,648 avec un seul technicien. 3. On gagne en moyenne machine en marche, soit environ 6 % de production en plus ( machines en marche au lieu de ). La probabilité d’arrêt total passe de 2,5 % à 0,7 %. Le premier technicien n’est occupé que 47 % du temps : l’embauche ne se justifie que si une machine arrêtée coûte très cher.
En code
import numpy as np
def stationnaire_nm(taux_naissance, taux_mort, n_max): gamma = np.ones(n_max + 1) for n in range(1, n_max + 1): gamma[n] = gamma[n - 1] * taux_naissance(n - 1) / taux_mort(n) return gamma / gamma.sum()
lam, mu = 0.1, 0.5panne = lambda n: (3 - n) * lamfor techniciens in (1, 2): pi = stationnaire_nm(panne, lambda n: min(n, techniciens) * mu, 3) en_panne = (np.arange(4) * pi).sum() print(techniciens, np.round(pi, 3), round(en_panne, 3), round(3 - en_panne, 2))# 1 [0.53 0.318 0.127 0.025] 0.648 2.35# 2 [0.577 0.346 0.069 0.007] 0.506 2.49stationnaire_nm <- function(taux_naissance, taux_mort, n_max) { gamma <- cumprod(c(1, sapply(1:n_max, function(n) taux_naissance(n - 1) / taux_mort(n)))) gamma / sum(gamma)}lam <- 0.1; mu <- 0.5panne <- function(n) (3 - n) * lamfor (techniciens in 1:2) { pi_ <- stationnaire_nm(panne, function(n) min(n, techniciens) * mu, 3) en_panne <- sum(0:3 * pi_) cat(techniciens, round(pi_, 3), round(en_panne, 3), round(3 - en_panne, 2), "\n")}## 1 0.53 0.318 0.127 0.025 0.648 2.35## 2 0.577 0.346 0.069 0.007 0.506 2.49Exercice · Des clients découragés
difficileDevant un guichet unique, les clients arrivent au taux , mais se découragent quand il y a du monde : lorsqu’il y a déjà personnes, un client qui se présente n’entre qu’avec probabilité . Le service est exponentiel de taux .
- Justifiez que le nombre de personnes présentes est un processus de naissance et de mort, et donnez ses taux.
- Montrez que la loi stationnaire existe toujours et identifiez-la.
- Application : clients par heure, par heure. Quelle est la probabilité que le guichet soit vide ? Combien de personnes sont présentes en moyenne ?
Voir la solution
- Les arrivées effectives se font au taux (un processus d’arrivées au taux dont on ne garde chaque arrivée qu’avec probabilité ), et les départs au taux pour . L’état ne varie que de : c’est un processus de naissance et de mort.
- avec . La série converge toujours (vers ), donc le régime stationnaire existe quels que soient et , et : c’est une loi de Poisson de paramètre , la même que pour la file M/M/∞.
- : , et le nombre moyen de personnes présentes est l’espérance de la loi de Poisson, .
En code
import numpy as npfrom scipy.stats import poisson
lam, mu, n_max = 3.0, 2.0, 60 # espace tronqué à 60 personnesgamma = np.ones(n_max + 1)for n in range(1, n_max + 1): gamma[n] = gamma[n - 1] * (lam / n) / mu # lambda_{n-1} = lam / n, mu_n = mupi = gamma / gamma.sum()
print(pi[0], (np.arange(n_max + 1) * pi).sum()) # 0.2231 1.5print(np.abs(pi - poisson.pmf(np.arange(n_max + 1), lam / mu)).max()) # 5.6e-17 : Poisson(1.5)lam <- 3; mu <- 2; n_max <- 60 # espace tronqué à 60 personnesgamma <- cumprod(c(1, (lam / (1:n_max)) / mu)) # lambda_{n-1} = lam / n, mu_n = mupi_ <- gamma / sum(gamma)
c(vide = pi_[1], moyenne = sum(0:n_max * pi_)) # 0.2231 1.5max(abs(pi_ - dpois(0:n_max, lam / mu))) # 5.6e-17 : c'est une Poisson(1.5)