Bonjour,
Dans la leçon précédente, nous avons vu la puissance de la récurrence forte, notamment pour prouver des propriétés sur des suites ou des algorithmes où la dépendance récursive saute des crans, comme dans le cas de l'exponentiation rapide (calcul de via ). Vous avez ainsi acquis l'un des outils de raisonnement les plus fondamentaux en informatique théorique.
Aujourd'hui, nous allons systématiser l'usage du raisonnement par récurrence pour une tâche essentielle à l'agrégation : la preuve de correction d'algorithmes. Un algorithme qui ne produit pas le résultat attendu est inutile, et savoir démontrer formellement qu'il est correct est une compétence discriminante. L'objectif de cette leçon est donc de vous apprendre à appliquer le raisonnement par récurrence pour prouver la correction d'algorithmes simples, qu'ils soient récursifs ou itératifs.
Nous verrons que si la preuve pour les algorithmes récursifs est une application directe de l'induction, les algorithmes itératifs (avec des boucles while ou for) nécessitent un outil intermédiaire puissant : l'invariant de boucle.
1. Preuve de Correction des Algorithmes Récursifs
Prouver la correction d'une fonction récursive f(n) revient presque toujours à effectuer une preuve par récurrence sur le paramètre n. La propriété P(n) que l'on cherche à démontrer est généralement : "la fonction f(n) termine et renvoie la valeur correcte".
La structure de la preuve est celle que vous connaissez :
- Cas de base (Initialisation) : Montrer que
P(n_0)est vraie, oùn_0est le cas d'arrêt de la récursion. On vérifie que pour cette valeur, la fonction termine et renvoie le bon résultat. - Hérédité : Supposer que la propriété est vraie pour
n-1(récurrence simple) ou pour tous lesk < n(récurrence forte). Ensuite, montrer que sous cette hypothèse,f(n)termine (car elle fait un appel sur une valeur plus petite) et que le résultat qu'elle calcule à partir de l'appel récursif est correct.
L'exemple le plus canonique est celui de la fonction factorielle.
2.2 - Induction and Recursive Algorithms
La vidéo suivante, bien qu'en anglais, illustre parfaitement la démarche de preuve par récurrence appliquée à une fonction récursive. L'exemple de la factorielle est un point de départ idéal.
Regardez l'extrait de 06:09 à 08:44. Concentrez-vous sur la décomposition de la preuve : Base Case: Vérification pour n=1. Termination: Argumenter que l'appel récursif se fait sur une valeur qui décroît, garantissant d'atteindre le cas de base. Induction Step: Hypothesis: factorial(k) est supposée correcte. Proof: Montrer que factorial(k+1), qui calcule (k+1) * factorial(k), est alors correcte grâce à l'hypothèse.
Pour une formulation en français et parfaitement rigoureuse, vous pouvez consulter l'exercice 6 du document "Rappels : Preuves des algorithmes", qui formalise la même preuve pour la fonction factorielle(n).
Rappels : Preuves des algorithmes
Ce document, tiré d'un support de CPGE, vous propose une rédaction type de ce genre de preuve, ce qui est un excellent entraînement pour le concours.
Lisez l'"Exercice 6 : Terminaison et correction d’un programme récursif" (page 9). Observez comment la terminaison et la correction sont traitées conjointement dans la même preuve par récurrence. C'est la méthode standard pour les algorithmes récursifs.
2. Preuve de Correction des Algorithmes Itératifs : L'Invariant de Boucle
Comment appliquer un raisonnement par récurrence à une boucle while ? L'induction se fait sur le nombre de passages dans la boucle. Pour formaliser cela, on introduit la notion d'invariant de boucle.
Un invariant de boucle est une propriété des variables de l'algorithme qui est :
- Vraie avant d'entrer dans la boucle.
- Reste vraie après chaque itération.
- Lorsque la boucle se termine, la propriété (jointe à la condition d'arrêt de la boucle) implique que l'algorithme a produit le résultat attendu.
Ceci établit une analogie parfaite avec la récurrence :

La preuve de correction à l'aide d'un invariant se déroule en trois temps :
- Initialisation : Démontrer que l'invariant est vrai avant la première itération de la boucle. (Le cas de base de notre récurrence)
- Conservation (Hérédité) : Démontrer que si l'invariant est vrai au début d'une itération, il le reste à la fin de cette itération. (L'étape d'hérédité)
- Conclusion : Démontrer que lorsque la boucle termine (c'est-à-dire que sa condition devient fausse), l'invariant implique la correction de l'algorithme.
Notez qu'un invariant ne prouve que la correction partielle : si l'algorithme termine, le résultat est correct. Pour prouver la correction totale, il faut aussi prouver la terminaison, ce qui se fait généralement en exhibant un variant de boucle : une quantité entière positive qui décroît strictement à chaque itération.
La vidéo suivante met en œuvre cette méthode de A à Z sur un exemple simple.
Variant de boucle et invariant de boucle : théorie et exercice d’application
Cette vidéo de MPSI2 Lycée CARNOT est une excellente introduction pratique aux concepts de variant et d'invariant de boucle, appliqués à un algorithme calculant la puissance de manière itérative. Elle vous guidera à travers chaque étape de la preuve formelle.
Regardez la vidéo de 00:46 à 08:04. Suivez attentivement les étapes : Recherche du variant (00:46) : Comment i garantit la terminaison. Définition de l'invariant (02:05) : Présentation de la propriété res * k^i = k^n. Preuve de l'Initialisation (03:36) : Vérification avant la boucle. Preuve de l'Hérédité (04:50) : La partie la plus technique, montrant que l'invariant se maintient. Conclusion sur la Correction (06:40) : Comment l'invariant et la condition de sortie i=0 prouvent que res = k^n.
3. Application : L'Algorithme d'Euclide
Mettons maintenant en pratique cette méthode sur un algorithme fondamental que vous connaissez bien : l'algorithme d'Euclide pour le calcul du plus grand commun diviseur (PGCD).
Considérez l'algorithme suivant pour calculer le PGCD de deux entiers naturels a et b.
fonction euclide(a, b):
x ← a
y ← b
tant que y ≠ 0 faire
r ← x mod y
x ← y
y ← r
retourner x
Votre tâche est de prouver sa correction totale.
1. Preuve de terminaison (Variant de boucle)
Pouvez-vous identifier une quantité qui est un entier, reste positive et décroît strictement à chaque itération ?
Solution
Le variant de boucle est la variable `y`. À chaque itération, `y` prend la valeur `r`, qui est le reste de la division euclidienne de `x` par l'ancienne valeur de `y`. Par définition de la division euclidienne, on a `0 ≤ r < y`. Donc, la valeur de `y` décroît strictement tout en restant positive ou nulle. Comme `y` est un entier, il atteindra nécessairement la valeur 0, provoquant l'arrêt de la boucle.2. Preuve de correction partielle (Invariant de boucle)
L'étape la plus difficile est de trouver le bon invariant. L'invariant doit capturer l'essence de l'algorithme. Ici, l'algorithme d'Euclide repose sur la propriété que .
Quel invariant reliant x, y aux entrées initiales a, b pourrait-on utiliser ?
Solution
L'invariant de boucle est la proposition $P: \text{pgcd}(x, y) = \text{pgcd}(a, b)$. Nous allons prouver que cette propriété est un invariant.Maintenant, essayez de dérouler les trois étapes de la preuve.
Cliquez ici pour la preuve complète
Invariant : .
-
Initialisation : Avant la boucle, on a
x = aety = b. L'invariant est trivialement vrai. -
Conservation : Supposons qu'au début d'une itération, l'invariant est vrai. Dans la boucle, les variables sont mises à jour comme suit :
r ← x mod yx_nouveau ← yy_nouveau ← r
Nous devons montrer que .
Par la propriété fondamentale de l'algorithme d'Euclide, nous savons que .
Donc, .
Par hypothèse de récurrence (conservation de l'invariant), on a .
Par transitivité, on conclut que . L'invariant est conservé. -
Conclusion : La boucle se termine lorsque
y = 0. À ce moment, l'invariant est toujours vrai. On a donc :Par définition, le PGCD de tout nombre
xet 0 estx. Donc, .
L'algorithme retournex, qui est bien égal à . La correction est prouvée.
Vous pouvez retrouver une rédaction très similaire de cette preuve dans le document ci-dessous.
[PDF] Algorithmique - Groupe Enseignement de l'informatique
Pour une rédaction formelle de cette preuve, je vous suggère de lire la section 1.4.4 du document "Algorithmique".
Lisez la section 1.4.4 "Algorithme d’Euclide pour le calcul du PGCD de nombres entiers" (pages 38-39). Comparez cette rédaction avec votre propre raisonnement.
Conclusion
Félicitations, vous avez maintenant une méthode systématique pour aborder la preuve de correction des deux grandes familles d'algorithmes. Cette compétence est absolument centrale.
À retenir :
- Algorithmes récursifs : La correction se prouve par récurrence (simple ou forte) sur le paramètre de la récursion. La propriété
P(n)englobe à la fois la terminaison et la validité du résultat. - Algorithmes itératifs : La correction se prouve via un invariant de boucle, qui est lui-même une forme de raisonnement par récurrence sur le nombre d'itérations.
- Une preuve par invariant comporte trois étapes cruciales : Initialisation, Conservation, Conclusion.
- Pour une preuve de correction totale d'un algorithme itératif, il faut également prouver la terminaison à l'aide d'un variant de boucle.
Nous avons achevé notre premier module sur la logique et les méthodes de preuve. Vous disposez désormais des outils formels pour raisonner de manière rigoureuse sur les algorithmes. Dans le prochain module, nous aborderons les Mathématiques Discrètes pour l'Informatique, en commençant par les techniques de dénombrement et de combinatoire, qui sont indispensables pour analyser la complexité de nombreux algorithmes et structures de données.