WikiPrépaLivrets

Mines Option Informatique MP 2018Sujet, corrigé et rapport du jury

Pas encore noté
Faisable en Sup
  • Automates finis déterministes
  • Langages reconnaissables
  • Programmation en Caml
  • Listes et tableaux
  • Types enregistrements
  • Complexité des algorithmes
  • Preuve de terminaison

Téléchargements

Présentation du sujet

Recherche de motifs dans un texte : automates finis déterministes à repli et algorithme de Knuth-Morris-Pratt
Afficher ou masquer la section

Le sujet étudie des algorithmes de recherche efficace des occurrences d'un ou plusieurs motifs dans une longue chaîne de caractères, en Caml. Il part d'une recherche naïve, introduit les automates finis déterministes à repli, construit l'automate de Knuth-Morris-Pratt puis ouvre sur la recherche simultanée d'un ensemble de motifs.

  1. 1Partie 1 : recherche naïve d'un motifRecouvrement possible des occurrences, fonctions longueur et préfixe sur les listes, recherche naïve et sa complexité.
  2. 2Partie 2 : automates finis déterministes à repliDéfinition des automates à repli, équivalence avec un automate déterministe complet, copie et suppression des replis, calcul des occurrences en temps linéaire.
  3. 3Partie 3 : automate de Knuth-Morris-PrattConstruction de l'automate KMP associé à un motif, preuve de sa caractérisation, complexité et comparaison avec la recherche naïve.
  4. 4Partie 4 : ensemble de motifs et automates à repli arborescentsRecherche d'un dictionnaire de motifs par KMP répété, puis stratégie plus efficace inspirée d'un automate arborescent.

Ce qu'a observé le jury

5 erreurs relevées
Recouvrement des occurrences ignoré · Fonction préfixe et appels inutiles à longueur · Calculs de complexité interminables
Afficher ou masquer la section

Le sujet, qui combine la notion formelle d'automate et la manipulation de structures de données élaborées, permet selon le jury de bien évaluer le programme des deux années. La grande majorité des candidats aborde l'ensemble des questions et certains finissent en passant les plus difficiles. Le jury regrette le peu d'efforts de rédaction sur les questions théoriques et des codes parfois trop compliqués.

Les erreurs les plus sanctionnées

  1. 1
    Recouvrement des occurrences ignoréQ1, Q2

    Les questions 1 et 2 visaient à montrer que deux occurrences d'un motif peuvent se chevaucher ; ne pas le voir fausse ensuite les codes.

    « Beaucoup de candidats passent à côté de cette finesse et se trouvent ensuite pénalisés dans l’écriture des codes. »
  2. 2
    Fonction préfixe et appels inutiles à longueurQ3, Q4

    Les cas d'arrêt de la fonction préfixe sont mal gérés, et appeler longueur sur le texte rend la complexité linéaire en la taille du texte au lieu de celle du motif.

    « La fonction préfixe pose parfois des difficultés cependant (mauvaise gestion des cas d’arrêt). »
  3. 3
    Calculs de complexité interminablesQ6

    Certains se perdent dans de longues sommes pour un résultat faux ; on attend un O cohérent avec le code proposé.

    « Le calcul de complexité conduit parfois le candidat à se perdre dans de très gros calculs de sommes »
  4. 4
    Justifications théoriques imprécisesQ7

    Des arguments contradictoires, comme une suite à la fois strictement décroissante et stationnaire, sont trop fréquents.

    « Les arguments théoriques attendus ici sont précis. »
  5. 5
    Complexité imposée non respectéeQ10, Q11

    Peu de candidats voient la subtilité de la complexité demandée et annoncent le résultat de l'énoncé alors que leur propre code ne le vérifie pas.

Ce qui a été bien réussi

  • Une certaine aisance dans la manipulation des objets de type élaboré a été globalement appréciée.
  • Les candidats montrent une certaine aisance dans la manipulation des listes (question 5).
  • La présentation des copies est globalement satisfaisante et quelques rares excellentes copies ont été lues.

Conseils du jury

  • Donner des arguments précis aux questions théoriques plutôt que des justifications superficielles.
  • Écrire des codes clairs et simples, en utilisant l'indentation.
  • Construire les automates en suivant exactement la construction décrite par l'énoncé.
  • Vérifier que la complexité annoncée correspond bien au code écrit.

Synthèse rédigée par WikiPrépa à partir du rapport officiel du jury (à télécharger en PDF). Les citations sont extraites du rapport.

Ces sujets peuvent vous intéresser

Lecture du sujet en ligne

