Adloun

Probleme – De à , et la mesure qui le confirme

Exercice · niveau 3 (difficile) · informatique (MP2I/MPI), chapitre 3 — Algorithmes, programmes et complexité

Énoncé

Étant donné un tableau d'entiers relatifs, on cherche la plus grande somme d'un segment (une tranche contiguë, éventuellement vide).

Corrigé

1. L'algorithme naïf.


/* Renvoie la plus grande somme d'un segment de t[0..n-1]. Le segment
   vide etant admis, le resultat est toujours >= 0.
   Precondition : n >= 0. */
long max_segment_naif(const int t[], int n) {
    long meilleur = 0;
    for (int i = 0; i < n; i = i + 1) {
        long s = 0;
        for (int j = i; j < n; j = j + 1) {
            s = s + t[j];                        /* somme de t[i..j] */
            if (s > meilleur) { meilleur = s; }
        }
    }
    return meilleur;
}

Il examine les segments, en temps constant chacun grâce à la somme accumulée : en temps, en espace. (Une version qui recalculerait chaque somme de zéro serait en — c'est la faute la plus fréquente sur cet exercice.)

2. L'algorithme en un parcours.


/* Meme specification. Complexite : Theta(n) en temps, Theta(1) en espace. */
long max_segment(const int t[], int n) {
    long meilleur = 0, courant = 0;
    /* INVARIANT (avant le tour i) :
         meilleur = plus grande somme d'un segment de t[0..i-1] ;
         courant  = plus grande somme d'un segment SE TERMINANT en i-1
                    (le segment vide comptant pour 0). */
    for (int i = 0; i < n; i = i + 1) {
        courant = courant + t[i];
        if (courant < 0) { courant = 0; }
        if (courant > meilleur) { meilleur = courant; }
    }
    return meilleur;
}

Correction. Initialisation : avant le tour , les deux tranches sont vides et les deux variables valent .

Conservation. Soit l'invariant vrai avant le tour . Un segment se terminant en est, ou bien le segment vide (somme ), ou bien un segment se terminant en auquel on ajoute . Le meilleur de la seconde famille vaut donc , et le meilleur des deux familles vaut — précisément ce que calculent les deux premières lignes du corps. Ensuite, le meilleur segment de est ou bien inclus dans (valeur meilleur), ou bien se termine en (valeur courant recalculée) : le maximum des deux est ce que pose la troisième ligne.

Utilisation : à la sortie, et meilleur est la plus grande somme d'un segment de . Terminaison : variant .

Vérification. Sur , les deux fonctions rendent — c'est le segment . Sur , les deux rendent : le segment vide, conformément à la spécification. Ce second cas est le test qui compte : c'est le seul endroit où une lecture distraite de l'invariant donne au lieu de .

3. La mesure.


    n | naif (ms) | Kadane (ms) | operations naif | operations Kadane
 1000 |     0,355 |     0,00103 |          500500 |              1000
 2000 |     1,414 |     0,00208 |         2001000 |              2000
 4000 |     5,656 |     0,00417 |         8002000 |              4000
 8000 |    22,531 |     0,00837 |        32004000 |              8000
16000 |    90,087 |     0,01676 |       128008000 |             16000

Les rapports de temps entre deux lignes consécutives :

doublé de à à à à
naïf
un parcours

Doubler multiplie l'un par et l'autre par : c'est la signature de et de , lue directement sur les mesures. À , le rapport entre les deux programmes atteint .

4. Ce que la mesure prouve, et ce qu'elle ne prouve pas.

Elle prouve que la transcription est fidèle : si le code écrit ne réalisait pas l'algorithme analysé, les rapports ne seraient pas et . C'est un contrôle puissant et rarement pratiqué — et c'est pourquoi il faut regarder les rapports et non les temps absolus, qui ne disent rien hors de cette machine.

Elle ne prouve pas que les fonctions sont correctes : elles pourraient rendre toutes deux la même valeur fausse, et les rapports seraient inchangés. Elle établit mal, aussi, la différence entre et : un coût quasi-linéaire donnerait sur cette plage des rapports allant de à , et il faut des mesures très propres pour les séparer de . Les nôtres, à et , y parviennent — mais de justesse, et une machine chargée aurait suffi à brouiller la conclusion. Seule la lecture du code établit qu'il y a une boucle et une seule.

Preuve et mesure ne se remplacent donc pas : la preuve dit ce que fait l'algorithme, la mesure dit que le programme est bien celui-là. C'est la répartition des rôles du chapitre chap:discipline, et elle vaut pour tout le livre.

Les autres exercices de ce chapitre Le cours du chapitre

Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.