8
Preuves de programmes
⋄ Faire la preuve d’un programme consiste à démontrer deux points :
• saterminaison: le fait que ce programme s’arrête après un nombre fini d’étapes. Avec ce que l’on a vu jusqu’à présent, le seul point qui peut empêcher la terminaison d’un programme est la présence de boucleswhilemal construites ;
• sacorrection: le fait que les résultats produits par le programme sont bien ceux atten- dus.
Pour simplifier, on s’intéresse dans la suite à faire la preuve defonctionsPYTHON.
⋄ Résultat clé pour laterminaison d’une boucle while : il n’existe pas de suite infinie, à valeurs entières et positives qui soit strictement décroissante. Conséquence : si on arrive à mettre en évidence une quantitéϕ, à valeurs entières et positives, telles queϕ décroit strictement à chaque tour de la boucle, alors la boucle termine nécessairement.
⋄ Résultat clé pour lacorrectiond’une bouclewhile: si on ar- rive à mettre en évidente une propriétéP telle que
• P est vraie au point①;
• si P est vraie au point②,alors P est vraie au point③, alorsP sera vraie au point④. Une telle propriétéP est appe- lée uninvariant de boucle. Noter l’analogie avec le principe de récurrence en mathématiques.
①
tant que (condition)
②
I n s t r u c t i o n s . . .
③
f i n tant que
④
Exemple Python. Somme des termes d’une listeL(si la liste est vide, alors la somme est nulle). On noten=len(L).
Le principe du programme :
• On a une variables qui vaut initialement 0 ;
• On parcourt tous les termes de la liste et chaque terme est ajouté às.
Ainsi, une fois que toute la liste a été parcourue,scontient la somme de tous les termes de la liste.
def somme(L):
s=0 i=0
# Point 1
while i<len(L):
# Point 2 s=s+L[i]
i=i+1
# Point 3
# Point 4 return s
⋄ Pour montrer que cette fonction termine, on remarque que la quantitén−i est entière, positive (car dans la boucle, on a toujoursn−i Ê0) et strictement décroissante à chaque tour de la boucle (puisquei augmente à chaque fois de 1). Comme il n’existe pas de suite infinie qui soit à valeurs entières, positives et strictement décroissante, la bouclewhilene peut être effectuée qu’un nombre fini de fois, donc la fonction termine.
⋄ Pour montrer la correction de cette fonction, on démontre que la propriété : P:s=L[0]+ · · · +L[i−1]
est un invariant de boucle. Tout d’abord,P est vraie au point 1 (indiqué par un commen- taire). SupposonsPvraie au point 2, c’est à dires=L[0]+ · · · +L[i−1]. Notonss′la nouvelle valeur desau point 3 eti′la nouvelle valeur dei au point 3, on ai′=i+1 et :
s′=s+L[i]=L[0]+ · · · +L[i−1]+L[i]=L[0]+ · · · +L[i′−1]
Par conséquentP est vraie au point 3. La propriétéP est bien un invariant de boucle, elle est donc vraie au point 4 (juste à la sortie de la boucle). Au point 4, on ai =n=len(L), donc s=L[0]+ · · · +L[n−1]. Par conséquent la fonction est correcte.
Exemple Python. Déterminer le maximum des élé- ments d’une liste de longueurn Ê1. Le principe du pro- gramme :
• On a une variablemqui vaut initialementL[0] ;
• On parcourt tout les termes L[1], . . . ,L[n−1] et à chaque fois que l’on rencontre un terme strictement supérieur àm, on donne àmla valeur de ce terme.
Ainsi, une fois que toute la liste a été parcourue, m contient le plus grand terme de la liste.
⋄ Comme pour la fonction précédente, la quantitén−iest entière, positive et strictement décroissante à chaque tour de la boucle, donc la fonction termine.
def maximum(L):
m=L[0]
i=1
# Point 1
while i<len(L):
# Point 2 if L[i]>m:
m=L[i]
i=i+1
# Point 3
# Point 4 return m
⋄ Pour montrer la correction de cette fonction, on démontre que la propriété : P:m=max(L[0], . . . ,L[i−1])
est un invariant de boucle. En effet, cette propriété est vraie au point 1 (indiqué par un commentaire). SupposonsPvraie au point 2, c’est à direm=max(L[0],· · ·,L[i−1]). Notons m′la nouvelle valeur demau point 3 eti′la nouvelle valeur dei au point 3 (i′=i+1), on distingue deux cas. SiL[i]>m, alorsm′=L[i] et :
max(L[0], . . . ,L[i′−1])=max(L[0], . . . ,L[i−1]
max :m
,L[i]
>m
)=L[i]=m′
SiL[i]Ém, alorsm′=met :
max(L[0], . . . ,L[i′−1])=max(L[0], . . . ,L[i−1]
max :m
,L[i]
Ém
)=m=m′
Dans tous les cas,Pest vraie au point 3. La propriétéP est bien un invariant de boucle, elle est donc vraie au point 4. Au point 4, on ai =n=len(L), doncm=max(L[0],· · ·,L[n−1]).
Par conséquent la fonction est correcte.
Deux exemples fondamentaux à connaitre
Trois manières de calculer la somme des termes d’une liste
⋄ Première version : dans le style PYTHON, on prend chaque élément appartenant à la liste.
def somme(L):
"""
Calcule la somme des éléments de L
L : liste d'éléments de type int ou float
"""
s=0
for x in L:
s=s+x return s
⋄ Deuxième version : avec une bouclefor, on parcourt tous lesindicesde la liste (qui vont de 0 jusqu’à len(L)−1).
def somme(L):
"""
Calcule la somme des éléments de L
L : liste d'éléments de type int ou float
"""
s=0
for i in range(len(L)):
s=s+L[i]
return s
⋄ Troisième version : on remplace la boucleforpar une bouclewhile.
def somme(L):
"""
Calcule la somme des éléments de L
L : liste d'éléments de type int ou float
"""
s=0 i=0
while i<len(L):
s=s+L[i]
i=i+1 return s
Trois manières de calculer le maximum d’une liste
⋄ Première version : avec une bouclewhile.
def maximum(L):
"""
Détermine le maximum de L
L : liste (non vide) d'éléments de type int ou float
"""
m=L[0]
i=1
while i<len(L):
if L[i]>m:
m=L[i]
i=i+1 return m
⋄ Deuxième version : avec une bouclefor.
def maximum(L):
"""
Détermine le maximum de L
L : liste (non vide) d'éléments de type int ou float
"""
m=L[0]
for i in range(1,len(L)):
if L[i]>m:
m=L[i]
return m
⋄ Troisième version : dans le style PYTHON, en parcourant les éléments de la liste.
def maximum(L):
"""
Détermine le maximum de L
L : liste (non vide) d'éléments de type int ou float
"""
m=L[0]
for x in L[1:]:
if x>m:
m=x return m
Remarque.La notationL[1:]désigne la liste obtenue à partir deLen ne gardant que les éléments à partir de l’indice 1. SiL=[a0,a1, . . . ,an−1] alors :
L[1 : ]=[a1, . . . ,an−1]