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