PSI* — 2015/2016 Le 02/02/2016.
Informatique — D.S. 2 (2 heures)
Problème A — Recherche de motifs
L’objet du problème est l’étude de deux méthodes de programmation qui répondent à la question
suivante : “étant données deux chaînes de caractères source et motif, est-ce que motif est un sous-
mot de source ?”.
Les définitions et notations introduites ici sont valables dans tout le problème.
Soit Aun alphabet, ensemble de symboles aussi appelés lettres.
A
désigne l’ensemble des séquences finies, éventuellement vides, d’éléments de A, c’est-à-dire l’ensemble
de tous les mots, éventuellement vides, construits sur A.
Pour x,ydans A
,x y désigne le mot issu de la concaténation de xavec y.
Pour un mot zdans A
, l’ensemble sousmots (z)est défini par :
sousmots (z) = {wA
/z
1
A
z
2
A
z=z
1
w z
2
}.
Si wsousmots (z), on dit que west un sous-mot de z;
Pour deux mots w,zdans A
,west un préfixe de zsi et seulement s’il existe yA
tel que z=w y ;
on dit alors que yest un suffixe de z.
Avec ce formalisme, la question étudiée s’écrit : “soient deux mots source et motif dans A
, est-ce
que motif sousmots (source)?”.
Dans tout le problème, les chaînes de caractères sont représentées par des objets Python de type string.
On accède au contenu comme si la chaîne était une liste de caractères, indexée à partir de 0.
Ainsi, si s=’Pythonest une telle chaîne, len(s) renvoie la longueur de la chaîne, ici 6 ; s[0] renvoie
’P’,s[1] renvoie ’y’, etc. La chaîne vide ’’ est l’unique chaîne de longueur 0.
On rappelle que, si sest non vide, s[1:] renvoie la chaîne privée de son premier caractère, ici ’ython’.
I : méthode itérative
La fonction itérative Python suivante permet de répondre à la question.
1
def Recherche_iterative(motif,source):
2
i=0
3
j=0
4
while i<len(motif) and j<len(source):
5
if motif[i]==source[j]:
6
i=i+1
7
j=j+1
8
else:
9
j=j-i+1
10
i=0
11
return i==len(motif)
1) Donner un invariant de boucle permettant de justifier la correction de l’algorithme.
(On pourra introduire l’indice kinitialisé à 0et correspondant à la mise à jour de jà la ligne 9.)
2) Montrer la terminaison de l’algorithme.
II : méthode récursive
Le raisonnement suivant permet de construire une méthode récursive :
le mot motif est un sous-mot de source quand motif est un préfixe de source ou quand motif
est un sous-mot de source privé de son premier caractère ;
le mot motif est un préfixe de source quand motif est vide ou quand il satisfait les deux conditions
suivantes :
le premier caractère de motif est identique au premier caractère de source ;
motif privé de son premier caractère est un préfixe de source privé de son premier caractère.
PSI* — 2015/2016 — Informatique D.S. 2
(2 heures)
Page 2/3
1) Écrire en Python une fonction récursive d’en-tête Est_Prefixe(motif,source), renvoyant True ou
False selon que motif est ou pas un préfixe de source.
2) Écrire en Python une fonction récursive d’en-tête Recherche_recursive(motif,source), renvoyant
True ou False selon que motif est ou pas un sous-mot de source.
Probme B — Produits de matrices
Dans tout le problème, on appellera matrice de type (p, q)tout tableau rectangulaire de nombres réels,
comportant plignes et qcolonnes, pet qétant deux entiers naturels non nuls. Une telle matrice Asera
encore notée (a
i,j
)
0i<p
0j<q
a
i,j
désigne, pour tout couple (i, j)de [[0, p 1]] ×[[0, q 1]], l’élément sit
à l’intersection de la ligne iet de la colonne j.
Pour les programmes en Python, on stockera les matrices dans des tableaux numpy de flottants.
On supposera numpy chargé avec l’alias np par : import numpy as np.
On rappelle qu’alors np.zeros((p,q)) renvoie un tableau de type (p, q)rempli de zéros.
On rappelle enfin que, si Mest un tel tableau numpy,len(M) donne le nombre de lignes de Met len(M[0])
le nombre de colonnes (à savoir le nombre d’éléments de la première ligne !).
On ne se préoccupera pas de la place nécessitée en mémoire par les tableaux manipulés.
Partie I : produit de deux matrices
Soient A= (a
i,j
)
0i<p
0j<q
une matrice de type (p, q)et B= (b
i,j
)
0i<q
0j<r
une matrice de type (q, r),
le nombre de colonnes de Aétant égal au nombre de lignes de B.
La matrice produit de Apar Best la matrice C=AB, de type (p, r), définie par
C= (c
i,j
)
0i<p
0j<r
(i, j)[[0, p 1]] ×[[0, r 1]] c
i,j
=
q1
k=0
a
i,k
b
k,j
.
1) En appliquant cette définition, écrire une fonction Python d’en-tête Prod_mat(A,B) recevant comme
paramètres les tableaux A,Breprésentant A,Bet renvoyant un tableau représentant le produit AB.
2) Calculer, en fonction de p, q, r, le nombre de multiplications de flottants effectuées lors de l’appel
Prod_mat(A,B).
Partie II : produits en chaîne
On considère dorénavant nN
, un (n+ 1)-uplet (d
0
, d
1
, . . . , d
n
)d’entiers naturels non nuls et une
famille (A
1
, . . . , A
n
)de matrices telles que, pour tout ide [[1, n]],A
i
soit de type (d
i1
, d
i
). On peut ainsi
itérer la multiplication matricielle pour calculer le produit (. . . ((A
1
A
2
)A
3
)A
4
...)A
n
, de type (d
0
, d
n
).
On peut montrer – ce que l’on admettra ici – que le choix du parenthésage précisant l’ordre dans
lequel on effectue les multiplications (en respectant les positions respectives de A
1
, . . . , A
n
, de gauche
à droite !) n’a pas d’influence sur le résultat (pseudo-associativité de la multiplication matricielle).
Puisqu’il n’y a pas d’ambiguïté, on peut noter le produit A
1
. . . A
n
sans parenthèses.
Mais, pour effectuer le calcul, il faut bien décider de l’ordre des opérations !
On définit récursivement un produit complètement parenthésé de matrices comme étant, soit une matrice
unique, soit le produit – placé entre parenthèses – de deux produits complètement parenthésés.
Par exemple, pour n= 4, on a 5 produits complètement parenthésés permettant le calcul de A
1
A
2
A
3
A
4
:
(((A
1
A
2
)A
3
)A
4
) = ((A
1
(A
2
A
3
)) A
4
) = ((A
1
A
2
) (A
3
A
4
)) = (A
1
((A
2
A
3
)A
4
)) = (A
1
(A
2
(A
3
A
4
))) .
Dans la suite, on appellera coût d’un calcul de produit matriciel le nombre de multiplications de flottants
nécessaires aux calculs successifs. On admettra que le coût du produit d’une matrice de type (p, q)par
une matrice de type (q, r)est pqr.
PSI* — 2015/2016 — Informatique D.S. 2
(2 heures)
Page 3/3
1) Intérêt d’un bon choix : on considère, dans cette question seulement, le cas particulier suivant ;
n= 4 ; (d
0
, d
1
, d
2
, d
3
, d
4
) = (10,5,100,3,50) .
Déterminer le coût du calcul de A
1
A
2
A
3
A
4
pour chacun des 5 parenthésages ci-dessus. Commenter.
2) Dénombrement des parenthésages possibles : trouver une relation de récurrence vérifiée par les P(n),
nN
, où P(n)désigne le nombre de parenthésages complets possibles pour le calcul de A
1
. . . A
n
(bien entendu, P(1) = P(2) = 1 !). Calculer P(5) et P(6).
On peut montrer, ce qui n’est pas demandé ici, que
nN
P(n)
n→∞
1
π·4
n1
n
3/2
.
Il n’est donc pas question d’envisager un à un tous les parenthésages possibles. . .
3) Structure d’un choix optimal : soient i, j dans [[1, n]], tels que ij; on note Π (i..j)le produit A
i
. . . A
j
(avec bien sûr Π (i..i) = A
i
).
a) Justifier l’existence d’un parenthésage optimal (de coût minimum) pour le calcul de Π (i..j).
b) Montrer que, si un parenthésage optimal pour le calcul de Π (i..j)conduit en fin de calcul à effectuer
le produit de Π (i..k)par Π (k+ 1..j)(où ik < j), alors les parenthésages pour les calculs de
Π (i..k)et de Π (k+ 1..j)sont également optimaux.
c) On note m(i, j)le coût minimum pour le calcul de Π (i..j). Établir :
m(i, j) = 0si i=j
min
ik<j
m(i, k) + m(k+ 1, j) + d
i1
d
k
d
j
si i < j .
4) Programmation récursive
a) Écrire une fonction Python d’en-tête Cout_min(d) recevant comme paramètre une liste Python d
contenant (d
0
, . . . , d
n
)et renvoyant la valeur de m(1, n)(on pourra utiliser une fonction auxiliaire
récursive d’en-tête m(i,j) basée sur le résultat de la question précédente).
b) Montrer que le nombre M(n)de multiplications d’entiers effectuées lors de l’appel Cout_min(d) est
supérieur ou égal à 2
n1
, pour tout n2. Commenter.
5) Programmation dynamique : l’inefficacité de la fonction précédente tient au fait qu’elle calcule plusieurs
fois les mêmes valeurs. D’où l’idée de mémoriser dans un tableau auxiliaire les valeurs de m(i, j), pour
1ijnau fur et à mesure de leur obtention.
a) Écrire une fonction itérative, d’en-tête Tableau_m(d), renvoyant le tableau mainsi associé à la liste
dcontenant (d
0
, . . . , d
n
),(on initialisera mà zéro, puis on reprendra le résultat du 3)c) et l’on pourra
raisonner sur la valeur de jipour remplir la partie utile de m).
b) Calculer le nombre de multiplications d’entiers nécessaires à l’obtention de m(1, n)par cette mé-
thode. Commenter.
c) Modifier la fonction du a) pour renvoyer – en même temps que m– un second tableau kop, de
sorte que kop[i,j] contienne une valeur optimale ktelle que celle considérée au 3)b).
d) Écrire enfin une fonction d’en-tête Parenthesage(kop) recevant comme paramètre le tableau kop
(préalablement rempli comme au c) !) et renvoyant un parenthésage complet optimal sous la forme
d’une chaîne de caractères, telle que :
((A[1](A[2]A[3]))A[4])
(on rappelle que l’opérateur +réalise en Python la concaténation des chaînes de caractères et que le
transtypage str(x) convertit la valeur numérique xen chaîne de caractères).
1 / 3 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !