Correction du DS n°2 Python

Transcription

Correction du DS n°2 Python
PSI 2014/2015.
Correction DS n◦2 d’informatique
Sujet 0 CCP d’informatique
Il s’agit d’un sujet 0, donc d’une ébauche de ce qui pourra tomber au concours.
Au niveau de l’algorithmique, je trouve le sujet très pauvre : uniquement des boucles for,
très rarement imbriqués. Aucune boucle while.
Les notions abordés ne font appel qu’au programme de première année : pas de récursivité
ni d’algorithme de tri, les structures de données sont uniquement des tableaux, à 1 ou
deux dimensions (matrices), il n’ y a pas de structure de piles.
Les algorithmes au programme sont uniquement des algorithmes de première année :
la méthode d’Euler, l’algorithme de Gauss, la recherche d’un maximum dans un tableau.
La compréhension du sujet, toutefois intéressant, prend du temps et n’apporte pas grand
chose à l’intérêt informatique des problèmes (il s’agit d’un sujet d’informatique, rappelonsle).
Q1. Au vu de la fonction geometrie, la fonction main() sera
def main ():
[L,n,m,k,c] = geometrie(0)
[T , omega , fmaw , dt , nbpts ] = p a r a m e t r e s _ c a l c u l ()
sauve (L ,n ,m ,k ,c ,T , omega , fmax , dt , nbpts )
[M ,K , C ]= c r e a t i o n _ o p e r a t e u r (n ,m ,k , c )
X = calcul (n ,M ,K , C )
p o s t t r a i t e m e n t (X ,L ,n , c )
Q2. En suivant les valeur numérique de l’enoncé, on a au début L_local=0.5 , n_local=3
et m_local=[].
On exécute ensuite la boucle for i in range(3): et on aura m_local=[0.1, 0.2, 0.1].
On a ensuite k_local=[ ], puis c_local=[ ] et on rexecute une boucle for i in
range(3):.
Ce qui donne k_local=[20000,20000,1000] , puis c_local=[1000,10,10]
Q3. Pour les anglophobe, open(nom_fic,r) ouvre le fichier nom_fic en mode lecture.
Ensuite chaque appel à f.readline() extrait une ligne du fichier (sous forme d’une
chaîne de caractères, avec le caractère \n en fin de ligne) puis passe à la ligne suivante.
def l i r e _ f i c h i e r ( n o m _ f i c ):
res =[]
f = open ( nom_fic , r )
L = float ( f . r e a d l i n e ()[: -1])
n = int ( f . r e a d l i n e ()[: -1])
[m ,k , c ]=[[] ,[] ,[]]
for liste in [m ,k , c ]:
for i in range ( n ):
liste . append ( float ( f . r e a d l i n e ()[: -1]))
return [l ,n ,m ,k , c ]
1
Q4. r e q u e t e 1= ' SELECT nom , date, id FROM CALCUL '
Q5. L’énoncé est flou. Il ne dit pas si le tableau resultat, contient des chaînes de caractères (qu’il faut donc convertir en entier ou flottant), ou s’il contient déjà des entiers
et des flottants. Je considèrerait qu’on est dans le second cas.
Une fois qu’on sait qu’on connaît le numéro de calcul, il n’y a plus qu’à récupérer
les informations dans la base de données.
En notant num l’identifiant du calcul, pour récupérer L et n, la requête est :
SELECT L , n
FROM CALCUL
WHERE id = num
pour récupérer le tableau des masse :
SELECT masse
FROM POUTRE WHERE i d _ c a l c u l = num
et pour récupérer les valeurs de k et c
SELECT raideur , a m o r t i s s e m e n t
FROM L I A I S O N WHERE i d _ c a l c u l = num
La zone à compléter est donc la suivante :
[ L_local , n _ l o c a l ] = i n t e r r o g e _ b d d ( ' SELECT L , n FROM CALCUL WHERE id ='+s t r ( i d _ c a l c u l ) )
m_local = i n t e r r o g e _ b d d ( ' SELECT masse FROM POUTRE WHERE id =' + s t r ( i d _ c a l c u l ) )
r e q = i n t e r r o g e _ b d d ( ' SELECT r a i d e u r ,
a m o r ti s s em en t FROM LIAISON WHERE id =
+ str ( id_calcul ))
k _ l o c a l=r e q [ : , 0 ]
c _ l o c a l=r e q [ : , 1 ]
en supposant que interroge_bdd renvoie des tableaux numpy, ou plus simplement :
L _ l o ca l
n_local
m_local
k_local
c_local
i n t e r r o g e _ b d d ( ' SELECT L FROM CALCUL WHERE id ='+s t r ( i d _ c a l c u l ) )
= i n t e r r o g e _ b d d ( ' SELECT n FROM CALCUL WHERE id ='+s t r ( i d _ c a l c u l ) )
= i n t e r r o g e _ b d d ( ' SELECT masse FROM POUTRE WHERE i d _ c a l c u l =' + s t r ( i d _ c a l c u l ) )
= i n t e r r o g e _ b d d ( ' SELECT r a i d e u r FROM LIAISON WHERE i d _ c a l c u l =
+ str ( id_calcul ))
= i n t e r r o g e _ b d d ( ' SELECT a m o r ti s s em en t FROM LIAISON WHERE i d _ c a l c u l =
+ str ( id_calcul ))
Q6. Attention, les équations données dans le sujet correspondent à l’écriture sous forme
¨
˙
de système M X(t)
= −C X(t)
− KX(t) + F (t)
M est la matrice diagonale d’éléments diagonaux m1 , m2 , . . . , mn . K et C sont tridiagonales c’est-à-dire que seul leurs éléments d’indice (i,i+1),(i,i) et (i-1,i) peuvent
être non nuls :

