Correction

Transcription

Correction
ENSAE exercice de préparation pour le TD noté, mardi
27 novembre 2012
Ces exercices abordent des sujets en rapport avec le TD noté.
1
On construit une séquence selon le procédé suivant :
1. On tire un nombre entier entre 0 et 2.
2. On l’ajoute à la séquence.
3. Si le nombre tiré est 0, on s’arrête.
4. Si c’est 1, on tire à nouveau une fois et on répète le même processus depuis l’étape 2.
5. Si c’est 2, on tire deux nombres qu’on ajoute à la séquence et on tire encore autant de fois
que la somme des deux nombres tirés. Pour chacun d’entre eux, on répète le processus depuis
l’étape 3.
Rappel : voici deux lignes de code permettant de générer un nombre aléatoire entier entre 0 et 5
inclus
import random
i = random.randint(0,5)
1) Construire une fonction qui construit une séquence telle que celle définie plus haut.
2) Construire une fonction qui calcule la moyenne des longueurs des séquences obtenues (sur 1000
séquences par exemple) ?
Correction
L’énoncé peut suggérer qu’il faut agir différemment selon que le nombre entier aléatoire est 0, 1 ou 2.
Cependant, il est utile de remarquer que le nombre de tirages restant à faire dépend de la longueur
de la séquence de nombres et de la somme des nombres qu’elle contient. Si on note s la séquence de
nombres aléatoires dans un état intermédiaire, le nombre de tirages aléatoires restant à effectuer est
égal à sum(s) − len(s) + 1. On vérifie que cela fonctionne lorsque s contient juste un nombre.
La seconde question ne pose pas de problème puisqu’il s’agit de faire une moyenne des longueurs
d’un grand nombre de séquences, 100 dans le programme qui suit.
#coding:latin-1
import random
# question 1
def sequence () :
res = [ ]
nb = 1
while nb > 0 :
i = random.randint(0,2)
nb += i - 1
res.append (i)
1
return res
# question 2
def moyenne (nb_tirage) :
somme = 0.0
for i in range(nb_tirage) :
s = sequence()
somme += len(s)
return somme / nb_tirage
s = sequence ()
print len(s),s
m = moyenne (100)
print m
Après quelques exécutions, on remarque que cette moyenne n’est pas jamais la même ou tout simplement que le programme ne se termine pas. Il y a deux explications possibles :
1. Soit 100 tirages ne suffisent pas pour faire converger la moyenne des longueurs,
2. Soit la moyenne n’existe pas.
Le programme informatique ne permet pas de répondre de manière certaine à cette question, il
permet juste d’avoir une intuition qui serait dans ce cas que la moyenne n’existe pas. La preuve doit
être mathématique.
Aparté
On note Sn = (N1 , N2 , ..., Nn ) une séquence de nombres aléatoires tirés dans l’ensemble {0, 1, 2} avec
les probabilités (a, b, c). Cette séquence correspond à celle de l’énoncé dans le cas où a = b = c = 13 .
L’intuition est que si a > c, la moyenne des longueurs des séquences est finie et si a 6 c alors elle
est infinie.
La démonstration qui suit repose sur l’indépendance des tirages aléatoires. On note la variable
aléatoire #S qui désigne la longueur d’une séquence générée selon le processus décrit au paragraphe
précédent. On décompose cette variable comme ceci :
#S = k + #Sk
(1)
Où #Sk est la longueur de la séquence après le k ième élément exclu. En tenant compte de l’indépendance des tirages et en supposant que l’espérance de #S existe, on peut dire que :

E #Sk |
k
X

Nj 6 k + 1 = 0
(2)
j=0

E #Sk |
k
X

