Mines Informatique 2 MPI 2024Sujet et rapport du jury
1,0(1 vote)
Téléchargements
- Corrigé : pas encore disponible
L'épreuve en chiffres
Moyenne 10,97 / 20 · écart-type 3,95 · 839 présents · où vous situez-vous ?Afficher ou masquer la section
L'épreuve en chiffres
Moyenne 10,97 / 20 · écart-type 3,95 · 839 présents · où vous situez-vous ?
- Moyenne
- 10,97/ 20
- Écart-type
- 3,95
- Présents
- 839
- Coefficient
- 4
- Durée
- 4 h
Votre note sur 20 à ce sujet, en conditions de concours.
Source : document officiel du concours, épreuve du 15 mai 2024. Notes publiées par le concours (après harmonisation le cas échéant). Courbe : estimation par une loi normale.
Ces sujets peuvent vous intéresser
Pas encore de corrigé pour ce sujet : voici des sujets proches corrigés.
Lecture du sujet en ligne
L'énoncé complet, avec les formules et les figures, sans ouvrir le PDF.Afficher ou masquer la section
Lecture du sujet en ligne
L'énoncé complet, avec les formules et les figures, sans ouvrir le PDF.
ÉCOLE DES PONTS PARISTECH, ISAE-SUPAERO, ENSTA PARIS, TÉLÉCOM PARIS, MINES PARIS, MINES SAINT-ÉTIENNE, MINES NANCY, IMT ATLANTIQUE, ENSAE PARIS, CHIMIE PARISTECH - PSL.
CONCOURS 2024
DEUXIÈME ÉPREUVE D'INFORMATIQUE
Durée de l'épreuve : 4 heures
L'usage de la calculatrice et de tout dispositif électronique est interdit.
Cette épreuve concerne uniquement las candidats de la filière MPI.
L'énoncé de cette épreuve comporte 12 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.
Préliminaires
L'épreuve est composée d'un problème unique, comportant 36 questions. Le problème est divisé en quatre sections. Dans la première section (page 1), nous introduisons une forme paresseuse de listes, les flots de données, et construisons quelques fonctions de base utiles tout au long du sujet. Dans la deuxième section (page 4), nous nous intéressons à un algorithme de détermination à la volée du cardinal d'un flot, dont l'inspiration est probabiliste. Dans la troisième section (page 7), nous nous appuyons sur des raisonnements de logique pour analyser le chiffrement par flot. Dans la quatrième section (page 9), nous traitons quelques questions de combinatoire énumérative à l'aide d'une grammaire ou simplement d'un procédé manuel de dérécursification.
Les sections 2,3 et 4 peuvent être vues comme des exercices indépendants qui ne dépendent que de la première section.
Dans tout l'énoncé, un même identificateur écrit dans deux polices de caractères différentes désigne 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).
Des rappels portant sur des extraits du manuel de documentation de OCaml et sur les règles de la déduction naturelle sont fournis en annexe.
Travail attendu
Pour répondre à une question, il est permis de réutiliser le résultat d'une question antérieure, même sans avoir réussi à établir ce résultat.
Il faudra coder des fonctions à l'aide du langage de programmation OCaml exclusivement, en reprenant l'en-tête de fonctions fourni par le sujet, sans s'obliger à recopier la déclaration des types. Il est permis d'utiliser la totalité du langage OCaml mais il est recommandé de s'en tenir aux fonctions les plus courantes afin de rester compréhensible. Quand l'énoncé demande de coder une fonction, sauf demande explicite, il n'est pas nécessaire de justifier que celle-ci est correcte ou de tester que des préconditions sont satisfaites.
Le barème tient compte de la clarté et de la concision des programmes : nous recommandons de choisir des noms de variables intelligibles ou encore de structurer de longs codes par des blocs ou par des fonctions auxiliaires dont on décrit le rôle.
1. Flots de données
1.1. Motivation
En langage OCaml, le type natif 'a list est défini comme point fixe de l'équation
type 'a list = [] | (::) of 'a * 'a list
Ce type permet de définir des listes finies tout comme certaines listes infinies, ainsi que l'expose l'exemple suivant, qui est parfaitement licite :
let list_finite = [ 1; 2; 3 ] (* liste finie a 3 elements *)
let rec list_ones = 1 :: list_ones (* liste infinie toute a 1 *)
Les termes de la suite de Fibonacci
(F_n)_(n ∈ ℕ) obéissent aux relations :
Nous nous enhardissons à définir la liste des termes de la suite de Fibonacci
(F_n)_(n ∈ ℕ) en écrivant la déclaration récursive suivante :
let list_fibo : int list =
let rec list_fibo_with_internal_state (a:int) (b:int) : int list =
a :: (list_fibo_with_internal_state b (a+b))
in
list_fibo_with_internal_state 0 1
Cependant, à l'évaluation de cette expression par un interpréteur (ou toplevel ou encore
REPL ), le système renvoie le message d'erreur suivant :
9. Stack overflow during evaluation (looping recursion?).
2 - Traduire en français le mot stack. Expliquer le message d'erreur en présentant le déroulement des premières étapes de création de la variable list_fibo par l'interpéteur OCaml.
9. Stack overflow during evaluation (looping recursion?).
2 - Traduire en français le mot stack. Expliquer le message d'erreur en présentant le déroulement des premières étapes de création de la variable list_fibo par l'interpéteur OCaml.
Nous recopions le code fautif dans un fichier fibo.ml et — horresco referens — nous nous apprêtons à appeler successivement depuis un terminal les commandes ocamlopt fibo.ml -o fibo pour la compilation de la source vers un exécutable puis ./fibo pour l'exécution.
3 - Dire si l'une des deux étapes, compilation ou exécution, renvoie une erreur et, le cas échéant, préciser laquelle des étapes.
3 - Dire si l'une des deux étapes, compilation ou exécution, renvoie une erreur et, le cas échéant, préciser laquelle des étapes.
1.2. Définition des flots de données
Définition: Un flot de données est une suite, finie ou infinie, d'éléments de même type.
Indication OCaml : Afin de représenter les flots de données, nous fixons le type suivant :
Indication OCaml : Afin de représenter les flots de données, nous fixons le type suivant :
type 'a stream = Nil | Cons of 'a * (unit -> 'a stream)
Le constructeur Nil qualifie le flot vide. Définir la suite infinie constante égale à 1 en tant que int stream demeure possible. Nous parvenons de surcroît à déclarer la suite de Fibonacci en tant que int stream sans encombre. En voici le code :
let rec (ones : int stream) = Cons (1, fun () -> ones)
let fibo : int stream =
let rec fibo_with_internal_state a b =
Cons (a, fun () -> fibo_with_internal_state b (a+b))
in
fibo_with_internal_state 0 1
1.3. Quelques manipulations de base des flots de données
12 - Écrire une fonction zip (w : 'a stream array) : 'a array stream qui transforme un tableau de flots de données
w = [(u_n)_(n ∈ ℕ), (v_n)_(n ∈ ℕ), …] en un flot de données tabulaire
([u_n, v_n, …])_(n ∈ ℕ) . Si l'un des flots de
w est vide à partir d'un certain rang, la valeur de retour est aussi vide à partir de ce rang.
Par exemple, zip [lones; range 0100 ; fibol] désigne le flot fini des tableaux d'entiers de longueur trois([1, k, F_k])_(0 ⩽ k < 100) .
◻13 - Écrire une fonction intertwin (u : 'a stream) (v : 'a stream) : 'a stream dont la valeur de retour est le flot obtenu en prenant alternativement des éléments du flot
u et du flot
v , en cessant de prendre des éléments d'un flot une fois que celui-ci est vide. Par exemple, intertwin ones fibo désigne le flot d'entiers
1, F_0, 1, F_1, 1, F_2, 1, F_3 , etc., tandis que intertwin (range 02 ) fibo désigne le flot d'entiers
0, F_0, 1, F_1, F_2, F_3, F_4 , etc.
Par exemple, zip [lones; range 0100 ; fibol] désigne le flot fini des tableaux d'entiers de longueur trois
Nous nous proposons d'écrire une fonction product (u1 : 'a stream) (u2 : 'b stream) : ('
a∗ 'b) stream dont la valeur de retour est un flot qui énumère tous les couples tirés du flot
u_1 et du flot
u_2 dans un ordre non spécifié. Nous écrivons le code suivant :
let rec product_wrong u1 u2 =
match u1,u2 with
| _, Nil | Nil, _ -> Nil
| Cons(hd1, tl_begetter1), Cons(hd2, tl_begetter2) ->
let part1 = product_wrong (tl_begetter1 ()) u2 in
let part2 = map (fun y -> (hd1, y)) (tl_begetter2 ()) in
Cons((hd1, hd2), fun () -> intertwin part1 part2)
14 - Montrer que l'appel product_wrong u1 u2 ne se termine pas toujours mais qu'il suffit de déplacer quelques mots au sein du code pour le rendre correct.
1.4. Filtre d'un flot
16 - Énoncer le théorème de Turing relatif au problème de l'arrêt.
Pour répondre à la question 17, on pourra admettre sans justification l'existence d'une machine universelle à chronomètre, c'est-à-dire une fonction OCaml run : string -> int -> int qui se termine toujours et telle que:
Pour répondre à la question 17, on pourra admettre sans justification l'existence d'une machine universelle à chronomètre, c'est-à-dire une fonction OCaml run : string -> int -> int qui se termine toujours et telle que:
- si la chaîne de caractères
x est le code source d'une expression OCaml et si l'exécution du codex se termine sans erreur en moins den étapes élémentaires de calcul, alors run x n a pour valeur de retour l'entier 0 ; - sinon, run x n a pour valeur de retour l'entier 1.
17 - Décrire la construction ou bien réfuter l'existence d'une fonction OCaml filter (f : 'a -> bool) (u : 'a stream) -> 'a stream dont la valeur de retour est formé des éléments du flotu satisfaisant le prédicatf , l'ordre des éléments deu étant préservé. Par exemple, let is_negativex = x < 0 in filter is_negative ones vaut Nil.
2. Estimation du cardinal d'un flot de données
Définition : Nous appelons cardinal d'un flot de données le cardinal de l'ensemble des valeurs distinctes appartenant à ce flot. Ce cardinal peut être fini même si le flot est infini.
Dans cette section, nous cherchons à estimer le cardinal
s d'un flot de chaînes de caractères
(u_n)_(n ∈ ℕ) de cardinal fini avec peu de mémoire et en supposant que
0 ⩽ s < 2^(62) .
Définition : Nous appelons premier bit activé d'un entier
h ∈ [ [0, 2^(62) − 1] ] , et notons
ρ(h) , le plus grand entier
i tel que les
i − 1 bits les plus à droite dans la représentation binaire de
h sont tous nuls. Par convention, nous fixons
ρ(0) = 63 .
Par exemple, nous avonsρ(1) = ρ(00001^–_((2))) = 1, ρ(6) = ρ(00110^–_((2))) = 2 , ou encore
ρ(8) = ρ(01000^–_((2))) = 4 .
Par exemple, nous avons
18 - Écrire une fonction OCaml ffs (h:int) : int dont la valeur de retour est le premier bit activé
ρ(h) de l'entier
h . En anglais, ffs désigne find first set.
Indication OCaml : Nous disposons d'une fonction de hachage
H à valeur dans l'intervalle entier
[ [0, 2^(62) − 1] ] que nous réalisons à l'aide de String.hash : string -> int.
Soit
s un entier naturel non nul. Nous tirons
s chaînes de caractères aléatoirement et notons
(H_j)_(1 ⩽ j ⩽ s) leur haché par la fonction de hachage
H . Pour tout indice
j compris entre 1 et
s , nous supposons que chaque variable aléatoire
H_j est distribuée selon une loi uniforme dans l'intervalle entier
[ [0, 2^(62) − 1] ] . Nous posons
Une analyse mathématique, que nous admettons, montre alors que les variables aléatoires
ρ(H_j) sont tirées selon des lois géométriques et que la variable
R est proche de
log_2 s , si bien que la quantité
2^R est une bonne approximation de
s .
Soit
(u_n)_(n ∈ ℕ) un flot de chaînes de caractères de cardinal
s , l'entier
s étant inconnu. Nous proposons deux algorithmes qui estiment le cardinal
s par l'observation des
t premiers termes du flot, en supposant que les
s valeurs distinctes apparaissent parmi les
t premiers termes.
- Algorithme naïf : garnir à la volée une table de hachage avec les chaînes
(u_n)_(n ⩽ t) , puis renvoyer le compte des éléments présents dans la table. En voici le code :
let cardinality_nf (t:int) (u: string stream) : float =
let htb = Hashtbl.create 1 in
iter (fun x-> Hashtbl.add htb x ()) t u;
float_of_int (Hashtbl.length htb)
où l'on réutilise la fonction iter de la question 10 et des fonctions du module Hashtbl rappelées en annexe.
- Algorithme de Flajolet-Martin, inspiré par les observations ci-dessus. En voici le code :
let cardinality_fm (t:int) (u: string stream) : float =
let r = ref 0 in
let update x = r:= max !r (ffs (String.hash x)) in
iter update t u;
float_of_int (1 lsl !r) (* calcule 2^r en flottant *)
19 - Comparer la complexité en espace des algorithmes cardinality_nf et cardinality_fm.
Nous rappelons que la moyenne harmonique dem réels
z_1, …, z_m strictement positifs se calcule par la formule
Nous rappelons que la moyenne harmonique de
La suite de chaînes de caractères
(u_n)_(n ∈ ℕ) et l'entier
m étant fixés, pour tout entier
i compris entre 0 et
m − 1 et pour tout entier naturel
t , nous notons
U_t^i l'ensemble de chaînes de caractères
Afin d'obtenir une estimation de cardinal du flot
(u_n)_(n ∈ ℕ) plus robuste et de diminuer la variabilité associée à l'unicité du point de mesure, nous proposons une amélioration de la fonction cardinality_fm qui utilise un effet de moyenne.
- Algorithme HyperLogLog : Nous divisons les premiers termes du flot
(u_n)_(n ∈ ℕ) enm sous-flots disjointsU_t^0, …, U_t^(m − 1) . Nous estimons le cardinal de chaque sous-flot comme le fait l'algorithme de Flajolet-Martin et obtenons des valeurs(2^(r_i))_(0 ⩽ i ⩽ m − 1) , où
qui, intuitivement, forment chacune une estimation grossière du quotient
s/m . Nous calculons la moyenne harmonique
Harm(2^(r_0), …, 2^(r_(m − 1))) , qui, intuitivement, constitue une estimation robuste du quotient
s/m .
Une analyse mathématique poussée confirme notre intuition. Il s'avère que le cardinals est très bien approché par la quantité
Une analyse mathématique poussée confirme notre intuition. Il s'avère que le cardinal
où
α_m est une constante, valant ici
α_m = (m∫_0^∞(log_2((2 + u)/(1 + u)))^m du)^(− 1) . On utilisera l'équation (%) sans la démontrer durant l'épreuve.
Indication OCaml : Nous fixons les constantes globales pour le reste de la section 2.
let m = 16
let alpha16 = 0.6731 (* calcul numerique admis *)
L'algorithme HyperLogLog se présente alors sous la forme
let cardinality_hll (t:int) (u : string stream) : float =
let r = Array.make m 0 in
iter (hll_update r) t u;
mean_estimate r
où les fonctions hll_update et mean_estimate seront écrites aux questions 21 et 22.
21 - Écrire une fonction OCaml hll_update (r : int array) (x : string) : unit ainsi spécifiée :
Précondition : Il existe un flot de chaînes de caractères(u_n)_(n ∈ ℕ) , des entiers
m et
t tels que
x = u_t et le tableau
r contient
(max_(u ∈ U_(t − 1)^i)ρ(H(u)/m))_(0 ⩽ i ⩽ m − 1) .
Postcondition : Le tableaur contient
(max_(u ∈ U_t^i)ρ(H(u)/m))_(0 ⩽ i ⩽ m − 1) .
◻22 - Écrire une fonction OCaml mean_estimate (
r : int array) : float ainsi spécifiée Précondition : Le tableau
r contient les valeurs
(r_i)_(0 ⩽ i ⩽ m − 1) avec
21 - Écrire une fonction OCaml hll_update (r : int array) (x : string) : unit ainsi spécifiée :
Précondition : Il existe un flot de chaînes de caractères
Postcondition : Le tableau
pour un certain flot de chaînes de caractères
(u_n)_(n ∈ ℕ) et un certain entier
m .
Valeur de retour : Estimation du cardinal du flot(u_n)_(n ∈ ℕ) d'après l'équation (%).
Nous nous plaçons finalement dans la situation où deux flots de chaînes de caractères(u_n)_(n ∈ ℕ) et
(v_n)_(n ∈ ℕ) nous parviennent simultanément. Nous chargeons deux fils d'exécution auxiliaires distincts de construire indéfiniment leurs tableaux respectifs de maxima de bit activés tandis que le fil d'exécution principal déclenche toute les cinq secondes l'affichage du cardinal. Voici une ébauche de code :
Valeur de retour : Estimation du cardinal du flot
Nous nous plaçons finalement dans la situation où deux flots de chaînes de caractères
let cardinality_threadedhll u v =
let r_u = Array.make m 0 in
let f1 () = iter (hll_update r_u) Int.max_int u in
let _ = Thread.create f1 () in
let r_v = Array.make m 0 in
let f2 () = iter (hll_update r_v) Int.max_int v in
let _ = Thread.create f2 () in
while true do
let r = Array.init m (fun i -> max r_u.(i) r_v.(i)) in
print_float (mean_estimate r);
Thread.delay 5. (* mise en pause de 5 secondes *)
done
dans laquelle Int.max_int représente le plus grand entier représentable.
◻23 - Identifier les portions de code sujettes à des courses critiques. Indiquer un mécanisme qui permet de corriger l'ébauche de code.
3. Chiffrement par flot de booléens
Dans cette partie, nous nous appuyons sur des variables booléennes
(x_j)_(j ⩽ k) et sur les constantes
T (tautologie) et
⊥ (antilogie) pour former des formules, à l'aide des trois connecteurs
¬ (négation),
∧ (conjonction) et
∨ (disjonction). Pour toutes formules de logique
φ et
ψ , nous notons
X(φ, ψ) la nouvelle formule
Les règles d'inférence de la déduction naturelle sont rappelées dans l'annexe B .
24 - Soitφ une formule. Construire des arbres de preuve qui démontrent les séquents
24 - Soit
à partir des règles d'inférence de la déduction naturelle.
25 - Soit
ψ une formule. Construire des arbres de preuve qui démontrent les séquents
Nous admettons que, pour toutes formules de logique
φ et
ψ , il existe des arbres de preuve qui démontrent les séquents
X(X(φ, φ), ψ)⊢ψ et
ψ⊢X(X(φ, φ), ψ) .
Définitions : Nous notons
𝔹 = {V, F} l'ensemble des valeurs de vérité. Nous introduisons la fonction booléenne
⊕ : 𝔹 × 𝔹 → 𝔹 telle que
⊕ (x, y) est l'évaluation de la formule
X(x, y) .
◻26 - Justifier que les fonctions booléennes
𝔹 × 𝔹 → 𝔹 suivantes
(x, y) ↦ ⊕ (⊕ (x, x), y) et
(x, y) ↦ y sont égales.
Nous admettons, plus généralement, que la fonction booléenne
⊕ : 𝔹 × 𝔹 → 𝔹 est commutative et associative. Pour tout entier
m ⩾ 1 et pour tous booléens
(b_i)_(1 ⩽ i ⩽ m) , la somme
⨁_(i = 1)^m b_i est définie comme
⊕ (⋯ ⊕ (⊕ (b_1, b_2), b_3), …, b_m) mais peut être calculée dans n'importe quel ordre. La somme vide vaut, par convention, la valeur de vérité
F .
Définition : Nous appelons registre à décalage à rétroaction linéaire (ou encore LFSR d'après l'anglais linear feedback shift register) de longueur
m , de germe
(b_i)_(0 ⩽ i < m) ∈ 𝔹^m et de connexion
C ⊆ [ [0, m − 1] ] , le flot de booléens
(b_n)_(n ∈ ℕ) défini par la relation de récurrence
Indication OCaml : Nous utilisons le type bool array pour représenter le germe et le type int list pour représenter la connexion d'un LFSR. La longueur s'obtient avec Array. length.
◻27 - Écrire une fonction OCaml lfsr (g:bool array) (c:int list) : bool stream dont la valeur de retour est le flot de données constitué par le LFSR de germe
g et de connexion
c .
Indication OCaml : Nous représentons les formules de logique à l'aide du type
type formula = | Var of int
| Not of formula
| And of formula * formula
| Or of formula * formula
Pour toute formule de logique
φ définie à partir des variables booléennes
(x_j)_(1 ⩽ j ⩽ k) et pour tout
k -upplet de valeurs de vérité
b = (b^1, …, b^k) ∈ 𝔹^k , nous notons
φ(b^1, …, b^k) l'évaluation de la formule
φ en
b .
28 - Écrire une fonction OCaml logical_map (phi : formula) (w : bool stream array) : bool stream ainsi spécifiée :
Précondition : La formuleφ ne dépend que des variables
x_1, …, x_k . Le tableau
w est de longueur
k . Nous notons
w = [(b_n^((1)))_(n ∈ ℕ), …, (b_n^((k)))_(n ∈ ℕ)] son contenu.
Valeur de retour : Flot des évaluations booléennes(φ(b_n^((1)), …, b_n^((k))))_(n ∈ ℕ) .
28 - Écrire une fonction OCaml logical_map (phi : formula) (w : bool stream array) : bool stream ainsi spécifiée :
Précondition : La formule
Valeur de retour : Flot des évaluations booléennes
Dans la question 29, deux personnages, Alice et Bob, se sont accordés, lors de leur tout premier tête-à-tête et à l'abri de toute écoute par un tiers, au sujet de
k germes et de
k connexions de LFSR ainsi qu'au sujet d'une formule de logique
ψ_0(x_1, …, x_k) . Nous notons
(b_n^((1)))_(n ∈ ℕ), …, (b_n^((k)))_(n ∈ ℕ) les
k flots de données booléens associés aux LFRS. À présent, Alice souhaite communiquer à Bob la suite de bits
c = (c_n)_(n ∈ ℕ) via un canal public. Elle transmet à Bob la suite des évaluations
(X(ψ_0(b_n^((1)), …, b_n^((1))), c_n))_(n ∈ ℕ) .
◻29 - Dire si Bob peut toujours parvenir à reconstituer le flot
c = (c_n)_(n ∈ ℕ) et, le cas échéant, expliquer comment.
4. Énumération d'objets combinatoires
4.1. Flot des mots de Dyck
Soit
Σ l'alphabet binaire
Σ = {a, b} . Nous nous intéressons à la constante OCaml dyck définie par le code suivant
let rec dyck =
let f (x,y) = "a" ^ x ^ "b" ~ y in
Cons("", fun () -> map f (product dyck dyck))
où la fonction product a été introduite à la question 14. Nous notons
D ⊆ Σ^∗ le langage constitué des mots appartenant au flot de données dyck.
◻30 - Exhiber une grammaire non contextuelle
G telle que le langage
L(G) engendré par la grammaire
G coïncide avec le langage
D .
31 - Énoncer une propriété de la grammaireG de la question 30 qui permet d'établir que le flot de chaînes de caractères dyck n'énumère jamais deux fois le même mot. La démontrer.
31 - Énoncer une propriété de la grammaire
4.2. Flot des permutations d'un tableau
Nous partageons une variante d'un algorithme dû à B. R. Heap sous la forme du pseudocode suivant. Dans ce pseudo-code, les positions de tableau sont numérotées à partir de l'indice 0 .
Algorithme 1 : Algorithme de B. R. Heap
Entrées : Entier $k$, tableau $t$ de longueur $\geqslant k$.
Effet : Effectue des échanges en place dans le tableau $t$ et des
affichages de $t$.
Sortie : Aucune valeur de retour.
si $k=1$ alors
Afficher le tableau $t$.
sinon
pour $i=0$ à $k-1$ (inclus) faire
Exécuter Heap $((k-1), t)$.
si $k$ est pair alors
Échanger $t[i]$ et $t[k-1]$
sinon
Échanger $t[0]$ et $t[k-1]$
32 - Soient
k un entier et
t un tableau de longueur supérieure à
k . Dénombrer le nombre d'appels
A(k) à la fonction «afficher» lorsque l'on exécute Heap
(k, t) .
33 - Soientk un entier et
t un tableau de longueur supérieure à
k . Démontrer, pour tout entier naturel non nul
k , la proposition
P(k) suivante:
33 - Soient
Après l'exécution de Heap
(k, t) , si
k est un entier impair, alors le tableau
t est inchangé; en revanche, si
k est un entier pair, alors les
k premiers coefficients du tableau
t ont subi une permutation circulaire vers la droite : autrement dit, le nouvel état du tableau est
34 - Soient
k un entier et
t un tableau de longueur supérieure à
k . Démontrer que l'exécution de
Heap(k, t) affiche, pour toute permutation des
k premiers alvéoles du tableau
t , le tableau dans lequel les
k premiers alvéoles ont été permutés et dans lequel les derniers alvéoles ont été laissés inchangés.
35 - Écrire une fonction OCaml pivot (k:int) (i:int) (t:'a array) : unit dont l'effet est d'appliquer au tableaut les opérations des lignes 6 à 9 de l'algorithme 1 .
36 - Écrire une fonction OCaml permstream_of_array (t :'a array) : 'a array stream dont la valeur de retour est un flot de données fini constitué de toutes les permutations du tableau
t énumérées dans l'ordre d'affichage de l'algorithme de Heap et qui utilise efficacement la mémoire.
35 - Écrire une fonction OCaml pivot (k:int) (i:int) (t:'a array) : unit dont l'effet est d'appliquer au tableau
36 - Écrire une fonction OCaml permstream_of_array (
A. Annexe : rappels de programmation
(D'après https://v2.ocaml.org/api/index.html)
Opérations générales : Le module Stdlib, chargé par défaut, offre les fonctions suivantes :
- max : 'a -> 'a -> 'a
Return the greater of the two arguments. The result is unspecified if one of the arguments contains the float value nan.
- float_of_int : int -> float
Convert an integer to floating-point.
- (lsl) : int -> int -> int
n lsl m shiftsn to the left bym bits.
Opérations sur les tableaux : Le module Array offre les fonctions suivantes :
- make : int -> 'a -> 'a array
make n x returns a fresh array of lengthn , initialized withx . - init : int -> (int -> 'a) -> 'a array
init n f returns a fresh array of lengthn , with element numberi initialized to the result off(i) . - exists : ('a -> bool) -> 'a array -> bool
exists f [|a1; ...; an |] checks if at least one element of the array satisfies the predicate. That is, it returns (f a1) || (f a2) || ... || (f an).
Opérations sur les tables de hachage : Le module Hashtbl offre les fonctions suivantes :
- create : int -> ('a, 'b)
t
Hashtbl. create n creates a new, empty hash table, with initial size
n .
- add : ('a, 'b) t -> 'a -> 'b -> unit
Hashtbl. add
tkd adds a binding of key
k to data
d in table
t .
- length : ('a, 'b) t -> int
Hashtbl.length tt returns the number of bindings in
t . It takes constant time. Multiple bindings are counted once each.
Opérations sur les fils d'exécution : Le module Thread offre les fonctions suivantes :
- create : ('a -> 'b) -> 'a -> t
Thread. create f x creates a new thread of control, in which the function application
f(x) is executed concurrently with the other threads of the domain. The application of Thread.create returns the handle of the newly created thread.
- delay : float -> unit
delay d suspends the execution of the calling thread ford seconds. The other program threads continue to run during this time.
Opérations sur les verrous : Le module Mutex offre les fonctions suivantes :
- create : unit -> t
Return a new mutex.
- lock : t -> unit
Lock the given mutex. Only one thread can have the mutex locked at any time. A thread that attempts to lock a mutex already locked by another thread will suspend until the other thread unlocks the mutex.
- unlock : t -> unit
Unlock the given mutex. Other threads suspended trying to lock the mutex will restart. The mutex must have been previously locked by the thread that calls Mutex.unlock.
B. Annexe : règles de la déduction naturelle
Dans les tableaux suivants, la lettre
Δ désigne un ensemble de formules de logique; les lettres
A, B et
C désignent des formules de logique.
| Axiome |
|
|
| Introduction | Élimination | |
| T |
|
|
|
|
|
|
|
|
|
|
| V |
|
|
|
|
|
|
Fin de l'épreuve
- Les sujets sont la propriété du GIP CCMP. Ils sont publiés sous 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.
Pas de description pour le moment