K=
k1 + k2

 −k2











0
−k2
k2 + k3
−k 3
0

−kn−1 kn−1 + kn −kn
−kn
2
kn















C=
 c1 + c2

 −c2











0
−c2
c2 + c3
−c3
0

−cn−1 cn−1 + cn −cn
−cn
cn














Q7. L’énoncé est mal posé pour python. Il aurait fallu écrire dans le sujet : « Écrire une
fonction creation_operateur(n,m,k,c) qui renvoie la liste [M,K,C] ». Les concepteurs du sujet paraissent donc familiers de Scilab et pas de python,
def c r e a t i o n _ o p e r a t e u r (n ,m ,k , c ):
M = zeros ((n , n ) , float )
C = zeros ((n , n ) , float )
K = zeros ((n , n ) , float )
M [0 ,0] = m [0]
K [0 ,0] = k [0]+ k [1]
K [0 ,1] = -k [1]
C [0 ,0] = c [0]+ c [1]
C [0 ,1] = -c [1]
M [n -1 , n -1] = m [n -1]
K [n -1 , n -1] = k [n -1]
K [n -1 , n -2] = -k [n -1]
C [n -1 , n -1] = c [n -1]
C [n -1 , n -2] = -c [n -1]
for i in range ( n -1):
M [i , i ] = m [ i ]
K [i , i ] = k [ i ]+ k [ i +1]
K [i ,i -1] = -k [ i ]
K [i , i +1] = -k [ i +1]
C [i , i ] = c [ i ]+ c [ i +1]
C [i ,i -1] = -c [ i ]
C [i , i +1] = -c [ i +1]
return [M ,K , C ]
Q8. Si f est de classe C 1 , la formule de Taylor-Young, permet d’écrire f (a − h) = f ′ (a) −
f (a) − f (a − h)
hf ′ (a) + o(h) d’où f ′ (a) ≈
h
˙ q ) ≈ X(tq ) − X(tq − dt) d’où le shéma d’Euler
Appliqué ici, on X(t
dt
∀ q > 1, Vq =
De la même manière Aq =
Xq − Xq−1
dt
Vq − Vq−1
d’où en remplaçant avec la formule précédente
dt
∀ q > 2, Aq =
Xq − 2Xq−1 + Xq−2
dt2
¨ q ) + C X(t
˙ q ) + KX(tq ) = F (tq ),
En réinjectant dans l’équation M X(t
3
d’où M(Xq − 2Xq−1 + Xq−2 ) + dt C(Xq − Xq−1 ) + dt2 KXq = dt2 Fq , ainsi
(M + dt C + dt2 K) Xq = (2M + dt C)Xq−1 − MXq−2 + dt2 Fq = Gq
|
Q9.
{z
Hq
}
• Même remarque sur le style scilab de la question.
• Sinon, je n’ai aucune idée de X0 ni de V0 : masses espacées régulièrement ? en
équilibre ? Vitesses initiales nulles ? Rien n’est dit.
Je vais supposer la vitesse initiale nulle et les masses espacées régulièrement
• Pour faire les addition de matrices, il va falloir prendre garde à bien avoir des
tableaux (array) : avec les listes classiques le signe ’+’ fait des concaténations.
• L’énoncé ne donne pas de fonction faisant le produit d’une matrice carré et
d’une matrice colonne, il va falloir programmer une telle fonction.
!
Attention :
A*B ne correspond pas au produit de matrice.
from numpy import array , sin
def calcul (n ,M ,K ,C , npts , dt , fmax , omega ):
def mult (A , X ):
# r e n v o i e le p r o d u i t de A par X
B =[]
for j in range ( n )
S =0
for i in range ( n ):
S += A [i , k ]* X [ k ]
B . append ( S )
return B
# On c o n v e r t i t les t a b l e a u en array numpy
# pour b é n é ficier des op é r a t i o n s m a t r i c i e l l e s f o u r n i e s par numpy
M = array ( M )
K = array ( K )
C = array ( C )
F = array ([0]* ntps )
H = M + dt * C + dt * dt * K
# p r e n d r e soin d ' avoir des tableaux , et non des listes
# masses espac é es r é guli è rement
for i in range ( n )]
X0 = [( i +1)* L / n
V = [0]* n # v i t e s s e i n i t i a l l e nulle
X1 =[ X0 [ i ] + V [ i ]* dt for i in range ( n )]
X =[ X0 , X1 ]
A =2* M + dt * C
for q in range (2 , ntps ):
Fq [ -1]= fmax * sin ( omega * q * dt )
Gq = mult (A , X [ -1]) - mult (M , X [ -2])+ Fq
X . append ( resoud (H , Gq ))
return X
4
Q10. def resoud (H , Gq ):
for i in range ( n -1):
H [ i +1 , i +1] = H [ i +1 , i +1] - H [ i +1 , i ]/ H [i , i ]* H [i , i +1]
H [ i +1 , i +2] = H [ i +1 , i +2] - H [ i +1 , i ]/ H [i , i ]* H [i , i +2]
Gq [ i +1] = G [ i +1] - H [ i +1 , i ]/ H [i , i ]* Gq [ i +1]
# m a i n t e n a n t H est t r i a n g u l a i r e s u p e r i e u r e
# avec 3 coef non nul max par ligne
Xq = [0]* n
Xq [n -1] = Gq [n -1]/ H [n -1 ,n -1]
Xq [n -2] = ( Gq [n -2] - Xq [n -1]* H [n -2 , n -1])/ H [n -2 ,n -2]
for i in range ( n -3 , -1 , -1):
Xq [ i ] = ( Gq [ i ] - Xq [ i +1]* H [i , i +1] - Xq [ i +2]* H [i , i +3])/ H [i , i ]
return Xq
Q11. Linéaire en n : O(n) car juste 2 boucles for successives de longueur n.
On ne peut espérer mieux. Avec le pivot classique il faut annuler tout le triangle
inférieur de la matrice H, donc O(n2 ) coefficients, donc une complexité quadratique.
T
0, 3
=
= 150 000,
dt
2.10−6
Les codages double précision corresponde au stockage sur 64 bits. J’en profite pour
faire un rappel de cours :
Q12. X est une matrice de taille ntps×n. On a ntps=
Rappel :
Les réel en python sont stockés sous la forme ε · m · 2n où ε ∈ {−1, 1}, m ∈ [1, 2[ et
n ∈ Z.
On stocke un réel sur 64bits, soit 8 octets. Ainsi, comme n = 200, pour stocker X en
mémoire il faut 150 000 × 200 × 8 = 240 000 000 octets, soit 240 Mo ou si l’on préfère
0,24 Go.
La RAM est loin d’être saturé.
Q13. Je trouve très limite que l’on ne redonne pas la définition des fonctions de matplotlib.
Elles ne sont pas explicitement au programme ! Mais bon, n’oublions pas qu’il s’agit
d’un sujet zero...
from m a t p l o t l i b . pyplot import plot , show
def a f f i c h e _ d e p l a c e m e n t _ p d t (q ,X ,L ,n , ampl ):
A = [ x * ampl for x in X [q ,:]]
B = [0]* n
plot (A ,B , ' D ' )
show ()
Q14. Dis plus clairement, on veut le coefficient maximal de la matrice X et sa position
dans la matrice :
def l i e u _ t e m p s _ d e p l _ m a x ( X ):
pmax , qmax , imax = 0 ,0 ,0
for q in range ( npts ):
for i in range ( n ):
if abs( X [q , i ]) > pmax :
pmax = abs ( X [q , i ])
5
qmax = q
imax = i
return [ imax , qmax , pmax ]
Q15. L’énergie cherchée est Ediss (T ).
p
q(b − a)
b−a X
On va calculer l’intégrale avec la méthode des rectangles : lim
f a+
p→+∞ p
p
q=0
ici a = 0, b = T , p = ntps d’où
b−a
= dt et f = Pdiss . Plus explicitement
p
Ediss (T ) ≈
ntps
X
dt · Pdiss (q · dt)
q=0
Rappelons les notations de la question 8 :

u1 (t)

˙ q ) = Xq − Xq−1 . On a alors
X(t) =  ...  , Xq = X(tq ) = X(q · dt) et X(t
dt
un (t)
def Pdiss ( q ):
# r e n v o i e la p u i s s a n c e au temps q * dt
s = 0
for i in range (1 , n ): # ne pas o u b l i e r qu ' en python , on c o m m e n c e á 0
s = s + c [ i ]*(( X [q , i ] -X [q -1 , i ]) -( X [q ,i -1] -X [q -1 , i - 1 ] ) ) * * 2
return s / dt **2
def c a l c u l _ e n e r g i e (X , c ):
Ediss = 0
for q in range ( ntps ):
Ediss = Ediss + dt * Pdiss ( q )
return Ediss
6
!
=
Z
b
a
f