Module L09 · Partie G · Mathématiques de l’informatique
Prouver qu’un programme est juste.
Les tests montrent la présence de bugs, jamais leur absence (Dijkstra). Pour un algorithme de tri, un contrôleur de robot ou un protocole de sécurité, on veut plus : une preuve. Ce module donne les outils — logique propositionnelle, récurrence, invariants de boucle, variants pour la terminaison, triplets de Hoare — et les applique aux algorithmes des modules précédents. C’est le cœur de l’épreuve d’informatique des concours.
Durée : 3 séances · Prérequis : L03-L05. Objectifs : manipuler la logique (tables de vérité, formes normales, quantificateurs), raisonner par récurrence forte et structurelle, écrire et vérifier des invariants, prouver la terminaison par un variant, rédiger une preuve de correction complète, connaître l’existence des assistants de preuve.
Ce que vous saurez faire à la fin
- Écrire l’invariant d’une boucle et prouver initialisation, conservation, conclusion.
- Exhiber un variant et prouver qu’un algorithme termine.
- Prouver la correction de la dichotomie, du tri par insertion, d’Euclide, de BFS.
- Traduire un raisonnement en assertions exécutables qui vérifient l’invariant à chaque tour.
Références : programme MP2I (« preuves de programmes »), Software Foundations (Pierce, en Coq), cours de Xavier Leroy, CLRS chapitre 2.
Fiche de cours · Définitions
Logique et preuves : définitions
Fiche de cours · Formules
Équivalences et règles à connaître
| Nom | Équivalence | Usage |
|---|---|---|
| De Morgan | ¬(p ∧ q) ≡ ¬p ∨ ¬q ; ¬(p ∨ q) ≡ ¬p ∧ ¬q | Nier une condition composée dans un if |
| Implication | p → q ≡ ¬p ∨ q ≡ ¬q → ¬p | Contraposée ; not p or q |
| Distributivité | p ∧ (q ∨ r) ≡ (p ∧ q) ∨ (p ∧ r) ; p ∨ (q ∧ r) ≡ (p ∨ q) ∧ (p ∨ r) | Forme normale conjonctive (SAT) |
| Absorption | p ∨ (p ∧ q) ≡ p | Simplifier |
| Tiers exclu, non-contradiction | p ∨ ¬p ≡ ⊤ ; p ∧ ¬p ≡ ⊥ | Preuve par cas ; par l’absurde |
| Modus ponens / tollens | p, p → q ⊢ q ; ¬q, p → q ⊢ ¬p | Règles de déduction |
| Négation des quantificateurs | ¬∀x P ≡ ∃x ¬P ; ¬∃x P ≡ ∀x ¬P | Écrire un contre-exemple |
Fiche de cours · Théorèmes et démonstrations
Démonstrations à savoir refaire (1/2)
Fiche de cours · Théorèmes et démonstrations
Démonstrations à savoir refaire (2/2) : programmes
def puiss(x, n): r, b, e = 1, x, n ; while e > 0: if e % 2: r *= b ; b *= b ; e //= 2 ; return r renvoie xⁿ en O(log n) multiplications.while b: a, b = b, a % b ; return a renvoie pgcd(a₀, b₀).Fiche de cours · Méthodes
Méthodes de rédaction et pièges
Pièges : confondre p → q et sa réciproque ; « prouver » P(n+1) sans utiliser P(n) (ce n’est alors pas une récurrence, ou l’hérédité est fausse) ; oublier le cas de base (la « preuve » que tous les chevaux ont la même couleur échoue en n = 2) ; un exemple n’est pas une preuve ; ∀x ∃y ≠ ∃y ∀x.
Fiche de cours · Exercices corrigés
Exercices corrigés
def somme_chiffres(n): s = 0 ; while n > 0: s += n % 10 ; n //= 10 ; return s pour n ≥ 0.01 / Logique
Propositions, connecteurs, tables de vérité
Vocabulaire
Une tautologie est vraie pour toute valuation ; une formule satisfiable l’est pour au moins une ; une contradiction pour aucune. Deux formules sont équivalentes si elles ont la même table. Toute formule s’écrit en forme normale conjonctive (ET de OU de littéraux) — c’est l’entrée du problème SAT (module L17). Piège classique : confondre l’implication et sa réciproque. « S’il pleut, le sol est mouillé » n’implique pas « si le sol est mouillé, il pleut ».
01 / Logique
Quantificateurs et négation : ce que dit exactement un énoncé
Savoir écrire « la liste est triée », « x est le maximum », « le tableau ne contient pas de doublon », « le chemin est valide » avec des quantificateurs est la première étape de toute preuve — et de tout test par propriétés (module L01).
02 / Récurrence
Récurrence simple, forte, structurelle
La récurrence structurelle suit la définition inductive du type (module L07, types algébriques d’OCaml) : un cas par constructeur. C’est la raison profonde pour laquelle la récursion et la preuve vont ensemble.
03 / Invariants
L’invariant de boucle : la propriété qui survit à chaque tour
Les trois étapes d’une preuve par invariant
- Initialisation : l’invariant est vrai avant le premier tour. Pour
maximum: i = 1, m = t[0] = max(t[:1]). ✓ - Conservation : s’il est vrai avant un tour, il l’est après. Si m = max(t[:i]) et qu’on fait
if t[i] > m: m = t[i], alors m = max(t[:i+1]). ✓ - Conclusion : à la sortie, l’invariant plus la négation de la condition donnent la postcondition. i = len(t) ⇒ m = max(t). ✓
C’est exactement la récurrence sur le numéro du tour. L’invariant se trouve en se demandant « qu’est-ce que la boucle a construit jusqu’ici ? ». Les assert dans le code sont des invariants exécutables : en développement, ils attrapent la boucle qui déraille au tour précis où ça arrive.
03 / Invariants
Cas d’école : dichotomie et tri par insertion
Notez le lien entre invariant et correction (la bonne réponse) d’une part, variant et terminaison d’autre part. La correction sans terminaison est une « correction partielle » : « si ça s’arrête, c’est juste ». La correction totale exige les deux.
04 / Terminaison
Le variant : une quantité entière positive qui décroît strictement
Ordres bien fondés
Un variant est une fonction de l’état vers un ensemble bien fondé (sans suite infinie strictement décroissante) : les entiers naturels, les couples d’entiers en ordre lexicographique (Ackermann), la taille d’une structure (récursion structurelle). Pour la fonction 91 de McCarthy ou Collatz, on ne connaît pas de variant simple : la terminaison est prouvée autrement (McCarthy) ou pas du tout (Collatz). Le problème de l’arrêt (module L23) dit qu’aucun programme ne peut décider dans tous les cas si un autre programme termine — c’est pour cela qu’on doit fournir le variant soi-même.
05 / Hoare
Triplets de Hoare : {P} programme {Q}
Ce que les assistants de preuve automatisent
Coq, Isabelle, Lean, Why3, Dafny, F* : on écrit le programme, ses spécifications (pré/post/invariants) et l’outil vérifie mécaniquement chaque étape ou génère les obligations de preuve à démontrer. Le compilateur C CompCert (Xavier Leroy, Inria) est prouvé en Coq : il ne peut pas produire de code faux. Le noyau seL4 est prouvé sans bug. Ces outils sont utilisés pour l’avionique, les cartes bancaires, la cryptographie et de plus en plus pour les systèmes embarqués critiques. Lean est aujourd’hui aussi utilisé par des mathématiciens pour formaliser des théorèmes récents — un sujet de recherche très actif.
05 / Hoare
Rédiger une preuve complète : BFS trouve le plus court chemin
La rédaction attendue en concours
Terminaison. Chaque sommet est ajouté à la file au plus une fois (on l’ajoute seulement s’il n’est pas dans dist, et on l’y met aussitôt). Le nombre d’extractions est donc ≤ |S| : la boucle termine.
Correction. Montrons par récurrence sur les extractions que (I1) tient. Initialement dist = {s: 0} : vrai. Supposons (I1)-(I3) avant l’extraction de u, de distance k. Pour un voisin v non encore vu : d(s, v) ≤ k + 1 via u. Si d(s, v) ≤ k, alors par (I3) v serait déjà dans dist : contradiction. Donc d(s, v) = k + 1 = dist[v]. (I2) reste vrai car on n’ajoute que des sommets de distance k + 1 en queue. À la fin, tout sommet accessible a été atteint (sinon considérer le premier sommet non atteint d’un plus court chemin : son prédécesseur a été extrait et l’aurait ajouté). ∎
Cette structure — invariants, variant, récurrence, argument « premier élément qui échoue » — est celle de toutes les preuves d’algorithmes de graphes (Dijkstra : « le sommet extrait a sa distance définitive »).
Cours
Cours 1 — Rédiger une preuve : structure, vocabulaire, erreurs classiques
| Type de preuve | Schéma | Quand l’utiliser |
|---|---|---|
| Directe | Hypothèses ⇒ … ⇒ conclusion | Par défaut |
| Par contraposée | Pour montrer P ⇒ Q, montrer ¬Q ⇒ ¬P | Quand ¬Q donne plus de prise (« si n² est pair alors n est pair ») |
| Par l’absurde | Supposer ¬conclusion, dériver une contradiction | Existence, unicité, impossibilité (arrêt, √2) |
| Par récurrence (simple, forte, structurelle) | Base + hérédité | Propriétés indexées par un entier ou une structure |
| Par disjonction de cas | Cas 1, cas 2, …, exhaustifs | Quand une condition sépare les situations (filtrage OCaml) |
| Par invariant / variant | Initialisation, conservation, conclusion ; décroissance | Boucles et algorithmes itératifs |
| Par argument d’échange | Transformer une solution optimale sans perte | Gloutons (L04) |
| Par « premier élément qui échoue » | Considérer le plus petit contre-exemple | Parcours de graphes (L05), minimalité |
Les mots qui comptent. « Soit x » (on prend un élément quelconque : prouve un ∀) ; « il existe » (on exhibe ou on construit) ; « supposons » (hypothèse de récurrence ou d’absurde : à refermer explicitement) ; « donc », « car », « d’où » (chaque étape justifiée par une hypothèse, une définition, un résultat antérieur). Une preuve se termine par la phrase de conclusion et ∎.
Erreurs qui coûtent tous les points. Prouver la réciproque au lieu de l’énoncé ; utiliser la conclusion dans la preuve (circularité) ; oublier le cas de base ; hérédité qui ne marche pas pour n = 0 ou 1 (la fameuse preuve que « tous les chevaux ont la même couleur ») ; « c’est évident » à l’endroit précis où ça ne l’est pas ; confondre « pour tout x, il existe y » et « il existe y, pour tout x ».
Cours
Cours 2 — Exemple travaillé : prouver l’exponentiation rapide de A à Z
def puissance(x, n): # précondition : n entier ≥ 0
r, b, e = 1, x, n
while e > 0:
if e % 2 == 1:
r = r * b
b = b * b
e = e // 2
return r # postcondition : r = x^nInvariant I : r · be = xn et e ≥ 0.
Initialisation. Avant le premier tour : r = 1, b = x, e = n, donc r · be = xn. ✓
Conservation. Supposons I vrai en début de tour avec e > 0. Notons r′, b′, e′ les valeurs en fin de tour. Deux cas. e pair : r′ = r, b′ = b², e′ = e/2, donc r′ · b′e′ = r · b2·e/2 = r · be = xn. e impair : r′ = r·b, b′ = b², e′ = (e−1)/2, donc r′ · b′e′ = r · b · be−1 = r · be = xn. Dans les deux cas e′ ≥ 0. ✓
Terminaison. Variant e : entier ≥ 0, et e′ = ⌊e/2⌋ < e dès que e > 0. ✓
Conclusion. À la sortie, e = 0 et I donne r · b0 = r = xn. ∎
Complexité. e est divisé par 2 à chaque tour : au plus ⌊log₂ n⌋ + 1 tours, chacun avec au plus 2 multiplications : O(log n) multiplications. (Sur de grands entiers, chaque multiplication coûte elle-même — module L04.)
Cours
Cours 3 — Spécifier avant de prouver : contrats, et ce qu’un outil peut vérifier
Le contrat d’une fonction (Meyer, « design by contract ») : pré (ce que l’appelant garantit), post (ce que la fonction garantit), invariants de classe (toujours vrais entre deux appels de méthode). Violer la pré est un bug de l’appelant ; violer la post un bug de la fonction. En Python, les assert en entrée et sortie matérialisent le contrat ; en Ada/SPARK, Eiffel, Dafny, ils font partie du langage et sont vérifiés statiquement.
// Dafny : le vérificateur prouve automatiquement (ou demande des indices)
method Dichotomie(t: array<int>, x: int) returns (i: int)
requires forall a, b :: 0 <= a < b < t.Length ==> t[a] <= t[b] // pré : trié
ensures 0 <= i < t.Length ==> t[i] == x // post : si trouvé, c'est x
ensures i == -1 ==> forall k :: 0 <= k < t.Length ==> t[k] != x // post : si -1, x absent
{
var bas, haut := 0, t.Length;
while bas < haut
invariant 0 <= bas <= haut <= t.Length
invariant forall k :: 0 <= k < t.Length && t[k] == x ==> bas <= k < haut
decreases haut - bas
{
var m := (bas + haut) / 2;
if t[m] < x { bas := m + 1; } else if t[m] > x { haut := m; } else { return m; }
}
return -1;
}Le vérificateur (Z3 derrière) prouve initialisation, conservation, terminaison et postcondition ; si vous vous trompez dans l’invariant, il refuse et montre l’étape qui coince. Essayez en ligne (dafny.org, « Try Dafny ») : c’est la version exécutable du module L09, et un excellent moyen de tester vos invariants avant de les rédiger.
| Outil | Ce qu’il vérifie | Effort |
|---|---|---|
| Types (mypy, OCaml) | Cohérence des types | Nul à faible |
| Analyse statique (ruff, Frama-C pour C) | Bugs de forme, débordements (Frama-C/Eva) | Faible |
| Tests par propriétés (Hypothesis) | Invariants sur des entrées aléatoires | Faible |
| Vérification déductive (Dafny, Why3, SPARK) | Contrats prouvés pour toutes les entrées | Moyen à élevé |
| Assistants de preuve (Coq, Lean, Isabelle) | Tout, y compris les mathématiques | Élevé |
| Vérification de modèles (TLA+, SPIN) | Protocoles, concurrence, machines à états | Moyen |
TP guidé
TP — Prouver avec un outil : Dafny, puis Lean (sur PC, 2 h 30)
- Dafny en ligne. Ouvrez « Try Dafny » (ou VS Code + extension Dafny). Copiez la dichotomie du cours 3 ; vérifiez qu’elle passe (coche verte). Supprimez l’invariant sur
bas ≤ k < haut: lisez l’erreur (« postcondition might not hold »). Remettez-le, puis remplacezbas := m + 1parbas := m: Dafny signale la non-terminaison (« decreases might not decrease »). Notez les trois messages. - Prouver vos algorithmes. Écrivez en Dafny avec contrats et invariants :
Maximum(postcondition : ≥ tous les éléments et présent),SommePrefixe,Puissance(cours 2),TriInsertion(postcondition : trié et permutation — utilisezmultiset(t[..]) == multiset(old(t[..]))). Chaque preuve acceptée est un invariant que vous avez trouvé vous-même. - Lean, les nombres. Faites les 3 premiers mondes du « Natural Number Game » (adam.math.hhu.de) : addition, multiplication, récurrence. Vous prouvez 0 + n = n, la commutativité, etc., avec les tactiques
induction,rw,simp. C’est la récurrence du cours, vérifiée par la machine. - Lean sur PC (optionnel). Installer via elan + VS Code « Lean 4 » ; créer un projet ; prouver
theorem somme_pairs (n : ℕ) : 2 ∣ n * (n + 1)et un lemme sur les listes (List.length (l ++ m) = l.length + m.length) par induction structurelle. - Retour au Python. Pour chaque fonction prouvée en Dafny, réécrivez-la en Python avec les invariants en
assertet un test Hypothesis. Comparez : ce que Dafny garantit pour toutes les entrées, Hypothesis ne fait que l’échantillonner. - Livrable. Les fichiers
.dfyvérifiés (captures des coches vertes), les captures du Natural Number Game, et une page : « ce que j’ai dû ajouter comme invariant pour que la machine accepte, et pourquoi ».
Exercices
Exercices auto-corrigés — logique et quantificateurs
Exercice 1 — Vérifier des équivalences par table de vérité
Écrivez equivalentes(f, g, n) qui teste si deux formules booléennes à n variables sont équivalentes sur les 2ⁿ valuations, puis tautologie(f, n). Ensuite complétez le dictionnaire verdicts (True = équivalence valide).
Correction
def equivalentes(f, g, n): return all(f(*v) == g(*v) for v in product([False, True], repeat=n))
def tautologie(f, n): return all(f(*v) for v in product([False, True], repeat=n))
# True, True, False, True, True (la dernière est la loi de Peirce, valide en logique classique)Exercice 2 — Écrire des propriétés avec des quantificateurs
Implémentez chaque propriété comme une fonction booléenne sur une liste, avec all/any exactement comme la formule le dit.
Correction
def strictement_croissante(t): return all(t[i] < t[i + 1] for i in range(len(t) - 1))
def a_un_doublon(t): return any(t[i] == t[j] for i in range(len(t)) for j in range(i + 1, len(t)))
def est_permutation_de(t, u): return all(t.count(x) == u.count(x) for x in set(t) | set(u))
def chaque_element_a_un_plus_grand(t): return all(any(t[j] > t[i] for j in range(len(t))) for i in range(len(t)))
def existe_un_majorant(t): return any(all(t[j] >= t[i] for i in range(len(t))) for j in range(len(t)))Exercices
Exercices auto-corrigés — invariants et variants
Exercice 3 — Trouver l’invariant qui rend le test vert
Chaque fonction a un trou INV = … : une expression booléenne, évaluée avant chaque tour, qui doit être vraie à tous les tours et suffisante pour prouver la postcondition (elle est vérifiée en sortie combinée à la négation de la condition). Écrivez-la avec les variables du programme.
Correction
INV = r * r <= n # et à la sortie : (r+1)² > n, d'où la postcondition
INV2 = gcd(a, b) == gcd(a0, b0) # invariant d'Euclide : le PGCD est conservé ; à la sortie b = 0 donc gcd(a, 0) = aExercice 4 — Variant et terminaison
Pour chaque boucle, donnez un variant (expression entière ≥ 0 strictement décroissante) sous forme de fonction des variables ; la cellule vérifie qu’il décroît strictement et reste ≥ 0 sur des exécutions.
Correction
def variant_binaire(bas, haut): return haut - bas
def variant_collatz_borne(n, k): return 1000 - k
def variant_deux_indices(i, j): return j - i06 / Défis
Défi ★ — Invariants à compléter
Consigne
Pour chacune de ces fonctions, écrivez l’invariant de boucle en commentaire, ajoutez l’assert correspondant, identifiez le variant, puis rédigez les trois étapes de la preuve. 1) inverser(t) qui inverse une liste en place avec deux indices ; 2) puissance(x, n) par multiplications successives ; 3) compter(t, x).
Correction
# inverser : soit T la liste d'origine.
# INVARIANT : t[:i] == T[len−i:][::-1] et t[j+1:] == T[:len−j−1][::-1] et t[i:j+1] == T[i:j+1]
# (les extrémités déjà échangées, le milieu intact)
# VARIANT : j − i. Conclusion : i ≥ j ⇒ tout est échangé (le milieu a ≤ 1 élément).
# puissance :
# INVARIANT : r == x ** k et 0 ≤ k ≤ n. Init : 1 == x**0. Conservation : r·x == x**(k+1).
# Conclusion : k == n ⇒ r == x**n. VARIANT : n − k.06 / Défis
Défi ★★ — Trouver le bug par l’invariant
Consigne
Cette fonction est censée partitionner une liste autour d’un pivot (tri rapide) : à la fin, tous les éléments < pivot sont avant l’indice renvoyé, les ≥ après. Écrivez l’invariant attendu (« t[lo..i[ < pivot, t[i..j[ ≥ pivot, t[j..hi[ pas encore vus »), ajoutez-le en assert, trouvez le tour où il casse, corrigez, puis écrivez le tri rapide complet avec preuve de terminaison (variant : hi − lo, et il faut que chaque sous-appel soit strictement plus petit — attention aux listes d’éléments tous égaux !).
Correction
def partition(t, lo, hi):
pivot = t[hi - 1]; i = lo
for j in range(lo, hi - 1):
# INVARIANT : ∀k∈[lo,i[ t[k] < pivot ; ∀k∈[i,j[ t[k] ≥ pivot
assert all(t[k] < pivot for k in range(lo, i)) and all(t[k] >= pivot for k in range(i, j))
if t[j] < pivot:
t[i], t[j] = t[j], t[i]; i += 1 # i += 1 SEULEMENT après un échange
t[i], t[hi - 1] = t[hi - 1], t[i] # placer le pivot
return i
def tri_rapide(t, lo=0, hi=None):
if hi is None: hi = len(t)
if hi - lo > 1:
p = partition(t, lo, hi) # p ∈ [lo, hi[ : les deux sous-intervalles sont strictement plus petits
tri_rapide(t, lo, p); tri_rapide(t, p + 1, hi)
return t
import random
for _ in range(300):
l = [random.randint(0, 5) for _ in range(random.randint(0, 20))]
assert tri_rapide(list(l)) == sorted(l)
print("OK")Le bug : i += 1 inconditionnel. L’invariant casse dès le premier élément ≥ pivot. Terminaison : après partition, le pivot est à sa place définitive en p ; les appels portent sur [lo, p[ et [p+1, hi[, de taille < hi − lo. Sans le placement du pivot hors des sous-appels, une liste de valeurs égales donnerait p = lo et une récursion infinie.
06 / Défis
Défi ★★★ — Esprit prépa : preuve de Dijkstra et exponentiation rapide
Consigne
1) Pour l’exponentiation rapide itérative du module L04 (while n: if n & 1: r = r·x ; x = x·x ; n >>= 1), trouvez l’invariant qui lie r, x, n à la valeur cherchée x₀n₀, écrivez-le en assert, prouvez. 2) Pour Dijkstra, énoncez précisément l’invariant « pour tout sommet extrait u, dist[u] = d(s, u) », et rédigez la preuve par l’absurde (considérer un plus court chemin vers u et le premier sommet de ce chemin non encore extrait). 3) Montrez par un contre-exemple que l’invariant est faux avec un poids négatif, et dites quelle étape de la preuve utilise la positivité.
Correction
# 1) INVARIANT : r · x**n == x0**n0 (et n ≥ 0). VARIANT : n.
# Init : 1 · x0**n0. Si n pair : r · (x²)**(n/2) = r · x**n. Si n impair : (r·x) · (x²)**((n−1)/2) = r · x**n. ✓
# Sortie : n = 0 ⇒ r = x0**n0. ✓
# 2) Dijkstra. INVARIANT : (a) pour tout u extrait, dist[u] = d(s,u) ; (b) pour tout v non extrait,
# dist[v] = longueur du plus court chemin de s à v n'utilisant que des sommets extraits comme intermédiaires.
# Soit u le sommet extrait (dist minimal parmi les non extraits). Supposons d(s,u) < dist[u]. Sur un plus court
# chemin s → … → u, soit y le premier sommet non extrait, x son prédécesseur (extrait). Par (b), dist[y] ≤
# dist[x] + w(x,y) = d(s,y) ≤ d(s,u) < dist[u] (poids ≥ 0 pour la 2e inégalité). Donc dist[y] < dist[u] :
# contradiction avec le choix de u comme minimum. ∎
# 3) A→B (5), A→C (2), C→B (−4) : Dijkstra extrait C (2) puis B (5) alors que d(A,B) = −2.
# L'étape « d(s,y) ≤ d(s,u) » suppose que le reste du chemin (y → u) est de longueur ≥ 0.07 / Vérification
Qu’est-ce qu’un variant de boucle ?
Deux questions supplémentaires
1. Pourquoi les tests ne remplacent-ils pas une preuve ? Ils couvrent un nombre fini d’entrées ; la preuve couvre toutes les entrées vérifiant la précondition.
2. Quelle est la négation de « tous les capteurs répondent en moins de 10 ms » ? « Il existe un capteur qui répond en 10 ms ou plus ».
Référence
Les mots à retenir
| Mot | Définition |
|---|---|
| Tautologie | Formule vraie pour toute valuation. |
| Contraposée | (p → q) ≡ (¬q → ¬p) ; ne pas confondre avec la réciproque. |
| Récurrence forte | Supposer P(k) pour tous k < n. |
| Récurrence structurelle | Récurrence sur la construction d’une donnée (liste, arbre). |
| Précondition / postcondition | Ce qu’on suppose en entrée / ce qu’on garantit en sortie. |
| Invariant | Propriété vraie avant chaque tour de boucle (correction). |
| Variant | Quantité bien fondée strictement décroissante (terminaison). |
| Correction partielle / totale | Juste si ça termine / juste et termine. |
| Triplet de Hoare | {P} C {Q}. |
| Assistant de preuve | Coq, Lean, Isabelle… : vérification mécanique des preuves. |
Pour continuer
Vous prouvez ce que vous codez
Module suivant : l’algèbre linéaire numérique — vecteurs, matrices, systèmes linéaires, moindres carrés, valeurs propres — avec NumPy, pour la robotique et l’IA.
À faire chez soi
- Prouver la correction et la terminaison du tri fusion, du tri par tas et de Kruskal.
- Faire les 3 premiers chapitres de Software Foundations (Coq) ou le tutoriel « Natural Number Game » (Lean).
- Prendre un sujet MP2I de preuve de programme et le rédiger entièrement.