CCCPaste

85ef49fa302c2

/*@
 predicate swap{L1, L2}(int* a, integer i, integer j) =
    \at(a[i], L1) == \at(a[j], L2) && 
    \at(a[j], L1) == \at(a[i], L2) && 
    \forall integer k; 
      k != i && k != j ==> \at(a[k], L1) == \at(a[k], L2);

  inductive permutate{L1, L2}(int* a) {
    case permutate_id{L1}:
      \forall int* a; permutate{L1, L1}(a);
    case permutate_swap{L1, L2}:
      \forall int* a, integer i, integer j;
        swap{L1, L2}(a, i, j) ==> permutate{L1, L2}(a);
    case permutate_trans{L1, L2, L3}:
      \forall int* a;
        permutate{L1, L2}(a) ==> permutate{L2, L3}(a) ==> permutate{L1, L3}(a);
  }
*/

/* Dudu: je ne comprends pas pourquoi tu as changé la signature de ma version 
 * pour remplacer le type de retour `void` par `int *`. Comme pour le tri
 * par sélection qu'on a étudié hier, ce tri est en place, c'est-à-dire que le
 * tableau est modifié directement et la fonction ne retourne aucune valeur. */

/*@
   requires \valid(a + (0 .. sz - 1));
   requires sz > 0;
   ensures \forall integer p; 0 <= p < sz ==> 
    \forall integer  q; 0 <= q < p  ==> a[q] <= a[p]; 
 */  
int* bubble_sort(int* a, int sz) {
  /* Dudu: tu n'as pas besoin de définir ces variables en dehors des boucles
   * afin d'y faire référence dans les invariants de la boucle. Lorsque tu écris
   * ```c
   * for (int i = 0; i < sz; i++) {
   *   ...
   * }
   * ```
   * le scope de la variable `i` est bien limité au bloc de la boucle for mais 
   * tu peux regarder le code C affiché dans frama-c-gui et constater que les 
   * boucles for sont en fait transformées en boucles while et que les 
   * invariants sont insérés après la déclaration de la variable i. Plus précisément:
   * ```c
   * int i = 0;
   * // LES INVARIANTS ICI
   * while (i < sz) {
   *   ...
   *   i++;
   * } */
  int i, j;

  /* Dudu: je ne comprends pourquoi tu as l'invariant `sz`? Remarque que en C
   * les types entiers sont automatiquement convertis en booléen et donc que 
   * la proposition `sz` ici signifie exactement `sz != 0`, ce qui est d'ailleurs 
   * rendu visible par la fonction d'affichage dans l'interface `frama-c-gui`.
   * En particulier cet invariant est impliqué par le second qui stipule déjà 
   * que 0 < sz est toujours vrai. */

  /* Dudu: tu as tout à fait raison, l'invariant I1 n'est pas vrai en entrée 
   * boucle, je pense que tu es sur la bonne voie. */

 /*@
    loop invariant sz; 
    loop invariant 0 <= i < sz;
    loop assigns i, j, a[0..sz-1];
    loop invariant I1: \forall integer p; i <= p < sz ==> 
      \forall integer q; 0 <= q < p  ==> a[q] <= a[p]; 
    loop variant i;
  */
  for (i = sz - 1; i >= 1; i--) {
     /* Dudu: c'est un bon début :D. Ton invariant:
          \forall integer q; 0 <= q < j   ==> a[q] <= a[j];
        stipule que a[j] est un maximum du segment [0..j] du tableau a.
      */

    /* Dudu: comme dans le tri par sélection, l'invariant établit par la boucle
     * extérieure doit être présent dans les invariants de la boucle intérieure,
     * sinon ces informations sont perdues après l'exécution de la boucle. */

     /*@
      loop invariant sz;
      loop invariant 0 <= i < sz;
      loop assigns j, a[0..sz-1];
      loop invariant  \forall integer q; 0 <= q < j   ==> a[q] <= a[j];
      loop invariant 0 <= j <= i;
      loop variant sz - j; 
      */

    for (j = 0; j < i; j++) {
      if (a[j + 1] < a[j]) {
        int tmp = a[j];
        a[j] = a[j + 1];
        a[j + 1] = tmp;
      }
    }
  }
  return a; 
}