L'énoncé complet, avec les formules et les figures, sans ouvrir le PDF.
Afficher ou masquer la section

ÉCOLE DES PONTS PARISTECH, ISAE-SUPAERO, ENSTA PARISTECH, TELECOM PARISTECH, MINES PARISTECH, MINES SAINT-ÉTIENNE, MINES NANCY, IMT Atlantique, ENSAE PARISTECH.
Concours Centrale-Supélec (Cycle International), Concours Mines-Télécom, Concours Commun TPE/EIVP.

CONCOURS 2018

ÉPREUVE D'INFORMATIQUE MP

Durée de l'épreuve : 3 heures

L'usage de la calculatrice et de tout dispositif électronique est interdit.
Cette épreuve concerne uniquement les candidats de la filière MP.
Les candidats sont priés de mentionner de façon apparente sur la première page de la copie :

INFORMATIQUE - MP

L'énoncé de cette épreuve comporte 8 pages de texte.

Abstract

Si, au cours de l'épreuve, un candidat repère ce qui lui semble être une erreur d'énoncé, il le signale sur sa copie et poursuit sa composition en expliquant les raisons des initiatives qu'il est amené à prendre.

L'épreuve est composée d'un unique problème, comportant 24 questions. Après un préliminaire et des définitions générales, ce problème est divisé en 4 parties; la partie 2 est indépendante de la partie 1 .
Le but du problème est d'étudier des algorithmes permettant de rechercher efficacement des occurrences d'une ou plusieurs chaînes de caractères (appelées motifs) à l'intérieur d'une longue chaîne de caractères.

Préliminaire concernant la programmation

Il faudra coder des fonctions à l'aide du langage de programmation Caml, tout autre langage étant exclu. Lorsque le candidat écrira une fonction, il pourra faire appel à d'autres fonctions définies dans les questions précédentes; il pourra aussi définir des fonctions auxiliaires. Quand l'énoncé demande de coder une fonction, il n'est pas nécessaire de justifier que celle-ci est correcte, sauf si l'énoncé le demande explicitement. Enfin, si les paramètres d'une fonction à coder sont supposés vérifier certaines hypothèses, il ne sera pas utile dans l'écriture de cette fonction de tester si les hypothèses sont bien vérifiées.
Dans les questions du problème, un même identificateur écrit dans deux polices de caractères différentes désignera la même entité, mais du point de vue mathématique pour la police en italique (par exemple n ) et du point de vue informatique pour celle en romain avec espacement fixe (par exemple n ).

Définitions générales

On fixe un alphabet Σ, c'est-à-dire un ensemble fini, dont les éléments sont appelés symboles. On note λ > 0 le nombre d'éléments de cet alphabet, et on suppose que cette taille λ est disponible depuis les fonctions Caml à implémenter sous la forme d'une constante globale lambda. Par exemple :
let lambda = 5; ;
On supposera que les éléments de Σ sont ordonnés, par exemple par ordre alphabétique, et on les note dans l'ordre α_0 < ⋯ < α_(λ − 1). On dit que le code d'un symbole α de l'alphabet est l'entier i tel que α = α_i(0 ⩽ i ⩽ λ − 1).
Une chaîne de caractères s est une suite finie non vide u_1…u_k de symboles de Σ. La longueur de s est son nombre de symboles, c'est-à-dire, ici, k. On représentera en Caml les chaînes de caractères par des listes d'entiers (int list), chaque entier étant le code d'un symbole. Ainsi, si l'alphabet est Σ = {a, b, c}, dans cet ordre, la chaîne de caractères « abac » sera représentée par la liste [0; 1; 0; 2]. En particulier, on n'utilisera jamais le type string de Caml.

1 Recherche naïve d'un motif

Une occurrence d'une chaîne de caractères s = α_1…α_k (aussi appelée un motif) dans une autre chaîne de caractères t = β_1…β_n est un entier naturel y avec 1 ⩽ y ⩽ n tel que, pour tout entier i tel que 0 ⩽ i ⩽ k − 1, α_(k − i) = β_(y − i). En d'autres termes, l'occurrence indique la position du dernier caractère du motif s au sein de la chaîne de caractères t (les positions commençant à 1 ).
Par exemple, si Σ = {a, b, c, d, e}, s est le motif « abc » et t la chaîne de caractères «abcabcdababcdabcdabde», il y a quatre occurrences de s dans t, à savoir :
  • 3
  • 6
  • 12
  • 16