Nj = k + 2 = E (#S)
(3)
j=0

E #Sk |
k
X

Nj = k + 3 = 2E (#S)
(4)
j=0
La première assertion est évidente. Si à partir d’un certain rang, la somme des nombres tirés est
inférieure à k + 1, la séquence s’arrête. La deuxième assertion l’est également, à partir du rang k, il
2
reste un nombre à tirer, l’espérance de la longueur de la séquence qui commence à partir de cette
position est identique à celle au début de celle-ci.
Pour la dernière assertion, imaginons que nous devions tirer 2 nombres aléatoires. On peut le faire
aux positions k + 1 et k + 2 ou on peut tirer le premier nombre, continuer la séquence, attendre qu’il
n’y ait plus de nombres à tirer puis tirer le second. Dans ce cas, on comprend que l’espérance de la
longueur est bien 2 fois celle d’une séquence. On en déduit que :
E (#Sk ) =
∞
X
m=0
=
∞
X
m=0

E #Sk |
k
X
 
Nj = k + m + 1 P 
j=0
k
X

Nj = k + m + 1 
(5)
j=0

mE (#S) P 
k
X

Nj = k + m + 1
(6)
j=0
Pour utiliser ce raisonnement, on isole le premier nombre s0 de la séquence aléatoire S en S =
(N0 , S N0 ). #S1 est la séquence S privée de N0 . On applique le résultat précédent :

 1
1 + E (#S)
E (#S) =

1 + 2E (#S)
si N0 = 0
si N0 = 1
si N0 = 2
(7)
On en déduit que :
E (#S) = a + b [1 + E (#S)] + c [1 + 2E (#S)]
= a + b + c + E (#S) (b + 2c)
= 1 + E (#S) (1 − a + c)
(8)
On en déduit que :
E (#S) =
1
a−c
(9)
Sachant que cette quantité est forcément positive, elle n’est définie que si a > c. Le programme
suivant permet de vérifier qu’en simulant des séquences pour plusieurs valeurs a, b, c, on retrouve
bien une espérance proche de celle donnée par cette formule.
#coding:latin-1
import random
def randomint (a,b,c) :
x = random.random()
if x <= a : return 0
elif x <= a+b : return 1
else : return 2
3
def sequence (a,b,c) :
res = [ ]
nb = 1
while nb > 0 :
i = randomint(a,b,c)
nb += i - 1
res.append (i)
return res
def moyenne (nb_tirage,a,b,c) :
somme = 0.0
for i in range(nb_tirage) :
s = sequence(a,b,c)
somme += len(s)
return somme / nb_tirage
a,c = 0.3, 0.2
b = 1-a-c
moy = 1.0 / (a-c)
print "calcul",moy
m1 = moyenne (100000, a,b,c)
print "simulée", m1
Second aparté
Sn = (N1 , N2 , ..., Nn ) est toujours une séquence de nombres aléatoires tirés dans l’ensemble {0, 1, 2}
avec des probabilités équiprobables (a, b, c), le nombre de tirages Tn restant à effectuer après n tirages
est :
Tn =
n
X
Ni − n + 1
(10)
i=1
Si définit la séquence Sn0 = (N10 , ..., Nn0 ) = (N1 − 1, ..., Nn − 1) où Ni0 est une variable aléatoire à
valeur dans l’ensemble {−1, 0, +1} :
Tn =
n
X
Ni0 + 1 = Tn0 + 1
(11)
i=1
La séquence Sn0 est de longueur finie s’il existe n tel que Tn0 = 0. Tn0 est en quelque sorte une marche
aléatoire dont on peut définir l’espérance et la variance :
E
Tn0
=
V Tn0 =
n
X
i=1
n
X
E Ni0 = nE N10 = 0
(12)
V Ni0 = nV N10 = n E (N10 )2 − (E N10 )2 ] = n(a + c − (c − a)2 )
(13)
i=1
Dans la suite, on pose e = −1. On définit le nombre U tel que : U = inf {u|Tu0 = e}. U est la
longueur de la séquence S. C’est aussi une variable aléatoire qui vérifie :
0
TU = e
(14)
∀u < U, Tu0 6= e
4
U est un temps d’arrêt pour le processus aléatoire (S 0 n)n . On s’intéresse maintenant à la séquence
Sn0 . Etant donné que chaque élément peut prendre trois valeurs, il existe 3n séquences différentes.
On va chercher à calculer la probabilité de chaque séquence Sn0 vérifiant :
∀u < n,
Tu0
=
u
X
Ni0 6= e
(15)
i=1
Donc notre cas, on suppose e = −1 ce qui implique pour la marche aléatoire de rester positive. Le
raisonnement serait le même pour e > 0. La probabilité P (U = u) revient à énumérer toutes les
marches aléatoires (ou le nombre de chemins) qui terminent à e tout en restant supérieures à e entre
1 et u exclu. On définit pui le nombre de chemins terminant par Tu0 = e et ne passant jamais par e
(∀k < u, Tk0 6= e). On définit :
pue = fe (u) = P Tu0 = e, Tk0 6= e ∀k < u
(16)
Si e < 0, on peut construire pui par récurrence :
p1k =
puk
0
1
si k 6= 1
si k = 0
(17)

c pu−1,k−1 +b pu−1,k +a pu−1,k+1



b pu−1,k
+a pu−1,k+1
=
a pu−1,k+1



0
si k > e + 1
si k = e + 1
si k = e
(18)
sinon
A partir de cette définition, on peut désormais écrire que si l’espérance de U existe, alors :
E (U ) =
∞
X
uP (U = u) = lim
n→∞
u=1
= lim
n→∞
= lim
n→∞
n
X
n
X
uP (U = u)
(19)
u=1
uP (Tu = e, Tk 6= e ∀k < u)
(20)
upue = lim rn
(21)
u=1
n
X
n→∞
u=1
On repasse à l’informatique pour avoir l’intuition mathématique de la limite de (ru )u lorsque u tend
vers l’infini.
#coding:latin-1
import random, math
# question 1
def calcul_suite_a (n, e, a,b,c) :
p = {}
p [0,0] = 1
for u in range (1,n+1) :
for k in range (e,u+2) :
if
k == e
: p [u,k] = a * p.get ( (u-1,k+1), 0 )
5
elif k == e+1 : p [u,k] = a
b
elif k > e+1 : p [u,k] = a
b
c
return p
*
*
*
*
*
p.get
p.get
p.get
p.get
p.get
(
(
(
(
(
(u-1,k+1),
(u-1,k ),
(u-1,k+1),
(u-1,k ),
(u-1,k-1),
0
0
0
0
0
) + \
)
) + \
) + \
)
def affiche_proba (ps, e) :
n
= max ( [ k[1] for k,z in ps.iteritems () ] )
moy = 0.0
logru = []
logu = []
for u in range (1, n+1) :
p = ps.get((u,e),0)*1.0
moy += p * u
mes = "u % 3d P(U=u) %1.6g r_u %1.6g" % (u, p, moy)
if u < 3 or u %50 == 0 : print mes
logru.append(math.log(moy))
logu.append(math.log(u))
import pylab
pylab.plot ( logu, logru, "o")
pylab.show()
a,c = 1.0/3, 1.0/3
b = 1-a-c
e = -1
su = calcul_suite_a(600,e,a,b,c)
affiche_proba(su, e)
Pour a > c, on vérifie que la suite (ru )u converge vers l’expression (9). Pour a = b = c = 13 , cela
donne :
u
u
u
u
u
u
u
u
u
u
u
u
u
u
1
2
50
100
150
200
250
300
350
400
450
500
550
600
P(U=u)
P(U=u)
P(U=u)
P(U=u)
P(U=u)
P(U=u)
P(U=u)
P(U=u)
P(U=u)
P(U=u)
P(U=u)
P(U=u)
P(U=u)
P(U=u)
0.333333
0.111111
0.0013566
0.00048407
0.000264311
0.000171942
0.000123146
9.37388e-05
7.44204e-05
6.09325e-05
5.10779e-05
4.36202e-05
3.78157e-05
3.31933e-05
r_u
r_u
r_u
r_u
r_u
r_u
r_u
r_u
r_u
r_u
r_u
r_u
r_u
r_u
0.333333
0.555556
5.57241
8.38753
10.5627
12.4016
14.0242
15.4926
16.8438
18.1021
19.2843
20.4028
21.4669
22.4839
Il en ressort que la suite P (U = u) semble tendre vers 0 à l’infini. Ceci signifierait que la probabilité
de construire une séquence Sn infinie est nulle. Mais la suite (ru )u semble tendre vers l’infini ce qui
signifirait que la moyenne des longueurs des séquences initiales Sn n’existe pas. On vérifie en traçant
le graphe (log u, log ru )u (voir figure 1). Il suggère que rn ∼ cnα avec 0 < α < 1.
Il reste à démontrer formellement que la suite rn tend vers l’infini. Pour cela, on définit :
fe (n) = P (U = n) = P Tn0 = e, Ti0 6= e si i < n
6
(22)
Figure 1 : Graphe (log u, log ru )u défini
par (21).
fe (n) est différent de la suite pn0 . La marche aléatoire pour atteindre -1 au temps n doit nécessaire
commencer par 0 ou 1. Si on note, k le premier temps auquel elle passe par 0, on peut décompser
f−1 (n) :
f−1 (1) = c
(23)
f−1 (n) = bf−1 (n − 1) + c
"n−1
X
P
k=2
k
X
!
Si0 = −1 P
i=2
n
X
!#
Si0 = −1
(24)
i=k+1
On en déduit que :
f−1 (1) = a
(25)
f−1 (n) = bf−1 (n − 1) + c
"n−1
X
#
f−1 (k − 1)f−1 (n − k)
(26)
k=2
On pose :
Fe (s) =
∞
X
fe (n)sn
(27)
n=1
P
Fe (1) = ∞
n=1 fe (n) correspond à la probabilité que la marché aléatoire atteint e en un temps fini.
0
La
P∞moyenne des longueurs des séquences S n est défini comme 1le temps moyen d’arrivée en e :
n=1 nfe (n). On utilise le théorème de la convergence monotone pour montrer que :
1. http://fr.wikipedia.org/wiki/Th%C3%A9or%C3%A8me_de_convergence_monotone
7
∞
X
nfe (n)sn = Fe0 (s)
n=1
=⇒ lim
s→1
∞
X
nfe (n)sn =
n=1
∞
X
nfe (n) = Fe0 (1)
(28)
n=1
On cherche une relation fonctionnelle du type x[F−1 (s)]2 + yF−1 (s) + z = 0 en utilisant (26).
"
[F−1 (s)]2 =
=
=
∞
X
n=1
∞
X
s
n=3
∞
X
n=3
#2
f−1 (n)sn
n−1
"n−1
X
#
f−1 (k − 1)f−1 (n − k)
k=2
1
sn−1 [f−1 (n) − bf−1 (n − 1)]
c
∞
∞
n=3
n=3
b X n
1 X n
s f−1 (n) −
s f−1 (n − 1)
=
cs
cs
1
b
=
[F−1 (s) − f−1 (1)s] − F−1 (s)
cs
c
1
b
f−1 (1)
= F−1 (s)
−
−
cs c
c
=⇒
cs[F−1 (s)]2 − F−1 (s)(1 − bs) − sf−1 (1) = 0
(29)
En résolvant le polynôme csx2 − (1 − bs)x − sf−1 (1) = 0, il est possible de déterminer l’expression
de F−1 (s). On rappelle que f−1 (1) = a. Une seule des solutions du polynôme du second degré est
positive 2 .
F−1 (s) =
(1 − bs) +
p
(1 − bs)2 + 4acs2
2cs
(30)
Il ne reste plus qu’à dériver et à trouver la limite lorsque s → 1.
A suivre.
2
On considère une matrice 10 × 10 remplie de 0 et de 1 aléatoirement avec la probabilité d’avoir 1
égale à 0,2.
1) Construire une telle matrice.
2) Compter le nombre de points mij de la matrice vérifiant les conditions suivantes :
√
2. Les solutions d’un polynôme du second degré de type ax2 + bx + c = 0 sont de type : x =
8
−b+/− b2 −4ac
.
2a
1. mij = 0
2. mi−1,j = 1 ou mi+1,j = 1 ou mi,j−1 = 1 ou mi,j+1 = 1
Correction
Pour obtenir 1 avec une probabilité de 0,2, il suffit de tirer un nombre aléatoire N entre 1 et 5 inclus
et de ne considérer que le cas où N = 1.
import random
N = 10
M = [ [ 1 if random.randint(1,5) == 1 else 0 for i in range (N) ] for j in range(N) ]
for l in M : print l
nb = 0
for i in range(N) :
for j in range (N) :
if
i > 0
and
elif i < N-1 and
elif j > 0
and
elif j < N-1 and
print nb
M[i-1][j]
M[i+1][j]
M[i][j-1]
M[i][j+1]
==
==
==
==
1
1
1
1
:
:
:
:
nb
nb
nb
nb
+=
+=
+=
+=
1
1
1
1
Cela donne pour un exemple :
[0,
[0,
[0,
[0,
[0,
[0,
[0,
[0,
[0,
[0,
46
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
0,
0,
0,
1,
1,
0,
0,
1,
0,
0,
0,
0,
0,
0,
1,
1,
0,
0,
0,
0,
1,
1,
0,
1,
0,
1,
0,
0,
0,
0,
0]
0]
0]
1]
1]
1]
0]
0]
0]
0]
Ce n’est pas évident de vérifier qu’on ne s’est pas trompé. Un moyen simple consiste à prendre une
valeur de N plus petite.
[0, 1, 0]
[0, 0, 1]
[0, 0, 0]
4
3
On considère une matrice 10 × 10 remplie de nombres entiers aléatoires tirés entre 0 et 100. On
apelle M cette matrice.
1) Créer une autre matrice N qui vérifie : Nij =
programme.
9
M
P10 ij
.
i=1 Mij
Le module numpy simplifie l’écriture du
Correction
import random, numpy
N = 10
M = [ [ 1.0 if random.randint(1,5) == 1 else 0.0 for i in range (N) ] for j in range(N) ]
M = numpy.matrix(M)
MM = numpy.matrix(M)
for i in range (N) :
s = numpy.sum(M[i,:]) # ou M[i,:].sum()
if s > 0 : MM [i,:] = M [i,:] / s
print MM
Le dernier exercice cache deux pièges. Le premier est le problème des divisions entières. Si on remplace
1.0 et 0.0 par 1 et 0 sur la troisième ligne, tous les nombres manipulés deviennent entiers. La matrice
MM est alors peuplée de 0 et de 1 uniquement. Le second piège intervient quand on pense avoir résolu
le premier en forçant une division réelle en multipliant d’un côté par 1.0 :
import random, numpy
N = 5
M = [ [ 1 if random.randint(1,5) == 1 else 0 for i in range (N) ] for j in range(N) ]
M = numpy.matrix (M)
MM = numpy.matrix(M)
for i in range (N) :
s = numpy.sum(M[i,:])
if s > 0 : MM [i,:] = M [i,:]*1.0 / s
# multiplication par 1.0
print MM
Comme initialement, on a créé la matrice M avec des entiers, le module numpy refuse l’ajout ultérieur
de nombres réels. On peut regretter que le module numpy soit aussi strict ou ne jette une erreur
indiquant au programmeur qu’il s’est trompé. Le fait même de vérifier les types des objets contenus
dans la matrice et ceux qu’on lui injecte aurait le désavantage de ralentir les calculs.
10