Version interactive avec LaTeX compilé
ÉCOLE DES PONTS PARISTECH, ISAE-SUPAERO, ENSTA PARIS, TÉLÉCOM PARIS, MINES PARISTECH, MINES SAINT-ÉTIENNE, MINES NANCY, IMT ATLANTIQUE, ENSAE PARIS, CHIMIE PARISTECH.
CONCOURS 2020
ÉPREUVE D'INFORMATIQUE MP
Durée de l'épreuve :
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 :
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 9 pages de texte.
L'énoncé de cette épreuve comporte 9 pages de texte.
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.
Les techniques de compression sans perte permettent d'encoder des données telles que des textes afin de les stocker en occupant un minimum d'espace. Elles s'appuient sur une estimation de la fréquence d'apparition des symboles qui composent le texte. Dans ce problème, nous étudions comment compter efficacement le nombre d'occurrences de chaque symbole dans un texte, que l'on entendra dans la suite comme une suite finie de numéros (par exemple, des numéros Unicode), et comment optimiser le fonctionnement d'un encodeur pour passer d'un texte à une suite de bits.
Préliminaires
L'épreuve est composée d'un problème unique, comportant 33 questions. Après cette section de préliminaires, le problème est divisé en deux parties indépendantes. Pour répondre à une question, un candidat pourra réutiliser le résultat d'une question antérieure, même s'il n'est pas parvenu à établir ce résultat.
Concernant la programmation
Il faudra coder des fonctions à l'aide du langage de programmation OCaml, 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 de la même sous-partie; 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. Si les paramètres d'une fonction à coder sont supposés vérifier certaines hypothèses, il ne sera pas utile de tester si les hypothèses sont bien vérifiées dans le code de la fonction.
Dans tout l'énoncé, 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
) et du point de vue informatique pour celle en romain avec espacement fixe (par exemple n).
On suppose codées les fonctions suivantes :
- list_length, de type 'a list -> int, de complexité en temps linéaire, qui renvoie la longueur d'une liste,
- list_append, de type 'a list -> 'a list -> 'a list, de complexité en temps linéaire en la longueur du premier argument, qui concatène deux listes,
- array_make, de type int -> 'a -> 'a array, de complexité en temps linéaire en la valeur du premier argument, qui crée un tableau d'une longueur spécifiée en premier argument et dont chacune des cases est initialisée à une valeur donnée en second argument,
- array_length, de type 'a array -> int, de complexité en temps constante, qui renvoie la longueur d'un tableau.
On rappelle que a mod b renvoie le reste de la division euclidienne depar .
Dans les calculs de complexité en espace, on considérera qu'un entier occupe une place constante en mémoire quelle que soit sa valeur.
Concernant les objets manipulés et leur type
L'intervalle des entiers compris entre
et
est noté
.
La lettre désigne un alphabet fini ordonné de cardinal
; ses lettres, numérotées dans l'ordre croissant, sont les éléments
La lettre
Par exemple, la norme Unicode est une norme fréquemment utilisée en informatique qui consiste à travailler sur un alphabet de 1114112 symboles. Elle permet d'identifier toute sorte de caractères (lettre de l'alphabet latin, idéogramme chinois, émoticône, symbole de l'alphabet phonétique international, etc.) par un numéro unique entre 0 et 1114111 quelle que soit la plate-forme informatique employée.
Définitions : Un mot sur un alphabet
est une suite finie de lettres de
. Leur ensemble est noté
, le mot vide est noté
. Un mot possède plusieurs caractéristiques : la longueur d'un mot
, notée
, est le nombre de lettres qui composent
; la fréquence d'une lettre
dans un mot
, notée
, est le nombre d'occurrences de
dans
; la valence d'un mot
, notée
, est le nombre de symboles distincts qui composent
.
Un texte est une suite finie d'entiers de l'intervalle . Le mot associé au texte de
entiers
est le mot
.
Un texte est une suite finie d'entiers de l'intervalle
Indication OCaml : On définit les types unicode, texte et la constante globale lambda par les déclarations suivantes :
type unicode = int;;
type texte = unicode list;;
let lambda = 1114112;;
Une fonction de l'alphabet
vers un ensemble
est représentée par un tableau de longueur
de type 'a array où 'a est le type par lequel on représente les éléments de
.
1 Fonction de distribution des lettres d'un texte
Le but de cette partie est de produire une structure de données qui permette de vérifier la présence d'une lettre dans un mot et de stocker les valeurs non nulles de la fonction de distribution des fréquences des lettres dans un mot
définie comme suit
de trois manières différentes et de comparer les complexités en temps et en espace de chaque approche.
1.1 Avec un tableau exhaustif et une liste
1 - On définit une fonction fonction1 par le code suivant
let rec fonction1 (t:texte) =
match t with
| [ ] -> array_make lambda 0
| u::tprime -> let theta = fonction1 tprime in
theta.(u)<-theta.(u)+1;
theta;;
Inférer le type de la fonction fonction1. Expliquer ce que calcule fonction1
et le démontrer par récurrence sur
.
Définition : Soit
un sous-alphabet de l'alphabet
. On appelle répartition du sousalphabet
dans le mot
toute liste constituée de tous les couples
tels que
et
. Cette liste peut être dans un ordre quelconque. La répartition d'un sous-alphabet dans un texte est la répartition de ce sous-alphabet dans le mot associé au texte.
Par exemple, une répartition des lettres du mot acad est la liste .
Indication OCaml : En OCaml, on pourra se servir du type
type repartition (unicode * int) list;;
- Écrire une fonction cree_repartition, de type texte -> repartition qui renvoie une répartition d'un texte en utilisant la fonction fonction1 définie à la question 1 .
- Déterminer la complexité en temps de la fonction cree_repartition en fonction du cardinal
de l'alphabet et d'une caractéristique du texte donné en entrée.
- Déterminer la complexité en espace de la fonction cree_repartition en fonction du cardinal
de l'alphabet.
- Donner sans justification un ordre de grandeur de la taille de la valeur de retour de cree_repartition en fonction d'une caractéristique du texte donné en entrée.
- Comparer les ordres de grandeur obtenus dans les trois questions précédentes quand le texte donné en entrée est le texte d'un courriel de la vie courante rédigé en langue française et
est l'alphabet Unicode.
Par exemple, une répartition des lettres du mot acad est la liste
Indication OCaml : En OCaml, on pourra se servir du type
type repartition
1.2 Avec une table modulaire
Définition : Soient
un mot et
un entier non nul. Pour tout entier
compris entre 0 et
, on note
le sous-alphabet de
défini par
Une table modulaire de comptage d'ordre
du mot
est un tableau de longueur
dont la
-ième case contient une répartition des lettres de
dans
.
Par exemple, avec l'alphabet muni de l'ordre alphabétique et l'entier
, une table modulaire de comptage d'ordre 3 du mot acad est le tableau de trois listes
Par exemple, avec l'alphabet
7 - Écrire une fonction incremente_repartition, de type repartition
unicode -> repartition telle que incremente_repartition
u renvoie la répartition d'un mot qui contient la lettre
une fois de plus qu'un mot de répartition
.
- Écrire une fonction cree_modulaire, dont le type est texte -> int -> repartition array, qui utilise la fonction définie à la question 7 , telle que la valeur de retour de cree_modulaire t m est une table modulaire de comptage d'ordre
du texte
.
Le recours à la fonction fonction1 de la question 1 n'est pas autorisé pour répondre à cette question.
- Écrire une fonction valence, de type repartition array -> int, qui renvoie la valence d'un mot à partir de sa table modulaire de comptage.
- Soient
et
deux entiers non nuls et
des variables aléatoires discrètes à valeurs dans l'intervalle entier
, mutuellement indépendantes et qui suivent la loi de distribution uniforme. Soient encore un entier
fixé dans l'intervalle
et un entier
fixé dans l'intervalle
. Pour tout entier
compris entre 0 et
, on appelle
le cardinal
Le recours à la fonction fonction1 de la question 1 n'est pas autorisé pour répondre à cette question.
Pour tout entier
compris entre 0 et
, calculer l'espérance
11 - Soit
le mot d'un texte
de valence
. En supposant que l'ensemble des
lettres distinctes présentes dans le mot
a été choisi uniformément dans l'ensemble des parties à
éléments de l'alphabet
, montrer que la complexité moyenne en temps de la fonction cree_modulaire t m est
1.3 Avec un tableau creux
Définition : Un tableau creux de comptage du mot
est un quadruplet (
) formé d'un entier
et de trois fonctions
et
tels que
(i) l'entier est la valence du mot
,
(ii) pour toute lettre présente dans le mot
, il existe une lettre
telle que
et
.
(iii) pour toute lettre telle que
, on a
,
(iv) pour toute lettre présente dans le mot
, on a
.
(i) l'entier
(ii) pour toute lettre
(iii) pour toute lettre
(iv) pour toute lettre
Par exemple, avec l'alphabet
, le mot
admet comme tableau de comptage le quadruplet (
)
|
|
|
|
|
|
|
|
||
|
|
|
12 |
|
|
1 |
|
|
9 |
|
|
|
|
|
|
|
|
|
où chaque symbole
représente une valeur particulière mais non significative.
Indication OCaml : En OCaml, on pourra se servir du type
type creux int
int array
unicode array
unicode array;;
On pourra utiliser une fonction make_creux, de type int -> creux qui crée et renvoie un tableau creux de comptage du mot vide en temps constant, aucune hypothèse ne pouvant être faite sur le contenu des trois tableaux constituant la valeur de retour de cette fonction.
- Soit (
) un tableau creux de comptage du mot
. Montrer que pour toute lettre
avec
, la lettre
est une lettre présente dans le mot
.
- Soit (
) un tableau creux de comptage du mot
. Montrer que pour toute lettre
, la lettre
est présente dans le mot
si et seulement si on a
et
.
- Écrire une fonction est_present de type creux -> unicode -> bool telle que la valeur de retour de tableau_creux theta u est vraie si et seulement si la lettre
est une lettre présente dans un mot de tableau creux de comptage
. Justifier la correction et la terminaison de la fonction.
- Écrire une fonction incremente_tableaucreux, de type creux -> unicode -> creux, telle que la valeur de retour de incremente_tableaucreux theta u est un tableau creux de comptage d'un mot qui contient la lettre
une fois de plus qu'un mot de tableau creux de comptage
.
- Écrire une fonction cree_tableaucreux de type texte -> creux qui renvoie le tableau creux de comptage du texte donné en argument.
Le recours à la fonction fonction1 de la question 1 n'est pas autorisé pour répondre à cette question.
- Déterminer la complexité en temps de la fonction cree_tableaucreux.
- Donner sans justification la complexité en espace de la fonction cree_tableaucreux.
- Est-il réaliste d'utiliser cette fonction pour le texte d'un courriel de la vie courante rédigé en langue française encodé avec l'alphabet Unicode lorsqu'on utilise un ordinateur ou un téléphone actuel?
type creux
On pourra utiliser une fonction make_creux, de type int -> creux qui crée et renvoie un tableau creux de comptage du mot vide en temps constant, aucune hypothèse ne pouvant être faite sur le contenu des trois tableaux constituant la valeur de retour de cette fonction.
Le recours à la fonction fonction1 de la question 1 n'est pas autorisé pour répondre à cette question.
2 Un encodeur optimal
2.1 Codes et codages
Définitions : Un code
est une application
Le codage associé à un code
est l'application
Un arbre de code représentant un code
est un arbre binaire, dont l'ensemble des sommets est
, tel que
- pour toute lettre
, l'étiquette du sommet est , - pour toutes lettres
et de l'alphabet , si appartient au sous-arbre gauche de , alors on a dans l'ordre de l'alphabet ; si appartient au sous-arbre droit de , alors on a dans l'ordre de l'alphabet .
Indication OCaml : On adopte les déclarations de type suivantes afin de représenter les mots binaires et les arbres de code en OCaml :
type binaire = bool list;;
type code =
| Nil
| Noeud of unicode * binaire * code * code;;
On note
- Pour un code donné, exprimer la complexité en temps de la fonction encodeur à l'aide de , des profondeurs des sommets de l'arbre de code et de la distribution des fréquences dans le mot donnés en argument
2.2 Arbre de code optimal
On fixe un code
de l'alphabet
ainsi que des poids réels positifs sous la forme d'une application
. La profondeur pondérée d'un arbre de code
représentant le code
est la somme
On dit qu'un arbre de code est optimal si sa profondeur pondérée est la plus petite des profondeurs pondérées des arbres de code représentant un code de l'alphabet
. Pour tous entiers
et
compris entre 0 et
avec
, on note
la restriction du code
à l'alphabet
. On note
la profondeur pondérée d'un arbre de code représentant le code
optimal.
- Pour tout entier
compris entre 0 et
, calculer
.
Pour tous entiers et
compris entre 0 et
vérifiant
, exprimer une relation entre
et les quantités
et
.
- Concevoir et présenter un algorithme qui reçoive en entrée un code
et une distribution de fréquences
sous la forme de tableaux et qui construise un arbre de code optimal en temps
. Il n'est pas exigé d'utiliser la syntaxe OCaml pour répondre à cette question. On décomposera l'algorithme en sous-programmes élémentaires dont on caractérisera les entrées, les sorties ou les effets suffisamment pour que l'établissement d'une preuve de correction de l'algorithme soit facile. Cette preuve de correction n'est pas exigée. On justifiera la complexité en temps.
Pour tous entiers
2.3 Un arbre de code optimal calculé plus rapidement
Pour tous entiers
et
avec
, on appelle
le plus grand entier
inférieur à
tel qu'il existe un arbre optimal pour le code
ayant la lettre
comme racine. On se propose de démontrer, pour tout
compris entre 0 et
, l'encadrement
Soient
et
deux entiers avec
.
- Montrer que, dans un arbre de code qui représente le code
, le sommet qui contient la lettre
ne possède jamais de fils droit.
- Dans cette question, on suppose que le poids
est nul. Soit
un arbre de code optimal pour le
et
l'arbre obtenu en ajoutant à
le sommet
comme fils droit du sommet qui contient la lettre
. Montrer que
est un arbre de code optimal pour le code
.
Dans les trois questions qui suivent, on suppose que les poids restent constants tandis que le poids
est variable.
Dans les trois questions qui suivent, on suppose que les poids
30 - Montrer que l'application
est une application continue et affine par morceaux sur
dont on précisera la pente pour chaque morceau et que, pour tout intervalle ouvert
sur lesquels l'application
est affine, les indices
sont constants lorsque
varie dans
.
Soit
un point de changement de pente de l'application
, soit
un réel tel que l'application
soit affine sur l'intervalle
et soit
un réel tel que l'application
soit affine sur l'intervalle
.
On construit deux suites
et
par récurrence. Chaque suite s'arrête si le terme suivant n'est plus défini. Pour construire la première suite, on choisit
dans l'intervalle
et on pose
Pour construire la seconde suite, on choisit
dans l'intervalle
et on pose
Dans la mesure où les entiers
dépendent de la valeur de
, les deux suites (
) et
ne sont pas forcément égales et ne dépendent que du fait que
appartient à
ou à
.
- Montrer que les suites (
) et (
) sont finies et que, en appelant
l'indice du dernier terme défini de la suite (
) et
l'indice du dernier terme défini de la suite (
), on a
.
On suppose avoir démontré la validité de l'encadrement pour un certain entier
. On suppose que les entiers
et
vérifient
.
- En faisant l'hypothèse
, montrer qu'il existe un indice
tel qu'on ait
et tel que, pour tout entier
compris entre 0 et
, on ait
. En déduire une contradiction en échangeant les descendants du sommet
et du sommet
dans certains arbres.
- Montrer que l'encadrement
est satisfait pour tous entiers
avec
.
On suppose avoir démontré la validité de l'encadrement
Fin de l'épreuve
- Les sujets sont la propriété du GIP CCMP. Ils sont publiés les termes de la licence
Creative Commons Attribution - Pas d'Utilisation Commerciale - Pas de Modification 3.0 France.
Tout autre usage est soumis à une autorisation préalable du Concours commun Mines Ponts.