1 - Soit s, t deux chaînes de caractères. Est-il possible d'avoir deux occurrences y et y^′ de s dans t avec y < y^′ et y ⩾ y^′ − k + 1 ? Si oui, donner un exemple ; sinon, le prouver.
◻2 - Quel est le nombre maximal d'occurrences d'un motif de longueur k dans une chaîne de caractères de longueur n ⩾ k ? Prouver que cette borne est toujours respectée, et que cette borne est atteinte.
◻3 - Programmer en Caml une fonction longueur : 'a list -> int qui prend en entrée une liste et qui renvoie la longueur de cette liste. Quelle est la complexité de cette fonction, en terme du nombre n d'éléments de la liste?
◻4 - Programmer en Caml une fonction int list -> int list -> bool prenant en entrée deux listes d'entiers s et t codant des chaînes de caractères et testant si s est un préfixe de t. Quelle est la complexité de cette fonction, en terme des longueurs k et n de s et t ?
◻5 - À l'aide des fonctions longueur et prefixe, programmer une fonction recherche_naive : string -> string -> int list, la plus directe possible, telle que si s est un motif et t une chaîne de caractères, recherche_naive s t renvoie la liste des entiers y qui sont des occurrences de s dans t, triés par ordre croissant.
◻6 - Quelle est la complexité de la fonction recherche_naive, en terme des longueurs k et n de ses deux paramètres s et t ?

2 Automates finis déterministes à repli

