Integrales PDF
Integrales PDF
Integrales PDF
1. Introduction
Ce document explique le principe du calcul d’une intégrale par la méthode de Monte-Carlo.
On fera une comparaison avec la méthode des rectangles, pour mettre en évidence l’avantage
de la méthode de Monte-Carlo sur les méthodes de quadrature pour les calculs d’intégrale dans
un espace de dimension élevée.
import numpy
from matplotlib.pyplot import *
def integrale(N):
x = numpy.linspace(0,numpy.pi,N)
f = numpy.sin(x)
return abs(f.sum()*numpy.pi/N-2.0)
Voici un exemple :
e = integrale(100)
print(e)
--> 0.020166157744947677
Frédéric Legrand Licence Creative Commons 2
e = integrale(1000)
print(e)
--> 0.0020016465809187256
L’erreur est divisée par 10. La méthode des rectangles a une erreur d’ordre 1, proportion-
nelle à h1 . D’autres méthodes ont une erreur d’ordre plus élevé par rapport à h, qui permet de
converger plus rapidement. Par exemple, la méthode des trapèzes a une erreur d’ordre 2 : une
réduction de h d’un facteur 10 réduit l’erreur d’un facteur 100.
Considérons à présent le cas des intégrales doubles. Pour un domaine d’intégration carré
[a,b]x[a,b], la méthode des rectangles s’écrit :
Z bZ b 2
b−a X
f (x, y) dxdy ' f (xi , yj ) (4)
a a N i,j
def integrale2(N):
dx = numpy.pi/N
def f(i,j):
return numpy.sin(i*dx)*numpy.cos(j*dx)
f = numpy.fromfunction(f,(N,N))
return abs(f.sum()*(numpy.pi/N)**2)
e=integrale2(100)
print(e)
--> 0.062826685274008073
e=integrale2(1000)
print(e)
--> 0.0062831801394658184
La division du pas par 10 a le même effet que pour l’intégration simple : l’erreur est divi-
sée par 10. Cependant, le nombre de calculs effectués (évaluation de f et somme) est multiplié
par 100. De manière générale, un calcul d’intégrale en dimension d par la méthode des rec-
tangles nécessite une augmentation du temps de calcul d’un facteur 10d pour augmenter la
précision d’un facteur 10. Pour les autres méthodes de quadrature plus précises, on retrouve
cette dépendance en puissance par rapport à la dimension de l’espace.
Frédéric Legrand Licence Creative Commons 3
3. Méthode de Monte-Carlo
3.a. Principe
On reprend l’exemple de l’intégrale d’une fonction à une variable sur l’intervalle [a, b].
Soient N réels xi tirés aléatoirement sur l’intervalle [a, b] avec une densité de probabilité uni-
forme, égale à
1
p(x) = (6)
b−a
L’évaluation de l’intégrale par la méthode de Monte-Carlo consiste (dans sa forme élémentaire)
à calculer la somme suivante :
N −1
1 X
SN = (b − a) f (xi ) (7)
N i=0
Il s’agit de la même formule que celle de la méthode des rectangles, avec des points répartis
aléatoirement sur l’intervalle.
En introduisant la variable aléatoire X, cette somme est une évaluation de l’espérance de
f (X), multipliée par (b − a).
Pour obtenir une expression plus générale, considérons une variable aléatoire réelle X sur
l’intervalle [a, b] avec une densité de probabilité p(x).
Pour une fonction g, l’espérance de g(X) est :
Z b
E(g(X)) = p(x)g(x) dx (8)
a
σ2
var(SN ) = (12)
N
Il s’en suit que l’écart-type se réduit comme l’inverse de la racine carré de N lorsqu’on aug-
mente le nombre d’échantillons. Ce résultat reste valable pour une intégrale double, triple, etc.
L’évolution de la variance de la somme avec N est indépendante
√ de la dimension d de l’espace.
Pour une intégrale simple, cette convergence en 1/ N est plus lente que la convergence en
1/N de la méthode des rectangles, qui est la méthode de quadrature la plus lente. La méthode
Frédéric Legrand Licence Creative Commons 4
de Monte-Carlo peut cependant devenir avantageuse pour les intégrales triples ou en dimension
d supérieure à 3, lorsque la précision souhaitée est faible.
Pour évaluer la précision du résultat, il faut évaluer la variance σ 2 . Cela peut se faire avec
le calcul de la moyenne, en calculant la variance empirique :
N −1 2
1 X f (xi ) 2
vN = var(f /p, N ) = − SN (13)
N i=0 p(xi )
En divisant par N , on obtient la variance de la somme. L’intervalle de confiance à 95 pour cent
est :
√ √
1, 96 vN 1, 96 vN
SN − √ , SN + √ (14)
N N
L’intégrale considérée a une probabilité 0,95 de se trouver dans cet intervalle. √
La dépendance de la variance de la somme en fonction de N est toujours 1/ N , quelle que
soit la dimension de l’espace et la fonction intégrée. Pour réduire la variance, il faut réduire
la variance σ 2 de f /p. L’amélioration de la convergence consiste donc à choisir une densité
de probabilité p(x) qui minimise la variance et qui ne soit pas trop difficile à échantillonner.
Supposons que f (x) ≥ 0 et considérons la densité de probabilité particulière suivante :
f (x)
po (x) = R b (15)
a
f (x) dx
La variance est dans ce cas :
Z b
2
σ = var f (x) dx =0 (16)
a
La variance est nulle, mais cette densité de probabilité po (x) n’est pas réalisable car il faudrait
pour cela connaître l’intégrale que l’on cherche. Pour réduire la variance, on cherche à définir
une densité de probabilité qui s’approche au mieux de la forme de la fonction f , tout en étant
simple et peu coûteuse à échantillonner. C’est ce qu’on appelle l’échantillonnage préférentiel
(importance sampling). La densité de probabilité doit être grande là où la fonction f a une
valeur absolue grande.
import numpy.random
import random
import math
import numpy
def integration1d(fonction,a,b,N):
x = a+(b-a)*numpy.random.random_sample(N)
p = 1.0/(b-a)
f = fonction(x)
Frédéric Legrand Licence Creative Commons 5
moyenne = f.sum()/(N*p)
g = f* f
variance = g.sum()*1.0/(N*p*p)-moyenne*moyenne
return (moyenne,math.sqrt(variance/N)*1.96)
def f(x):
return numpy.sin(x)
(integrale,intervalle) = integration1d(f,0,math.pi,1000)
print((integrale,intervalle))
--> (1.9776925716412701, 0.06172322830900628)
Pour le même nombre de points calculés, la méthode des rectangles est beaucoup plus
précise. Pour réduire la variance, on peut chercher à augmenter la densité de probabilité autour
de π/2, où la fonction est maximale. Bien sûr, ce type d’amélioration suppose que l’on ait des
informations sur la fonction à intégrer. Une densité constante par morceau est un bon choix, car
elle peut être échantillonnée simplement. Pour obtenir une distribution non uniforme simple,
on peut diviser l’intervalle en trois parts égales, et attribuer une probabilité double à l’intervalle
central :
1/2
1/4
x
a c1 c2 b
Pour échantillonner cette distribution, il suffit de tirer un nombre aléatoire p parmi 1,2,3,4 avec
une égale probabilité. Si p=1, on tire x dans le premier intervalle avec une densité uniforme.
Si p=2 ou 3, on tire x dans le second intervalle. Si p=4, on tire x dans le troisième intervalle.
Pour chaque tirage, on doit diviser la valeur de f (x) par la densité de probabilité. Les densités
de probabilité des trois intervalles sont respectivement égales à 1/4, 1/2 et 1/4 divisés par la
largeur de chaque intervalle.
Frédéric Legrand Licence Creative Commons 6
def integration1d_importance(fonction,a,b,N):
delta = (b-a)*1.0/3
c1 = a+delta
c2 = a+2*delta
somme = 0.0
somme2 = 0.0
for i in range(N):
p = random.randint(1,4)
if p==1:
x = random.uniform(a,c1)
f = fonction(x)*4
elif p==2 or p==3:
x = random.uniform(c1,c2)
f = fonction(x)*2
else:
x = random.uniform(c2,b)
f = fonction(x)*4
somme += f
somme2 += f*f
moyenne = somme*delta/N
variance = somme2*delta*delta/N-moyenne*moyenne
return (moyenne,math.sqrt(variance/N)*1.96)
(integrale,intervalle) = integration1d_importance(f,0,math.pi,1000)
print((integrale,intervalle))
--> (1.9782931763755307, 0.04799482505984376)
On a bien une réduction de la variance pour le même nombre d’échantillons. Pour évaluer
l’efficacité de la nouvelle méthode, il faudrait aussi tenir compte du surcoût dû au tirage d’un
nombre aléatoire supplémentaire. Lorsque l’évaluation de f est très coûteuse (ce n’est pas le
cas ici) et domine le temps de calcul, l’échantillonnage préférentiel est certainement un bon
choix.
Il est possible d’échantillonner avec une densité uniforme dans un disque (voir plus loin), mais
une méthode plus générale consiste à échantillonner uniformément dans le domaine carré Ω.
D’une manière plus générale, le domaine d’intégration D peut avoir une forme complexe, et
on choisit le domaine rectangulaire Ω le plus petit (parallèle aux axes) qui contienne D. Il suffit
alors de poser f (x) = 0 en dehors de D.
Voici une fonction qui fait l’intégration dans un domaine rectangulaire. La densité de pro-
babilité est l’inverse de l’aire du rectangle.
def integration2d(fonction,a,b,c,d,N):
x = a+(b-a)*numpy.random.random_sample(N)
y = c+(d-c)*numpy.random.random_sample(N)
p = 1.0/((b-a)*(d-c))
somme = 0.0
somme2 = 0.0
for i in range(N):
f = fonction(x[i],y[i])
somme += f
somme2 += f*f
moyenne = somme/(p*N)
variance = somme2/(p*p*N)-moyenne*moyenne
return (moyenne,math.sqrt(variance/N)*1.96)
Voici par exemple le calcul de l’intégrale de la fonction qui vaut 1 sur le disque, qui est
égale à π :
def f(x,y):
if x*x+y*y <= 1:
return 1
else:
return 0
(integrale,intervalle) = integration2d(f,-1,1,-1,1,10000)
print((integrale,intervalle))
--> (3.156, 0.0319886411440061)
Frédéric Legrand Licence Creative Commons 8
On remarque que les points tirés en dehors du cercle ne sont pas pris en compte dans la
somme (puisque f prend une valeur nulle). Cela revient à échantillonner des points dans le
disque avec une méthode de rejet.
Pour revenir au cas plus général d’une fonction f à intégrer sur le disque, on remarque
qu’il y a un échantillonnage préférentiel évident consistant à échantillonner seulement sur
le disque. Pour ce faire, il ne faut pas utiliser une méthode de rejet, qui nous ramènerait au
cas précédent. Dans le cas du disque, l’inversion de la fonction de répartition a une solution
analytique. Pour deux variables aléatoires (u1 , u2 ) de densité uniforme sur l’intervalle [0,1],
les variables polaires suivantes :
θ = 2πu1 (18)
√
r = R u2 (19)
donnent une distribution uniforme sur le disque de rayon R. La fonction suivante calcule une
intégrale sur le disque de rayon R. Les variables de la fonction sont en coordonnées polaires.
def integrationDisque(fonction,R,N):
theta = 2*numpy.pi*numpy.random.random_sample(N)
r = R*numpy.sqrt(numpy.random.random_sample(N))
p = 1.0/(numpy.pi*R*R)
somme = 0.0
somme2 = 0.0
for i in range(N):
f = fonction(r[i],theta[i])
somme += f
somme2 += f*f
moyenne = somme/(p*N)
variance = somme2/(p*p*N)-moyenne*moyenne
return (moyenne,math.sqrt(variance/N)*1.96)
Dans ce cas, le calcul de π avec f = 1 n’a plus de sens puisque la densité est l’inverse de
π. Considérons plutôt l’intégration d’une fonction :
def f(r,theta):
return 1-r*r
(integrale,intervalle) = integrationDisque(f,1.0,10000)
print((integrale,intervalle))
--> (1.5654527243187746, 0.017746448191176947)
On peut citer l’espace des phases utilisé en physique statistique pour représenter la configu-
ration d’un système comportant un grand nombre d’atomes. Les méthodes de quadrature sont
très inefficaces, voire inutilisables, lorsque la dimension est élevée. Par exemple pour la mé-
thode des rectangles, le nombre de points nécessaires pour maintenir une précision constante
évolue comme N d . Le logarithme du nombre de points est donc proportionnel à la dimension
d, une loi que l’on retrouve pour toutes les méthodes de quadrature. La méthode de Monte-
Carlo ne présente pas cette dépendance par rapport à la dimension. La variance de la somme
calculée est :
σ2
var(SN ) = (20)
N
La variance σ 2 de la variable f /p est susceptible d’augmenter avec la dimension, mais pas se-
lon une loi en puissance. La méthode de Monte-Carlo a donc un avantage décisif en dimension
élevée.
Comme exemple, nous allons calculer, en dimension d, le volume compris entre les hyper-
sphères de rayons R1 et R2 . La fonction renvoie aussi l’estimation de la variance σ 2 .
def volume(dim,R1,R2,N):
somme = 0.0
somme2 = 0.0
R12 = R1*R1
R22 = R2*R2
p = 1.0/math.pow(2*R2,dim)
for i in range(N):
r2 = 0.0
for d in range(dim):
x = random.uniform(-R2,R2)
r2 += x*x
if r2>= R12 and r2<=R22:
f = 1.0
else:
f = 0.0
somme += f
somme2 += f*f
moyenne = somme/(p*N)
variance = somme2/(p*p*N)-moyenne*moyenne
return (moyenne,variance,math.sqrt(variance/N)*1.96)
(m,v,e) = volume(3,0,1,10000)
print((m,v,e))
--> (4.1168, 15.98635776, 0.07836656938441033)
(m,v,e) = volume(5,0,1,10000)
Frédéric Legrand Licence Creative Commons 10
print((m,v,e))
--> (5.4112, 143.87731456, 0.2350997855408839)
(m,v,e) = volume(5,0,1,10000*90)
print((m,v,e))
--> (5.253582222222223, 140.51450494546174, 0.024490372761522387)
Avec la méthode des rectangles, il aurait fallu augmenter le nombre de points d’un facteur
2
N pour maintenir la précision constante. Même si la variance augmente avec la dimension, la
méthode de Monte-Carlo est incomparablement plus efficace en dimension élevée.
Voyons le volume d’une coque d’épaisseur un dixième du rayon :
(m,v,e) = volume(5,0.9,1,10**5)
print((m,v,e))
--> (2.1328, 63.70076416, 0.04946846021426743)
(m,v,e) = volume(7,0,1,10**7)
print((m,v,e))
--> (4.7254144, 582.5235019482726, 0.014959352543089837)
(m,v,e) = volume(7,0.9,1,10**7)
print((m,v,e))
--> (2.4641664, 309.34118315311105, 0.010901215937687829)