==== Preuves de correction (suite) ====
=== Exemple ===
Démontrons ce théorème d la logique de Hoare :
a:= n; b:= m
while b<>0 do
a:=a+1; b:=b-1
{a=n+m}
| {n+m = n+m} a:=n {a+m = n+m} | Axiome 1 |
| {a+m = n+m} b:=m {a+b = n+m} | Axiome 1 |
| {n+m = n+m} a:=n; b:=m {a+b = n+m} | R1 |
| vrai => n+m = n+m | |
| {vrai} a:=n; b:=m {a+b = n+m= | Règle 4 |
^ corps de l'itération ^ ^
| {a+1+b-1 = n+m} a:= a+1 {a+b-1 = n+m} | Axiome 1 |
| {a+b-1 = n+m} b:= b-1 { {a+b = n+m } | Axiome 1 |
| {a+1+b-1 = n+m} a:=a+1; b:=b-1 {a+b = n+m} [ Règle 1 |
| {a+b = n+m ∧ b≠0} a:=a+1; b:= b-1 {{a+b = n+m} | R1, puisque a+b=n+m ∧ b≠0 => a+1+b-1 = n+m |
| {a+b = n+m} \\ while b≠0 do\\ [a:=a+1; b:=b-1]\\ {a+b = n+m ∧ ¬(b≠0) } | pre- \\ P \\ \\ post (R3) |
| {a+b = n+m} \\ while b≠0 do\\ [a:=a+1; b:=b-1]\\ {a = n+m } | Règle 4, car a+b=n+m ∧ ¬(b≠0) => a=n+m |
| {vrai //pre-// \\ a:=n; b:=m \\ while b≠0 do\\ [a:=a+1; b:=b-1]\\ {a = n+m } //post// | Règle 1 |
== Résumé de la preuve (par annotation du programme) ==
* //{vrai} => {n+m = n+m} : pre-condition//
* a:= n;
* //{a+m = n+m}//
* b:= m;
* //{a+b = n+m}//
* while b≠0 do
* {
* //{a+b = n+m ∧ b≠0} => {a+1+b-1 = n+m} //
* a:= a+1
* //{a+b-1 = n+m}//
* b:= b-1
* //{a+b =n+m}} // : invariant
* }
* //{a+b = n+m ∧ ¬(b≠0) } => {a = n+m} // : post-condition
__ Correction partielle __ : si precondition **et si programme termine!**
=== Extension de la logique de Hoare ===
On peut, en effet, étendre la logique de Hoare pour montrer correction totale, c'est à dire correction partielle plus terminaison. Pour cela, il faut completer la règle de l'itération et en démontrer la terminaison.
=== Preuve de terminaison ===
En interprétant l'itération (en utilisant l'interprétation associée à la logique de Hoare) et en choisissant une expression (appelée __ variant __) dont les valeurs au cours de l'itération sont
* bornées inférieurement
* strictement décroissantes à chaque étape de l'itération.
== Exemple : racine carrée entière ==
{n ≥ 0}
r:= 0; s:= n+1;
while (s ≠ r+1) do
{
m:= (r+s) div 2;
if m*m=n then s:= m
else r:= m
}
{r*r ≤ n < (r+1)*(r+1) }
Exercice (à faire soi-même) : On démontre ce théorème (correction partielle) en prenant pour invariant r*r ≤ n < s*s. :!:
Pour la preuve de terminaison, choisissons pour variant l'expression s-r. Les valeurs de cette expression sont bornées en bas par 1 (d'après l'invariant r*r ≤ n < s*s => s-r≥1). Elles sont strictement décroissantes : soient E1 et E2 tels que E2 = δ(A) E1, alors E2(s-r) < E1(s-r). CQFD.
Autres exemples pour montrer l'utilisation en pratique de la logique de Hoare pour prouver des programmes classiques :
== Somme des n premiers entiers ==
s:=0; i:=1;
while i ≠ n do
{
i:=i+1;
s:=s+i;
}
Une technique pour trouver un invariant consiste à décomposer la post-condition sous la forme p ∧ ¬b où p est l'invariant recherché et b est la condition de l'itération. Ici la post-condition est \left\{s=\sum_{k=1}^{n} k\right\}. Réécrit en \left\{s=\sum _{k=1}^{i} k \& \not\left(i\neq n\right) \right\}
On va montrer que \left\{s=\sum _{k=1}^{i} k \ \right\} est un invariant.
Démonstration (en remontant les instruction).
| {vrai} => {0=∑k=1,0 k } | l'invariant de boucle est vrai sans plus forte pré-condition que {vrai} |
| s:=0 ; | { s = ∑k=1,0 k } |
| i:=0 ; | { s = ∑k=1,i k } ^ on avait i:=1 en cours, je crois, mais ça ne marche pas! |
| while i <> n do | |
| { s + i + 1 = = ∑k=1,i+1 k } | |
| i:= i+1 | { s + i = = ∑k=1,i k } |
| s:=s+i | { s = = ∑k=1,i k } |
| } | fin de satisfaction de la condition |
| {s = ∑k=1,i k ∧ ¬(i ≠ n)} => {s =∑k=1,n k } ||
Pour montrer la terminaison, il suffit de
* prendre {n≥0} comme pré-condition initiale
* ajouter {0 ≤ i ≤ n } à l'invariant
* prendre n-i comme variant (0 = borne inf.)
=== Minimum d'un tableau de nombres ===
=== PGCD de 2 nombres entiers ===
FIXME trois pages à rajouter.