Un automate fini déterministe à repli (ou AFDR ) sur l'alphabet Σ est un quadruplet A = (k, F, δ, ρ) tel que :
− k ∈ ℕ est un entier strictement positif représentant le nombre d'états de A; l'ensemble des états de A est Q_A = {0, 1, …, k − 1} et 0 est appelé l'état initial.
  • F ⊆ Q_A est un ensemble d'états, appelés finals.
  • δ : Q_A × Σ → Q_A est une fonction partielle de transition (c'est-à-dire, une fonction dont le domaine de définition est un sous-ensemble de Q_A × Σ ); on impose que δ(0, α) soit défini pour tout α ∈ Σ.
  • ρ : Q_A∖{0} → Q_A est une application (c'est-à-dire, une fonction totale), appelée fonction de repli, telle que pour tout q ∈ Q_A avec q ≠ 0, ρ(q) < q. On prolonge ρ en convenant ρ(0) = 0.
    Un AFDR est représenté en Caml par le type enregistrement suivant :
type afdr = {
    final : bool vect;
    transition : int vect vect;
    repli: int vect;
};;;
où :
  • final est un tableau de taille k de booléens tel que si q ∈ Q_A, final. (q) contient true si et seulement si q ∈ F;
  • transition est un tableau de taille k de tableaux de taille λ d'entiers, tel que si q ∈ Q_A et α_i ∈ Σ de code i, transition. (q). (i) contient -1 si δ(q, α_i) n'est pas défini, et contient δ(q, α_i) sinon;
  • repli est un tableau de taille k d'entiers tel que repli. (0) contient 0 et repli. (q) pour q ∈ Q_A∖{0} contient ρ(q).
    On observe que le type afdr ne code pas explicitement la valeur de k, mais k est par exemple la longueur du tableau final.
On dessine un AFDR de manière similaire au dessin d'un automate fini déterministe classique, en faisant figurer en pointillés une flèche indiquant les replis d'un état vers un autre. Les états finals sont figurés par un double cercle.
Considérons par exemple l'automate A_1 = (k_1, F_1, δ_1, ρ_1) sur l'alphabet Σ = {a, b} défini par k_1 = 4, F_1 = {3}, et les fonctions δ_1 et ρ_1 suivantes:
δ_1
q δ_1(q, a) δ_1(q, b) ρ_1
0 1 0 ρ_1(q)
1 2
2 3
3
A_1 peut être dessiné comme suit :

◻7 - Soit A = (k, F, δ, ρ) un AFDR. Pour tout q ∈ Q_A, on note ρ^j(q) pour j ∈ ℕ l'application répétée j fois de la fonction ρ à q, c'est-à-dire
Montrer que pour tout q ∈ Q_A, pour tout α ∈ Σ, il existe j ⩾ 0 tel que δ(ρ^j(q), α) est défini.
On dit qu'un AFDR A = (k, F, δ, ρ) accepte un mot u = u_1…u_p ∈ Σ^∗ s'il existe une suite finie q_0, q_1^′, q_1, q_2^′, q_2, …, q_(p − 1)^′, q_(p − 1), q_p^′, q_p d'états de A avec :
  • q_0 = 0;
  • pour tout 1 ⩽ i ⩽ p, q_i^′ = ρ^j(q_(i − 1)) avec j ⩾ 0 le plus petit entier tel que δ(ρ^j(q_(i − 1)), u_i) est défini ;
  • pour tout 1 ⩽ i ⩽ p, q_i = δ(q_i^′, u_i);
  • q_p ∈ F.
Le langage accepté par un AFDR est l'ensemble des mots acceptés.
Ainsi, A_1 accepte le mot «ababa», comme le montre la suite d'états parcourus
0, 0, 1, 1, 2, 2, 3, 1, 2, 2, 3.
On remarque qu'un AFDR dont la fonction de transition δ est définie partout peut être vu comme un automate fini déterministe classique, et que cet automate fini déterministe est complet (ce qui signifie précisément que sa fonction de transition est définie partout). En effet, les puissances non nulles de la fonction de repli ρ ne sont utilisées que si la fonction de transition n'est pas définie. On appellera un tel automate fini déterministe complet un AFDC.
◻8 - Construire (sans justification) un AFDC sur l'alphabet {a, b} reconnaissant le même langage que A_1 et ayant le même nombre d'états que A_1.
◻9 - Donner (sans justification) une description concise du langage reconnu par l'AFDR A_1.
◻10 - Programmer en Caml une fonction copie_afdr : afdr -> afdr qui renvoie un nouvel AFDR identique à l'AFDR fourni en entrée, mais ne partageant aucune donnée avec lui. On pourra utiliser la fonction standard copie_vect : 'a vect -> 'a vect qui renvoie un nouveau tableau contenant les mêmes éléments que les éléments d'entrée et s'exécute en un temps proportionnel au nombre d'éléments du tableau d'entrée.
◻11 - En s'inspirant de la réponse aux questions 7 et 8 , et en utilisant la fonction copie_afdr, programmer une fonction enleve_repli : afdr -> afdr telle que, si A est un AFDR , enleve_repli A renvoie un AFDC reconnaissant le même langage. On souhaite que cette fonction s'exécute en temps O(k × λ), où k est le nombre d'états de A et λ est la taille de l'alphabet. Montrer que la fonction proposée a bien cette complexité.
◻12 - Étant donné un AFDC A et un mot u = u_1…u_n sur Σ, proposer un algorithme (pas un programme Caml) en O(n) pour calculer la liste triée des entiers i avec 1 ⩽ i ⩽ n tels que le préfixe u_1…u_i de u est accepté par A.
◻13 - Implémenter en Caml l'algorithme de la question précédente : programmer une fonction occurrences : afdr -> int list -> int list telle que, si A est un AFDC et liste une liste d'entiers j_1, …, j_n codant des symboles α_(j_1), …, α_(j_n) de l'alphabet Σ, occurrences A liste renvoie la liste des entiers i avec 1 ⩽ i ⩽ n tels que le mot α_(j_1)…α_(j_i) est reconnu par A. Quelle est la complexité de cette fonction en terme de la longueur n de la liste d'entiers, du nombre k d'états de l'automate A et de λ ?

3 Automate de Knuth-Morris-Pratt

L'automate de Knuth-Morris-Pratt (ou automate KMP) associé à un motif s = u_1…u_k sur l'alphabet Σ est un AFDR A_s^(KMP) = (k^′, F, δ, ρ) sur Σ avec :
− k^′ = k + 1.
  • F = {k}.
  • Pour tout 1 ⩽ i ⩽ k, δ(i − 1, u_i) = i et, pour tout α ∈ Σ∖{u_1}, δ(0, α) = 0; aucune autre transition n'est définie.
  • Pour tout 1 ⩽ i ⩽ k, ρ(i) est le plus grand entier 0 ⩽ j < i tel que u_1…u_j est un suffixe de u_1…u_i.
    On peut ainsi vérifier que l'automate A_1 de la question précédente est l'automate KMP associé à « aba »sur l'alphabet Σ = {a, b}.
14 - Construire (sans justification) l'automate KMP associé à «ababc»sur l'alphabet {a, b, c}.
◻15 - Donner (sans justification) une description concise du langage reconnu par l'AFDR A_s^(KMP) pour un motif s arbitraire.
◻16 - Montrer que si s = u_1…u_k est un motif et ( k + 1, F, δ, ρ ) l'automate KMP associé à s, alors pour tout 1 ⩽ i ⩽ k, si j ⩾ 0 est le plus petit entier tel que δ(ρ^j(ρ(i − 1)), u_i) est défini (qui existe d'après la question 7), alors ρ(i) = δ(ρ^j(ρ(i − 1)), u_i).
◻17 - En utilisant la caractérisation de la question 16, programmer une fonction automate_kmp : int list -> afdr qui prend en entrée une liste d'entiers s codant une chaîne de caractères s et qui renvoie l'AFDR A_s^(KMP).
◻18 - Pour un motif s = u_1…u_k et pour tout 1 ⩽ i ⩽ k, on note j_i le plus petit entier tel que δ(ρ^(j_i)(ρ(i − 1)), u_i) est défini, comme à la question 16. Montrer que pour tout 1 ⩽ i ⩽ k, ρ(i) ⩽ ρ(i − 1) + 1 − j_i et en déduire que ∑_(i = 1)^k j_i est en O(k).
◻19 - Quelle est la complexité de la fonction automate_kmp en terme de la longueur k du motif s passé en argument et de λ ? Prouver cette affirmation.
◻20 - En s'appuyant sur les fonctions Caml automate_kmp, enleve_repli et occurrences, programmer une fonction Caml recherche_kmp : string -> string -> int list telle que, si s est un motif de longueur k et t une chaîne de caractères, recherche_kmp s t renvoie la liste des occurrences y de s dans t, triés par ordre croissant.
Quelle est la complexité de cette fonction en terme des longueurs k et n de s et t et de λ ? Comparer avec la complexité de la fonction recherche_naive obtenue en question 6.

4 Ensemble de motifs et automates à repli arborescents

On considère maintenant l'AFDR A_2 suivant, sur l'alphabet Σ = {a, b} :

◻21 - Donner (sans justification) une description concise du langage reconnu par l'AFDR A_2.
◻22 - On considère l'alphabet Σ = {a, b, c}. Construire (sans justification) un AFDR dont le langage reconnu est l'ensemble des mots dont un suffixe est « baa », « bab » ou « bc ». Indication : on cherchera un AFDR tel que si δ(q, α) est défini et q est non nul, alors δ(q, α) > q.
On fixe maintenant un ensemble fini S de motifs. L'ensemble des occurrences de S dans une chaîne de caractères t est l'ensemble des occurrences de chacun des motifs de S dans t.
◻23 - En utilisant la fonction recherche_kmp, programmer une fonction recherche_dictionnaire_kmp : int list list -> int list -> int list qui est telle que, si S est un ensemble fini de motifs codé comme une liste de motifs, et t une chaîne de caractères, recherche_dictionnaire_kmp S t renvoie la liste des occurrences y d'un motif s ∈ S dans t. On n'impose pas d'ordre particulier sur cette liste, et on autorise les doublons.
Quelle est la complexité de cette fonction, en terme du nombre |S| de motifs, de la longueur k maximale d'un motif, de λ et de la longueur n de t ?
◻24 - En s'inspirant de l'automate A_2, de la réponse à la question 22 et de la partie 3, proposer une approche pour calculer efficacement les occurrences d'un ensemble fini S de motifs dans une chaîne de caractères t. On ne demande
ni une formalisation complète de cette approche, ni une implémentation, mais une stratégie générale et les grandes étapes nécessaires à la résolution du problème. On pourra faire l'hypothèse, pour simplifier, que l'ensemble S ne contient pas deux mots qui sont préfixes l'un de l'autre.
Quelles difficultés sont à prévoir dans l'implémentation? Quelle complexité peut-on espérer avec une telle approche, en terme du nombre |S| de motifs, de la longueur k maximale d'un motif, de λ et de la longueur n de t ? Comparer avec la complexité obtenue en réponse à la question précédente.

Fin de l'épreuve

Questions fréquentes

3 questions
Sur quoi porte l'épreuve d'informatique Mines-Ponts MP 2018 ?
Afficher ou masquer la section

Sur quoi porte l'épreuve d'informatique Mines-Ponts MP 2018 ?

Le sujet traite de la recherche de motifs dans un texte : recherche naïve, automates finis déterministes à repli, automate de Knuth-Morris-Pratt et recherche d'un ensemble de motifs, avec des fonctions à écrire en Caml.

Quelles erreurs le jury a-t-il relevées en informatique option MP Mines 2018 ?

Le jury cite l'oubli du recouvrement possible des occurrences, une mauvaise gestion des cas d'arrêt, des calculs de complexité faux ou incohérents avec le code et des justifications théoriques imprécises.

Quels conseils de rédaction pour le code en informatique Mines MP 2018 ?

Le jury demande des codes clairs et indentés, des arguments précis pour les questions théoriques et une complexité réellement cohérente avec la fonction écrite.

Pas de description pour le moment