Idées mathématiques en Python Automne 2016 Prof : Simon Plouffe, IUT Note sur les classes Il y a les classe définies par défaut comme Int, float, tuple, list, str Mais si on veut aller plus loin ? On peut définir sa propre classe, on le voit ici dans le cas d’un polynôme. La manière la plus naturelle de représenter un polynôme est d’utiliser une liste contenant ses coefficients 𝑝 = 𝑎0 + 𝑎1 𝑋 + 𝑎2 𝑋 2 + … 𝑎𝑛 𝑋 𝑛 Si l’on dispose alors de deux listes pl et p2 représentant deux polynômes, on souhaiterait pouvoir les additionner en utilisant l’opérateur +. Mais en l’état, la liste renvoyée serait le résultat de la concaténation des deux listes. De plus, on souhaiterait pouvoir afficher le polynôme de manière conventionnelle. C’est ici que la définition d’une classe nous permettra de définir de nouvelles fonctions (les méthodes) propres aux polynômes. Pour créer une classe, on utilise le mot-clé class : class Polynome(object): Après ça, au choix on peut compléter avec des constructions qui permettent d’avoir le degré, la somme, le produit, l’inverse, etc sur les polynômes. Ou bien sûr utiliser ‘def’ directement et ‘return’, ce qui convient parfaitement pour tous les ‘one-liners’. One-liners : tous les algorithmes que nous verrons peuvent être décrits de cette façon. Les matrices avec numpy et scipy On charge tout d’abord les modules Pas la même chose(!) Erreur ?! Oui mais non, on peut y remédier en utilisant ‘allclose’. np.eye(3) = matrice 3 x 3 avec des 1 en diagonale et des 0 partout ailleurs. Donc, malgré les erreurs inévitables, il est tout de même possible de contrôler la précision au final. Opérations de base #Produit matriciel A=np.array([(1,2),(3,4)]) A array([[1, 2], [3, 4]]) B=np.array([(3,5),(7,11)]) Comme chacun le sait, le déterminant d’une matrice 2 x 2 est 𝑎 𝑏 det( ) = ad − bc. 𝑐 𝑑 C=dot(A,B) C array([[17, 27], [37, 59]]) On peut écrire aussi C=A.dot(B) mais … pas une bonne pratique (IMHO). De la même façon, pour le déterminant par exemple : DD=linalg.det(B) DD -1.9999999999999989 Alors que le produit 3 x 11 – 5 x 7 = -2 est bien clair et entier. L’erreur ou faute n’est pas due à Python mais à l’emploi d’un calculateur numérique en binaire. Autre aspect très important : La vitesse. Avec Python, c’est interprété, ce n’est pas une bête de guerre en vitesse (mais ça marche quand même assez bien). Si on veut aller beaucoup plus vite, on peut utiliser Cython. Mais bien sûr, Cython n’est pas aussi lisible que Python, il a un fort accent en C, mais c’est très rapide. On est limité par la précision du ‘float64’, environ 16 chiffres décimaux. Il ne faut pas négliger ce facteur, pour de petits exemples ça suffit mais pour des systèmes plus complexes ou plus volumineux, ça pose un réel problème de calcul. Exemple de Poincaré, si la trajectoire en rouge dévie de très peu alors la trajectoire finale est à ~180 degrés. Limites vites atteintes Si on prend une 10 x 10, A=array([(1, 1, 1, 1, 1, 1, 1, 1, 1, 1), (2, 4, 8, 16, 32, 64, 128, 256, 512, 1024), (3, 9, 27, 81, 243, 729, 2187, 6561, 19683, 59049), (4, 16, 64, 256, 1024, 4096, 16384, 65536, 262144, 1048576), (5, 25, 125, 625, 3125,15625, 78125, 390625, 1953125, 9765625), (6, 36, 216, 1296, 7776, 46656, 279936, 1679616, 10077696, 60466176), (7, 49, 343, 2401, 16807, 117649, 823543, 5764801, 40353607, 282475249), (8, 64, 512, 4096, 32768,262144, 2097152, 16777216, 134217728, 1073741824), (9, 81, 729, 6561, 59049, 531441, 4782969, 43046721, 387420489, 3486784401), (10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000)]) array([[ L’inverse est (très petit) [ [ [ [ [ [ [ [ [ 1.00000000e+01, -2.25000000e+01, -5.25000000e+01, 5.04000000e+01, 1.71428571e+01, -5.62500000e+00, -1.00000000e-01], -1.92896825e+01, 5.46517857e+01, 1.40645833e+02, -1.37540000e+02, -4.77619048e+01, 1.57723214e+01, 2.82896825e-01], 1.58557540e+01, -5.17513393e+01, -1.49352083e+02, 1.49625000e+02, 5.34261905e+01, -1.77977679e+01, -3.23164683e-01], -7.31857363e+00, 2.62665675e+01, 8.43271991e+01, -8.68736111e+01, -3.20951058e+01, 1.08108383e+01, 1.99426808e-01], 2.09756944e+00, -8.05303819e+00, -2.83529514e+01, 3.00826389e+01, 1.15569444e+01, -3.94522569e+00, -7.42187500e-02], -3.88252315e-01, 1.56657986e+00, 5.96232639e+00, -6.51201389e+00, -2.61041667e+00, 9.05121528e-01, 1.74363426e-02], 4.65277778e-02, -1.94965278e-01, -7.92013889e-01, 8.88888889e-01, 3.72420635e-01, -1.31423611e-01, -2.60416667e-03], -3.48875661e-03, 1.50545635e-02, 6.45833333e-02, -7.43055556e-02, -3.25396825e-02, 1.17063492e-02, 2.39748677e-04], 1.48809524e-04, -6.57242063e-04, -2.95138889e-03, 3.47222222e-03, 1.58730159e-03, -5.82837302e-04, -1.24007937e-05], -2.75573192e-06, 1.24007937e-05, 5.78703704e-05, -6.94444444e-05, -3.30687831e-05, 1.24007937e-05, 2.75573192e-07]]) 4.00000000e+01, -3.50000000e+01, 1.11111111e+00, -1.03825397e+02, 9.66805556e+01, -3.13095238e+00, 1.05973280e+02, -1.06895602e+02, 3.55716490e+00, -5.73728836e+01, 6.32942130e+01, -2.17968474e+00, 1.85402778e+01, -2.24074653e+01, 8.04050926e-01, -3.76319444e+00, 4.96579861e+00, -1.86863426e-01, 4.84722222e-01, -6.94097222e-01, 2.75462963e-02, -3.84920635e-02, 5.93750000e-02, -2.49669312e-03, 1.71957672e-03, -2.83564815e-03, 1.26763668e-04, -3.30687831e-05, 5.78703704e-05, -2.75573192e-06, C=dot(A,B) donne ??!? array([[ [ [ [ [ [ [ [ [ [ 1.00000000e+00, -1.38238803e-11, -2.45984665e-11, -7.84559824e-11, 1.44422082e-11, -1.24994267e-11, 1.54597396e-13], -5.97933595e-13, 1.00000000e+00, -3.20781457e-11, -1.70335537e-10, -6.82015555e-12, -7.48629631e-12, 3.33770880e-13], -2.19113616e-12, 2.57325272e-11, -7.16657844e-11, -2.22770247e-10, -1.02340358e-11, -5.17108578e-12, 3.20413834e-13], 9.02167230e-12, -9.89430760e-13, 1.00000000e+00, -1.63268510e-10, 2.46132004e-11, -1.11768372e-11, 1.54654067e-13], 7.25819405e-12, 2.23820962e-11, -1.98951966e-10, 1.00000000e+00, -1.79625204e-11, 9.02389274e-12, 4.15667500e-13], 1.00044417e-11, 2.11457518e-11, -3.13320925e-10, -2.84671842e-10, 1.77351467e-11, 6.25277607e-12, -1.10134124e-13], 2.14868123e-11, -3.54702934e-11, -5.80257620e-10, -1.41881173e-10, 1.00000000e+00, -2.77395884e-11, -1.33582034e-12], 3.04680725e-11, -2.36468622e-11, -5.52972779e-10, -2.47382559e-10, 5.82076609e-11, 1.00000000e+00, -5.68434189e-13], 4.00177669e-11, -1.45519152e-11, -1.16415322e-09, -4.36557457e-10, -7.27595761e-11, -6.54836185e-11, -1.13686838e-12], 1.09139364e-11, 1.01863407e-10, -6.98491931e-10, -2.32830644e-10, 2.32830644e-10, 4.36557457e-11, 1.00000000e+00]]) -9.93298046e-12, -7.07729635e-11, 1.41501596e-12, -7.75418896e-11, -4.39893330e-11, 2.71792224e-12, 1.00000000e+00, -4.49715820e-11, 6.00913763e-12, -7.15942861e-11, -1.43778323e-10, 1.10551568e-11, -1.21133326e-10, -1.13800525e-10, 1.06368248e-11, -9.11768439e-11, 1.00000000e+00, 1.58593139e-11, 6.73026079e-11, -4.71118256e-10, 2.93312041e-11, 0.00000000e+00, -3.12866177e-10, 2.45563569e-11, 1.45519152e-10, 2.91038305e-10, 1.00000000e+00, -1.74622983e-10, -1.16415322e-10, 2.18278728e-11, La solution : Maple avec n chiffres de précision A=Array([seq([seq(k^i,i=1..10)],k=1..10)]); [ 1 [ [ 2 [ [ 3 [ [ 4 [ [ 5 A = [ [ 6 [ [ 7 [ [ 8 [ [ 9 [ [10 1 1 1 1 1 1 1 1 4 8 16 32 64 128 256 512 9 27 81 243 729 2187 6561 19683 16 64 256 1024 4096 16384 65536 262144 25 125 625 3125 15625 78125 390625 1953125 36 216 1296 7776 46656 279936 1679616 10077696 49 343 2401 16807 117649 823543 5764801 40353607 64 512 4096 32768 262144 2097152 16777216 134217728 81 729 6561 59049 531441 4782969 43046721 387420489 100 1000 10000 100000 1000000 10000000 100000000 1000000000 1] ] 1024] ] 59049] ] 1048576] ] 9765625] ] 60466176] ] 282475249] ] 1073741824] ] 3486784401] ] 10000000000] La vraie réponse est : Le produit est bien la matrice identité. [1 [ [0 [ [0 [ [0 [ [0 [ [0 [ [0 [ [0 [ [0 [ [0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0] ] 0] ] 0] ] 0] ] 0] ] 0] ] 0] ] 0] ] 0] ] 1] Mais comment Maple fait-il ?? Le calcul est en entiers exacts et fractions. C’est une precision dite infinite, en autant que la machine puisse aller aussi loin que necessaire. g=array([[ 1.00000000e-20, 0.00000000e+00, 1.00000000e+00], [ 1.00000000e+00, 1.00000000e+20, 1.00000000e+00], [ 0.00000000e+00, 1.00000000e+00, -1.00000000e+00]]) >>> ggg=linalg.inv(g) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib/python3.4/site-packages/numpy/linalg/linalg.py", line 520, in inv ainv = _umath_linalg.inv(a, signature=signature, extobj=extobj) File "/usr/lib/python3.4/site-packages/numpy/linalg/linalg.py", line 90, in _raise_linalgerror_singular raise LinAlgError("Singular matrix") numpy.linalg.linalg.LinAlgError: Singular matrix Aie, ça ne s’arrange pas: Autre exemple : >>> g=array([(1e-10,0,1),(1,1e10,1),(0,1,-1)]) >>> h=linalg.inv(g) >>> h array([[ 9.99999917e+19, -9.99999917e+09, 9.99999917e+19], [ -9.99999917e+09, 9.99999917e-01, 9.99999917e+09], [ -9.99999917e+09, 9.99999917e-01, 9.99999917e+09]]) >>> dot(h,g) array([[ 1.00000191, 0. , 0. ], [ 0. , 1. , 0. ], [ 0. , 0. , 1. ]]) C’est mieux, enfin presque… On peut corriger le tir avec la fonction ‘allclose’. Mais ce comportement inquiète beaucoup de monde. Donc, la plupart des programmes connus utilisent le IEEE 754 qui est bon et même excellent pour la plupart des calculs ‘normaux’, mais qui dérapent dès que la taille des matrices augmente. À cette date, il n’y a que les programmes CAS (Maple, Mathematica, …) qui peuvent s’affranchir de la précision en calculant exactement ou avec suffisamment de précision numérique Il n’y a pas que la taille des matrices qui cause un problème au calcul théorique. Au 18ème siècle déjà on savait que le fameux problème des 3 corps était difficile. C’est simple : il y a la lune, la terre et le soleil, ce qui fait 3 corps exactement. Problème : trouver l’équation exacte qui décrit l’orbite de ces 3 corps. Comme ça on pourra prévoir les nombreux mouvements de la lune, les marées et bien d’autres mouvements aux noms exotiques : les syzygies, la nutation, la libration, la révolution sidérale, synodique, draconique et anomalistique. Mais où est le problème exactement ? C’est qu’on veut être en mesure de calculer la date de Pâques (authentique) voir les références. Commençons par le début avec Ptolémée : Il a trouvé ça sans utiliser de télescope, juste en regardant attentivement. Méthode des phases Ces exemples montrent les trajectoires à deux dimensions. Lorsque le nombre de dimensions augmente, il n'est plus possible de les représenter. Jacques Laskar, est un drôle de lascar, il a prouvé qu’éventuellement les planètes du système solaire allaient se rentrer dedans, Vénus qui nous arrive dessus, la lune qui se fait la belle, etc. Dans plusieurs cas, cette déformation de l'orbite de Mercure conduit alors à une collision avec Vénus ou avec le Soleil d'ici à 5 Ga, tandis que l'orbite de la Terre reste peu affectée. En revanche, pour l'une de ces orbites, l'augmentation de l'excentricité de Mercure est suivie d'une augmentation de l'excentricité de Mars, et d'une déstabilisation complète des planètes du Système solaire interne (Mercure, Vénus, Terre, Mars) dans 3,4 Ga. Les chaînes de Markov Vecteurs de probabilité et matrice stochastique On dit qu'un vecteur 𝑢 = 𝑢1 , 𝑢1 , … , 𝑢𝑛 est un vecteur de probabilité si ses composantes sont positives ou nulles et si la somme de ces composantes est égale à 1. On dit qu’une matrice carrée est une matrice stochastique si chacune des lignes est un vecteur de probabilité, si chaque élément de cette matrice est positif ou nul et si la somme de chaque ligne est 1. Exemple On dit qu’une matrice stochastique 𝐴 est régulière si tous les éléments d’une puissance quelconque 𝐴𝑚 sont strictement positifs ( > 0 ). Il y a au plus m-1 puissances qui ont des lignes contenant des zéros, Si à la puissance m, une ligne contient un zero la matrice n’est PAS régulière. Dit autrement : les puissances d’une matrice stochastique régulière P convergent vers une matrice T donc les lignes sont le point fixe t. Par exemple avec la matrice 𝑃 = 0 1 , 1/2 1/2 les puissances de 𝑃 convergent vers la matrice 1 1 3 3 2 2 3 3 . Tout ça pour en arriver à ceci Qui dit matrice de transition dit aussi graphe de transition Qui se lit, lorsque c’est ensoleillé il y a 90 % de chances que ça le reste le lendemain et 10 % de chance qu’il pleuve. Quand il pleut, il y a 50% de chance que ça le reste le lendemain et 50 % de chances qu’il fasse soleil. En effectuant les puissances, on en vient à la conclusion qu’à la longue, il fait soleil 83,3 % du temps et il pleut 16,67 % du temps. Pour l’exemple du train et voiture : l’ouvrier en vient à prendre le train 1/3 du temps et sa voiture 2/3 du temps. 20 0 1 0 ce calcul correspond à l’état de la matrice après 0 0 1 0.5 0.5 0 20 tirs de ballons. Donne la matrice (qui semble se stabiliser). 0.19921875 0.2001953125 0.2001953125 0.400390625 0.3994140625 0.400390625 0.400390625 0.400390625 0.3994140625 Après 40 tirs on a la matrice : 0.200000762939453125 0.3999996185302734375 0.19999980926513671875 0.40000057220458984375 0.19999980926513671875 0.3999996185302734375 0.3999996185302734375 0.3999996185302734375 0.40000057220458984375 >>> gar=array([(0,1,0),(0,0,1),(0.5, 0.5, 0)]) >>> gar array([[ 0. , 1. , 0. ], [ 0. , 0. , 1. ], [ 0.5, 0.5, 0. ]]) >>> g40=np.linalg.matrix_power(gar,40) >>> g40 array([[ 0.20000076, 0.39999962, 0.39999962], [ 0.19999981, 0.40000057, 0.39999962], [ 0.19999981, 0.39999962, 0.40000057]]) Donc, après 40 tirs, la situation ‘instantanée’ dit que A a en sa possession le ballon 20 % du temps, et 40 % du temps pour B et C. Comment interpréter les puissances de la matrice de transition D’un graphe à une matrice de transition En résumé On appelle stochastique une matrice carrée dont la somme des lignes = 1. Ça correspond à un vecteur de probabilité du passage d’un état à un autre. Si la matrice est doublement stochastique (lignes et colonnes) elle est dite bistochastique. Si les puissances de la matrice donnent (éventuellement) des lignes SANS 0 alle est alors dite régulière. Si la diagonale principale ne contient aucun 1. 1 = ou équivalent à une boucle dans le graphe de transition. La propriété intéressante est que si la matrice est régulière : ses puissances convergeront vers une valeur (toutes les lignes semblables) fixe. Si ce n’est pas fixe : ça peut osciller entre 2 valeurs. Méthode de Briggs pour le calcul des logarithmes Méthode des différences de Newton et application au calcul des logarithmes En regardant de près, on aperçoit un motif assez simple dans les ‘puissances’ de ∆. Newton avait l’habitude de mettre ces résultats sous cette forme. À la main (sans fioritures) ça donne ceci: Mais plus général : (voir suivante). Hum, pas si mal, sachant que log(3,5) en base 10 est 0.5440680443502756… Application des différences finies Voici une application de l’utilisation des différences finies. Sachant que si on a la suite 𝑛2 1 4 9 16 25 36 3 5 7 11 13 2 2 2 2 0 0 0 Les différences successives nous donneront (1, 3, 2). Que la suite n, est équivalente à (1,1). Le problème du gâteau en un maximum de parts. Un traiteur paresseux à qui on demande de couper un gâteau décide de couper le gâteau de manière à avoir un maximum de parts. Ce qui amène à la suite 1,2,4, 7, 11, 16, … Mais, quel est le terme général ? La formule ?? On utilise les différences finies (et un peu d’astuce). 1 2 4 7 11 16 1 2 3 4 5 1 1 1 1 Ce qui donne (1,1,1), mais (1,1,1) c’est quoi ? Bien si (1,3,2) est 𝑛2 𝑛2 alors (1,1,1) est de l’ordre de , et si (1,1) est 𝑛 2 alors il reste à combiner les termes. a) b) c) d) On enlève (1/2,3/2, 1) à (1, 1, 1) il reste (1, 1, 1) – (1/2,3/2, 1) = (1/2, - 1/2, 0). qui amène , (1/2, -1/2) + (1/2, 1/2) . (1) qui est le terme constant 1. e) En collectant les termes on obtient 𝑓 𝑛 = 𝑛2 2 𝑛 2 − + 1. Références et lectures de chevet Classes : https://openclassrooms.com/courses/apprenez-a-programmer-en-python/premiereapproche-des-classes Calculs en multi-précision sur les matrices (jusqu’à 180 chiffres). http://robert.mellet.pagesperso-orange.fr/mult_prec/mult_pr_05.htm L’orbite compliquée de la lune : http://www.clubvega.fr/Club_Vega/Dossiers4_files/MOUVEMENT%20de%20la%20LUNE%20su r%20la%20SPHERE.pdf Tout sur la lune : http://www.palais-decouverte.fr/fileadmin/fileadmin_Palais/fichiersContribs/vousetes/enseignant/Documents-pedagogiques/_documents/Expositionspermanentes/Astronomie/Lune-commun.pdf Encore plus compliqué : http://villemin.gerard.free.fr/Wwwgvmm/Chaos/DiagPhas.htm Le problème des 3 corps : http://villemin.gerard.free.fr/aScience/Physique/TroiCorp.htm Quelques mots sur Jacques Laskar : https://fr.wikipedia.org/wiki/Jacques_Laskar Les collisions dans le système solaire: http://6yes.net/mp3/stabilit%C3%A9-syst%C3%A8me-solaire-et-collision.html Calcul de la date de Pâques sur wikipedia (pour les curieux). https://fr.wikipedia.org/wiki/Calcul_de_la_date_de_P%C3%A2ques Graphe d'une chaîne de Markov : https://fr.wikipedia.org/wiki/Graphe_d%27une_cha%C3%AEne_de_Markov_et_c lassification_des_%C3%A9tats Animation avec un automate : http://setosa.io/markov/index.html#%7B%22tm%22%3A[[0.9%2C0.1]%2C[0.5%2C 0.5]]%7D