C ORRIGÉ S UJET 0 M INES 1. n est de type int (entier). Si x ∈ [0, 1[, alors 0 ≤ ( h + 2)/2 × x < ( h + 2)/2, donc n est un entier tel h que : 0 ≤ n < + 2. 2 2. def c a l c u l _ n ( h ) : i f h>1 : return i n t ( ( h + 2 . 0 ) / 2 * random ( ) ) + 1 else : return 0 3. Petite difficulté : si on ne fait rien, toute variable piles définie dans le corps de la fonction est locale et sera "détruite" à la fin de l’exécution. On rend une variable "globale" en la déclarant, à l’aide du mot-clé "global". def i n i t i a l i s a t i o n (P ) : global piles p i l e s = [ 0 ] *P Méthodes alternatives pour créer la liste [0, · · · , 0] : p i l e s =[0 f o r i in range ( P ) ] ou piles =[] f o r i in range (P ) : p i l e s . append ( 0 ) On évite le problème de la variable globale en définissante une fonction qui renvoie une liste [0, · · · , 0], on ne définit piles que dans le programme principal : def i n i t i a l i s a t i o n (P) return [ 0 ] * P p i l e s = i n i t i a l i s a t i o n ( 1 0 0 ) # par exemple Rappel cours : Les variables créées par une fonction sont, par défaut, locales, et masquent (sans les "écraser") les variables globales de même nom. Elles sont "détruites" à la fin de l’évaluation. Les paramètres formels de la fonction sont des variables locales qui sont initialisées avec la même identité (et en particulier la même valeur) que les arguments passés à la fonction. Il n’est pas interdit de modifier leur valeur pendant l’évaluation, mais à la fin de l’évaluation, ces modifications ne sont pas conservées car les variables locales sont détruites. Deux exceptions : La déclaration "global" permet à la fonction de créer et modifier des variables globales, ces modifications étant conservées après l’évaluation de la fonction. Quand l’argument est une liste (type "mutable"), les modifications apportées à ses termes sont conservées, car elle conserve son identité, ce sont les identités des termes qui changent (ce n’est pas le cas si on ré-affecte directement la liste). En Python, les listes (et les dictionnaires) sont mutables. Attention : les entiers, les floats, mais aussi les strings et les tuples ne sont pas mutables ! 4. def a c t u a l i s e ( p i l e s , perdus ) : g l o b a l perdus # pas n é c e s s a i r e pour une l i s t e f o r p in range ( len ( p i l e s ) − 1 ) : h= p i l e s [ p+1] − p i l e s [ p ] i f h>1: n= c a l c u l _ n ( h ) p i l e s [ p ] −= n p i l e s [ p+1] +=n h= p i l e s [ − 1] n= c a l c u l _ n ( h ) p i l e s [ − 1] −= n perdus +=n 5. L’utilisateur entre P à l’aide de la commande "input". Attention, input lit ce qu’on entre au clavier comme une chaîne. Il faut penser à convertir en entier. P= i n t ( input ( " nombre de p i l e s " ) ) i n i t i a l i s a t i o n (P) n b _ i n s t r u c t i o n s =0 perdus=0 while ( perdus <1000): i f n b _ i n s t r u c t i o n s % 10 ==0 : p i l e s [ 0 ] +=1 a c t u a l i s e ( p i l e s , perdus ) 6. Pour tracer une courbe connaissant une liste x d’abscisses et y d’ordonnées, on utilise la fonction plot de la bibliothèque matplotlib.pyplot (abrégée en plt). x =[ i f o r i in range (P ) ] # ou bien x= np . arange ( P ) y= p i l e s plt . plot (x , y ) Si on se contente de fournir une liste, les indices sont pris comme listes d’abscisses, les termes comme liste d’ordonnées, ce qui simplifie le code : plt . plot ( piles ) 7. L’intitulé des colonnes est trompeur : Votant sans "s", et aucune répétition dans cette colonne. La colonne Votant contient bien le nombre de votants qu’il y a dans chaque laboratoire, la requète est donc naturellement : SELECT densite , R, Kn, Gamma, Kt , mu FROM granular_base WHERE mat = " verre " AND geom = " sphere " AND note >= 3 AND Votant >=3; 8. On définit une classe "grain". Pour créer une instance (c-à-d., un objet de cette classe), on utilise la syntaxe G=grain(x,y), ce qui appelle en réalité la fonction __init__(G,x,y) et initialise un grain G possédant les attributs : G.pos (position) de valeur initiale ( x, y), G.vit (vitesse) de valeur initiale (0, 0), G.force (force d’interaction) de valeur initiale (0, 0). 9. Les grains sont empilés comme sur le schéma : 2/ 4 10. Les erreurs d’arrondis font qu’il n’est pas possible numériquement d’avoir une distance entre les grains qui soit exactement de 2R . 11. hypotenuse = s q r t ( ( Xi −Xj ) * * 2 + ( Yi −Yj ) * * 2 ) cos_alpha = ( Xj −Xi ) / hypotenuse sin_alpha = ( Yj −Yi ) / hypotenuse 12. def somme_int ( ) : # sommation pour chaque grain des i n t e r a c t i o n s f o r i in range ( len ( tas ) ) : f o r j in range ( len ( tas ) ) : i f j != i : Fjin , F j i t = calcul_Fnt ( i , j ) F j i x = F j i n * cos_alpha − F j i t * sin_alpha F j i y = F j i n * sin_alpha + F j i t * cos_alpha tas [ i ] . f o r c e [ 0 ] += F j i x tas [ i ] . f o r c e [ 1 ] += F j i y 13. En considérant, l’accélération constante égale à a k sur l’intervalle ]( k − 1/2)∆ t, ( k + 1/2)∆ t[, on obtient une approximation à l’ordre 1 de la vitesse vk+1/2 ; de même, en considérant la vitesse constante égale à vk+1/2 sur l’intervalle ] k∆ t, ( k + 1)∆ t[, on obtient une approximation à l’ordre 1 de la position xk : ( vk+1/2 = vk−1/2 + a k ∆ t xk+1 = xk + vk+1/2 ∆ t 14. Delta_t = T_stop / i n c f o r k in range ( i n c ) : somme_int ( ) f o r i in range ( len ( tas ) ) : Fix , Fiy=tas [ i ] . f o r c e mi = M ax = Fix / mi ay = Fiy / mi−g x , y = tas [ i ] . pos vx , vy = tas [ i ] . v i t vx += ax * Delta_t x += vx * Delta_t vy += ay * Delta_t y += vy * Delta_t tas [ i ] . pos = x , y tas [ i ] . v i t = vx , vy 15. Dans tout schéma d’intégration numérique, on approche la courbe entre deux instants par une courbe plus simple (ici, un segment). Il faut bien chosir le pas car : augmenter le pas augmente le risque d’un écart entre la courbe et son approximation ; diminuer le pas augmente le temps de calcul et les accumulations d’erreurs d’arrondi. 16. L’introduction du terme d’ordre 1 est problématique car dans la méthode, la vitesse est calculée en fonction de l’accélération. On résout le problème en calculant a k en fonction de vk−1/2 , c’est-àdire : ax ay vx x = Fix / mi − 1/ tau / mi * vx = Fiy / mi − 1/ tau / mi * vy −g += ax * Delta_t += vx * Delta_t 3/ 4 vy += ay * Delta_t y += vy * Delta_t mais on a une méthode proche de celle d’Euler. Il vaut mieux approcher : vk = obtient la formule de récurrence : µ ¶ µ ¶ ∆t ∆t F 1+ vk+1/2 = 1 − vk−1/2 + ∆t 2τ m i 2τ m i mi vk−1/2 + vk+1/2 . On 2 Il est préférable de choisir ∆ t petit devant τ m i . 17. Le calcul de somme_int() est quadratique (2 boucles imbriquées). 18. Un grain de sable semble n’interagir qu’avec (environ) 6 autres grains. Si on a un accès direct à ces grains-là, on peut espérer une complexité de l’ordre de 6 n, donc linéaire, pour cette partie de l’algorithme. 19. ? ? ? 4/ 4