Vous êtes sur la page 1sur 12

Le tri à bulles

Preuve formelle avec dafny

par Emmanuel Nativel et Thomy Fontaine


le 24 septembre 2020
» Présentation

∗ Algorithme de tri basique


∗ Parcours de gauche à droite
∗ Comparaison d’éléments adjacents en changeant leur
position si ils sont dans le désordre
∗ Arrêt quand tous les éléments sont parcourus
∗ Le plus lent des algorithmes de tri.

[1/11]
» Exemple sur une instance

[2/11]
» Implémentation sans vérification

1 method BubbleSort(a: array?<int>) {


2 var i := a.Length - 1;
3 while(i > 0) {
4 var j := 0;
5 while (j < i) {
6 if(a[j] > a[j+1]) {
7 a[j], a[j+1] := a[j+1], a[j];
8 }
9 j := j + 1;
10 }
11 i := i -1;
12 }
13 }
14

[3/11]
» Pré-conditions

1 requires a != null
2

[4/11]
» Post-conditions
1 ensures sorted(a, 0, a.Length-1) //Vérifie que le
résultat est un tableau trié
2 ensures multiset(a[..]) == multiset(old(a[..])) //
Vérifie que le résultat est une permutation des
éléments de a
3

1 predicate sorted(a: array?<int>, l: int, u: int)


2 reads a
3 requires a != null
4 {
5 forall i, j :: 0 <= l <= i <= j <= u < a.Length
==> a[i] <= a[j]
6 }
7

Si 0 ≤ l ≤ u < a.Length le prédicat retournera vrais sans


tenir compte du contenu de a.

[5/11]
» Recherche des invariants

Boucle externe : i ∈ [−1, a.Length − 1].


Si i = −1 alors a.Length = 0.
1 invariant i < 0 ==> a.Length == 0
2

Boucle interne : j ∈ [0, i] et i ∈ [1, a.Length − 1] :


1 invariant 0 < i < a.Length && 0 <= j <= i
2

Concentrons-nous maintenant sur le contenu de a.

[6/11]
» Invariants : Propagation des post-conditions.
∗ Le tableau est toujours trié dans la plage [i, a.Length − 1].
∗ Le résultat est une permutation de a.

Dans la boucle externe :


1 invariant i < 0 ==> a.Length == 0
2 invariant sorted(a, i, a.Length-1)
3 invariant multiset(a[..]) == multiset(old(a[..]))
4

Dans la boucle interne :


1 invariant 0 < i < a.Length && 0 <= j <= i
2 invariant sorted(a, i, a.Length-1)
3 invariant multiset(a[..]) == multiset(old(a[..]))
4

[7/11]
» Invariants : Partition de a

Il y a une partition sur a.


∀m, n : 0 ≤ m ≤ i ∧ i < n < a.Length =⇒ a[m] ≤ a[n]

1 predicate partitioned(a: array?<int>, i: int)


2 reads a
3 requires a != null
4 {
5 forall m, n :: 0 <= m <= i < n < a.Length ==> a[m]
<= a[n]
6 }
7

[8/11]
» Invariants : Partition de a
Nous ajoutons cet invariant aux deux boucles car la boucle
interne conserve cette propriété. Boucle externe :

1 invariant i < 0 ==> a.Length == 0


2 invariant sorted(a, i, a.Length-1)
3 invariant partitioned(a, i)
4 invariant multiset(a[..]) == multiset(old(a[..]))
5

Boucle interne :
1 invariant 0 < i < a.Length && 0 <= j <= i
2 invariant sorted(a, i, a.Length-1)
3 invariant partitioned(a, i)
4 invariant multiset(a[..]) == multiset(old(a[..]))
5

[9/11]
» Invariants : boucle interne

a[j] va faire remonter la plus grande valeur des non-triés :


∀k, 0 ≤ k ≤ j =⇒ a[k] ≤ a[j]

1 invariant 0 < i < a.Length && 0 <= j <= i


2 invariant sorted(a, i, a.Length-1)
3 invariant partitioned(a, i)
4 invariant multiset(a[..]) == multiset(old(a[..]))
5 invariant forall k :: 0 <= k <= j ==> a[k] <= a[j]
6

[10/11]
» Les fonctions de rang

Pour la boucle externe : i


1 while(i > 0) {
2 //...
3 i := i -1;
4 }
5

Pour la boucle interne : i − j


1 while (j < i) {
2 //...
3 j := j + 1;
4 }
5

[11/11]

Vous aimerez peut-être aussi