M1 Info UFR d’IEEA – USTL AAC-TP 2008–2009 Correction Diviser pour Régner Exercice 1 Recherche d’une valeur encadrée //A4; int m; int g:=0; int d:=n-1; while (g <= d){ m:=(g+d)/2; if (T[m] >= b) d:=m-1; else if (T[m] <= a) g:=m+1; else return true; } return false; Preuve de correction partielle Précondition et post-conditions Pour prouver que l’algorithme est correct s’il termine, il faut d’abord déterminer les deux post-conditions qui doivent être vérifiées si l’algorithme retourne true et s’il retourne false, et établir une précondition que l’on peut déduire des données et des initialisations auxquelles on procéde sur d et g. 1. Pour qu’il soit correct de retourner true il faut prouver qu’il existe bien un indice i tel que a < T[i] < b, on défini donc : Qt = ∃ i tq. a < T[i] < b 2. Pour qu’il soit correct de retourner false il faut prouver que toutes les cases du tableau contiennent un entier soit supérieur ou égal à b, soit inférieur ou égale à a, on défini : Qf = ∀ i ∈ 0..n-1, T[i] leq a ou T[i] geq b 3. on défini finalement la post condition globale de l’algorithme : Q = Qt ou Qf Au début de l’algorithme on ne connaît que d et g, la précondition va dépendre de ces deux variables. Tout ce que l’on sait, c’est que g=0 et d=n-1, c’est-à-dire que g est l’indice de la première case du tableau et d l’indice de la dernière case. On définit la précondition : P = g=0 et d=n-1 Invariant de boucle Pour prouver qu’une boucle effectue bien le calcul souhaité, il faut trouver un invariant I : une assertion qui reste vraie quelle que soit l’itération de la boucle considérée. Ici la boucle se termine soit par le cas où on retourne true et il faut prouver que Qt est vraie, soit par le cas oùn on retourne false et il faut alors prouver Qf . On essaie donc de s’inspirer de Qt et Qf pour orienté notre recherche de I. Les deux post-conditions portent sur la relation entre les/une case du tableau et a et b, on étudie un peu l’algorithme pour voir si on sait dire quelque chose qui impliquerait a, b, g et d et pourrait être déduit de la précondition P . Comme le tableau est trié, on déduit de l’algorithme que au début de chaque itération on doit avoir (il faut encore le prouver !) : ∀ i < g, T[i] ≤ a et ∀ j > d, T[j] ≥ b, c’est ce qu’on prend pour invariant I. 1 Preuve partielle //A4; int m; int g:=0; int d:=n-1; {P} while (g <= d){ {I} _ m:=(g+d)/2; if (T[m] >= b) d:=m-1; else if (T[m] <= a) g:=m+1; else {Qt} return true; | | | | | | _| A } {Qf} return false; En suivant ce qui est indiqué dans le cours, on doit prouver plusieurs choses pour arriver à la conclusion P Algorithme Q, c’est-à-dire que partant de P soit on trouve un indice qui marche, soit on est certain qu’il n’y en a aucun. Précondition → Invariant On doit commencer par vérifier : P et (g ≤ d)) ⇒ I. Comme g et d sont respectivement la première et la dernière case du tableau, il n’y a aucune case d’indice < g ou d’indice > d, donc l’invariant n’est pas faux : il est vrai. Invariant → Qf On sort de la boucle lorsque g > d, mais l’invariant est (on le prouve juste après) vrai. On doit déduire de tout celà que Qf est vraie, ie que I et (g > d) ⇒ Qf : I = ∀ i < g, T[i] ≤ a et ∀ j > d, T[j] ≥ b donc, si g > d ∀ i ∈ 0..n-1, T[i] ≤ a ou T[i] ≥ b, ce qui est exactement Qf . Invariant → A → invariant On doit montrer que l’invariant de boucle reste vrai après avoir executé le corps de la boucle (A) lorsque la condition d’arret du tant que n’est pas encore fausse. Comme la partie A de l’algorithme a une structure conditionnelle on doit prouver trois choses : g+d 1. {I et (g ≤ d) et (T[ g+d 2 ] ≥ b)} d ← 2 − 1 {I} : comme le tableau est trié par ] ≥ b) que ∀ i ≥ g+d ordre croissant on peut déduire de (T[ g+d 2 2 , T[i] ≥ b, ainsi après g+d l’affectation d ← 2 − 1 on a ∀ i > d, T[i] ≥ b. La seconde moitié de I concernant g n’est pas modifiée, donc I est toujours vraie. g+d g+d 2. {I et (g ≤ d) et (T[ g+d 2 ] < b) et (T[ 2 ] ≤ a)} g ← 2 +1 {I} : comme le tag+d bleau est trié par ordre croissant on peut déduire de (T[ 2 ] ≤ a) que ∀ i ≤ g+d 2 , T[i] g+d ≤ a, ainsi après l’affectation g ← 2 + 1 on a ∀ i < g, T[i] ≤ a. La seconde moitié de I concernant d n’est pas modifiée, donc I est toujours vraie. 2 g+d 3. {I et (g ≤ d) et (T[ g+d 2 ] < b) et (T[ 2 ] > a)} ⇒ {Qt } : on déduit directement g+d g+d g+d Qt de (T[ 2 ] < b) et (T[ 2 ] > a) : 2 est un indice du tableau (on peut le prouver en alourdissant encore l’invariant avec (0≥g) et (d≥n-1), la condition (g≤d) et les affectations effectuées font le reste) qui marche. Conclusion : en partant de P on arrive soit à Qt soit à Qf , donc s’il termine l’algorithme est correct. 3