Vous êtes sur la page 1sur 474

Calcul mathmatique avec

SAGE

Calcul mathmatique avec Sage


Alexandre Casamayou Nathann Cohen Guillaume Connan Thierry Dumont Laurent Fousse Franois Maltey Matthias Meulien Marc Mezzarobba Clment Pernet Nicolas M. Thiry Paul Zimmermann

C
Cette uvre est mise disposition selon les termes de la licence Creative Commons Paternit Partage dans les mmes conditions 3.0 France (cc by-sa 3.0 fr). Extrait de http://creativecommons.org/licenses/by-sa/3.0/fr/deed.fr :
Ceci est le rsum explicatif lisible par les humains du Code Juridique (la version intgrale de la licence). Vous tes libre de : partager reproduire, distribuer et communiquer luvre remixer adapter luvre dutiliser cette uvre des ns commerciales Selon les conditions suivantes :

b a

Attribution Vous devez attribuer luvre de la manire indique par lauteur de luvre ou le titulaire des droits (mais pas dune manire qui suggrerait quils vous approuvent, vous ou votre utilisation de luvre). Partage dans les Mmes Conditions Si vous modiez, transformez ou adaptez cette uvre, vous navez le droit de distribuer votre cration que sous une licence identique ou similaire celle-ci.

comprenant bien que : Renonciation Nimporte laquelle des conditions ci-dessus peut tre leve si vous avez lautorisation du titulaire de droits. Domaine Public L o luvre ou un quelconque de ses lments est dans le domaine public selon le droit applicable, ce statut nest en aucune faon aect par la licence. Autres droits Les droits suivants ne sont en aucune manire aects par la licence : Vos prrogatives issues des exceptions et limitations aux droits exclusifs ou fair use ; Les droits moraux de lauteur ; Droits quautrui peut avoir soit sur luvre elle-mme soit sur la faon dont elle est utilise, comme le droit limage ou les droits la vie prive. Remarque A chaque rutilisation ou distribution de cette uvre, vous devez faire apparatre clairement au public la licence selon laquelle elle est mise disposition. La meilleure manire de lindiquer est un lien vers cette page web.

Des parties de cet ouvrage sont inspires de louvrage Calcul formel : mode demploi. Exemples en Maple de Philippe Dumas, Claude Gomez, Bruno Salvy et Paul Zimmermann [DGSZ95], dius sous la mme licence, notamment les sections 2.1.5, 2.3.5 et 5.3. Une partie des exemples Sage du chapitre 15 sont tirs du tutoriel des logiciels MuPAD-Combinat [HT04] et Sage-combinat. Le dnombrement des arbres binaires complets de 15.1.2 est en partie inspir dun sujet de TP de Florent Hivert. Lexercice 9 sur le problme de Gauss est tir dun problme de Franois Pantigny et lexercice 17 sur leet Magnus est extrait dun TD de Jean-Guy Stoliaro. Les graphiques de la gure 4.9 et leur interprtation reproduisent une partie du paragraphe III.4 du Que sais-je ? Les nombres premiers de Grald Tenenbaum et Michel Mends France [TMF00].

Prface
Ce livre est destin tous ceux qui dsirent utiliser ecacement un systme de calcul mathmatique, en particulier le logiciel Sage. Ces systmes orent une multitude de fonctionnalits, et trouver comment rsoudre un problme donn nest pas toujours facile. Un manuel de rfrence fournit une description analytique et en dtail de chaque fonction du systme ; encore faut-il savoir le nom de la fonction que lon cherche ! Le point de vue adopt ici est complmentaire, en donnant une vision globale et synthtique, avec un accent sur les mathmatiques sous-jacentes, les classes de problmes que lon sait rsoudre et les algorithmes correspondants. La premire partie, plus spcique au logiciel Sage, constitue une prise en main du systme. Cette partie se veut accessible tous les tudiants scientiques (BTS, IUT, classes prparatoires, licence), et dans une certaine mesure aux lves des lyces. Les autres parties sadressent des tudiants au niveau agrgation. Contrairement un manuel de rfrence, les concepts mathmatiques sont clairement noncs avant dillustrer leur mise en uvre avec Sage. Ce livre est donc aussi un livre sur les mathmatiques. Pour illustrer cet ouvrage, le choix sest port naturellement vers Sage, car cest un logiciel libre, que tout un chacun peut utiliser, modier et redistribuer loisir. Ainsi llve qui a appris Sage au lyce pourra lutiliser quelle que soit sa voie professionnelle : en licence, master, doctorat, en cole dingnieur, en entreprise, etc. Sage est un logiciel encore jeune par rapport aux logiciels concurrents, et malgr ses capacits dj tendues, il comporte encore de nombreux bogues. Mais par sa communaut trs active de dveloppeurs, Sage volue trs vite. Chaque utilisateur de Sage peut rapporter un bogue et ventuellement sa solution sur trac.sagemath.org ou via la liste sage-support. Pour rdiger ce livre, nous avons utilis la version 5.9 de Sage. Nanmoins, les exemples doivent fonctionner avec toute version ultrieure. Par contre, certaines armations pourraient ne plus tre vries, comme par exemple le fait que Sage utilise Maxima pour valuer des intgrales numriques. Quand jai propos en dcembre 2009 Alexandre Casamayou, Guillaume Connan, Thierry Dumont, Laurent Fousse, Franois Maltey, Matthias Meulien, Marc Mezzarobba, Clment Pernet et Nicolas Thiry dcrire un livre sur Sage, tous ont rpondu prsent, malgr une charge de travail dj importante, comme Nathann Cohen qui nous a rejoint dans cette aventure. Je tiens les remercier, notamment pour le respect du planning serr que javais x, et plus particulirement

iv Nathann Cohen, Marc Mezzarobba et Nicolas Thiry pour leur investissement dcisif dans la dernire ligne droite. Tous les auteurs remercient les personnes suivantes qui ont relu des versions prliminaires de ce livre : Gatan Bisson, Franoise Jung, Hugh Thomas, Anne Vaugon, Sbastien Desreux, Pierrick Gaudry, Maxime Huet, Jean Thiry, Muriel Shan Sei Fan, Timothy Walsh, Daniel Duparc, Kvin Rowanet et Kamel Naroun (une mention spciale tous les deux qui ont relev des coquilles qui avaient rsist 17 relectures) ; ainsi quEmmanuel Thom pour son aide prcieuse lors de la ralisation de ce livre, Sylvain Chevillard, Gatan Bisson et Jrmie Detrey pour leurs conseils typographiques aviss et les erreurs quils ont releves. Le dessin de la couverture a t ralis par Corinne Thiry, sur une ide originale dAlbane Saintenoy. En rdigeant ce livre, nous avons beaucoup appris sur Sage, nous avons bien sr rencontr quelques bogues, dont certains sont dj corrigs. Nous esprons que ce livre sera utile dautres, lycens, tudiants, professeurs, ingnieurs, chercheurs ou amateurs ! Cet ouvrage comportant certainement encore de nombreuses imperfections, nous attendons en retour du lecteur quil nous fasse part de toute erreur, critique ou suggestion pour une version ultrieure ; merci dutiliser pour cela la page sagebook.gforge.inria.fr. Nancy, France Mai 2013 Paul Zimmermann

Table des matires

I 1

Prise en main de Sage Premiers pas 1.1 Le logiciel Sage . . . . . . . . . . . . . . . . . . . . . 1.1.1 Un outil pour les mathmatiques . . . . . . 1.1.2 Accs Sage . . . . . . . . . . . . . . . . . . 1.1.3 Ressources . . . . . . . . . . . . . . . . . . . 1.2 Sage comme calculatrice . . . . . . . . . . . . . . . . 1.2.1 Premiers calculs . . . . . . . . . . . . . . . . 1.2.2 Fonctions lmentaires et constantes usuelles 1.2.3 Aide en ligne et compltion automatique . . 1.2.4 Variables Python . . . . . . . . . . . . . . . 1.2.5 Variables symboliques . . . . . . . . . . . . . 1.2.6 Premiers graphiques . . . . . . . . . . . . . . Analyse et algbre 2.1 Expressions symboliques et simplication . . . . 2.1.1 Expressions symboliques . . . . . . . . . 2.1.2 Transformation dexpressions . . . . . . . 2.1.3 Fonctions mathmatiques usuelles . . . . 2.1.4 Hypothses sur une variable symbolique . 2.1.5 Quelques dangers . . . . . . . . . . . . . 2.2 quations . . . . . . . . . . . . . . . . . . . . . . 2.2.1 Rsolution explicite . . . . . . . . . . . . 2.2.2 quations sans solution explicite . . . . . 2.3 Analyse . . . . . . . . . . . . . . . . . . . . . . . 2.3.1 Sommes . . . . . . . . . . . . . . . . . . 2.3.2 Limites . . . . . . . . . . . . . . . . . . . 2.3.3 Suites . . . . . . . . . . . . . . . . . . . . 2.3.4 Dveloppements limits . . . . . . . . . . 2.3.5 Sries . . . . . . . . . . . . . . . . . . . . 2.3.6 Drivation . . . . . . . . . . . . . . . . . 2.3.7 Drives partielles . . . . . . . . . . . . . 2.3.8 Intgration . . . . . . . . . . . . . . . . . 2.4 Algbre linaire lmentaire . . . . . . . . . . . . 2.4.1 Rsolution de systmes linaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1 3 . 3 . 3 . 5 . 8 . 8 . 8 . . 11 . 13 . 13 . 15 . 16 . . . . . . . . . . . . . . . . . . . . 17 17 17 18 20 22 22 24 24 26 27 27 28 29 30 32 33 33 34 35 36

vi 2.4.2 2.4.3 2.4.4 3

TABLE DES MATIRES Calcul vectoriel . . . . . . . . . . . . . . . . . . . . . . . Calcul matriciel . . . . . . . . . . . . . . . . . . . . . . . Rduction dune matrice carre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 37 38 41 42 42 43 43 44 45 52 53 56 59 60 60 62 66 68 69 70 72 73 74

Programmation et structures de donnes 3.1 Syntaxe . . . . . . . . . . . . . . . . . . . . . . . . 3.1.1 Syntaxe gnrale . . . . . . . . . . . . . . . 3.1.2 Appel de fonctions . . . . . . . . . . . . . 3.1.3 Complments sur les variables . . . . . . . 3.2 Algorithmique . . . . . . . . . . . . . . . . . . . . 3.2.1 Les boucles . . . . . . . . . . . . . . . . . . 3.2.2 Les tests . . . . . . . . . . . . . . . . . . . 3.2.3 Les procdures et les fonctions . . . . . . . 3.2.4 Exemple : exponentiation rapide . . . . . . 3.2.5 Achage et saisie . . . . . . . . . . . . . . 3.3 Listes et structures composes . . . . . . . . . . . 3.3.1 Dnition des listes et accs aux lments . 3.3.2 Oprations globales sur les listes . . . . . . 3.3.3 Principales mthodes sur les listes . . . . . 3.3.4 Exemples de manipulation de listes . . . . 3.3.5 Chanes de caractres . . . . . . . . . . . . 3.3.6 Structure partage ou duplique . . . . . . 3.3.7 Donnes modiables ou immuables . . . . 3.3.8 Ensembles nis . . . . . . . . . . . . . . . 3.3.9 Dictionnaires . . . . . . . . . . . . . . . . . Graphiques 4.1 Courbes en 2D . . . . . . . . . . . . . . . . . . . 4.1.1 Reprsentation graphique de fonctions . 4.1.2 Courbe paramtre . . . . . . . . . . . . 4.1.3 Courbe en coordonnes polaires . . . . . 4.1.4 Courbe dnie par une quation implicite 4.1.5 Trac de donnes . . . . . . . . . . . . . 4.1.6 Trac de solution dquation direntielle 4.1.7 Dveloppe dune courbe . . . . . . . . . 4.2 Courbes en 3D . . . . . . . . . . . . . . . . . . . Domaines de calcul 5.1 Sage est orient objet . . . . . . . 5.1.1 Objets, classes et mthodes 5.1.2 Objets et polymorphisme . 5.1.3 Introspection . . . . . . . . 5.2 lments, parents, catgories . . . 5.2.1 lments et parents . . . . 5.2.2 Constructions . . . . . . . 5.2.3 Complment : catgories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

77 . 77 . 77 . 80 . 80 . . 81 . 83 . 87 . . 91 . 93 . . . . . . . . 97 97 97 99 100 . 101 . 101 102 103

TABLE DES MATIRES 5.3 5.4 Domaines de calcul reprsentation normale . . . 5.3.1 Domaines de calcul lmentaires . . . . . . 5.3.2 Domaines composs . . . . . . . . . . . . . Expressions versus domaines de calcul . . . . . . . 5.4.1 Les expressions comme domaine de calcul . 5.4.2 Exemples : polynmes et formes normales 5.4.3 Exemple : factorisation des polynmes . . 5.4.4 Synthse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

vii . 103 . 105 . 109 . . 111 . . 111 . 112 . 113 . 114

II 6

Algbre et calcul formel

117

Corps nis et thorie des nombres 119 6.1 Anneaux et corps nis . . . . . . . . . . . . . . . . . . . . . . . . 119 6.1.1 Anneau des entiers modulo n . . . . . . . . . . . . . . . . 119 6.1.2 Corps nis . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 6.1.3 Reconstruction rationnelle . . . . . . . . . . . . . . . . . 122 6.1.4 Restes chinois . . . . . . . . . . . . . . . . . . . . . . . . 123 6.2 Primalit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 6.3 Factorisation et logarithme discret . . . . . . . . . . . . . . . . . 127 6.4 Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 6.4.1 La constante . . . . . . . . . . . . . . . . . . . . . . . . 128 6.4.2 Calcul dintgrale multiple via reconstruction rationnelle 129 Polynmes 7.1 Anneaux de polynmes . . . . . . . . . . . . . . 7.1.1 Introduction . . . . . . . . . . . . . . . . 7.1.2 Construction danneaux de polynmes . 7.1.3 Polynmes . . . . . . . . . . . . . . . . . 7.2 Arithmtique euclidienne . . . . . . . . . . . . . 7.2.1 Divisibilit . . . . . . . . . . . . . . . . . 7.2.2 Idaux et quotients . . . . . . . . . . . . 7.3 Factorisation et racines . . . . . . . . . . . . . . 7.3.1 Factorisation . . . . . . . . . . . . . . . . 7.3.2 Recherche de racines . . . . . . . . . . . 7.3.3 Rsultant . . . . . . . . . . . . . . . . . . 7.3.4 Groupe de Galois . . . . . . . . . . . . . 7.4 Fractions rationnelles . . . . . . . . . . . . . . . 7.4.1 Construction et proprits lmentaires . 7.4.2 Dcomposition en lments simples . . . 7.4.3 Reconstruction rationnelle . . . . . . . . 7.5 Sries formelles . . . . . . . . . . . . . . . . . . . 7.5.1 Oprations sur les sries tronques . . . . 7.5.2 Dveloppement de solutions dquations . 7.5.3 Sries paresseuses . . . . . . . . . . . . . 7.6 Reprsentation informatique des polynmes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 . 132 . 132 . 132 . 134 . 137 . 137 . 140 . . 141 . 142 . 143 . 145 . 146 . 147 . 147 . 147 . 149 . . 151 . 152 . 154 . 155 . 156

viii 8

TABLE DES MATIRES Algbre linaire 159 8.1 Constructions et manipulations lmentaires . . . . . . . . . . . 159 8.1.1 Espaces de vecteurs, de matrices . . . . . . . . . . . . . . 159 8.1.2 Construction des matrices et des vecteurs . . . . . . . . . . 161 8.1.3 Manipulations de base et arithmtique sur les matrices . 162 8.1.4 Oprations de base sur les matrices . . . . . . . . . . . . 164 8.2 Calculs sur les matrices . . . . . . . . . . . . . . . . . . . . . . . 164 8.2.1 limination de Gauss, forme chelonne . . . . . . . . . . 165 8.2.2 Rsolution de systmes ; image et base du noyau . . . . . 172 8.2.3 Valeurs propres, forme de Jordan et transformations de similitude . . . . . . . . . . . . . . . . . . . . . . . . . . . 174 Systmes polynomiaux 9.1 Polynmes plusieurs indtermines . . . . . . 9.1.1 Les anneaux A[x1 , . . . , xn ] . . . . . . . 9.1.2 Polynmes . . . . . . . . . . . . . . . . 9.1.3 Oprations de base . . . . . . . . . . . 9.1.4 Arithmtique . . . . . . . . . . . . . . . 9.2 Systmes polynomiaux et idaux . . . . . . . . 9.2.1 Un premier exemple . . . . . . . . . . . 9.2.2 Quest-ce que rsoudre ? . . . . . . . . 9.2.3 Idaux et systmes . . . . . . . . . . . 9.2.4 limination . . . . . . . . . . . . . . . 9.2.5 Systmes de dimension zro . . . . . . 9.3 Bases de Grbner . . . . . . . . . . . . . . . . 9.3.1 Ordres monomiaux . . . . . . . . . . . 9.3.2 Division par une famille de polynmes 9.3.3 Bases de Grbner . . . . . . . . . . . . 9.3.4 Proprits des bases de Grbner . . . . 9.3.5 Calcul . . . . . . . . . . . . . . . . . . 183 183 183 185 187 187 188 188 192 192 197 203 207 208 209 210 214 217

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

10 quations direntielles et rcurrences 10.1 quations direntielles . . . . . . . . . . . . . . . . 10.1.1 Introduction . . . . . . . . . . . . . . . . . . 10.1.2 quations direntielles ordinaires dordre 1 10.1.3 quations dordre 2 . . . . . . . . . . . . . . 10.1.4 Transforme de Laplace . . . . . . . . . . . . 10.1.5 Systmes direntiels linaires . . . . . . . . 10.2 Suites dnies par une relation de rcurrence . . . . 10.2.1 Suites dnies par un+1 = f (un ) . . . . . . . 10.2.2 Suites rcurrentes linaires . . . . . . . . . . 10.2.3 Suites rcurrentes avec second membre .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

221 . . 221 . . 221 . 222 . 230 . . 231 . 233 . 235 . 235 . 237 . 238

TABLE DES MATIRES III Calcul numrique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

ix 239 241 . . 241 . . 241 . 242 . 242 . 243 . 245 . 245 . 245 . 246 . 246 . . 251 . 252 . 253 255 . 255 . 255 . 256 . 257 . 257 . 258 . 260 . . 261 . 262 . 264 277 278 278 . 281 . 281 282 282 283 283 284 285 288 293 295 296 297 298

11 Nombres virgule ottante 11.1 Introduction . . . . . . . . . . . . . . . . 11.1.1 Dnition . . . . . . . . . . . . . 11.1.2 Proprits, exemples . . . . . . . 11.1.3 Normalisation . . . . . . . . . . . 11.2 Les nombres ottants . . . . . . . . . . . 11.2.1 Quel type de nombres choisir ? . . 11.3 Proprits des nombres virgule ottante 11.3.1 Des ensembles pleins de trous . . 11.3.2 Larrondi . . . . . . . . . . . . . . 11.3.3 Quelques proprits . . . . . . . . 11.3.4 Nombres ottants complexes . . . 11.3.5 Mthodes . . . . . . . . . . . . . . 11.4 En guise de conclusion . . . . . . . . . . .

12 quations non linaires 12.1 quations algbriques . . . . . . . . . . . . . . 12.1.1 Mthode Polynomial.roots() . . . . . 12.1.2 Reprsentation des nombres . . . . . . 12.1.3 Thorme de dAlembert . . . . . . . . 12.1.4 Distribution des racines . . . . . . . . . 12.1.5 Rsolution par radicaux . . . . . . . . . 12.1.6 Mthode Expression.roots() . . . . . 12.2 Rsolution numrique . . . . . . . . . . . . . . 12.2.1 Localisation des solutions des quations 12.2.2 Mthodes dapproximations successives

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . algbriques . . . . . . .

13 Algbre linaire numrique 13.1 Calculs inexacts en algbre linaire . . . . . . . . . . . . . . . . . 13.1.1 Normes de matrices et conditionnement . . . . . . . . . . 13.2 Matrices pleines . . . . . . . . . . . . . . . . . . . . . . . . . . . 13.2.1 Rsolution de systmes linaires . . . . . . . . . . . . . . 13.2.2 Rsolution directe . . . . . . . . . . . . . . . . . . . . . . 13.2.3 La dcomposition LU . . . . . . . . . . . . . . . . . . . . 13.2.4 La dcomposition de Cholesky des matrices relles symtriques dnies positives . . . . . . . . . . . . . . . . . . 13.2.5 La dcomposition QR . . . . . . . . . . . . . . . . . . . . 13.2.6 La dcomposition en valeurs singulires . . . . . . . . . . 13.2.7 Application aux moindres carrs . . . . . . . . . . . . . . 13.2.8 Valeurs propres, vecteurs propres . . . . . . . . . . . . . 13.2.9 Ajustement polynomial : le retour du diable . . . . . . . 13.2.10 Implantation et performances . . . . . . . . . . . . . . . 13.3 Matrices creuses . . . . . . . . . . . . . . . . . . . . . . . . . . . 13.3.1 Origine des systmes creux . . . . . . . . . . . . . . . . . 13.3.2 Sage et les matrices creuses . . . . . . . . . . . . . . . .

TABLE DES MATIRES 13.3.3 Rsolution de systmes linaires . . . . 13.3.4 Valeurs propres, vecteurs propres . . . 13.3.5 Thme de rexion : rsolution de trs non linaires . . . . . . . . . . . . . . . . . . . . . . . . . 298 . . . . . . . . . . 300 grands systmes . . . . . . . . . . . 301 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 303 309 315 317 318 321 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323 324 324 326 333 333 334 336 339 346 347 347 349 350 352

14 Intgration numrique 14.1 Intgration numrique . . . . . . . . . . . . 14.1.1 Fonctions dintgration disponibles 14.2 Rsolution dquations direntielles . . . . 14.2.1 Exemple de rsolution . . . . . . . . 14.2.2 Fonctions de rsolution disponibles IV Combinatoire

. . . . .

. . . . .

15 Dnombrement et combinatoire 15.1 Premiers exemples . . . . . . . . . . . . . . . . . . . 15.1.1 Jeu de poker et probabilits . . . . . . . . . . 15.1.2 Dnombrement darbres par sries gnratrices 15.2 Ensembles numrs usuels . . . . . . . . . . . . . . . 15.2.1 Exemple : les sous-ensembles dun ensemble . 15.2.2 Partitions dentiers . . . . . . . . . . . . . . . 15.2.3 Quelques autres ensembles nis numrs . . . 15.2.4 Comprhensions et itrateurs . . . . . . . . . . 15.3 Constructions . . . . . . . . . . . . . . . . . . . . . . . 15.4 Algorithmes gnriques . . . . . . . . . . . . . . . . . 15.4.1 Gnration lexicographique de listes dentiers 15.4.2 Points entiers dans les polytopes . . . . . . . . 15.4.3 Espces, classes combinatoires dcomposables 15.4.4 Graphes un isomorphisme prs . . . . . . . .

16 Thorie des graphes 16.1 Construire un graphe . . . . . . . . . . . . . . . . . . . 16.1.1 partir de zro . . . . . . . . . . . . . . . . . . 16.1.2 Les constructeurs disponibles . . . . . . . . . . . 16.1.3 Unions disjointes . . . . . . . . . . . . . . . . . 16.1.4 Achage des graphes . . . . . . . . . . . . . . . 16.2 Mthodes de la classe Graph . . . . . . . . . . . . . . . 16.2.1 Modication de la structure dun graphe . . . . 16.2.2 Oprateurs . . . . . . . . . . . . . . . . . . . . . 16.2.3 Parcours de graphes et distances . . . . . . . . . 16.2.4 Flots, connectivit, couplage (matching) . . . . 16.2.5 Problmes NP-complets . . . . . . . . . . . . . . 16.2.6 Reconnaissance et test de proprits . . . . . . . 16.3 Graphes en action . . . . . . . . . . . . . . . . . . . . . 16.3.1 Coloration gloutonne des sommets dun graphe . 16.3.2 Gnrer des graphes sous contraintes . . . . . .

355 . 355 . 355 . 357 . 360 . . 361 . 364 . 365 . 365 . 366 . 367 . 368 . 370 . 372 . 372 . 374

TABLE DES MATIRES 16.3.3 Appliquer un algorithme probabiliste pour trouver un grand ensemble indpendant . . . . . . . . . . . . . . . . 16.3.4 Trouver un sous-graphe induit dans un graphe alatoire . 16.4 Quelques problmes modliss par des graphes . . . . . . . . . . 16.4.1 Une nigme du journal Le Monde 2 . . . . . . . . . . 16.4.2 Aectation de tches . . . . . . . . . . . . . . . . . . . . 16.4.3 Planier un tournoi . . . . . . . . . . . . . . . . . . . . . 17 Programmation linaire 17.1 Dnition . . . . . . . . . . . . . . . . . . . . . 17.2 Programmation entire . . . . . . . . . . . . . 17.3 En pratique . . . . . . . . . . . . . . . . . . . . 17.3.1 La classe MixedIntegerLinearProgram 17.3.2 Variables . . . . . . . . . . . . . . . . . 17.3.3 Problmes infaisables ou non borns . . 17.4 Premires applications la combinatoire . . . 17.4.1 Sac dos . . . . . . . . . . . . . . . . . 17.4.2 Couplages . . . . . . . . . . . . . . . . 17.4.3 Flot . . . . . . . . . . . . . . . . . . . . 17.5 Gnration de contraintes et application . . . . Annexes A Solutions des exercices A.1 Premiers pas . . . . . . . . . . . . . . . . . . . A.2 Analyse et algbre avec Sage . . . . . . . . . . A.4 Graphiques . . . . . . . . . . . . . . . . . . . . A.5 Domaines . . . . . . . . . . . . . . . . . . . . . A.6 Corps nis et thorie lmentaire des nombres A.7 Polynmes . . . . . . . . . . . . . . . . . . . . A.8 Algbre linaire . . . . . . . . . . . . . . . . . A.9 Systmes polynomiaux . . . . . . . . . . . . . . A.10 quations direntielles et rcurrences . . . . . A.11 Nombres virgule ottante . . . . . . . . . . . A.12 quations non linaires . . . . . . . . . . . . . A.13 Algbre linaire numrique . . . . . . . . . . . A.14 Intgration numrique . . . . . . . . . . . . . . A.15 Dnombrement et combinatoire . . . . . . . . . A.16 Thorie des graphes . . . . . . . . . . . . . . . A.17 Programmation linaire . . . . . . . . . . . . . B Bibliographie C Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

xi

375 376 378 378 379 380

383 . 383 . 384 . 384 . 384 . 385 . 386 . 387 . 387 . 388 . 389 . . 391 399 399 . 399 . 399 . 408 . . 411 . 412 . 417 . . 421 . 422 . 426 . 427 . 430 . 433 . 434 . 435 . . 441 . 442 445 449

xii

TABLE DES MATIRES

Premire partie

Prise en main de Sage

Premiers pas
Ce chapitre dintroduction prsente la tournure desprit du logiciel mathmatique Sage. Les autres chapitres de cette partie dveloppent les notions de base de Sage : eectuer des calculs numriques ou symboliques en analyse, oprer sur des vecteurs et des matrices, crire des programmes, manipuler des listes de donnes, construire des graphiques, etc. Les parties suivantes de cet ouvrage approfondissent quelques branches des mathmatiques dans lesquelles linformatique fait preuve dune grande ecacit.

1.1
1.1.1

Le logiciel Sage
Un outil pour les mathmatiques

Sage est un logiciel qui implante des algorithmes mathmatiques dans des domaines varis. En premier lieu, le systme opre sur direntes sortes de nombres : les nombres entiers ou rationnels, les approximations numriques des rels et des complexes, avec une prcision variable, ou encore les lments des corps nis. Lutilisateur peut trs rapidement se servir de Sage comme de nimporte quelle calculette scientique ventuellement graphique. Mais le calcul mathmatique ne se limite pas aux nombres. Les collgiens apprennent par exemple rsoudre des quations anes, dvelopper, simplier, et parfois factoriser des expressions contenant des variables. Sage est aussi et surtout un systme de calcul formel, capable deectuer les calculs algbriques de ce genre y compris, pour une utilisation plus avance, dans un anneau de polynmes ou un corps de fractions rationnelles prcis. Ct analyse, Sage reconnat les fonctions usuelles comme la racine carre, la puissance, lexponentielle, le logarithme ou les fonctions trigonomtriques, et

CHAP. 1. PREMIERS PAS

Objectifs et dveloppement de Sage William Stein, un enseignant-chercheur amricain, commence le dveloppement de Sage en 2005 dans le but dcrire un logiciel de calcul mathmatique dont tout le code source soit accessible et lisible. Le logiciel est dabord centr sur le domaine de recherche de son auteur, la thorie des nombres. Progressivement se forme une communaut internationale de plusieurs centaines de dveloppeurs, la plupart enseignants ou chercheurs. Au fur et mesure des contributions, les fonctionnalits stendent pour couvrir bien dautres domaines des mathmatiques, ce qui fait de Sage le logiciel gnraliste quil est aujourdhui. Non seulement Sage est tlchargeable et utilisable gratuitement, mais cest un logiciel libre. Ses auteurs nimposent aucune restriction sa diusion, son installation et mme sa modication, pourvu que les versions modies soient, elles aussi, libres. Si Sage tait un livre, il pourrait tre emprunt et photocopi sans limite dans toutes les bibliothques ! Cette licence est en harmonie avec la diusion des connaissances vise par lenseignement et la recherche. Le dveloppement de Sage est relativement rapide car il privilgie la rutilisation de logiciels libres existants. Sage lui-mme est crit en Python, un langage de programmation largement utilis et rput facile apprendre. Ce code Python fait abondamment appel aux logiciels mathmatiques prexistants fournis avec Sage. Comme presque tous les logiciels de calcul mathmatique, Sage sutilise en saisissant des commandes crites dans un langage informatique. Mais il ny a pas proprement parler de langage Sage : cest Python qui joue ce rle, avec quelques raccourcis syntaxiques pour allger les notations mathmatiques. Les instructions entres par lutilisateur sont values par linterprteur Python. Il est possible, pour faire des calculs complexes ou simplement rptitifs, dcrire de vritables programmes au lieu de simples commandes dune ligne, voire, pourquoi pas, de les proposer pour inclusion dans Sage !

Figure 1.1 La premire apparition du nom de Sage, sur un carnet de W. Stein. Originellement Sage tait aussi un acronyme ; lorsque le systme sest largi lensemble des mathmatiques, seul le nom de la sauge sage en anglais est rest.

1.1. LE LOGICIEL SAGE

Figure 1.2 Une feuille de travail dans le bloc-notes de Sage.

les expressions formes partir de celles-ci. Il eectue drivations, intgrations et calculs de limites, simplie les sommes, dveloppe en sries, rsout certaines quations direntielles... Sage eectue les oprations usuelles de lalgbre linaire sur les vecteurs, les matrices et les sous-espaces vectoriels. Il permet aussi daborder, dillustrer et de traiter de direntes faons les probabilits, les statistiques et les questions de dnombrement. Ainsi, les domaines mathmatiques traits par Sage sont multiples, de la thorie des groupes lanalyse numrique. Il peut aussi reprsenter graphiquement les rsultats obtenus sous la forme dune image, dun volume, ou dune animation. Utiliser un mme logiciel pour aborder ces dirents aspects des mathmatiques libre le mathmaticien, quel que soit son niveau, des problmes de transfert de donnes entre divers outils et de lapprentissage des syntaxes de plusieurs langages informatiques. Sage se veut homogne entre ces dirents domaines.

1.1.2

Accs Sage

Pour utiliser Sage, il sut dun navigateur web tel que Firefox. Le plus simple dans un premier temps est de se connecter sur un serveur de calcul Sage public comme http://sagenb.org/. On a alors accs une interface utilisateur riche constitue dun bloc-notes (notebook en anglais) permettant dditer et partager des feuilles de travail (worksheets, voir gure 1.2). De nombreuses universits et institutions mettent de tels serveurs la disposition de leurs utilisateurs ; renseignez-vous autour de vous. Pour un usage plus intensif, on

CHAP. 1. PREMIERS PAS

Figure 1.3 Sage en ligne de commande.

installe gnralement Sage sur sa propre machine 1 . On peut alors toujours lutiliser avec linterface bloc-notes dans le navigateur web. Alternativement, on peut lutiliser en ligne de commande, comme une calculatrice (voir gure 1.3). Les gures 1.4 et 1.5 illustrent pas pas les tapes pour accder un serveur Sage public et lutiliser pour faire un calcul : 1. Ouvrez votre navigateur web et connectez-vous au site http://sagenb.org (gure 1.4). Vous pouvez ds prsent consulter les feuilles de travail publiques accessibles par le lien Browse published Sage worksheets. 2. Pour travailler sur vos propres feuilles de travail, vous devez vous authentier ; pour cela sagenb.org utilise le systme OpenID 2 . Si vous avez dj, par exemple, un compte Google ou Yahoo, il vous sut de suivre les liens correspondants. Sinon, vous devez dabord crer un compte OpenID 3 . Ensuite, il ne restera qu revenir sur la page daccueil, suivre le lien OpenID, et entrer votre identiant OpenID (par exemple http://votre-nom.myopenid.com/). 3. Vous tes maintenant sur la page principale de linterface web de Sage, depuis laquelle vous pouvez grer vos feuilles de travail. Crez-en une nouvelle (Create worksheet ) et donnez-lui un nom (Rename worksheet ). 4. Saisissez ensuite 1 + 1 dans la cellule de calcul, puis cliquez sur evaluate ou formez la combinaison de touches Alt + Entre (gure 1.5). Bravo, vous avez fait votre premier calcul avec Sage !
1. Sage est disponible pour la plupart des systmes dexploitation : Linux, Windows, Mac os x et Solaris. 2. Voir http://fr.wikipedia.org/wiki/OpenID. 3. ladresse https://www.myopenid.com/signup ou auprs de nimporte lequel des fournisseurs indiqus sur http://openid.net/get-an-openid/.

1.1. LE LOGICIEL SAGE

Figure 1.4 Connectez-vous sur http://sagenb.org...

Figure 1.5 Saisissez une commande, puis cliquez sur evaluate...

CHAP. 1. PREMIERS PAS

1.1.3

Ressources

Si vous lisez langlais, cest maintenant le bon moment pour jeter un coup dil longlet Help (gure 1.6). Vous y trouverez en particulier toutes les commandes pour diter votre feuille de travail ainsi quun tutoriel interactif (Tutorial ). Les adresses suivantes pointent vers le site internet de rfrence de Sage et quelques autres pages dinformations, dont une traduction franaise de ce tutoriel. http://www.sagemath.org/ site ociel http://www.sagemath.org/fr/ site ociel en franais http://www.sagemath.org/doc/ documentation http://www.sagemath.org/fr/html/tutorial/ tutoriel en franais http://wiki.sagemath.org/quickref ches de commandes http://ask.sagemath.org/ forum daide Par ailleurs, plusieurs listes de diusion accueillent les discussions des utilisateurs. La liste sage-support@googlegroups.com, en langue anglaise, est la plus adapte aux questions techniques. Les francophones peuvent aussi dialoguer sur la liste sagemath-edu@irem.univ-mrs.fr, consacre principalement lutilisation de Sage dans lenseignement.

1.2
1.2.1

Sage comme calculatrice


Premiers calculs

Dans la suite du livre, nous prsentons les calculs sous la forme suivante, qui imite lallure dune session Sage en ligne de commande : sage: 1+1 2 Le texte sage: au dbut de la premire ligne est linvite du systme. Linvite (qui napparat pas dans linterface bloc-notes) indique que Sage attend une commande de lutilisateur. La suite de la ligne correspond la commande saisir, puis valider en appuyant sur Entre . Les lignes suivantes correspondent la rponse du systme, cest--dire en gnral au rsultat du calcul. Certaines instructions stendent sur plusieurs lignes (voir chapitre 3). Les lignes de commande supplmentaires sont alors indiques par ... en dbut de ligne. Une commande sur plusieurs lignes doit tre saisie en respectant la position des retours la ligne et lventuelle indentation (dcalage par des espaces par rapport la ligne qui prcde) des lignes supplmentaires, sans recopier la marque ... qui les introduit. Dans le bloc-notes, on entre directement la commande indique dans une cellule de calcul, et on valide en cliquant sur evaluate ou en appuyant sur Maj + Entre . La combinaison de touches Alt + Entre cre une nouvelle cellule au-dessous de la cellule courante en plus de valider la commande. On peut aussi ajouter une cellule en cliquant dans lespace vertical juste au-dessus dune cellule existante ou au-dessous de la dernire cellule. Sage interprte les formules simples comme une calculatrice scientique. Les oprations +, , etc. ont leur priorit usuelle, et les parenthses leur rle habituel :

1.2. SAGE COMME CALCULATRICE

Figure 1.6 Laide du bloc-notes.

sage: ( 1 + 2 * (3 + 5) ) * 2 34 Ci-dessus, le signe * reprsente la multiplication. Il ne doit pas tre omis, mme dans des expressions comme 2x. La puissance se note ^ ou ** : sage: 2^3 8 sage: 2**3 8 et la division par / : sage: 20/6 10/3 Observons que le calcul est fait de manire exacte : le rsultat de la division, aprs simplication, est le nombre rationnel 10/3 et non une approximation comme 3,33333. Il ny a pas de limite 4 la taille des nombres entiers ou rationnels manipuls : sage: 2^10 1024 sage: 2^100 1267650600228229401496703205376 sage: 2^1000
4. Hormis celle lie la mmoire de lordinateur utilis.

10

CHAP. 1. PREMIERS PAS

Oprateurs arithmtiques de base quatre oprations puissance racine carre racine n-ime a+b, a-b, a*b, a^b ou a**b sqrt(a) a^(1/n) a/b

Oprations sur les entiers division entire modulo factorielle n! coecients binomiaux n k a // b a % b factorial(n) binomial(n,k)

Fonctions usuelles sur les rels, les complexes... partie entire valeur absolue, module fonctions lmentaires floor(a) abs(a) sin, cos,

... (voir tableau 2.2)

Tableau 1.1 Quelques oprations usuelles.

1071508607186267320948425049060001810561404811705533607443750\ 3883703510511249361224931983788156958581275946729175531468251\ 8714528569231404359845775746985748039345677748242309854210746\ 0506237114187795418215304647498358194126739876755916554394607\ 7062914571196477686542167660429831652624386837205668069376 Pour obtenir une approximation numrique, il sut dcrire au moins lun des nombres avec un point dcimal (on pourrait remplacer 20.0 par 20. ou 20.000) : sage: 20.0 / 14 1.42857142857143 Par ailleurs, la fonction numerical_approx prend le rsultat dun calcul exact et en donne une approximation numrique : sage: numerical_approx(20/14) 1.42857142857143 sage: numerical_approx(2^1000) 1.07150860718627e301 Il est possible de calculer des approximations prcision arbitrairement grande. Augmentons par exemple celle-ci 60 chires pour bien mettre en vidence la priodicit du dveloppement dcimal dun nombre rationnel : sage: numerical_approx(20/14, digits=60) 1.42857142857142857142857142857142857142857142857142857142857 Nous revenons sur les dirences entre calcul exact et numrique dans lencadr page 12. Les oprateurs // et % donnent le quotient et le reste de la division de deux entiers :

1.2. SAGE COMME CALCULATRICE sage: 20 // 6 3 sage: 20 % 6 2

11

De nombreuses autres fonctions sappliquent aux entiers. Parmi celles qui leur sont spciques, citons par exemple la factorielle ou les coecients binomiaux (voir tableau 1.1) : sage: factorial(100) 93326215443944152681699238856266700490715968264381621\ 46859296389521759999322991560894146397615651828625369\ 7920827223758251185210916864000000000000000000000000 Voici enn une manire de dcomposer un entier en facteurs premiers. Nous reviendrons sur ce problme au chapitre 5, puis nouveau au chapitre 6. sage: factor(2^(2^5)+1) 641 * 6700417 Fermat avait conjectur que tous les nombres de la forme 22 + 1 taient premiers. Lexemple ci-dessus est le plus petit qui invalide sa conjecture.
n

1.2.2

Fonctions lmentaires et constantes usuelles

On retrouve les fonctions et constantes usuelles (voir tableaux 1.1 et 1.2), y compris pour les nombres complexes. L encore, les calculs sont exacts : sage: sin(pi) 0 sage: tan(pi/3) sqrt(3) sage: arctan(1) 1/4*pi sage: exp(2 * I * pi) 1 quitte renvoyer des formules plutt que des valeurs numriques : sage: arccos(sin(pi/3)) arccos(1/2*sqrt(3)) sage: sqrt(2) sqrt(2) sage: exp(I*pi/6) e^(1/6*I*pi) Les formules que lon obtient ne sont pas toujours celles que lon attend. En eet, peu de simplications sont faites automatiquement. Quand un rsultat semble trop compliqu, on peut essayer dappeler explicitement une fonction de simplication : sage: simplify(arccos(sin(pi/3)))

12

CHAP. 1. PREMIERS PAS

Calcul formel et mthodes numriques Un systme de calcul formel est un logiciel qui a pour but de manipuler, de simplier et de calculer des formules mathmatiques en appliquant uniquement des transformations exactes. Le terme formel soppose ici numrique ; il signie que les calculs sont eectus sur des formules, de faon algbrique, en manipulant formellement des symboles. Pour cette raison lexpression calcul symbolique est parfois employe la place de calcul formel. En anglais, on dit computer algebra ou parfois symbolic computation. Les calculatrices manipulent de faon exacte les nombres entiers ayant moins dune douzaine de chires ; les nombres plus grands sont arrondis, ce qui entrane des erreurs. Ainsi une calculatrice numrique value de faon errone lexpression suivante en obtenant 0 la place de 1 : (1 + 1050 ) 1050 . De telles erreurs sont dicilement dtectables si elles se produisent lors dun calcul intermdiaire sans tre prvues ni facilement prvisibles par une tude thorique. Les systmes de calcul formel, au contraire, sappliquent repousser ces limites et ne faire aucune approximation sur les nombres entiers pour que les oprations qui en dcoulent soient exactes : ils rpondent 1 au calcul prcdent. Les mthodes danalyse numrique approchent une prcision donne (par une mthode des trapzes, de Simpson, de Gauss, etc.) lintgrale 0 cos t dt pour obtenir un rsultat numrique plus ou moins proche de zro ( 1010 prs par exemple) sans pouvoir armer si le rsultat est le nombre entier 0 de faon exacte ou au contraire est proche de zro mais est non nul. Un systme formel transforme par une manipulation de symboles math matiques lintgrale 0 cos t dt en la formule sin sin 0 qui est ensuite value de faon exacte en 0 0 = 0. Cette mthode prouve donc 0 cos t dt = 0. Cependant les transformations uniquement algbriques ont aussi des limites. La plupart des expressions manipules par les systmes formels sont des fractions rationnelles et lexpression a/a est automatiquement simplie en 1. Ce mode de calcul algbrique ne convient pas la rsolution des quations ; dans ce cadre, la solution de lquation ax = a est x = a/a qui est simplie en x = 1 sans distinguer suivant la valeur de a par rapport 0, valeur particulire pour laquelle tout nombre x est solution (voir aussi 2.1.5).

1.2. SAGE COMME CALCULATRICE

13

Quelques valeurs spciales valeurs de vrit vrai et faux unit imaginaire i inni True, False I ou i infinity ou

oo

Constantes mathmatiques usuelles constante dArchimde base du logarithme naturel e = exp(1) constante dEuler-Mascheroni nombre dor = (1 + 5)/2 constante de Catalan pi e euler_gamma golden_ratio catalan

Tableau 1.2 Constantes prdnies.

1/6*pi sage: simplify(exp(i*pi/6)) 1/2*sqrt(3) + 1/2*I Nous verrons en 2.1 comment contrler plus nement la simplication des expressions. Naturellement, on peut aussi calculer des approximations numriques (le plus souvent, prcision aussi grande que lon veut) des rsultats : sage: numerical_approx(6*arccos(sin(pi/3)), digits=60) 3.14159265358979323846264338327950288419716939937510582097494 sage: numerical_approx(sqrt(2), digits=60) 1.41421356237309504880168872420969807856967187537694807317668

1.2.3

Aide en ligne et compltion automatique

On peut accder interactivement au manuel de rfrence de toute fonction, constante ou commande en la faisant suivre dun point dinterrogation ? : sage: sin? La page de documentation (en anglais) contient la description de la fonction, sa syntaxe et des exemples dutilisation. La touche tabulation Tab la suite dun dbut de mot montre quelles sont les commandes commenant par ces lettres : arc suivi de la touche Tab ache ainsi le nom de toutes les fonctions trigonomtriques rciproques : sage: arc<tab> Possible completions are: arc arccos arccosh arccot arccoth arccsc arccsch arcsec arcsech arcsin arcsinh arctan arctan2 arctanh

1.2.4

Variables Python

Lorsque lon veut conserver le rsultat dun calcul, on peut laecter une variable :

14 sage: y = 1 + 2 pour le rutiliser par la suite : sage: y 3 sage: (2 + y) * y 15

CHAP. 1. PREMIERS PAS

Noter que le rsultat du calcul nest pas ach par dfaut lors dune aectation. Aussi, nous utiliserons souvent le raccourci suivant : sage: y = 1 + 2; y 3 le signe ; permettant de sparer plusieurs instructions sur la mme ligne. Le calcul du rsultat est eectu avant laectation. On peut donc rutiliser la mme variable : sage: y = 3 * y + 1; y 10 sage: y = 3 * y + 1; y 31 sage: y = 3 * y + 1; y 94 Enn Sage conserve le rsultat des trois calculs prcdents dans les variables spciales _, __ et ___ : sage: 1 + 1 2 sage: _ + 1 3 sage: __ 2 Les variables que nous venons de manipuler sont des variables au sens de la programmation Python ; nous y reviendrons plus en dtail en 3.1.3. Mentionnons seulement quil est recommand de ne pas craser les constantes ni les fonctions prdnies de Sage. Le faire ne perturbe pas le fonctionnement interne de Sage, mais les rsultats ultrieurs de vos calculs ou de vos programmes pourraient tre troublants : sage: pi = -I/2 sage: exp(2*i*pi) e Pour restaurer la valeur dorigine, on peut utiliser une instruction comme : sage: from sage.all import pi

1.2. SAGE COMME CALCULATRICE

15

1.2.5

Variables symboliques

Nous navons jusquici manipul que des expressions constantes telles que sin( 2). Sage permet aussi et surtout de calculer avec des expressions contenant des variables, comme x + y + z ou encore sin(x) + cos(x). Les variables symboliques du mathmaticien x, y, z apparaissant dans ces expressions dirent, en Sage, des variables du programmeur que nous avons rencontres dans la section prcdente. Sage dire notablement, sur ce point, dautres systmes de calcul formel comme Maple ou Maxima. Les variables symboliques doivent tre explicitement dclares avant dtre employes 5 : sage: z = SR.var( z ) sage: 2*z + 3 2*z + 3 Dans cet exemple, la commande SR.var(z) construit et renvoie une variable symbolique dont le nom est z . Cette variable symbolique est un objet Sage comme un autre : elle nest pas traite diremment dexpressions plus complexes comme sin(x) + 1. Ensuite, cette variable symbolique est aecte la variable du programmeur z, ce qui permet de sen servir comme de nimporte quelle expression pour construire des expressions plus complexes. On aurait pu tout aussi bien aecter z une autre variable que z : sage: y = SR.var( z ) sage: 2*y + 3 2*z + 3 Aecter systmatiquement la variable symbolique z la variable z nest donc quune simple convention, mais elle est recommande pour viter les confusions. Inversement, la variable z ninterfre en rien avec la variable symbolique z : sage: sage: sage: 2*z + sage: 2*z + c = 2 * y + 3 z = 1 2*y + 3 3 c 3

Comment faire alors pour donner une valeur une variable symbolique qui apparat dans une expression ? On utilise lopration de substitution, comme dans sage: x = SR.var( x ) sage: expr = sin(x); expr sin(x) sage: expr(x=1) sin(1)
5. En fait, la variable symbolique x est prdnie dans Sage. Mais cest la seule.

16

CHAP. 1. PREMIERS PAS

La substitution dans les expressions symboliques est prsente en dtail au chapitre suivant.
Exercice 1. Expliquer pas pas ce quil se passe lors de la squence dinstructions : sage: sage: sage: sage: u + 2 u = SR.var( u ) u = u+1 u = u+1 u

Comme il serait un peu laborieux de crer un grand nombre de variables symboliques de cette manire, il existe un raccourci var(x) qui est quivalent x = SR.var(x). Plus gnralement on peut faire par exemple : sage: var( a, b, c, x, y ) (a, b, c, x, y) sage: a * x + b * y + c a*x + b*y + c Si la dclaration explicite des variables symboliques est juge trop lourde, il est aussi possible dmuler le comportement de systmes comme Maxima ou Maple. Pour linstant (Sage 5.9), cette fonctionnalit nest disponible que dans le bloc-notes. Dans celui-ci, aprs un appel : sage: automatic_names(True) toute utilisation dune variable non aecte dclenche implicitement la cration dune variable symbolique du mme nom et son aectation : sage: 2 * bla + 3 2*bla + 3 sage: bla bla

1.2.6

Premiers graphiques

La commande plot permet de tracer facilement la courbe reprsentative dune fonction relle sur un intervalle donn. La commande plot3d sert aux tracs en trois dimensions, comme le graphe dune fonction relle de deux variables. Voici les commandes utilises pour produire les graphiques qui apparaissent sur la capture dcran en gure 1.3 (page 6) : sage: plot(sin(2*x), x, -pi, pi) sage: plot3d(sin(pi*sqrt(x^2 + y^2))/sqrt(x^2+y^2), ....: (x,-5,5), (y,-5,5)) Les capacits graphiques de Sage vont bien au-del de ces exemples. Nous les explorerons plus en dtail au chapitre 4.

Analyse et algbre
Ce chapitre prsente travers des exemples simples les fonctions de base utiles en analyse et en algbre. Les lycens et tudiants trouveront matire remplacer le crayon et le papier par le clavier et lcran tout en relevant le mme d intellectuel de comprhension des mathmatiques. Cet expos des principales commandes de calcul avec Sage se veut accessible aux lves de lyce ; gurent galement des complments signals par un astrisque (*) pour les tudiants de premire anne de licence. On renvoie aux autres chapitres pour plus de dtails.

2.1
2.1.1

Expressions symboliques et simplication


Expressions symboliques

Sage permet deectuer toutes sortes de calculs danalyse partir dexpressions symboliques combinant des nombres, des variables symboliques, les quatre oprations, et des fonctions usuelles comme sqrt, exp, log, sin, cos, etc. Une expression symbolique peut tre reprsente par un arbre comme ceux de la gure 2.1. Il est important de comprendre quune expression symbolique est une formule et non pas une valeur ou une fonction mathmatique. Ainsi, Sage ne reconnat pas que les deux expressions suivantes sont gales 1 : sage: bool(arctan(1+abs(x)) == pi/2 - arctan(1/(1+abs(x)))) False
1. Le test dgalit == nest par pour autant une simple comparaison syntaxique des formules : par exemple, avec Sage 5.9, les expressions arctan(sqrt(2)) et pi/2-arctan(1/sqrt(2)) sont considres comme gales. En fait, quand on compare deux expressions avec bool(x==y), Sage tente de prouver que leur dirence est nulle, et renvoie True si cela russit.

18 + ^ x 2 3 * x 2

CHAP. 2. ANALYSE ET ALGBRE * + x 1 x + 2

x^2 + 3*x + 2

(x + 1)*(x + 2)

Figure 2.1 Deux expression symboliques qui reprsentent le mme objet mathmatique.

Cest lutilisateur de transformer les expressions quil manipule an de les mettre sous la forme souhaite, grce aux commandes prsentes dans ce chapitre. Lopration peut-tre la plus commune consiste valuer une expression en donnant une valeur un ou plusieurs des paramtres qui y apparaissent. La mthode subs qui peut tre sous-entendue eectue cette manipulation : sage: a, x = var( a, x ); y = cos(x+a) * (x+1); y (x + 1)*cos(a + x) sage: y.subs(a=-x); y.subs(x=pi/2, a=pi/3); y.subs(x=0.5, a=2.3) x + 1 -1/4*(pi + 2)*sqrt(3) -1.41333351100299 sage: y(a=-x); y(x=pi/2, a=pi/3); y(x=0.5, a=2.3) x + 1 -1/4*(pi + 2)*sqrt(3) -1.41333351100299 Par rapport la notation mathmatique usuelle x f (x), le nom de la variable substitue doit tre indiqu. La substitution avec plusieurs paramtres est faite de faon parallle, alors que plusieurs substitutions eectuent des rcritures squentielles, comme le montrent les deux exemples ci-dessous : sage: x, y, z = var( x, y, z ) ; q = x*y + y*z + z*x sage: bool(q(x=y, y=z, z=x) == q), bool(q(z=y)(y=x) == 3*x^2) (True, True) Notons que pour remplacer une sous-expression plus complexe quune variable, on dispose de la fonction subs_expr : sage: y, z = var( y, z ); f = x^3 + y^2 + z sage: f.subs_expr(x^3 == y^2, z==1) 2*y^2 + 1

2.1.2

Transformation dexpressions

Les expressions avec variables les plus simples sont les polynmes et les fractions rationnelles une ou plusieurs variables. Les fonctions qui permettent de les rcrire sous diverses formes ou de les mettre en forme normale sont

2.1. EXPRESSIONS SYMBOLIQUES ET SIMPLIFICATION Fonctions symboliques

19

Sage permet aussi de dnir des fonctions symboliques pour la manipulation dexpressions : sage: f(x)=(2*x+1)^3 ; f(-3) -125 sage: f.expand() x |--> 8*x^3 + 12*x^2 + 6*x + 1 Une fonction symbolique nest autre quune expression que lon peut appeler comme une commande et o lordre des variables est x. Pour convertir une expression symbolique en fonction symbolique, on utilise soit la syntaxe dj mentionne, soit la mthode function : sage: y = var( y ); u = sin(x) + x*cos(y) sage: v = u.function(x, y); v (x, y) |--> x*cos(y) + sin(x) sage: w(x, y) = u; w (x, y) |--> x*cos(y) + sin(x) Les fonctions symboliques servent modliser des fonctions mathmatiques. Elles nont pas le mme rle que les fonctions (ou procdures ) Python, qui sont des constructions de programmation dcrites dans le chapitre 3. La dirence entre les deux est analogue celle entre variable symbolique et variable Python, prsente en 1.2.5. Une fonction symbolique sutilise pratiquement de la mme manire quune expression, ce qui nest pas le cas dune fonction Python ; par exemple, la mthode expand ne sapplique pas ces dernires.

rsumes dans le tableau 2.1. Par exemple, la mthode expand sert dvelopper les polynmes : sage: sage: sage: x^3 + x, y = SR.var( x,y ) p = (x+y)*(x+1)^2 p2 = p.expand(); p2 x^2*y + 2*x^2 + 2*x*y + x + y

tandis que la mthode collect regroupe les termes suivant les puissances dune variable donne : sage: p2.collect(x) (y + 2)*x^2 + x^3 + (2*y + 1)*x + y Ces fonctions sappliquent aussi des expressions qui sont polynomiales non pas en des variables symboliques, mais en des sous-expressions plus compliques comme sin x : sage: ((x+y+sin(x))^2).expand().collect(sin(x)) 2*(x + y)*sin(x) + x^2 + 2*x*y + y^2 + sin(x)^2

20

CHAP. 2. ANALYSE ET ALGBRE

Polynme

p = zx2 + x2 (x2 + y 2 )(ax 2by ) + zy 2 + y 2 ax3 axy 2 + 2 by 3 + (2 by + z + 1)x2 + y 2 z + y 2 2 bx2 y + 2 by 3 (ax z 1)x2 (ax z 1)y 2 ax3 axy 2 + 2 bx2 y + 2 by 3 + x2 z + y 2 z + x2 + y 2 x2 + y 2 (ax 2 by z 1) x2 + y 2 , 1 , (ax 2 by z 1, 1) , (1, 1) r=
x3 +x2 y +3 x2 +3 xy +2 x+2 y x3 +2 x2 +xy +2 y

p.expand().collect(x) p.collect(x).collect(y) p.expand() p.factor() p.factor_list()

Fraction rationnelle r.simplify_rational() r.factor() r.factor().expand()

(x+1)y +x2 +x x2 +y (x+1)(x+y ) x2 +y xy x2 + x2 x2 +y +y

x x2 +y

y x2 +y

Fraction rationnelle r.combine()

r=

(x1)x x2 7

y2 x2 7

b a

c a

1 x+1

(x1)x+y 2 x2 7

b+c a

1 x+1 1

Fraction rationnelle r.partial_fraction(x)


(x2) 3 (x2 x+1)y 2

r= +

(x3 +1)y2

1 3 (x+1)y 2

Tableau 2.1 Polynmes et fractions rationnelles.

Concernant les fractions rationnelles, la fonction combine permet de regrouper les termes qui ont mme dnominateur. Quant la fonction partial_fraction, elle eectue la dcomposition en lments simples dans Q. (Pour prciser le corps dans lequel il faut eectuer la dcomposition en lments simples, on se reportera au chapitre 7.4.) Les reprsentations les plus usites sont la forme dveloppe pour un polynme, et la forme rduite P/Q avec P et Q dvelopps dans le cas dune fraction rationnelle. Lorsque deux polynmes ou deux fractions rationnelles sont crits sous une de ces formes, il sut de comparer leur coecients pour dcider sils sont gaux : on dit que ces formes sont des formes normales.

2.1.3

Fonctions mathmatiques usuelles

La plupart des fonctions mathmatiques se retrouvent en Sage, en particulier les fonctions trigonomtriques, le logarithme et lexponentielle : elles sont rassembles dans le tableau 2.2. La simplication de telles fonctions est cruciale. Pour simplier une expression ou une fonction symbolique, on dispose de la commande simplify : sage: (x^x/x).simplify() x^(x - 1) Cependant, pour des simplications plus subtiles, on doit prciser le type de simplication attendue :

2.1. EXPRESSIONS SYMBOLIQUES ET SIMPLIFICATION

21

Fonctions mathmatiques usuelles Exponentielle et logarithme Logarithme de base a Fonctions trigonomtriques Fonctions trigonomtriques rciproques Fonctions hyperboliques Fonctions hyperboliques rciproques Partie entire, etc. Racine carre et n-ime exp, log log(x, a) sin, cos, tan arcsin, arccos, arctan sinh, cosh, tanh arcsinh, arccosh, arctanh floor, ceil, trunc, round sqrt, nth_root

Transformation des expressions trigonomtriques Simplication Linarisation Anti-linarisation simplify_trig reduce_trig expand_trig

Tableau 2.2 Fonctions usuelles et simplication.

sage: f = (e^x-1) / (1+e^(x/2)); f.simplify_exp() e^(1/2*x) - 1 Ainsi, pour simplier des expressions trigonomtriques, on utilise la commande simplify_trig : sage: f = cos(x)^6 + sin(x)^6 + 3 * sin(x)^2 * cos(x)^2 sage: f.simplify_trig() 1 Pour linariser (resp. anti-linariser) une expression trigonomtrique, on utilise reduce_trig (resp. expand_trig) : sage: f = cos(x)^6; f.reduce_trig() 15/32*cos(2*x) + 3/16*cos(4*x) + 1/32*cos(6*x) + 5/16 sage: f = sin(5 * x); f.expand_trig() sin(x)^5 - 10*sin(x)^3*cos(x)^2 + 5*sin(x)*cos(x)^4 On peut galement simplier des expressions faisant intervenir des factorielles : sage: n = var( n ); f = factorial(n+1)/factorial(n) sage: f.simplify_factorial() n + 1 La fonction simplify_rational, quant elle, cherche simplier une fraction rationnelle en dveloppant ses membres. Pour simplier des racines carres, des logarithmes ou des exponentielles, on utilise simplify_radical : sage: f = sqrt(abs(x)^2); f.simplify_radical() abs(x) sage: f = log(x*y); f.simplify_radical() log(x) + log(y)

22

CHAP. 2. ANALYSE ET ALGBRE

La commande simplify_full applique (dans lordre) les fonctions simplify_ factorial, simplify_trig, simplify_rational et simplify_radical. Tout ce qui concerne le classique tableau de variation de la fonction (calcul des drives, des asymptotes, des extremums, recherche des zros et trac de la courbe) peut tre facilement ralis laide dun systme de calcul formel. Les principales oprations Sage qui sappliquent une fonction sont prsentes dans la section 2.3.

2.1.4

Hypothses sur une variable symbolique

Lors des calculs, les variables symboliques qui apparaissent dans les expressions sont en gnral considres comme pouvant prendre nimporte quelle valeur complexe. Cela pose problme quand un paramtre reprsente une quantit restreinte un domaine particulier (par exemple, relle positive) dans lapplication que lutilisateur a en tte. Un cas typique est la simplication de lexpression x2 . Pour simplier de telles expressions, la bonne solution consiste utiliser la fonction assume qui permet de prciser les proprits dune variable. Si on souhaite annuler cette hypothse, on emploie linstruction forget : sage: assume(x > 0); bool(sqrt(x^2) == x) True sage: forget(x > 0); bool(sqrt(x^2) == x) False sage: n = var( n ); assume(n, integer ); sin(n*pi).simplify() 0

2.1.5

Quelques dangers

Soit c une expression un tout petit peu complique : sage: a = var( a ) sage: c = (a+1)^2 - (a^2+2*a+1) et cherchons rsoudre lquation en x donne par cx = 0 : sage: eq = c * x == 0 Lutilisateur imprudent pourrait tre tent de simplier cette quation par c avant de la rsoudre : sage: eq2 = eq / c; eq2 x == 0 sage: solve(eq2, x) [x == 0] Heureusement, Sage ne fait pas cette erreur : sage: solve(eq, x) [x == x]

2.1. EXPRESSIONS SYMBOLIQUES ET SIMPLIFICATION Le problme de la simplication

23

Les exemples de la section 2.1.5 illustrent limportance des formes normales, et en particulier du test de nullit. Sans lui, tout calcul faisant intervenir une division devient hasardeux. Certaines familles dexpressions, limage des polynmes, admettent une procdure de dcision pour la nullit. Cela signie que pour ces classes dexpressions, un programme peut dterminer si une expression donne est nulle ou non. Dans de nombreux cas, cette dcision se fait par rduction la forme normale : lexpression est nulle si et seulement si sa forme normale est 0. Malheureusement, toutes les classes dexpressions nadmettent pas une forme normale, et pour certaines classes, on peut dmontrer quil ny a pas de mthode gnrale pour vrier en un temps ni si une expression est nulle. Un exemple dune telle classe est fourni par les expressions composes partir des rationnels, des nombres et log 2 et dune variable, par utilisation rpte de laddition, de la soustraction, du produit, de lexponentielle et du sinus. Une utilisation rpte de numerical_approx en augmentant la prcision permet certes souvent de conjecturer si une expression particulire est nulle ou non ; mais il a t montr quil est impossible dcrire un programme prenant en argument une expression de cette classe et renvoyant le rsultat vrai si celle-ci est nulle, et faux sinon. Cest dans ces classes que se pose avec le plus dacuit le problme de la simplication. Sans forme normale, les systmes ne peuvent que donner un certain nombre de fonctions de rcriture avec lesquelles lutilisateur doit jongler pour parvenir un rsultat. Pour y voir plus clair, il faut identier des sous-classes dexpressions qui admettent des formes normales et savoir quelles fonctions appeler pour calculer ces dernires. Lapproche de Sage face ces dicults est prsente plus en dtail au chapitre 5.

Ici, Sage a pu rsoudre correctement le systme car le coecient c est une expression polynomiale. Il est donc facile de tester si c est nul ; il sut de le dvelopper : sage: expand(c) 0 et dutiliser le fait que deux polynmes sous forme dveloppe identiques sont gaux, autrement dit, que la forme dveloppe est une forme normale. En revanche, sur un exemple peine plus compliqu, Sage commet une erreur : sage: sage: sage: [x == c = cos(a)^2 + sin(a)^2 - 1 eq = c*x == 0 solve(eq, x) 0]

alors mme quil sait faire la simplication et mme le test zro correctement :

24

CHAP. 2. ANALYSE ET ALGBRE

quations numriques Rsolution symbolique Rsolution (avec multiplicit) Rsolution numrique solve roots find_root

quations vectorielles et quations fonctionnelles Rsolution dquations linaires Rsolution dquations direntielles Rsolution de rcurrences right_solve, left_solve desolve rsolve

Tableau 2.3 Rsolution dquations.

sage: c.simplify_trig() 0 sage: c.is_zero() True

2.2

quations

Nous abordons maintenant les quations et leur rsolution ; les principales fonctions sont rsumes dans le tableau 2.3.

2.2.1

Rsolution explicite
5 2 z+ 4 = 0, cos cos2

Considrons lquation dinconnue z et de paramtre suivante : z2 Elle scrit : sage: z, phi = var( z, phi ) sage: eq = z**2 - 2/cos(phi)*z + 5/cos(phi)**2 - 4 == 0; eq z^2 - 2*z/cos(phi) + 5/cos(phi)^2 - 4 == 0 On peut en extraire le membre de gauche (resp. de droite) laide de la mthode lhs (resp. rhs) : sage: eq.lhs() 2z 5 z 2 cos( ) + cos()2 4 sage: eq.rhs() 0 avec , . 2 2

puis la rsoudre avec solve : sage: solve(eq, z)

2.2. QUATIONS z=
2 cos()2 11 ,z cos()

25 =
2 cos()2 1+1 cos()

Soit maintenant rsoudre lquation y 6 = y . sage: y = var( y ); solve(y^6==y, y) [y == e^(2/5*I*pi), y == e^(4/5*I*pi), y == e^(-4/5*I*pi), y == e^(-2/5*I*pi), y == 1, y == 0] Les solutions peuvent tre renvoyes sous la forme dun objet du type dictionnaire (cf. 3.3.9) : sage: solve(x^2-1, x, solution_dict=True) [{x: -1}, {x: 1}] La commande solve permet galement de rsoudre des systmes : sage: solve([x+y == 3, 2*x+2*y == 6], x, y) [[x == -r1 + 3, y == r1]] Ce systme linaire tant indtermin, linconnue secondaire qui permet de paramtrer lensemble des solutions est un rel dsign par r1, r2, etc. Si le paramtre est implicitement un entier, il est dsign sous la forme z1, z2, etc. (ci-dessous z... dsigne z36, z60, ou autre suivant la version de Sage) : sage: solve([cos(x)*sin(x) == 1/2, x+y == 0], x, y) [[x == 1/4*pi + pi*z..., y == -1/4*pi - pi*z...]] Enn, la fonction solve peut tre utilise pour rsoudre des inquations : sage: solve(x^2+x-1 > 0, x) [[x < -1/2*sqrt(5) - 1/2], [x > 1/2*sqrt(5) - 1/2]] Il arrive que les solutions dun systme renvoyes par la fonction solve soient sous forme de ottants. Soit, par rsoudre dans C3 le systme suivant : exemple, 2 x yz = 18, xy 3 z = 24, xyz 4 = 3. sage: x, y, z = var( x, y, z ) sage: solve([x^2 * y * z == 18, x * y^3 * z == 24,\ ....: x * y * z^4 == 3], x, y, z) [[x == (-2.76736473308 - 1.71347969911*I), y == (-0.570103503963 + 2.00370597877*I), z == (-0.801684337646 - 0.14986077496*I)], ...] Sage renvoie ici 17 triplets de solutions complexes approches. Pour obtenir une solution symbolique, on se reportera au chapitre 9. Pour eectuer des rsolutions numriques dquations, on utilise la fonction find_root qui prend en argument une fonction dune variable ou une galit symbolique, et les bornes de lintervalle dans lequel il faut chercher une solution. sage: expr = sin(x) + sin(2 * x) + sin(3 * x) sage: solve(expr, x) [sin(3*x) == -sin(2*x) - sin(x)]

26

CHAP. 2. ANALYSE ET ALGBRE

Sage ne trouve pas de solution symbolique cette quation. Deux choix sont alors possibles : soit on passe une rsolution numrique, sage: find_root(expr, 0.1, pi) 2.0943951023931957 soit on transforme au pralable lexpression. sage: f = expr.simplify_trig(); f 2*(2*cos(x)^2 + cos(x))*sin(x) sage: solve(f, x) [x == 0, x == 2/3*pi, x == 1/2*pi] Enn la fonction roots permet dobtenir les solutions exactes dune quation, avec leur multiplicit. On peut prciser en outre lanneau dans lequel on souhaite eectuer la rsolution ; si on choisit RR R ou CC C on obtient les rsultats sous forme de nombres virgule ottante : la mthode de rsolution sous-jacente est spcique lquation considre, contrairement find_roots qui utilise une mthode gnrique. Considrons lquation du troisime degr x3 + 2 x + 1 = 0. Cette quation est de discriminant ngatif, donc elle possde une racine relle et deux racines complexes, que lon peut obtenir grce la fonction roots : sage: (x^3+2*x+1).roots(x) (1 3) I 31 1 1 1 I 3+1 3 59 + , 1 , 1 2 18 2 1 (3) 1 3 18 3 59 2 1 (3) I 3 1 1 1 1 + , 1 , I 3 + 1 3 59 1 2 18 2 1 1 (3) 3 18 3 59 2 1 (3) 1 1 2 3 59 + , 1 1 18 2 1 1 (3) 3 18 3 59 2 sage: (x^3+2*x+1).roots(x, ring=RR) [(0.453397651516404, 1)] sage: (x^3+2*x+1).roots(x, ring=CC) (0.453397651516404, 1), (0.226698825758202 1.46771150871022 I, 1), (0.226698825758202 + 1.46771150871022 I, 1)

2.2.2

quations sans solution explicite

Dans la plupart des cas, ds que le systme devient trop compliqu, il nest pas possible de calculer une solution explicite : sage: solve(x^(1/x)==(1/x)^x, x) [(1/x)^x == x^(1/x)]

2.3. ANALYSE

27

Contrairement ce que lon pourrait penser, cela nest pas forcment une limitation ! De fait, un leitmotiv du calcul formel est que lon peut trs bien manipuler des objets dnis par des quations, et en particulier calculer leurs proprits, sans passer par la rsolution explicite de celles-ci. Mieux encore, lquation dnissant un objet est souvent la meilleure description algorithmique de cet objet. Ainsi, une fonction dnie par une quation direntielle linaire et des conditions initiales est parfaitement prcise. Lensemble des solutions dquations direntielles linaires est clos par somme et produit (entre autres) et forme ainsi une importante classe o lon peut dcider de la nullit. En revanche, si lon rsout une telle quation, la solution, prive de son quation de dnition, tombe dans une classe plus grande o bien peu est dcidable : sage: y = function( y , x) sage: desolve(diff(y,x,x) + x*diff(y,x) + y == 0, y, [0,0,1]) -1/2*I*sqrt(pi)*sqrt(2)*e^(-1/2*x^2)*erf(1/2*I*sqrt(2)*x) Nous reviendrons sur ces considrations plus en dtail au chapitre 14 et au 15.1.2 du chapitre 15.

2.3

Analyse

Dans cette section, nous prsentons succinctement les fonctions couramment utiles en analyse relle. Pour une utilisation avance ou des complments, on renvoie aux chapitres suivants notamment ceux qui traitent de lintgration numrique (ch. 14), de la rsolution des quations non linaires (ch. 12), et des quations direntielles (ch. 10).

2.3.1

Sommes

Pour calculer des sommes symboliques on utilise la fonction sum. Calculons par exemple la somme des n premiers entiers non nuls : sage: k, n = var( k, n ) sage: sum(k, k, 1, n).factor() 1 2 (n + 1)n La fonction sum permet deectuer des simplications partir du binme de Newton : sage: n, k, y = var( n, k, y ) sage: sum(binomial(n,k) * x^k * y^(n-k), k, 0, n) n (x + y ) Voici dautres exemples, dont la somme des cardinaux des parties dun ensemble n lments : sage: k, n = var( k, n )

28

CHAP. 2. ANALYSE ET ALGBRE

sage: sum(binomial(n,k), k, 0, n),\ ....: sum(k * binomial(n, k), k, 0, n),\ ....: sum((-1)^k*binomial(n,k), k, 0, n) 2n , n2n1 , 0 Enn, quelques exemples de sommes gomtriques : sage: a, q, k, n = var( a, q, k, n ) sage: sum(a*q^k, k, 0, n)
aq n+1 a q 1

Pour calculer la srie correspondante, il faut prciser que le module de la raison est infrieur 1 : sage: assume(abs(q) < 1) sage: sum(a*q^k, k, 0, infinity) a q 1 sage: forget(); assume(q > 1); sum(a*q^k, k, 0, infinity) Traceback (most recent call last): ... ValueError: Sum is divergent.
Exercice 2 (Un calcul de somme par rcurrence). Calculer sans utiliser lalgorithme de Sage la somme des puissances p-imes des entiers de 0 n, pour p = 1, ..., 4 :
n

Sn (p) =
k=0

kp .

Pour calculer cette somme, on peut utiliser la formule de rcurrence suivante : 1 Sn (p) = p+1
p1

(n + 1)

p+1

j =0

p+1 Sn (j ) j

Cette relation de rcurrence stablit facilement en calculant de deux manires la somme tlescopique (k + 1)p+1 kp+1 .
0 k n

2.3.2

Limites

Pour calculer une limite, on utilise la commande limit ou son alias lim. Soient calculer les limites suivantes : 3 x2 a ) lim ; 3 x8 x + 19 3 cos 4 x tan x b) lim . x 1 sin 4 4 +x sage: limit((x**(1/3) - 2) / ((x + 19)**(1/3) - 3), x = 8) 9/4 sage: f(x) = (cos(pi/4-x)-tan(x))/(1-sin(pi/4 + x))

2.3. ANALYSE sage: limit(f(x), x = pi/4) Infinity

29

La dernire rponse indique que lune des limites gauche ou droite est innie. Pour prciser le rsultat, on tudie les limites gauche (minus) et droite (plus), en utilisant loption dir : sage: limit(f(x), x = pi/4, dir= minus ) +Infinity sage: limit(f(x), x = pi/4, dir= plus ) -Infinity

2.3.3

Suites

Les fonctions prcdentes permettent deectuer des tudes de suites. On donne un exemple dtude de croissance compare entre une suite exponentielle et une suite gomtrique.
n Exemple. (Une tude de suite ) On considre la suite un = 100 n . Calculer les 10 premiers termes de la suite. Quelle est la monotonie de la suite ? Quelle est la limite de la suite ? partir de quel rang a-t-on un 0, 108 ?
100

1. Pour dnir le terme de la suite un , on utilise une fonction symbolique. On eectue le calcul des 10 premiers termes la main (en attendant davoir vu les boucles au chapitre 3) : sage: u(n) = n^100 / 100^n sage: u(2.);u(3.);u(4.);u(5.);u(6.);u(7.);u(8.);u(9.);u(10.) 1.26765060022823e26 5.15377520732011e41 1.60693804425899e52 7.88860905221012e59 6.53318623500071e65 3.23447650962476e70 2.03703597633449e74 2.65613988875875e77 1.00000000000000e80 On pourrait en conclure htivement que un tend vers linni... 2. Pour avoir une ide de la monotonie, on peut tracer la fonction laide de laquelle on a dni la suite un (cf. gure 2.2). sage: plot(u(x), x, 1, 40) On conjecture que la suite va dcrotre partir du rang 22. sage: v(x) = diff(u(x), x); sol = solve(v(x) == 0, x); sol [x == 100/log(100), x == 0] sage: floor(sol[0].rhs()) 21

30

CHAP. 2. ANALYSE ET ALGBRE

1.6e90 1.4e90 1.2e90 1e90 8e89 6e89 4e89 2e89 0

10

15

20

25

30

35

40

Figure 2.2 Graphe de x x100 /100x .

La suite est donc croissante jusquau rang 21, puis dcroissante partir du rang 22. 3. On eectue ensuite le calcul de la limite : sage: limit(u(n), n=infinity) 0 sage: n0 = find_root(u(n) - 1e-8 == 0, 22, 1000); n0 105.07496210187252 La suite tant dcroissante partir du rang 22, on en dduit qu partir du rang 106, la suite reste conne lintervalle 0, 108 .

2.3.4

Dveloppements limits (*)

Pour calculer un dveloppement limit dordre n au sens fort 2 en x0 , on dispose de la fonction f(x).series(x==x0, n). Si lon ne sintresse qu la partie rgulire du dveloppement limit lordre n (au sens faible), on peut aussi utiliser la fonction taylor(f(x), x, x0, n). Dterminons le dveloppement limit des fonctions suivantes : a) (1 + arctan x) x b) ln(2 sin x)
1

lordre 3, en x0 = 0 ; lordre 3, en x0 =
6.

sage: taylor((1+arctan(x))**(1/x), x, 0, 3) 1 1 2 1 3 16 x e + 8 x e 2 xe + e
2. On appelle dveloppement limit en 0 au sens fort une galit de la forme f (x) = P (x)+ O(xn+1 ) avec P polynme de degr au plus n, par opposition la notion de dveloppement limit au sens faible qui dsigne une galit de la forme f (x) = P (x) + o(xn ).

2.3. ANALYSE

31

Fonctions et oprateurs Drivation Drive n-ime Intgration Intgration numrique Somme symbolique Limite Polynme de Taylor Dveloppement limit Trac dune courbe diff(f(x), x) diff(f(x), x, n) integrate(f(x), x) integral_numerical(f(x), a, b) sum(f(i), i, imin, imax) limit(f(x), x=a) taylor(f(x), x, a, n) f.series(x==a, n) plot(f(x), x, a, b)

Tableau 2.4 Rcapitulatif des fonctions utiles en analyse.

sage: (ln(2*sin(x))).series(x==pi/6, 3) 2 3 1 1 ( 3)( 1 6 + x) + (2)( 6 + x) + O 216 ( 6 x) Pour extraire la partie rgulire dun dveloppement limit obtenu laide de series, on utilise la fonction truncate : sage: (ln(2*sin(x))).series(x==pi/6, 3).truncate() 2 1 18 ( 6 x) 1 6 ( 6 x) 3 La commande taylor permet galement dobtenir des dveloppements asymptotiques. Par exemple, pour obtenir un quivalent au voisinage de + de la 1 1 fonction (x3 + x) 3 (x3 x) 3 : sage: taylor((x**3+x)**(1/3) - (x**3-x)**(1/3), x, infinity, 2) 2/3/x
Exercice 3 (Un calcul symbolique de limite). Soit f de classe C 3 au voisinage de a R. Calculer
h 0

lim

1 (f (a + 3h) 3f (a + 2h) + 3f (a + h) f (a)) h3

Gnralisation ?

Exemple (*). (La formule de Machin ) Montrer la formule suivante : 1 1 = 4 arctan arctan . 4 5 239 Cest laide de cette formule et du dveloppement darctan en srie entire, que lastronome John Machin (1680-1752) calcula cent dcimales de en 1706. Dduire de cette formule une valeur approche de en utilisant sa mthode. 1 On commence par remarquer que 4 arctan 1 5 et 4 + arctan 239 ont mme tangente : sage: tan(4*arctan(1/5)).simplify_trig() 120/119 sage: tan(pi/4+arctan(1/239)).simplify_trig() 120/119

32

CHAP. 2. ANALYSE ET ALGBRE

1 Or les rels 4 arctan 1 5 et 4 +arctan 239 appartiennent tous les deux lintervalle ouvert ]0, [, donc ils sont gaux. Pour obtenir une valeur approche de , on peut procder de la manire suivante :

sage: f = arctan(x).series(x, 10); f 1*x + (-1/3)*x^3 + 1/5*x^5 + (-1/7)*x^7 + 1/9*x^9 + Order(x^10) sage: (16*f.subs(x==1/5) - 4*f.subs(x==1/239)).n(); pi.n() 3.14159268240440 3.14159265358979
Exercice 4 (Une formule due Gauss). La formule suivante ncessite le calcul de 20 pages de tables de factorisations dans ldition des uvres de Gauss (cf. Werke, ed. Kngl. Ges. de Wiss. Gttingen, vol. 2, p. 477-502) : 1 1 1 1 = 12 arctan + 20 arctan + 7 arctan + 24 arctan . 4 38 57 239 268
1 1 1. On pose = 12 arctan 38 + 20 arctan 57 + 7 arctan Vrier laide de Sage, que tan = 1. 1 239

+ 24 arctan

1 . 268

2. Prouver lingalit : x 0,

, tan x

4 x.

En dduire la formule de Gauss.

3. En approchant la fonction arctan par son polynme de Taylor dordre 21 en 0, donner une nouvelle approximation de .

2.3.5

Sries (*)

On peut utiliser les commandes prcdentes pour eectuer des calculs sur les sries. Donnons quelques exemples. Exemple. (Calcul de la somme de sries de Riemann ) sage: k = var( k sage: sum(1/k^2, ....: sum(1/k^4, ....: sum(1/k^5, 1 2 1 4 6 , 90 , (5) ) k, 1, infinity),\ k, 1, infinity),\ k, 1, infinity)

Exemple. (Une formule due Ramanujan ) En utilisant la somme partielle des 12 premiers termes de la srie suivante, donnons une approximation de et comparons-la avec la valeur donne par Sage. 1 2 2 = 9801
+

k=0

(4k )! (1103 + 26390 k ) . (k !)4 3964k

sage: s = 2*sqrt(2)/9801*(sum((factorial(4*k)) * (1103+26390*k) / ....: ((factorial(k)) ^ 4 * 396 ^ (4 * k)) for k in (0..11))) sage: (1/s).n(digits=100) 3.141592653589793238462643383279502884197169399375105820974... sage: (pi-1/s).n(digits=100).n() -4.36415445739398e-96

2.3. ANALYSE

33

On remarque que la somme partielle des 12 premiers termes donne dj 95 dcimales signicatives de ! Exemple. (Convergence dune srie ) Soit tudier la nature de la srie sin
n 0

4 n2 + 1 .

Pour eectuer un dveloppement asymptotique du terme gnral, on utilise la 2 -priodicit de la fonction sinus pour que largument du sinus tende vers 0 : un = sin 4 n2 + 1 = sin 4 n2 + 1 2n .

On peut alors appliquer la fonction taylor cette nouvelle expression du terme gnral : sage: n = var( n ); u = sin(pi*(sqrt(4*n^2+1)-2*n)) sage: taylor(u, n, infinity, 3) 6 + 3 4 n 384 n3 On en dduit un 4 n . Donc, daprs les rgles de comparaison aux sries de Riemann, la srie un diverge.
n 0

Exercice 5 (Dveloppement asymptotique dune suite). Il est ais de montrer (en utilisant par exemple le thorme de la bijection monotone) que pour tout n N, lquation tan x = x admet une et une seule solution xn dans lintervalle [n, n + [. 2 Donner un dveloppement asymptotique de xn lordre 6 en +.

2.3.6

Drivation

La fonction derivative (qui a pour alias diff) permet de driver une expression symbolique ou une fonction symbolique. sage: diff(sin(x^2), x) 2*x*cos(x^2) sage: function( f , x); function( g , x); diff(f(g(x)), x) f(x) g(x) D[0](f)(g(x))*D[0](g)(x) sage: diff(ln(f(x)), x) D[0](f)(x)/f(x)

2.3.7

Drives partielles (*)

La commande diff permet galement de calculer des drives n-imes ou des drives partielles. sage: f(x,y) = x*y + sin(x^2) + e^(-x); derivative(f, x) (x, y) |--> 2*x*cos(x^2) + y - e^(-x) sage: derivative(f, y)

34 (x, y) |--> x

CHAP. 2. ANALYSE ET ALGBRE

Exemple. Soit vrier que la fonction suivante est harmonique 3 : 1 ln(x2 + y 2 ) pour tout (x, y ) = (0, 0). f (x, y ) = 2 sage: x, y = var( x, y ); f = ln(x**2+y**2) / 2 sage: delta = diff(f,x,2) + diff(f,y,2) sage: delta.simplify_full() 0
Exercice 6 (Un contre-exemple d Peano au thorme de Schwarz). Soit f lapplication de R2 dans R dnie par : f (x, y ) = A-t-on 1 2 f (0, 0) = 2 1 f (0, 0) ?
y xy x x2 +y 2
2 2

si (x, y ) = (0, 0), si (x, y ) = (0, 0).

2.3.8

Intgration

Pour calculer une primitive ou une intgrale, on utilise la fonction integrate (ou son alias integral) : sage: sin(x).integral(x, 0, pi/2) 1 sage: integrate(1/(1+x^2), x) arctan(x) sage: integrate(1/(1+x^2), x, -infinity, infinity) pi sage: integrate(exp(-x**2), x, 0, infinity) 1/2*sqrt(pi) sage: integrate(exp(-x), x, -infinity, infinity) Traceback (most recent call last): ... ValueError: Integral is divergent.
+

Exemple. Soit calculer, pour x R, lintgrale (x) =


0

x cos u du. u2 + x2

sage: u = var( u ); f = x * cos(u) / (u^2 + x^2) sage: assume(x>0); f.integrate(u, 0, infinity) 1/2*pi*e^(-x) sage: forget(); assume(x<0); f.integrate(u, 0, infinity) -1/2*pi*e^x On a donc : x R , (x) =
2

sgn(x) e|x| .

2 f + 2 f est nul. 3. Une fonction f est dite harmonique lorsque son Laplacien f = 1 2

2.4. ALGBRE LINAIRE LMENTAIRE

35

Pour eectuer une intgration numrique sur un intervalle, on dispose de la fonction integral_numerical qui renvoie un tuple deux lments, dont la premire composante donne une valeur approche de lintgrale, et la deuxime une estimation de lerreur eectue. sage: integral_numerical(sin(x)/x, 0, 1) (0.94608307036718287, 1.0503632079297086e-14) sage: g = integrate(exp(-x**2), x, 0, infinity) sage: g, g.n() (1/2*sqrt(pi), 0.886226925452758) sage: approx = integral_numerical(exp(-x**2), 0, infinity) sage: approx (0.88622692545275705, 1.7147744320162414e-08) sage: approx[0]-g.n() -8.88178419700125e-16
Exercice 7 (La formule BBP (*)). On cherche tablir par un calcul symbolique la formule BBP (ou Bailey-Borwein-Ploue) ; cette formule permet de calculer le n-ime chire aprs la virgule de en base 2 (ou 16) sans avoir en calculer les prcdents, et en utilisant trs peu de mmoire et de temps. Pour N N, on pose
N

SN =
n=0

4 2 1 1 8n + 1 8n + 4 8n + 5 8n + 6

1 16

1. Soit la fonction f : t 4 2 8t3 4 2t4 8t5 . Pour N N, exprimer en fonction de SN lintgrale suivante :
1/ 2 N

IN =
0 1/ 2

f (t)
n=0

t 8n

dt.

2. Pour N N, on pose J =
0

f (t) dt. Montrer 1 t8

N +

lim SN = J .

3. Montrer la formule BBP :


+

n=0

4 2 1 1 8n + 1 8n + 4 8n + 5 8n + 6

1 16

= .

Cette formule remarquable a t obtenue le 19 septembre 1995 par Simon Ploue en collaboration avec David Bailey et Peter Borwein. Grce une formule drive de la formule BBP, le 4 000 000 000 000 000e chire de en base 2 a t obtenu en 2001.

2.4

Calcul matriciel (*)

Dans cette section, on dcrit les fonctions de base utiles en algbre linaire : oprations sur les vecteurs, puis sur les matrices. Pour plus de dtails, on renvoie au chapitre 8 pour le calcul matriciel symbolique et au chapitre 13 pour le calcul matriciel numrique.

36

CHAP. 2. ANALYSE ET ALGBRE

Fonctions usuelles sur les vecteurs Dclaration dun vecteur Produit vectoriel Produit scalaire Norme dun vecteur vector cross_product dot_product norm

Tableau 2.5 Calcul vectoriel.

2.4.1

Rsolution de systmes linaires

Pour rsoudre un systme linaire, on peut utiliser la fonction solve dj rencontre.


Exercice 8 (Approximation polynomiale du sinus). Dterminer le polynme de degr au plus 5 qui ralise la meilleure approximation, au sens des moindres carrs, de la fonction sinus sur lintervalle [, ] :

5 = min

|sin x P (x)|2 dx P R5 [x]

2.4.2

Calcul vectoriel

Les fonctions de base utiles pour la manipulation des vecteurs sont rsumes dans le tableau 2.5. On peut se servir de ces fonctions pour traiter lexercice suivant.
Exercice 9 (Le problme de Gauss). On considre un satellite en orbite autour de la Terre et on suppose que lon connat trois points de son orbite : A1 , A2 et A3 . On souhaite dterminer partir de ces trois points les paramtres de lorbite de ce satellite. On note O le centre de la Terre. Les points O, A1 , A2 et A3 sont videmment situs dans un mme plan, savoir le plan de lorbite du satellite. Lorbite du satellite est une ellipse dont O est un foyer. On peut choisir un repre (O; , ) de telle sorte que lquation de lellipse en coordonnes polaires soit dans ce repre r = 1ep o e cos dsigne lexcentricit de lellipse et p son paramtre. On notera r = OA et r = r
i i i i

pour i {1, 2, 3}. On considre alors les trois vecteurs suivants qui se dduisent de la connaissance de A1 , A2 et A3 : D = r1 r2 + r2 r3 + r3 r1 , S = ( r1 r3 ) r2 + ( r3 r2 ) r1 + ( r2 r1 ) r3 , N = r (r r ) + r (r r ) + r (r r ) .
3 1 2 1 2 3 2 3 1

1. Montrer que D = 1 S et en dduire lexcentricit e de lellipse. e 2. Montrer que est colinaire au vecteur S D . 3. Montrer que N = p S et en dduire le paramtre p de lellipse. e 4. Exprimer le demi-grand axe a de lellipse en fonction du paramtre p et de lexcentricit e.

2.4. ALGBRE LINAIRE LMENTAIRE

37

5. Application numrique : dans le plan rapport un repre orthonorm direct, on considre les points suivants : A1 ( 0 1), A2 ( 2 2),
.5 A3 ( 30 ),

O(0 0).

Dterminer numriquement les caractristiques de lunique ellipse dont O est un foyer et qui passe par les trois points A1 , A2 et A3 .

2.4.3

Calcul matriciel

Pour dnir une matrice, on utilise linstruction matrix en prcisant ventuellement lanneau (ou le corps) de base : sage: A = matrix(QQ, [[1,2],[3,4]]); A [1 2] [3 4] Pour trouver une solution particulire lquation matricielle Ax = b (resp. xA = b), on utilise la fonction solve_right (resp. solve_left). Pour trouver toutes les solutions dune quation matricielle, il faut ajouter une solution particulire la forme gnrale de lquation homogne associe. Pour rsoudre une quation homogne de la forme Ax = 0 (resp. xA = 0), on utilisera la fonction right_kernel (resp. left_kernel), comme dans lexercice suivant.
Exercice 10 (Bases de sous-espaces vectoriels). 1. Dterminer une base de lespace des solutions du systme linaire homogne associ la matrice : 2 6 A= 10 2

3 1 29 0

2 26 18 8

12 16 53 18

33 69 . 32 84

2. Dterminer une base de lespace F engendr par les colonnes de A. 3. Caractriser F par une ou plusieurs quations. Exercice 11 (Une quation matricielle). On rappelle le lemme de factorisation des applications linaires. Soient E, F, G des K-espaces vectoriels de dimension nie. Soient u L(E, F ) et v L(E, G). Alors les assertions suivantes sont quivalentes : i ) il existe w L(F, G) tel que v = w u, ii ) Ker(u) Ker(v ). On cherche toutes les solutions ce problme dans un cas concret. Soient A=
2 1 1 8 1 5 4 3 3

et

C=

1 2 1 2 1 1 5 0 3

Dterminer toutes les solutions B M3 (R) de lquation A = BC .

38

CHAP. 2. ANALYSE ET ALGBRE

Fonctions usuelles sur les matrices Dclaration dune matrice Rsolution dune quation matricielle Noyau droite, gauche Rduction sous forme chelonne en ligne Sous-espace engendr par les colonnes Sous-espace engendr par les lignes Concatnation de matrices matrix solve_right, solve_left right_kernel, left_kernel echelon_form column_space row_space matrix_block

Rduction des matrices Valeurs propres dune matrice Vecteurs propres dune matrice Rduction sous forme normale de Jordan Polynme minimal dune matrice Polynme caractristique dune matrice eigenvalues eigenvectors_right jordan_form minimal_polynomial characteristic_polynomial

Tableau 2.6 Calcul matriciel.

2.4.4

Rduction dune matrice carre

Pour tudier les lments propres dune matrice, on dispose des fonctions rsumes dans le tableau 2.6. Ces fonctions seront dtailles dans le chapitre 8. On se contente de donner ici quelques exemples simples dutilisation. Exemple. La matrice A = 4 6 3 est-elle diagonalisable ? trigonali3 3 1 sable ? On commence par dnir la matrice A en indiquant le corps de base (QQ=Q), puis on dtermine les lments propres. sage: A = matrix(QQ, [[2,4,3],[-4,-6,-3],[3,3,1]]) sage: A.characteristic_polynomial() x^3 + 3*x^2 - 4 sage: A.eigenvalues() [1, -2, -2] sage: A.minimal_polynomial().factor() (x - 1) * (x + 2)^2 Le polynme minimal de A possde une racine simple et une racine double ; donc A nest pas diagonalisable. Par contre, le polynme minimal de A est scind donc A est trigonalisable. sage: A.eigenvectors_right() [(1, [(1, 1, 1)] , 1) , (2, [(1, 1, 0)] , 2)] sage: A.jordan_form(transformation=True) 1 0 0 1 1 1 0 2 0 1 , 1 1 1 0 1 0 2 0
2 4 3

2.4. ALGBRE LINAIRE LMENTAIRE


1 1/ 2

39

Exemple. Soit diagonaliser la matrice A = 1/2 1 . On peut essayer de diagonaliser cette matrice en utilisant la fonction jordan_form : sage: A = matrix(QQ, [[1,-1/2],[-1/2,-1]]) sage: A.jordan_form() Traceback (most recent call last): ... RuntimeError: Some eigenvalue does not exist in Rational Field. Mais, ici une petite dicult apparat : les valeurs propres ne sont pas rationnelles. sage: A = matrix(QQ, [[1,-1/2],[-1/2,-1]]) sage: A.minimal_polynomial() x^2 - 5/4 Il faut donc changer de corps de base. sage: R = QQ[sqrt(5)] sage: A = A.change_ring(R) sage: A.jordan_form(transformation=True, subdivide=False) 1 sqrt5 0 1 1 , 2 1 sqrt + 2 sqrt + 2 5 5 0 sqrt5 2 Ce qui sinterprte ainsi : 1 1 1 2 5 0 , 1 5+2 5+2 0 2 5 Exemple. Soit diagonaliser la matrice A =
2 6 2 3 3 6 2 3 1

Cette fois-ci, il faut travailler dans une extension de degr 4 du corps Q. On peut alors procder comme suit. sage: K.<sqrt2> = NumberField(x^2 - 2) sage: L.<sqrt3> = K.extension(x^2 - 3) sage: A = matrix(L, [[2, sqrt2*sqrt3, sqrt2], \ ....: [sqrt2*sqrt3, 3, sqrt3], \ ....: [sqrt2, sqrt3, 1]]) sage: A.jordan_form(transformation=True) 1 1 0 6 0 0 0 0 0 , 1 2 3 2 0 1 1 0 0 0 2 2 2 3

40

CHAP. 2. ANALYSE ET ALGBRE

Programmation et structures de donnes


Nous avons vu dans les chapitres prcdents comment eectuer des calculs mathmatiques par des commandes Sage isoles, mais le systme autorise aussi la programmation dune suite dinstructions. Le systme de calcul formel Sage est en fait une extension du langage informatique Python 1 et permet, quelques changements de syntaxe prs, dexploiter les mthodes de programmation de ce langage. Les commandes dcrites dans les chapitres prcdents prouvent quil nest pas ncessaire de connatre le langage Python pour utiliser Sage ; ce chapitre montre au contraire comment employer dans Sage les structures lmentaires de programmation de Python. Il se limite aux bases de la programmation et peut tre survol par les personnes connaissant Python ; les exemples sont choisis parmi les plus classiques rencontrs en mathmatiques pour permettre au lecteur dassimiler rapidement la syntaxe de Python par analogie avec les langages de programmation quil connat. Ce chapitre prsente la mthode algorithmique de programmation structure avec les instructions de boucles et de tests, et expose ensuite les fonctions oprant sur les listes et les autres structures composes de donnes. Le livre Apprendre programmer avec Python de G. Swinnen [Swi09, Swi12] (disponible sous licence libre) et le Syllabus en ligne de T. Massart [Mas13] prsentent de faon plus approfondie le langage Python.
1. La version 5.9 de Sage utilise Python 2.7 ; la syntaxe de Python change lgrement partir de la version 3.

42

CHAP. 3. PROGRAMMATION ET STRUCTURES DE DONNES

Mots-cls du langage Python while, for...in, if...elif...else continue, break try...except...finally, raise assert pass def, lambda return, yield global, del and, not, or print class, with from...import...as exec...in boucles et tests sortie anticipe dun bloc de code traitement et dclenchement dexceptions condition de dbogage instruction sans eet dnition dune fonction renvoi dune valeur porte et destruction des variables et fonctions oprations logiques achage de texte programmation objet, application dun contexte accs une bibliothque valuation dynamique de code

Tableau 3.1 Syntaxe gnrale du code Sage.

3.1
3.1.1

Syntaxe
Syntaxe gnrale

Les instructions lmentaires sont en gnral traites ligne par ligne. Python considre le caractre croisillon # comme un dbut de commentaire et ignore le texte saisi jusqu la n de la ligne. Le point-virgule ; spare les instructions places sur une mme ligne : sage: 2*3; 3*4; 4*5 6 12 20 # un commentaire, 3 rsultats

Dans le terminal, une commande peut tre saisie sur plusieurs lignes en faisant prcder les retours la ligne intermdiaires dune contre-oblique \ ; ces retours la ligne sont considrs comme de simples blancs : sage: 123 + \ ....: 345 468 Un identicateur cest--dire un nom de variable, de fonction, etc. est constitu uniquement de lettres, de chires ou du caractre de soulignement _ et ne peut commencer par un chire. Les identicateurs doivent tre dirents des mots-clefs du langage. Ces mots-clefs, rpertoris dans le tableau 3.1, forment le noyau du langage Python 2.7. De faon anecdotique, on peut obtenir la liste de ces mots-cls avec : sage: import keyword; keyword.kwlist [ and , as , assert , break , class , continue , def , del , elif , else , except , exec , finally , for , from , global , if , import , in , is , lambda , not , or , pass , print , raise , return , try , while , with , yield ]

3.1. SYNTAXE

43

Les caractres spciaux de Sage et leurs principales utilisations ; : . = + - * / ^ ** % // += -= *= /= **= == != <> is < <= > >= & | ^^ << >> # [...] (...) {...:...} \ @ ? _ __ ___ , sparateurs darguments et dinstructions ouverture dun bloc dinstructions, comprhension sparateur dcimal, accs aux champs dun objet aectation dune valeur une variable oprations arithmtiques lmentaires puissance quotient et reste dune division euclidienne oprations arithmtiques avec modication dune variable tests dgalit comparaisons oprations ensemblistes et oprations logiques bit bit commentaire (jusqu la n de la ligne) construction dune liste, accs un lment par son indice appel de fonction ou de mthode, tuples immuables construction de dictionnaires chappement dun caractre spcial (et algbre linaire) application dun dcorateur une fonction accs laide rappel des trois derniers rsultats obtenus

Tableau 3.2 Syntaxe gnrale du code Sage (suite).

ces mots clefs sajoutent les constantes None (valeur vide , quivalent approximatif de NULL dans dautres langages), True et False, ainsi que de nombreuses fonctions prdnies par Python et Sage comme len, cos et integrate. Il est prfrable de ne pas utiliser les identicateurs correspondants comme noms de variables, sous peine de rendre dicile laccs aux fonctionnalits du systme. Linterprteur accepte quelques commandes supplmentaires, comme quit pour quitter la session Sage en cours. Nous en dcouvrirons dautres comme time ou timeit au fur et mesure. Certains caractres jouent un rle spcial dans Sage. Ils sont numrs dans le tableau 3.2.

3.1.2

Appel de fonctions

Lvaluation dune fonction impose de placer ses ventuels arguments entre parenthses, comme dans cos(pi) ou dans la fonction sans argument reset(). Cependant ces parenthses sont superues pour les arguments dune commande : les instructions print(6*7) et print 6*7 sont quivalentes 2 . Le nom dune fonction sans argument ni parenthse reprsente la fonction elle-mme et neectue aucun calcul.

3.1.3

Complments sur les variables

Comme nous lavons vu, Sage note par le signe gal = la commande daectation dune valeur une variable. La partie situe droite du caractre
2. En Python 3.0, print est une fonction et impose de placer ses arguments entre parenthses.

44

CHAP. 3. PROGRAMMATION ET STRUCTURES DE DONNES

= est dabord value puis sa valeur est mmorise dans la variable dont le nom est gauche. Ainsi, on a : sage: y = 3; y = 3 * y + 1; y = 3 * y + 1; y 31 Les aectations prcdentes modient la valeur de la variable y sans acher de rsultat intermdiaire, la dernire de ces quatre commandes ache la valeur de la variable y la n de ces calculs. La commande del x supprime laectation de la variable x, et la fonction sans paramtre reset() rinitialise lensemble des variables. Laectation de plusieurs variables de faon parallle, ou synchronise, est aussi possible ; elle dire des aectations successives a = b; b = a : sage: a, b = 10, 20 # (a, b) = (10, 20) et [10, 20] possibles sage: a, b = b, a sage: a, b (20, 10) Laectation a, b = b, a est quivalente lchange des valeurs des variables a et b en utilisant une variable intermdiaire : sage: temp = a; a = b; b = temp # est quivalent : a, b = b, a Cet autre exemple change les valeurs de deux variables a et b sans variable intermdiaire ni aectation parallle, mais en utilisant des sommes et dirences : sage: x, y = var( x, y ); a = x ; b = y sage: a, b (x, y) sage: a = a + b ; b = a - b ; a = a - b sage: a, b (y, x) Laectation multiple aecte la mme valeur plusieurs variables, avec une syntaxe de la forme a = b = c = 0 ; les instructions x += 5 et n *= 2 sont respectivement quivalentes x = x+5 et n = n*2. Le test de comparaison entre deux objets se note par le double signe dgalit == : sage: 2 + 2 == 2^2, 3 * 3 == 3^3 (True, False)

3.2

Algorithmique

La programmation structure consiste dcrire un programme informatique comme une suite nie dinstructions eectues les unes la suite des autres. Ces instructions peuvent tre lmentaires ou composes : une instruction lmentaire correspond par exemple laectation dune valeur une variable (cf. 1.2.4), ou lachage dun rsultat ;

3.2. ALGORITHMIQUE

45

une instruction compose, comme une boucle ou une structure conditionnelle, est construite partir de plusieurs instructions qui peuvent tre elles-mmes simples ou composes.

3.2.1

Les boucles

Les boucles dnumration. Une boucle dnumration eectue les mmes calculs pour toutes les valeurs entires dun indice k {a, . . . , b} ; lexemple suivant 3 ache le dbut de la table de multiplication par 7 : sage: for k in [1..5]: ....: print 7*k # bloc qui contient une seule instruction 7 14 21 28 35 Les deux-points : la n de la premire ligne introduisent le bloc dinstructions qui est valu pour chaque valeur successive 1, 2, 3, 4 et 5 de la variable k. chaque itration Sage ache le produit 7 k par lintermdiaire de la commande print. Sur cet exemple, le bloc des instructions rptes contient une seule instruction (print) qui est saisie de faon dcale par rapport au mot-clef for. Un bloc compos de plusieurs instructions est caractris par des instructions saisies les unes sous les autres avec la mme indentation. La dnition des blocs est importante : les deux programmes ci-dessous dirent uniquement par lindentation dune ligne, et aboutissent des rsultats dirents. sage: sage: ... sage: sage: S = for S S = S 0 k in [1..3]: = S+k 2*S sage: S = 0 sage: for k in [1..3]: ... S = S+k ... S = 2*S sage: S

gauche linstruction S = 2*S est eectue une seule fois la n de la boucle, alors qu droite elle est eectue chaque itration, do des rsultats dirents : S = (0 + 1 + 2 + 3) 2 = 12 S = ((((0 + 1) 2) + 2) 2 + 3) 2 = 22.

Cette boucle sert entre autre calculer un terme donn dune suite rcurrente et est illustre dans les exemples placs la n de cette section. Cette syntaxe de boucle dnumration est la plus directe et peut tre utilise sans inconvnient pour 104 ou 105 itrations ; elle a cependant linconvnient de
3. Lorsque lon utilise Sage dans un terminal, la saisie dun tel bloc doit se terminer par une ligne vide supplmentaire. Cette condition nest pas ncessaire en utilisant Sage par lintermdiaire dun navigateur web et sera sous-entendue dans la suite.

46

CHAP. 3. PROGRAMMATION ET STRUCTURES DE DONNES

Fonctions ditrations de la forme ..range pour a, b, c entiers for k in for k in srange for k in range for k in xrange [a..b]: (a, b): (a, b): (a, b): ... ... ... ... construit la liste des entiers a k b de Sage construit la liste des entiers a k < b de Sage construit une liste dentiers int de Python numre des entiers int de Python sans construire explicitement la liste correspondante numre des nombres de Sage sans construire de liste nombres Sage a, a + c, a + 2c, . . . jusqu a + kc b est quivalent ..range (0, b) xe lincrment dnumration c la place de 1

for k in sxrange (a, b): ... [a,a+c..b], [a..b, step=c] ..range (b) ..range (a, b, c)

Tableau 3.3 Les direntes boucles dnumration.

construire explicitement la liste de toutes les valeurs de la variable de boucle avant de rpter les instructions itres, mais a lavantage de manipuler les entiers de Sage de type Integer (voir 5.3.1). Plusieurs fonctions ..range permettent aussi ces itrations avec deux choix indpendants possibles. Le premier choix consiste soit construire la liste des valeurs en mmoire avant le dbut de la boucle, soit dterminer ces valeurs au fur et mesure des itrations. Le second choix est faire entre entiers Integer de Sage 4 et entiers de type int de Python, ces deux types dentiers nont pas exactement les mmes proprits informatiques. Dans le doute, la forme [a..b] est celle qui rserve le moins de surprises. Boucles tant que. Lautre famille de boucles est constitue des boucles tant que. Comme les boucles dnumration for, celles-ci valuent un certain nombre de fois les mmes instructions ; en revanche le nombre de rptitions nest pas x au dbut de la boucle mais dpend de la ralisation dune condition. La boucle tant que, comme son nom lindique, excute des instructions tant quune condition est ralise. Lexemple suivant 5 calcule la somme des carrs des entiers naturels dont lexponentielle est infrieure ou gale 106 , soit 12 + 22 + + 132 : sage: S = 0 sage: while ....: S ....: k sage: S 819 La dernire instruction renvoie la valeur de la variable S et ache le rsultat :
13

; k e^k = S = k

= 0 <= 10^6: + k^2 + 1

# # #

La somme S commence 0 e^13 <= 10^6 < e^14 ajout des carrs k^2

S=
k N ek 106

k2 =
k=0

k 2 = 819,

e13 442413

106 < e14 1202604.

4. Les commandes srange, sxrange et [...] oprent aussi sur les nombres rationnels et ottants : que donne [pi,pi+5..20] ? 5. Lors de la saisie dans un terminal une ligne vide est ncessaire pour clore la dnition du bloc dinstructions de la boucle, avant de demander la valeur de la variable S.

3.2. ALGORITHMIQUE

47

Le bloc dinstructions ci-dessus comporte deux instructions daectation, la premire additionne le nouveau terme, et la seconde passe lindice suivant. Ces deux instructions sont bien places les unes sous les autres et indentes de la mme faon lintrieur de la structure while. Lexemple suivant est un autre exemple typique de la boucle tant que. Il consiste rechercher, pour un nombre x 1, lunique valeur n N vriant 2n1 x < 2n , cest--dire le plus petit entier vriant x < 2n . Le programme ci-dessous compare x 2n dont la valeur est successivement 1, 2, 4, 8, etc. ; il eectue ce calcul pour x = 104 : sage: x = 10^4; u = 1; n = 0 # invariant : u = 2^n sage: while u <= x: n = n+1; u = 2*u # ou n += 1; u *= 2 sage: n 14 x est vrie, ce programme calcule les nouvelles Tant que la condition 2n valeurs n + 1 et 2n+1 = 2 2n des deux variables n et u et les mmorise la place de n et 2n . Cette boucle se termine lorsque la condition nest plus vrie, cest--dire pour x < 2n : x = 104 , min{n N | x 2n } = 14, 213 = 8192, 214 = 16384.

Le corps dune boucle tant que nest pas excut lorsque le test est faux ds la premire valuation. Les blocs de commandes simples peuvent aussi tre saisis sur une ligne la suite des deux-points : sans dnir un nouveau bloc indent partir de la ligne suivante. Exemples dapplication aux suites et aux sries. La boucle for permet de calculer facilement un terme donn dune suite rcurrente. Soit par exemple (un ) la suite dnie par u0 = 1, n N un+1 = 1 . 1 + u2 n

Le programme ci-dessous dtermine une approximation numrique du terme un pour n = 20 ; la variable U est modie chaque itration de la boucle pour passer de la valeur un1 un en suivant la formule de rcurrence. La premire itration calcule u1 partir de u0 pour n = 1, la deuxime fait de mme de u1 u2 quand n = 2, et la dernire des n itrations modie la variable U pour passer de un1 un : sage: U = 1.0 # ou U = 1. ou U = 1.000 sage: for n in [1..20]: ....: U = 1 / (1 + U^2) sage: U 0.682360434761105

48

CHAP. 3. PROGRAMMATION ET STRUCTURES DE DONNES

Interruption de lexcution dune boucle Les boucles while et for rptent un certain nombre de fois les mmes instructions. La commande break lintrieur dune boucle termine de faon prmature cette boucle, et la commande continue passe directement litration suivante. Ces commandes permettent ainsi deectuer lvaluation de la condition nimporte quel endroit du corps de la boucle. Les quatre exemples ci-dessous dterminent le plus petit nombre entier strictement positif vriant log(x + 1) x/10. Le premier met en avant une boucle for dau maximum 100 essais qui se termine de faon prmature la premire solution, le deuxime prsente la recherche du plus petit entier vriant cette condition et risque de ne pas se terminer si cette condition nest jamais vrie, le troisime est quivalent au premier avec une condition de boucle plus complexe, enn le quatrime exemple possde une structure inutilement complique qui a pour unique but dillustrer la commande continue. Dans tous ces cas la valeur nale de x est 37.0. for x in [1.0..100.0]: if log(x+1)<=x/10: break x=1.0 while log(x+1)>x/10: x=x+1

x=1.0 x=1.0 while log(x+1)>x/10 and x<100: while True: x=x+1 if log(x+1)>x/10: x=x+1 continue break La commande return (qui termine lexcution dune fonction et dnit son rsultat, cf. 3.2.3) ore une autre manire dinterrompre prmaturment un bloc dinstructions.

Le mme programme avec lentier U = 1 la place de lapproximation numrique U = 1.0 sur la premire ligne fait des calculs exacts sur les nombres rationnels ; le rsultat exact u10 est une fraction avec plus dune centaine de chires, et u20 en comporte plusieurs centaines de milliers. Les calculs exacts sont intressants lorsque les erreurs darrondi se cumulent dans les approximations numriques. Sinon, la main comme la machine, les oprations sur les approximations numriques dune dizaine de dcimales sont plus rapides que celles sur des entiers ou des rationnels faisant intervenir 500, 1 000 chires, ou plus. Les sommes ou les produits peuvent tre mis sous forme de suites rcurrentes et se calculent de la mme manire :
n

Sn = S0 = 0,
k=1

(2k )(2k + 1) = 2 3 + 4 5 + + (2n)(2n + 1), Sn = Sn1 + (2n)(2n + 1) pour n N .

3.2. ALGORITHMIQUE

49

La mthode de programmation de cette srie est celle des suites rcurrentes ; le programme eectue des sommes successives partir de 0 en additionnant les termes pour k = 1, k = 2, jusqu k = n : sage: S = 0 ; n = 10 sage: for k in [1..n]: ....: S = S + (2*k) * (2*k+1) sage: S 1650 Cet exemple illustre une mthode gnrale de programmation dune somme, mais, dans ce cas simple, le calcul formel aboutit au rsultat en toute gnralit : sage: n, k = var( n, k ) ; res = sum(2*k*(2*k+1), k, 1, n) sage: res, factor(res) # rsultat dvelopp puis factoris (4/3*n^3 + 3*n^2 + 5/3*n, 1/3*(n + 1)*(4*n + 5)*n) Ces rsultats peuvent aussi tre obtenus avec un papier et un crayon partir de sommes bien connues :
n

k=
k=1 n

n(n + 1) , 2
n n

k2 =
k=1

n(n + 1)(2n + 1) , 6

2k (2k + 1) = 4
k=1 k=1

k2 + 2
k=1

k=

2 n (n + 1)(2n + 1) + n(n + 1) 3

n(n + 1) (4n + 2) + 3 n(n + 1)(4n + 5) = . = 3 3 Exemples dapproximation de limites de suites. La boucle dnumration permet de calculer un terme donn dune suite ou dune srie, la boucle tant que est quant elle bien adapte pour approcher numriquement une limite de suite. Si une suite (an )nN converge vers R, les termes an sont voisins de pour n assez grand. Il est donc possible dapprocher par un certain terme an , et le problme mathmatique consiste alors majorer plus ou moins facilement lerreur | an |. Cette majoration est immdiate pour des suites (un )nN et (vn )nN adjacentes, cest--dire telles que (un )nN est croissante, (vn )nN est dcroissante, lim vn un = 0.
n+

Dans ce cas, les deux suites convergent vers la mme limite , p N up lim un = = lim vn vp , n+ n+ up +vp vp up 2 . 2

50

CHAP. 3. PROGRAMMATION ET STRUCTURES DE DONNES

Une tude mathmatique prouve que les deux suites ci-dessous sont adjacentes et convergent vers ab lorsque 0 < a < b : u0 = a, v0 = b > a, un+1 = 2 un vn , un + vn vn+1 = un + vn . 2

La limite commune de ces deux suites porte le nom de moyenne arithmticoharmoniquedu fait que la moyenne arithmtique de deux nombres a et b est la moyenne au sens usuel (a + b)/2 et la moyenne harmonique h est linverse de la moyenne des inverses : 1/h = (1/a +1/b)/2 = (a + b)/(2ab). Le programme suivant vrie que la limite est la mme pour des valeurs numriques particulires : sage: U = 2.0; V = 50.0; sage: while V-U >= 1.0e-6: # 1.0e-6 signifie 1.0*10^-6 ....: temp = U ....: U = 2 * U * V / (U + V) ....: V = (temp + V) / 2 sage: U, V (9.99999999989..., 10.0000000001...) Les valeurs de un+1 et de vn+1 dpendent de un et vn ; pour cette raison la boucle principale de ce programme fait intervenir une variable intermdiaire appele ici temp de faon ce que les nouvelles valeurs un+1 , vn+1 de U, V dpendent des deux valeurs prcdentes un , vn . Les deux blocs de gauche ci-dessous dnissent les mmes suites alors que celui de droite construit deux autres suites (un )n et (vn )n ; laectation parallle vite dutiliser une variable intermdiaire : temp = 2*U*V/(U+V) V = (U+V)/2 U = temp U,V = 2*U*V/(U+V),(U+V)/2 (aectation parallle) U = 2*U*V/(U+V) V = (U+V)/2 2un vn un+1 = u + v vn+1 =
n un+1 +vn 2
n n

La srie Sn = k=0 (1)k ak est alterne ds que la suite (an )nN est dcroissante et de limite nulle. Dire que S est alterne signie que les deux suites extraites (S2n )nN et (S2n+1 )nN sont adjacentes de mme limite note . La suite (Sn )nN converge donc aussi vers cette limite et lon a S2p+1 = limn+ Sn S2p . Le programme suivant illustre ce rsultat pour la suite ak = 1/k 3 partir de k = 1, en mmorisant dans deux variables U et V les sommes partielles successives S2n et S2n+1 de la srie qui encadrent la limite : sage: sage: sage: sage: ....: ....: ....: sage: U = 0.0 # la somme S0 est vide, de valeur nulle V = -1.0 # S1 = -1/1^3 n = 0 # U et V contiennent S(2n) et S(2n+1) while U-V >= 1.0e-6: n = n+1 # n += 1 est quivalent U = V + 1/(2*n)^3 # passage de S(2n-1) S(2n) V = U - 1/(2*n+1)^3 # passage de S(2n) S(2n+1) V, U

3.2. ALGORITHMIQUE (-0.901543155458595, -0.901542184868447)

51

La boucle principale du programme modie la valeur de n pour passer lindice suivant tant que les deux valeurs S2n et S2n+1 ne sont pas assez proches lune de lautre. Les deux variables U et V mmorisent ces deux termes successifs ; le corps de la boucle dtermine partir de S2n1 successivement S2n et S2n+1 , do les aectations croises U et V. Le programme se termine lorsque deux termes conscutifs S2n+1 et S2n qui encadrent la limite sont susamment proches lun de lautre, lerreur dapproximation (sans tenir compte des erreurs darrondi) vrie alors 0 a2n+1 = S2n S2n+1 106 . La programmation de ces quatre sries alternes est similaire : (1)n , log n
n

n 2

n 1

(1)n , n

n 1

(1)n , n2 (1)n . nn

n 1

(1) , n4

(1)n en ln n =
n 1 n 1

Les termes gnraux de ces sries tendent plus ou moins vite vers 0 et les approximations des limites demandent, selon les cas, plus ou moins de calculs. La recherche dune prcision de 3, 10, 20 ou 100 dcimales sur les limites de ces sries consiste rsoudre les inquations suivantes : 1/ log n 1/n 1/n2 1/n4 n log n e 1/n2 1/n4 103 103 103 103 103 n n n n n e(10 ) 1.97 10434 3 10 103 32 (103 )1/4 6 5 1010 105 17
3

en log n 1/n2 1/n4

1/n 1/n2 1/n4

1010 1010 1010 1010

n n n n

1010 105 317 10 1050 1025 57

en log n

1020 n 1020 n 1020 n

en log n

10100 n 10100 n 10100 n

Dans les cas les plus simples la rsolution de ces inquations dtermine donc un indice n partir duquel la valeur Sn permet approcher la limite de la srie, ainsi une boucle dnumration for est aussi possible. Au contraire une boucle while est ncessaire ds que la rsolution algbrique en n de linquation an 10p savre impossible. Certaines approximations des limites prcdentes demandent trop de calculs pour tre obtenues directement, notamment ds que lindice n dpasse un ordre de grandeur de 1010 ou 1012 . Une tude mathmatique plus approfondie peut parfois permettre de dterminer la limite ou de lapprocher par dautres mthodes ; ainsi en est-il des sries de Riemann :
n n+

lim

k=1

(1)k 3 = (3), 3 k 4

avec (p) = lim

n+

k=1

1 , kp

52

CHAP. 3. PROGRAMMATION ET STRUCTURES DE DONNES


n n+

lim

k=1

(1)k = log 2, k
n n+

n n+ k

lim

k=1

2 (1)k = , k2 12

lim

k=1

7 4 (1) = . 4 k 6!

Par ailleurs Sage peut calculer formellement certaines de ces sries et dterminer une approximation de (3) avec 1200 dcimales en quelques secondes en eectuant bien moins doprations que les 10400 ncessaires par lapplication directe de la dnition : sage: k = var( k ) ; sum((-1)^k/k, k, 1, +oo) -log(2) sage: sum((-1)^k/k^2, k, 1, +oo), sum((-1)^k/k^3, k, 1, +oo) (-1/12*pi^2, -3/4*zeta(3)) sage: -3/4 * zeta (N(3, digits = 1200)) -0.901542677369695714049803621133587493073739719255374161344\ 203666506378654339734817639841905207001443609649368346445539\ 563868996999004962410332297627905925121090456337212020050039\ ... 019995492652889297069804080151808335908153437310705359919271\ 798970151406163560328524502424605060519774421390289145054538\ 901961216359146837813916598064286672255343817703539760170306262

3.2.2

Les tests

Lautre instruction compose importante est le test : les instructions excutes dpendent de la valeur boolenne dune condition. La structure et deux syntaxes possibles de cette instruction sont les suivantes : if une condition: une suite dinstructions if une condition: une suite dinstructions else: sinon dautres instructions

La suite de Syracuse est dnie selon une condition de parit : u0 N un+1 = un /2 3un + 1 si un est pair, si un est impair.

La conjecture tchque nonce sans preuve connue en 2012 que pour toutes les valeurs initiales u0 N il existe un rang n pour lequel un = 1. Les termes suivants sont alors 4, 2, 1, 4, 2, etc. Calculer chaque terme de cette suite se fait par lintermdiaire dun test. Ce test est plac lintrieur dune boucle tant que qui dtermine la plus petite valeur de n N vriant un = 1 : sage: u = 6 ; n = 0

3.2. ALGORITHMIQUE sage: while u != 1: # test "diffrent de" <> aussi possible ....: if u % 2 == 0: # l oprateur % donne le reste euclidien ....: u = u//2 # // : quotient de la division euclidienne ....: else: ....: u = 3*u+1 ....: n = n+1 sage: n 8

53

Tester si un est pair se fait en comparant 0 le reste de la division par 2 de un . Le nombre ditrations eectues est la valeur de la variable n la n du bloc. Cette boucle se termine ds que la valeur calcule de un est 1 ; par exemple si u0 = 6 alors u8 = 1 et 8 = min{p N |up = 1} : p= 0 1 up = 6 3 2 3 10 5 4 5 6 7 8 9 10 16 8 4 2 1 4 2

La vrication pas--pas du bon fonctionnement de ces lignes peut se faire par un print-espion de la forme print u, n plac dans le corps de la boucle. Linstruction if permet en outre des tests imbriqus dans la branche else laide du mot-clef elif. Ces deux structures sont quivalentes : if une condition cond1: une suite dinstructions inst1 else: if une condition cond2: une suite dinstructions inst2 else: if une condition cond3: une suite dinstructions inst3 else: dans les autres cas instn if cond1: inst1 elif cond2: inst2 elif cond3: inst3 else: instn

Comme pour les boucles, les instructions simples associes aux tests peuvent tre places la suite des deux-points et non dans un bloc en dessous.

3.2.3

Les procdures et les fonctions

Syntaxe gnrale. Comme bien dautres langages informatiques, Sage permet lutilisateur de dnir des fonctions ou des instructions sur mesure. La commande def dont la syntaxe est dtaille ci-dessous autorise la dnition de procdures et de fonctions, cest--dire de sous-programmes (respectivement qui ne renvoient pas de rsultat et qui en renvoient un), avec un ou plusieurs arguments. Ce premier exemple dnit la fonction (x, y ) x2 + y 2 : sage: def fct2 (x, y): ....: return x^2 + y^2 sage: a = var( a ) sage: fct2 (a, 2*a)

54 5*a^2

CHAP. 3. PROGRAMMATION ET STRUCTURES DE DONNES

Lvaluation de la fonction se termine par la commande return dont largument, ici x2 + y 2 , est le rsultat de la fonction. Une procdure est dnie de la mme faon sans renvoyer explicitement de rsultat, et en labsence de linstruction return le bloc dinstructions dnissant le programme est valu jusquau bout. En fait la procdure renvoie la valeur None qui veut bien dire ce quelle veut dire. Par dfaut, Sage considre que toutes les variables intervenant dans une fonction sont locales. Ces variables sont cres chaque appel de la fonction, dtruites la n, et sont indpendantes dautres variables de mme nom pouvant dj exister. Les variables globales ne sont pas modies par lvaluation dune fonction ayant des variables locales du mme nom : sage: def essai (u): ....: t = u^2 ....: return t*(t+1) sage: t = 1 ; u = 2 sage: essai(3), t, u (90, 1, 2) Pour modier une variable globale depuis une fonction, il faut la dclarer explicitement grce au mot-cl global : sage: a = b = 1 sage: def f(): global a; a = b = 2 sage: f(); a, b (2, 1) Lexemple suivant reprend le calcul de la moyenne arithmtico-harmonique de deux nombres supposs strictement positifs : sage: def MoyAH (u, v): ....: u, v = min(u, v), max(u, v) ....: while v-u > 2.0e-8: ....: u, v = 2*u*v/(u+v), (u+v)/2 ....: return (u+v) / 2 sage: MoyAH (1., 2.) 1.41421... sage: MoyAH <function MoyAH at ...>

# correspond une fonction

La fonction MoyAH comporte deux paramtres nots u et v qui sont des variables locales dont les valeurs initiales sont xes lors de lappel de cette fonction ; par exemple MoyAH(1., 2.) dbute lexcution de cette fonction avec les valeurs 1. et 2. des variables u et v. La programmation structure conseille de dnir une fonction de faon ce que return soit la dernire instruction du bloc de celle-ci. Place au milieu du bloc dinstructions dune fonction, cette commande return termine lexcution

3.2. ALGORITHMIQUE

55

de la fonction en interrompant avant la n lvaluation complte de ce bloc ; en outre il peut y en avoir plusieurs dans direntes branches des tests. La traduction informatique de ltat desprit des mathmatiques suggre de programmer des fonctions renvoyant chacune un rsultat partir de leurs arguments, plutt que des procdures achant ces rsultats par une commande print. Le systme de calcul formel Sage repose dailleurs sur de trs nombreuses fonctions, par exemple exp ou solve, qui renvoient toutes un rsultat, par exemple un nombre, une expression, une liste de solutions, etc. Mthode itrative et mthode rcursive. Une fonction dnie par lutilisateur est construite comme une suite dinstructions. Une fonction est dite rcursive lorsque son valuation ncessite dans certains cas dexcuter cette mme fonction avec dautres paramtres. La suite factorielle (n!)nN en est un exemple simple : 0! = 1, (n + 1)! = (n + 1) n! pour tout n N.

Les deux fonctions suivantes aboutissent au mme rsultat partir dun argument entier naturel n ; la premire fonction utilise la mthode itrative avec une boucle for, et la seconde la mthode rcursive traduisant mot pour mot la dnition rcurrente prcdente : sage: def fact1 (n): ....: res = 1 ....: for k in [1..n]: res = res*k ....: return res sage: def fact2 (n): ....: if n == 0: return 1 ....: else: return n*fact2(n-1) La suite de Fibonacci est une suite rcurrente dordre 2 car la valeur de un+2 dpend uniquement de celles de un et de un+1 : u0 = 0, u1 = 1, un+2 = un+1 + un pour tout n N.

La fonction fib1 ci-dessous applique une mthode de calcul itratif des termes de la suite de Fibonacci en utilisant deux variables intermdiaires U et V pour mmoriser les deux valeurs prcdentes de la suite avant de passer au terme suivant : sage: def fib1 (n): ....: if n == 0 or n == 1: return n ....: else: ....: U = 0 ; V = 1 # les termes initiaux u0 et u1 ....: for k in [2..n]: W = U+V ; U = V ; V = W ....: return V sage: fib1(8) 21

56

CHAP. 3. PROGRAMMATION ET STRUCTURES DE DONNES

La boucle applique partir de n = 2 la relation un = un1 + un2 . Par ailleurs laectation parallle U,V = V,U+V la place de W=U+V ; U=V ; V=W vite lutilisation de la variable W et traduit litration de la suite vectorielle Xn = (un , un+1 ) rcurrente dordre 1 dnie par Xn+1 = f (Xn ) quand f (a, b) = (b, a + b). Ces mthodes itratives sont ecaces mais leur programmation doit transformer la dnition de la suite de faon ladapter aux manipulations des variables. Au contraire la fonction rcursive fib2 suit de beaucoup plus prs la dnition mathmatique de cette suite, ce qui facilite sa programmation et sa comprhension : sage: def fib2 (n): ....: if 0 <= n <= 1: return n # pour n = 0 ou n = 1 ....: else: return fib2(n-1) + fib2(n-2) Le rsultat de cette fonction est la valeur renvoye par linstruction conditionnelle : 0 et 1 respectivement pour n = 0 et n = 1, et la somme fib2(n-1)+fib2(n-2) sinon ; chaque branche du test comporte une instruction return. Cette mthode est cependant moins ecace car beaucoup de calculs sont inutilement rpts. Par exemple fib2(5) value fib2(3) et fib2(4) qui sont eux aussi calculs de la mme manire. Ainsi Sage value deux fois fib2(3) et trois fois fib2(2). Ce processus se termine lors de lvaluation de fib2(0) ou de fib2(1), de valeur 0 ou 1, et lvaluation de fib2(n) consiste calculer nalement un en additionnant un uns et un1 zros. Le nombre total dadditions eectues pour dterminer un est donc gal un+1 1 ; ce nombre est considrable et crot trs rapidement. Aucun ordinateur, aussi rapide soit-il, ne peut calculer de cette manire u100 . Dautres mthodes sont aussi possibles, par exemple mmoriser les calculs intermdiaires grce au dcorateur @cached_function, ou exploiter une proprit des puissances de matrices : le paragraphe suivant sur lexponentiation rapide montre comment calculer le millionime terme de cette suite.

3.2.4

Exemple : exponentiation rapide

Une mthode nave de calcul de an consiste eectuer n N multiplications par a dans une boucle for : sage: a = 2; n = 6; res = 1 # 1 est le neutre du produit sage: for k in [1..n]: res = res*a sage: res # La valeur de res est 2^6 64 Les puissances entires interviennent sous de trs nombreux aspects en mathmatique et en informatique ; ce paragraphe tudie une mthode gnrale de calcul dune puissance entire an plus rapide que celle ci-dessus. La suite (un )nN dnie ci-aprs vrie un = an ; ce rsultat se dmontre par rcurrence partir des

3.2. ALGORITHMIQUE galits a2k = (ak ) et ak+1 = a ak : si n = 0, 1 2 un = un/2 si n est pair et strictement positif, a un1 si n est impair. Par exemple, pour u11 : u11 = a u10 , u2 = u2 1, ainsi : u2 = a 2 ,
4 u4 = u2 2 =a , 2

57

(3.1)

u10 = u2 5,

u5 = a u4 ,

u4 = u2 2,

u1 = a u0 = a ;

u5 = a a4 = a5 ,

10 u10 = u2 5 =a ,

u11 = a a10 = a11 .

Le calcul de un ne fait intervenir que des termes uk avec k {0 n 1}, et donc celui-ci est bien dcrit en un nombre ni doprations. En outre cet exemple montre que la valeur de u11 est obtenue par lvaluation des 6 termes u10 , u5 , u4 , u2 , u1 et u0 , et eectue uniquement 6 multiplications. Le calcul de un ncessite entre log n / log 2 et 2 log n / log 2 multiplications car aprs une ou deux tapes selon que n est pair ou impair un sexprime en fonction de uk , avec k n/2. Cette mthode est donc incomparablement plus rapide que la mthode nave quand n est grand ; une vingtaine de termes pour n = 104 et non 104 produits : indices traits : 10 000 39 5 000 2 500 38 19 1 250 18 625 9 624 8 312 4 156 2 78 1

Cette mthode nest cependant pas toujours la plus rapide ; les calculs suivants sur b, c, d et f eectuent 5 produits pour calculer a15 , alors que par cette mthode les oprations sur u, v , w, x et y ncessitent 6 multiplications sans compter le produit par 1 : b = a2 c = ab = a3 d = c2 = a6 f = cd = a9 u = a2 v = au = a3 w = v 2 = a6 x = aw = a7 y = x2 = a14 ay = a15 df = a15 : 5 produits ; : 6 produits.

La fonction rcursive puiss1 calcule la suite rcurrente (3.1) avec uniquement des multiplications pour programmer loprateur dlvation une puissance : sage: def puiss1 (a, n): ....: if n == 0: return 1 ....: elif n % 2 == 0: b = puiss1 (a, n//2); return b*b ....: else: return a * puiss1(a, n-1) sage: puiss1 (2, 11) 2048 # a pour rsultat 2^11

58

CHAP. 3. PROGRAMMATION ET STRUCTURES DE DONNES

Le nombre doprations eectues par cette fonction est le mme que celui fait par un calcul la main en reprenant les rsultats dj calculs. Au contraire si les instructions b = puiss(a, n//2);return b*b faites aprs le test de parit de n taient remplaces par puiss1(a, n//2)*puiss1(a, n//2) Sage eectuerait beaucoup plus de calculs car, comme pour la fonction rcursive fib2 calculant la suite de Fibonacci, certaines oprations seraient inutilement rptes. Il y aurait en dnitive de lordre de n multiplications, autant que via la mthode nave. Par ailleurs la commande return puiss1(a*a, n//2) peut remplacer de faon quivalente ces deux instructions. Le programme ci-dessous eectue le mme calcul par une mthode itrative : sage: def puiss2 (u, k): ....: v = 1 ....: while k != 0: ....: if k % 2 == 0: u = u*u ; k = k//2 ....: else: v = v*u ; k = k-1 ....: return v sage: puiss2 (2, 10) 1024 # a pour rsultat 2^10

Le fait que la valeur de puiss2(a, n) est an se dmontre en vriant quitration aprs itration les valeurs des variables u, v et k sont lies par lgalit v uk = an , que lentier k soit pair ou impair. la premire itration v = 1, u = a et k = n ; aprs la dernire itration k = 0, donc v = an . Les valeurs successives de la variable k sont entires et positives, et elles forment une suite strictement dcroissante. Cette variable ne peut donc prendre quun nombre ni de valeurs avant dtre nulle et de terminer ainsi linstruction de boucle. En dpit des apparences la fonction puiss1 est programme rcursivement, et puiss2 de faon itrative ces deux fonctions traduisent presque le mme 2 algorithme : la seule dirence est que la premire value a2k par (ak ) alors que k la seconde calcule a2k par (a2 ) lors de la modication de la variable u. Cette mthode ne se limite pas au calcul des puissances positives de nombres partir de la multiplication, mais sadapte toute loi de composition interne associative. Cette loi doit tre associative an de vrier les proprits usuelles des produits itrs. Ainsi en remplaant le nombre 1 par la matrice unit 1n les deux fonctions prcdentes valueraient les puissances positives de matrices carres. Ces fonctions illustrent comment programmer ecacement loprateur puissance partir de la multiplication, et ressemblent la mthode implante dans Sage. Par exemple une puissance de matrice permet dobtenir des termes dindices encore plus grands que prcdemment de la suite de Fibonacci : A= 0 1 1 , 1 Xn = un , un+1 AXn = Xn+1 An X0 = Xn .

Le programme Sage correspondant tient en deux lignes, et le rsultat recherch est la premire coordonne du produit matriciel An X0 , ce qui fonctionne eectivement

3.2. ALGORITHMIQUE

59

mme pour n = 107 ; ces deux programmes sont quivalents et leur ecacit provient du fait que Sage applique essentiellement une mthode dexponentiation rapide : sage: def fib3 (n): ....: A = matrix ([[0, 1], [1, 1]]) ; X0 = vector ([0, 1]) ....: return (A^n*X0)[0] sage: def fib4 (n): ....: return (matrix([[0,1], [1,1]])^n * vector([0,1]))[0]

3.2.5

Achage et saisie

Linstruction print est la principale commande dachage. Par dfaut, les arguments sont achs les uns la suite des autres spars par un espace ; Sage passe automatiquement la ligne la n de la commande : sage: print 2^2, 3^3, 4^4 ; print 5^5, 6^6 4 27 256 3125 46656 Une virgule la n de la commande print omet ce passage la ligne, et la prochaine instruction print continue sur la mme ligne : sage: for k in [1..10]: print + , k, + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 Il est possible dacher des rsultats sans espace intermdiaire en transformant ceux-ci en une chane de caractres par la fonction str(..), et en eectuant la concatnation des chanes de caractres par loprateur + : sage: print 10, 0.5 ; print 10+0.5 ; print 10.0, 5 10 0.500000000000000 10.5000000000000 10.0000000000000 5 sage: print 10+0, 5 ; print str(10)+str(0.5) 10 5 100.500000000000000 La dernire section de ce chapitre sur les listes et les structures prsente les chanes de caractres de manire plus approfondie. La commande print permet aussi de formater lachage des nombres pour les prsenter en tableaux, lexemple suivant partir du motif %.d et de loprateur % ache la table des puissances quatrimes les unes sous les autres : sage: for k in [1..6]: print %2d^4 = %4d % (k, k^4) 1^4 = 1 2^4 = 16 3^4 = 81 4^4 = 256 5^4 = 625 6^4 = 1296

60

CHAP. 3. PROGRAMMATION ET STRUCTURES DE DONNES

Loprateur % insre les nombres placs sa droite dans la chane de caractres sa gauche la place des signes de conversion comme %2d ou %.4f. Dans lexemple prcdent le terme %4d complte gauche par des espaces la chane de caractres reprsentant lentier k 4 de faon occuper au minimum quatre caractres. De mme le motif %.4f dans pi = %.4f % n(pi) ache pi = 3.1416 avec quatre chires aprs le sparateur dcimal. Dans un terminal, la fonction raw_input(message) ache le texte message, attend une saisie au clavier valide par un passage la ligne, et renvoie la chane de caractres correspondante.

3.3

Listes et structures composes

Cette section dtaille les structures de donnes composes de Sage : les chanes de caractres, les listes de type modiable ou immuable , les ensembles et les dictionnaires.

3.3.1

Dnition des listes et accs aux lments

La notion de liste en informatique et celle de n-uplet en mathmatiques permettent lnumration dobjets mathmatiques. Cette notion de couple avec (a, b) = (b, a) et de n-uplet prcise la position de chaque lment au contraire de la notion densemble. On dnit une liste en plaant ses lments entre crochets [...] spars par des virgules. Laectation du triplet (10, 20, 30) la variable L seectue de la manire suivante, et la liste vide, sans lment, est simplement dnie ainsi : sage: L = [10, 20, 30] sage: L [10, 20, 30] sage: [] []

# [] est la liste vide

Les coordonnes des listes sont numres dans lordre partir de lindice 0, puis 1, 2, etc. Laccs la coordonne de rang k dune liste L seectue par L[k], mathmatiquement ceci correspond la projection canonique de la liste considre comme un lment dun produit cartsien sur la coordonne dordre k . La fonction len renvoie le nombre dlments dune liste 6 : sage: L[1], len(L), len([]) (20, 3, 0) La modication dune coordonne est obtenue de la mme manire, par aectation de la coordonne correspondante. Ainsi la commande suivante modie le troisime terme de la liste indic par 2 : sage: L[2] = 33
6. Le rsultat de la fonction len est de type int propre Python, la composition Integer(len(..)) renvoie un entier Integer de Sage.

3.3. LISTES ET STRUCTURES COMPOSES sage: L [10, 20, 33]

61

Les indices ngatifs accdent aux lments de la liste compts partir du dernier terme : sage: L = [11, 22, 33] sage: L[-1], L[-2], L[-3] (33, 22, 11) La commande L[p:q] extrait la sous-liste [L[p], L[p+1], ..., L[q-1]] qui est vide si q p. Des indices ngatifs permettent dextraire les derniers termes de la liste ; enn la rfrence L[p:] construit la sous-liste L[p:len(L)] partir de lindice p jusqu la n, et L[:q] = L[0:q] numre les lments partir du dbut jusqu lindice q exclu : sage: L = [0, 11, 22, 33, 44, 55] sage: L[2:4] [22, 33] sage: L[-4:4] [22, 33] sage: L[2:-2] [22, 33] sage: L[:4] [0, 11, 22, 33] sage: L[4:] [44, 55] De la mme manire que la commande L[n] = ... modie un lment de la liste, laectation L[p:q] = [...] remplace la sous-liste entre les indices p compris et q exclu : sage: L = [0, 11, 22, 33, 44, 55, 66, 77] sage: L[2:6] = [12, 13, 14] # remplace [22, 33, 44, 55] Ainsi L[:1] = [] et L[-1:] = [] suppriment respectivement le premier et le dernier terme dune liste, et rciproquement L[:0] = [a] et L[len(L):] = [a] insrent un lment a respectivement en tte et la n de la liste. Plus gnralement les termes dune liste vrient ces galits : L = [ 0, 1, 2, . . . , pour 0 k = kn
n1 ]

= [ n , k < n,

1n , . . . 2 , 1 ] j

n+j

pour n

avec n = len(L), j < 0.

Loprateur in teste lappartenance dun lment une liste. Sage eectue le test dgalit de deux listes par == qui compare les lments un par un. Ces deux sous-listes avec des indices positifs ou ngatifs sont gales : sage: L = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19] sage: L[3:len(L)-5] == L[3-len(L):-5] True sage: [5 in L, 6 in L]

62

CHAP. 3. PROGRAMMATION ET STRUCTURES DE DONNES

[True, False] Les exemples ci-dessus concernent des listes dentiers, mais les lments des listes peuvent tre nimporte quels objets Sage, nombres, expressions, autres listes, etc.

3.3.2

Oprations globales sur les listes

Loprateur daddition + eectue la concatnation de deux listes, et loprateur de multiplication * associ un entier itre cette concatnation : sage: L = [1, 2, 3, sage: 4 * [1, 2, 3, [1, 2, 3] ; L + [10, 20, 30] 10, 20, 30] [1, 2, 3] 1, 2, 3, 1, 2, 3, 1, 2, 3]

La concatnation des deux sous-listes L[:k] et L[k:] reconstruit la liste initiale. Ceci explique pourquoi la borne gauche dindice p dune sous-liste L[p:q] est comprise, alors que la borne droite dindice q est exclue : L = L[:k]+L[k:] = [ 0 , 1 , 2 , . . . , n1 ] = [ 0 , 1 , 2 , . . . , k1 ] + [ k , k+1 , k+2 , . . . , Lexemple suivant illustre cette proprit : sage: L = 5*[10, 20, 30] ; L[:3]+L[3:] == L True Loprateur compos de deux points .. automatise la construction des listes dentiers sans numrer explicitement tous leurs lments. Lexemple suivant construit une liste faite dnumrations dentiers et dlments isols : sage: [1..3, 7, 10..13] [1, 2, 3, 7, 10, 11, 12, 13] La suite de ce paragraphe dcrit comment construire limage dune liste par une application et une sous-liste dune liste. Les fonctions associes sont map et filter, et la construction [..for..x..in..]. Les mathmatiques font souvent intervenir des listes constitues des images par une application f de ses lments : (a0 , a1 , a2 , . . . , an1 ) (f (a0 ), f (a1 ), . . . , f (an1 )). La commande map construit cette image ; lexemple suivant applique la fonction trigonomtrique cos une liste dangles usuels : sage: map (cos, [0, pi/6, pi/4, pi/3, pi/2]) [1, 1/2*sqrt(3), 1/2*sqrt(2), 1/2, 0] Il est aussi possible dutiliser une fonction de lutilisateur dnie par def, ou de dclarer directement une fonction par lambda ; la commande ci-dessous est quivalente la prcdente et applique la fonction dnie par t cos t : sage: map (lambda t: cos(t), [0, pi/6, pi/4, pi/3, pi/2]) [1, 1/2*sqrt(3), 1/2*sqrt(2), 1/2, 0]
n1 ].

3.3. LISTES ET STRUCTURES COMPOSES

63

La commande lambda est suivie de la dclaration du ou des paramtres spars par des virgules, et ne peut comporter aprs le deux-points quune et une seule expression qui est le rsultat de la fonction, sans utiliser linstruction return. Cette fonction lambda peut aussi comporter un test ; les codes suivants sont quivalents : fctTest1 = lambda x: res1 if cond else res2 def fctTest2 (x): if cond: return res1 else: return res2 Les trois commandes map suivantes sont quivalentes, la composition des applications N cos tant eectue dune faon ou dune autre : sage: map (lambda t: N(cos(t)), [0, pi/6, pi/4, pi/3, pi/2]) [1.00000000000000, 0.866025403784439, 0.707106781186548, 0.500000000000000, 0.000000000000000] sage: map (N, map (cos, [0, pi/6, pi/4, pi/3, pi/2])) [1.00000000000000, 0.866025403784439, 0.707106781186548, 0.500000000000000, 0.000000000000000] sage: map (compose(N, cos), [0, pi/6, pi/4, pi/3, pi/2]) [1.00000000000000, 0.866025403784439, 0.707106781186548, 0.500000000000000, 0.000000000000000] La commande filter construit une sous-liste des lments vriant une condition. Cet exemple applique le test de primalit is_prime aux entiers 1, ..., 55 : sage: filter (is_prime, [1..55]) [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53] La fonction de test peut aussi tre dnie lintrieur de la commande filter. Lexemple ci-dessous, par des essais exhaustifs, dtermine toutes les racines quatrimes de 7 modulo le nombre premier 37 ; cette quation comporte quatre solutions 3, 18, 19 et 34 : sage: p = 37 ; filter (lambda n: n^4 % p == 7, [0..p-1]) [3, 18, 19, 34] Par ailleurs, la commande [..for..x..in..] construit par comprhension une liste ; ces deux commandes numrent de faon quivalente les entiers impairs de 1 31 : sage: map(lambda n:2*n+1, [0..15]) [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31] sage: [2*n+1 for n in [0..15]] [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31] Cette commande est indpendante de la commande de boucle for. La condition if associe for aboutit cette construction quivalente la fonction filter :

64

CHAP. 3. PROGRAMMATION ET STRUCTURES DE DONNES (is_prime, [1..55]) 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53] p in [1..55] if is_prime(p)] 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53]

sage: filter [2, 3, 5, 7, sage: [p for [2, 3, 5, 7,

Les deux exemples suivants combinent les tests if et filter avec for pour dterminer une liste de nombres premiers qui sont congrus 1 modulo 4, puis une liste de carrs de nombres premiers : sage: filter (is_prime, [4*n+1 for n in [0..20]]) [5, 13, 17, 29, 37, 41, 53, 61, 73] sage: [n^2 for n in [1..20] if is_prime(n)] [4, 9, 25, 49, 121, 169, 289, 361] Dans le premier cas le test is_prime est eectu aprs le calcul 4n + 1 alors que dans le second le test est eectu avant le calcul du carr n2 . La fonction reduce opre par associativit de la gauche vers la droite sur les lments dune liste. Dnissons ainsi la loi de composition interne : x y = 10x + y , alors ((1 2) 3) 4 = (12 3) 4 = 1234.

Le premier argument de reduce est une fonction deux paramtres et le deuxime est la liste des arguments : sage: reduce (lambda x, y: 10*x+y, [1, 2, 3, 4]) 1234 Un troisime argument optionnel donne le rsultat sur une liste vide : sage: reduce (lambda x, y: 10*x+y, [9, 8, 7, 6], 1) 19876 Il correspond gnralement llment neutre de lopration applique. Ainsi, lexemple ci-dessous calcule un produit dentiers impairs : sage: L = [2*n+1 for n in [0..9]] sage: reduce (lambda x, y: x*y, L, 1) 654729075 Les fonctions add 7 et prod de Sage appliquent directement loprateur reduce pour calculer des sommes et des produits ; le rsultat est le mme dans les trois exemples ci-dessous, et la commande sur une liste autorise en outre dajouter un second terme optionnel reprsentant llment neutre, 1 pour le produit et 0 pour la somme, ou une matrice unit pour un produit matriciel : sage: prod ([2*n+1 for n in [0..9]], 1) # une liste avec for 654729075 sage: prod ( 2*n+1 for n in [0..9]) # sans liste 654729075 sage: prod (n for n in [0..19] if n%2 == 1) 654729075
7. ne pas confondre avec sum, qui cherche une expression symbolique pour une somme.

3.3. LISTES ET STRUCTURES COMPOSES

65

La fonction any associe loprateur or et la fonction all loprateur and sont de principe et de syntaxe quivalents. Cependant lvaluation se termine ds que le rsultat True ou False dun des termes impose ce rsultat sans eectuer lvaluation des termes suivants : sage: def fct (x): return 4/x == 2 sage: all (fct(x) for x in [2, 1, 0]) False sage: any (fct(x) for x in [2, 1, 0]) True En revanche la construction de la liste [fct(x) for x in [2, 1, 0]] et la commande all([fct(x) for x in [2, 1, 0]]) provoquent des erreurs car tous les termes sont valus, y compris le dernier avec x = 0. Limbrication de plusieurs commandes for permet de construire le produit cartsien de deux listes ou de dnir des listes de listes. Lexemple suivant montre que si lon combine plusieurs oprateurs for dans la mme dnition par comprhension, le plus gauche correspond la boucle la plus extrieure : sage: [[x, y] for x in [1..2] for y in [6..8]] [[1, 6], [1, 7], [1, 8], [2, 6], [2, 7], [2, 8]] Lordre ditration est donc dirent de celui obtenu en imbriquant plusieurs dnitions par comprhension : sage: [[[x, y] for x in [1..2]] for y in [6..8]] [[[1, 6], [2, 6]], [[1, 7], [2, 7]], [[1, 8], [2, 8]]] La commande map avec plusieurs listes en argument avance de faon synchronise dans ces listes. sage: map (lambda x, y: [x, y], [1..3], [6..8]) [[1, 6], [2, 7], [3, 8]] Enn la commande flatten permet de concatner des listes sur un ou plusieurs niveaux : sage: L = [[1, 2, [3]], [4, [5, 6]], [7, [8, [9]]]] sage: flatten (L, max_level = 1) [1, 2, [3], 4, [5, 6], 7, [8, [9]]] sage: flatten (L, max_level = 2) [1, 2, 3, 4, 5, 6, 7, 8, [9]] sage: flatten (L) # quivaut flatten (L, max_level = 3) [1, 2, 3, 4, 5, 6, 7, 8, 9] Ces manipulations lmentaires de listes interviennent de faon trs utile dans les autres branches de Sage ; lexemple suivant calcule les premires drives itres de x ex ; le premier argument de diff est lexpression driver, et le ou les suivants correspondent la variable de drivation, ces paramtres pouvant aussi tre la liste des variables par rapport auxquelles les drivations sont eectues : sage: x = var( x )

66

CHAP. 3. PROGRAMMATION ET STRUCTURES DE DONNES

sage: factor(diff(x*exp(x), [x, x])) (x + 2)*e^x sage: map(lambda n: factor(diff(x*exp(x), n*[x])), [0..6]) [x*e^x, (x + 1)*e^x, (x + 2)*e^x, (x + 3)*e^x, (x + 4)*e^x, (x + 5)*e^x, (x + 6)*e^x] sage: [factor (diff (x*exp(x), n*[x])) for n in [0..6]] [x*e^x, (x + 1)*e^x, (x + 2)*e^x, (x + 3)*e^x, (x + 4)*e^x, (x + 5)*e^x, (x + 6)*e^x] La commande diff possde plusieurs syntaxes. Les paramtres suivant la fonction f peuvent aussi bien tre la liste des variables de drivation que lnumration de ces variables, ou lordre de la drive : diff(f(x), x, x, x), diff(f(x), [x, x, x]), diff(f(x), x, 3).

On peut aussi employer diff(f(x), 3) pour les fonctions une seule variable. Ces rsultats se vrient directement par la formule de Leibniz de drive itre dun produit de deux termes o les drives dordre 2 ou plus de x sont nulles :
n

(xex )(n) =
k=0

n (k) x (nk) x (e ) = (x + n)ex . k

3.3.3

Principales mthodes sur les listes

La mthode reverse renverse lordre des lments dune liste, et la mthode sort transforme la liste initiale en une liste trie : sage: L = [1, 8, 5, 2, 9] ; L.reverse() ; L [9, 2, 5, 8, 1] sage: L.sort() ; L [1, 2, 5, 8, 9] sage: L.sort(reverse = True) ; L [9, 8, 5, 2, 1] Ces deux mthodes modient la liste L, et lancienne valeur est perdue. Un premier argument optionnel sort permet de choisir la relation dordre applique sous la forme dune fonction Ordre(x, y) deux paramtres. Le rsultat doit tre du type int des entiers Python ; il est strictement ngatif, nul ou positif, par exemple 1, 0 ou 1, selon que x y , x = y ou x y . La liste transforme (x0 , x1 , . . . , xn1 ) vrie x0 x1 xn1 . Lordre lexicographique de deux listes de nombres de mme longueur est similaire lordre alphabtique et est dni par cette quivalence en ignorant les premiers termes lorsquils sont gaux deux deux : P = (p0 , p1 , . . . pn1 ) lex Q = (q0 , q1 , . . . qn1 ) r {0, . . . , n 1} (p0 , p1 , . . . , pr1 ) = (q0 , q1 , . . . , qr1 ) et pr < qr . La fonction suivante compare deux listes supposes de mme longueur. Malgr la boucle a priori sans n while True, les commandes return sortent directement

3.3. LISTES ET STRUCTURES COMPOSES

67

de cette boucle et terminent la fonction. Le rsultat est 1, 0 ou 1 selon que P lex Q, P = Q ou P lex Q : sage: def alpha (P, Q): # len(P) = len(Q) par hypothse ....: i = 0 ....: while True: ....: if i == len(P): return int(0) ....: elif P[i] < Q[i]: return int(-1) ....: elif P[i] > Q[i]: return int(1) ....: else: i = i+1 sage: alpha ([2, 3, 4, 6, 5], [2, 3, 4, 5, 6]) 1 La commande suivante trie une liste de listes de mme longueur en suivant lordre lexicographique. Cette fonction correspond par ailleurs lordre implant dans Sage pour comparer deux listes ; la commande L.sort() sans paramtre optionnel est quivalente : sage: L = [[2, 2, 5], [2, 3, 4], [3, 2, 4], [3, 3, 3],\ ....: [1, 1, 2], [1, 2, 7]] sage: L.sort (cmp = alpha) ; L [[1, 1, 2], [1, 2, 7], [2, 2, 5], [2, 3, 4], [3, 2, 4], [3, 3, 3]] La dnition de lordre lexicographique homogne consiste dabord comparer les termes de mme poids avant dappliquer lordre lexicographique, o le poids est la somme des coecients : P = (p0 , p1 , . . . pn1 ) lexH Q = (q0 , q1 , . . . qn1 )
n1 n1 n1 n1

k=0

pk <
k=0

qk ou
k=0

pk =
k=0

qk et P lex Q

Le code ci-dessous implante cet ordre homogne : sage: ....: ....: ....: ....: def homogLex (P, Q): sp = sum (P) ; sq = sum (Q) if sp < sq: return int(-1) elif sp > sq: return int(1) else: return alpha (P, Q)

sage: homogLex ([2, 3, 4, 6, 4], [2, 3, 4, 5, 6]) -1 La fonction sorted de Sage est une fonction au sens mathmatique du terme ; elle prend une liste comme premier argument et, sans la modier, renvoie comme rsultat une liste trie, contrairement la mthode sort qui modie la liste en place. Sage propose dautres mthodes sur les listes, insertion dun lment en n de liste, concatnation en n de liste, et dnombrement du nombre de rptitions

68

CHAP. 3. PROGRAMMATION ET STRUCTURES DE DONNES

dun lment : L.append(x) L.extend(L1) L.insert(i, x) L.count(x) est est est est quivalent quivalent quivalent quivalent L[len(L):] = [x] L[len(L):] = L1 L[i:i] = [x] len (select (lambda t : t == x, L))

Les commandes L.pop(i) et L.pop() suppriment llment dindice i ou le dernier lment dune liste, et renvoient la valeur de cet lment ; les deux fonctions cidessous dcrivent leur fonctionnement respectif : def pop1 (L, i): a = L[i] L[i:i+1] = [] return a def pop2 (L): return pop1 (L, len(L)-1)

Par ailleurs L.index(x) renvoie lindice du premier terme gal x, et L.remove(x) supprime le premier lment de valeur x de la liste. Ces commandes provoquent une erreur si x nappartient pas la liste. Enn la commande del L[p:q] est quivalente L[p:q] = [], et del L[i] supprime llment dindice i. Contrairement ce quil se produit dans de nombreux autres langages informatiques, ces fonctions modient la liste L sans crer de nouvelle liste.

3.3.4

Exemples de manipulation de listes

Lexemple suivant construit la liste des termes pairs et celle des termes impairs dune liste donne. Cette premire solution parcourt deux fois la liste et eectue deux fois ces tests : sage: def fct1(L): ....: return [filter (lambda n: n % 2 == 0, L), ....: filter (lambda n: n % 2 == 1, L)] sage: fct1([1..10]) [[2, 4, 6, 8, 10], [1, 3, 5, 7, 9]] Cette deuxime solution parcourt une seule fois la liste initiale et construit petit petit ces deux listes rsultats : sage: def fct2 (L): ....: res0 = [] ; res1 = [] ....: for k in L: ....: if k%2 == 0: res0.append(k) # ou res0[len(res0):] = [k] ....: else: res1.append(k) # ou res1[len(res1):] = [k] ....: return [res0, res1] Ce programme remplace la boucle for et les variables auxiliaires par un appel rcursif et un paramtre supplmentaire :

3.3. LISTES ET STRUCTURES COMPOSES sage: def fct3a (L, res0, res1): ....: if L == []: return [res0, res1] ....: elif L[0]%2 == 0: return fct3a(L[1:], res0+[L[0]], res1) ....: else: return fct3a (L[1:], res0, res1+[L[0]]) sage: def fct3 (L): return fct3a (L, [], [])

69

Les paramtres res0 et res1 contiennent les premiers lments dj tris, et la liste paramtre L perd un terme chaque appel rcursif. Le deuxime exemple ci-dessous extrait toutes les suites croissantes dune liste de nombres. Trois variables sont utilises, la premire res mmorise les suites croissantes dj obtenues, la variable debut indique la position o la suite croissante en cours commence, et la variable k est lindice de boucle : sage: def sousSuites (L): ....: if L == []: return [] ....: res = [] ; debut = 0 ; k = 1 ....: while k < len(L): # 2 termes conscutifs sont dfinis ....: if L[k-1] > L[k]: ....: res.append (L[debut:k]) ; debut = k ....: k = k+1 ....: res.append (L[debut:k]) ....: return res sage: sousSuites([1, 4, 1, 5]) [[1, 4], [1, 5]] sage: sousSuites([4, 1, 5, 1]) [[4], [1, 5], [1]] Le corps de la boucle permet de passer au terme suivant de la liste. Si le test est vri, alors la sous-suite croissante en cours se termine, et il faut passer une nouvelle sous-suite, sinon elle se prolonge au terme suivant. Linstruction aprs la boucle ajoute au rsultat nal la sous-suite croissante en cours de parcours qui possde au moins un lment.

3.3.5

Chanes de caractres

Les chanes de caractres sont dlimites par des guillemets anglais droits, simples ... ou doubles "...". Les chanes dlimites par des guillemets simples peuvent contenir des guillemets doubles, et rciproquement. Les chanes peuvent aussi tre dlimites par des triples guillemets ... et, dans ce cas peuvent tre saisies sur plusieurs lignes et contenir des guillemets simples ou doubles. sage: S = Ceci est une chane de caractres. Le caractre dchappement est le signe \, il permet dinclure des passages la ligne par \n, des guillemets par \" ou par \ , le caractre de tabulation par \t, le signe dchappement par \\. Les chanes de caractres peuvent contenir des caractres accentus, et plus gnralement des caractres Unicode quelconques :

70

CHAP. 3. PROGRAMMATION ET STRUCTURES DE DONNES

sage: S = Ceci est une chane de caractres. ; S Ceci est une cha\xc3\xaene de caract\xc3\xa8res. sage: print S Ceci est une chane de caractres. La comparaison des chanes de caractres seectue en fonction du code interne de chaque caractre. La longueur dune chane est obtenue par la fonction len, et la concatnation de chanes se fait par les signes daddition + et de multiplication * . Laccs une sous-chane de caractres de S seectue comme pour les listes par des crochets S[n], S[p:q], S[p:] et S[:q], et le rsultat est une chane de caractres. Le langage ne permet pas de modier la chane initiale par une aectation de cette forme, pour cette raison le type chane de caractres est dit immuable. La fonction str convertit son argument en une chane de caractres. La mthode split dcoupe une chane de caractres en listes de sous-chanes au niveau des espaces : sage: S= un deux trois quatre cinq six sept ; L=S.split(); L [ un , deux , trois , quatre , cinq , six , sept ] La bibliothque trs complte re des expressions rgulires de Python peut aussi tre utilise pour la recherche des sous-chanes et la reconnaissance de motifs et de mots.

3.3.6

Structure partage ou duplique

Une liste entre crochets [...] peut tre modie par des aectations sur ses lments, par un changement du nombre de termes de la liste, ou des mthodes comme le tri sort ou le renversement reverse. Laectation dune liste une variable ne duplique pas la structure mais partage les mmes donnes. Dans lexemple suivant les listes L1 et L2 restent identiques ; elles correspondent deux alias du mme objet, et la modication de lune est visible sur lautre : sage: L1 = [11, 22, 33] ; L2 = L1 sage: L1[1] = 222 ; L2.sort() ; L1, L2 ([11, 33, 222], [11, 33, 222]) sage: L1[2:3] = []; L2[0:0] = [6, 7, 8] sage: L1, L2 ([6, 7, 8, 11, 33], [6, 7, 8, 11, 33]) Au contraire les images de listes par map, les constructions de sous-listes par L[p:q], filter ou [..for..if..], la concatnation par + et *, et laplatissement de listes par flatten dupliquent la structure des donnes. Dans lexemple prcdent remplacer sur la premire ligne L2 = L1 par lune des six commandes ci-aprs change compltement les rsultats suivants car les modications dune liste ne se propagent pas lautre. Les deux structures deviennent indpendantes, les deux listes sont distinctes mme si elles ont la

3.3. LISTES ET STRUCTURES COMPOSES

71

mme valeur ; ainsi laectation L2 = L1[:] recopie la sous-liste de L1 du premier au dernier terme, et donc duplique la structure complte de L1 : L2 = [11, 22, 33] L2 = copy(L1) L2 = []+L1 L2 = L1+[] L2 = L1[:] L2 = 1*L1

Le test du partage des structures de Sage seectue par loprateur binaire is ; si la rponse au test est vraie, alors toutes les modications portent sur les deux variables la fois : sage: L1 = [11, 22, 33] ; L2 = L1 ; L3 = L1[:] sage: [L1 is L2, L2 is L1, L1 is L3, L1 == L3] [True, True, False, True] Les oprations de copie oprent sur un seul niveau de listes. Ainsi la modication lintrieur dune liste de listes se propage malgr la copie de la structure au premier niveau : sage: La = [1, 2, 3] ; L1 = [1, La] ; L2 = copy(L1) sage: L1[1][0] = 5 # [1, [5, 2, 3]] pour L1 et L2 sage: [L1 == L2, L1 is L2, L1[1] is L2[1]] [True, False, True] Linstruction suivante recopie la structure sur deux niveaux : sage: map (copy, L) alors que la fonction copyRec duplique rcursivement les listes tous les niveaux : sage: def copyRec (L): ....: if type (L) == list: return map (copyRec, L) ....: else: return L Lordre lexicographique inverse est dni partir de lordre lexicographique sur des n-uplets numrs lenvers en renversant lordre appliqu chaque lment : P = (p0 , p1 , . . . pn1 ) lexInv Q = (q0 , q1 , . . . qn1 ) r {0, . . . , n 1}, (pr+1 , . . . , pn1 ) = (qr+1 , . . . , qn1 ) et pr > qr . La programmation de lordre lexicographique inverse peut se faire partir de la fonction alpha dnie prcdemment qui implante lordre lexicographique. La recopie des listes P et Q est ncessaire pour eectuer linversion sans modier les donnes. Plus prcisment la fonction lexInverse renverse lordre des n-uplets par reverse et renverse lordre nal par le rsultat renvoy (P1 lex Q1 ) : sage: def lexInverse (P, Q): ....: P1 = copy(P) ; P1.reverse() ....: Q1 = copy(Q) ; Q1.reverse() ....: return - alpha (P1, Q1)

72

CHAP. 3. PROGRAMMATION ET STRUCTURES DE DONNES

Les modications sur une liste passe en argument dune fonction se rpercutent de faon globale sur la liste car les fonctions ne recopient pas les structures de listes passes en argument. Ainsi une fonction eectuant uniquement P.reverse() la place de P1 = copy(P) et P1.reverse() modie dnitivement la liste P ; cet eet, appel eet de bord, nest gnralement pas souhait. La variable P est une variable locale de la fonction indpendamment de tout autre variable globale de mme nom P , mais cela est sans rapport avec les modications apportes lintrieur dune liste passe en argument. Les listes terme employ dans Python et Sage sont en fait implantes dans ces systmes sous la forme de tableau dynamique, et nont pas la mme structure que celles du Lisp et dOcaml dnies par un lment de tte t et une liste de queue Q. La commande Lisp lmentaire cons(t,Q) renvoie une liste avec le terme t en tte sans modier la liste Q ; au contraire ajouter un lment e un tableau T par T.append(e) en Python modie le tableau T . Les deux reprsentations de donnes ont chacune leurs avantages et le passage dune reprsentation des donnes lautre est possible, mais lecacit des algorithmes nest pas la mme dans les deux cas.

3.3.7

Donnes modiables ou immuables

Les listes permettent de structurer et de manipuler des donnes pouvant tre modies. Pour cette raison ces structures sont qualies de modiables ou de mutables. Au contraire, Python permet aussi de dnir des donnes ges ou immuables. La structure immuable correspondant aux listes est appele squence ou tuple daprs son nom anglais, et est note avec des parenthses (...) la place des crochets [...]. Une squence un seul argument est dnie en plaant explicitement une virgule aprs son argument. sage: S0 = (); S1 = (1, ); S2 = (1, 2) sage: [1 in S1, 1 == (1)] [True, True] Les oprations daccs aux squences sont essentiellement les mmes que celles sur les listes, par exemple la construction dimage de squence par map ou dextraction de sous-squence par filter. Dans tous les cas le rsultat est une liste, et cette commande for transforme une squence en liste : sage: S1 = (1, 4, 9, 16, 25); [k for k in S1] [1, 4, 9, 16, 25] La commande zip regroupe terme terme plusieurs listes ou squences de faon quivalente la commande map suivante : sage: L1 = [0..4]; L2 = [5..9] sage: zip(L1, L2) [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9)] sage: map(lambda x, y:(x, y), L1, L2) [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9)]

3.3. LISTES ET STRUCTURES COMPOSES

73

3.3.8

Ensembles nis

Contrairement aux listes, la notion densemble tient uniquement compte de la prsence ou non dun lment, sans dnir sa position ni le nombre de rptitions de cet lment. Sage manipule les ensembles de cardinal ni partir de la fonction Set applique la liste des lments. Le rsultat est ach entre accolades : sage: E = Set([1, 2, 4, 8, 2, 2, 2]); F = Set([7, 5, 3, 1]); E, F ({8, 1, 2, 4}, {1, 3, 5, 7}) Loprateur dappartenance in teste lappartenance dun lment un ensemble, et Sage autorise les oprations de runion densembles par + ou |, dintersection par &, de dirence par -, et de dirence symtrique par ^^ : sage: E = Set([1, 2, 4, 8, 2, 2, 2]); F = Set([7, 5, 3, 1]) sage: 5 in E, 5 in F, E + F == F | E (False, True, True) sage: E & F, E - F, E ^^ F ({1}, {8, 2, 4}, {2, 3, 4, 5, 7, 8}) La fonction len(E) renvoie le cardinal dun tel ensemble ni. Les oprations map, filter et for..if... sappliquent aux ensembles comme aux squences, et les rsultats sont des listes. Laccs un lment seectue par E[k]. Les deux commandes ci-dessous construisent de faon quivalente la liste des lments dun ensemble : sage: E = Set([1, 2, 4, 8, 2, 2, 2]) sage: [E[k] for k in [0..len(E)-1]], [t for t in E] ([8, 1, 2, 4], [8, 1, 2, 4]) La fonction suivante teste linclusion dun ensemble E dans F partir de la runion : sage: def inclus (E, F): return E+F == F Contrairement aux listes, les ensembles sont de type immuable et ne sont donc pas modiables ; leurs lments doivent aussi tre immuables. Les ensembles de tuples et les ensembles densembles sont donc possibles mais on ne peut pas construire des ensembles de listes : sage: Set([Set([]), Set([1]), Set([2]), Set([1, 2])]) {{1, 2}, {}, {2}, {1}} sage: Set([ (), (1, ), (2, ), (1, 2) ]) {(1, 2), (2,), (), (1,)} Cette fonction numre tous les sous-ensembles dun ensemble par une mthode rcursive : sage: def Parties (EE): ....: if EE == Set([]): return Set([EE]) ....: else: ....: return avecOuSansElt (EE[0], Parties(Set(EE[1:])))

74

CHAP. 3. PROGRAMMATION ET STRUCTURES DE DONNES

sage: def avecOuSansElt (a, E): ....: return Set (map (lambda F: Set([a])+F, E)) + E sage: Parties(Set([1, 2, 3])) {{3}, {1, 2}, {}, {2, 3}, {1}, {1, 3}, {1, 2, 3}, {2}} La fonction avecOuSansElt(a, E) prend un ensemble E de sous-ensembles, et construit lensemble ayant deux fois plus dlments qui sont ces mmes sousensembles et ceux auxquels llment a a t ajout. La construction rcursive commence avec lensemble un lment E = {}.

3.3.9

Dictionnaires

Enn Python, et donc Sage, intgre la notion de dictionnaire. Comme un annuaire, un dictionnaire associe une valeur chaque entre. Les entres dun dictionnaire sont de nimporte quel type immuable, nombres, chanes de caractres, squences, etc. La syntaxe est comparable celle des listes par des aectations partir du dictionnaire vide dict() pouvant tre abrg en {} : sage: D={}; D[ un ]=1; D[ deux ]=2; D[ trois ]=3; D[ dix ]=10 sage: D[ deux ] + D[ trois ] 5 Lexemple prcdent dtaille donc comment ajouter une entre dans un dictionnaire, et comment accder un champ par D[...]. Loprateur in teste si une entre fait partie dun dictionnaire, et les commandes del D[x] ou D.pop(x) eacent lentre x de ce dictionnaire. Lexemple suivant indique comment un dictionnaire peut reprsenter une application sur un ensemble ni : E = {a0 , a1 , a2 , a3 , a4 , a5 }, f (a0 ) = b0 , f (a3 ) = b0 , f (a1 ) = b1 , f (a4 ) = b3 , f (a2 ) = b2 , f (a5 ) = b3 .

Les mthodes sur les dictionnaires sont comparables celles portant sur les autres structures numres. Le code ci-dessous implante la fonction prcdente et construit lensemble de dpart E et lensemble image Im f = f (E ) par les mthodes keys et values : sage: ....: sage: sage: True D = { a0 : b0 , a1 : b1 , a2 : b2 , a3 : b0 ,\ a4 : b3 , a5 : b3 } E = Set(D.keys()) ; Imf = Set(D.values()) Imf == Set(map (lambda t:D[t], E)) # est quivalent

Cette dernire commande traduit directement la dnition mathmatique Im f = {f (x)|x E }. Les dictionnaires peuvent aussi tre construits partir de listes ou de couples [cl , valeur ] par la commande suivante : dict([a0, b0], [a1, b1], ...)

3.3. LISTES ET STRUCTURES COMPOSES

75

Les deux commandes suivantes appliques aux entres du dictionnaire ou au dictionnaire lui-mme sont, par construction, quivalentes la mthode D.values() : map (lambda t:D[t], D) map (lambda t:D[t], D.keys())

Le test suivant sur le nombre dlments dtermine si lapplication reprsente par D est injective, len(D) tant le nombre dentres dans le dictionnaire : sage: def injective(D): ....: return len(D) == len (Set(D.values())) Les deux premires commandes ci-dessous construisent limage directe f (F ) et limage rciproque f 1 (G) des sous-ensembles F et G dune application dnie par le dictionnaire D ; la dernire dnit un dictionnaire DR correspondant lapplication rciproque f 1 dune application f suppose bijective : sage: Set([D[t] for t in F]) sage: Set([t for t in D if D[t] in G]) sage: DR = dict((D[t], t) for t in D)

76

CHAP. 3. PROGRAMMATION ET STRUCTURES DE DONNES

Graphiques
La visualisation de fonctions dune ou deux variables, dune srie de donnes, facilite la perception de phnomnes mathmatiques ou physiques et permet de conjecturer des rsultats ecacement. Dans ce chapitre, on illustre sur des exemples les capacits graphiques de Sage.

4.1

Courbes en 2D

Une courbe plane peut tre dnie de plusieurs faons : comme graphe dune fonction dune variable, par un systme dquations paramtriques, par une quation en coordonnes polaires, ou par une quation implicite. Nous prsentons ces quatre cas, puis donnons quelques exemples de tracs de donnes.

4.1.1

Reprsentation graphique de fonctions

Pour tracer le graphe dune fonction symbolique ou dune fonction Python sur un intervalle [a, b], on dispose de deux syntaxes : plot(f(x), a, b) ou plot(f(x), x, a, b). sage: plot(x * sin(1/x), x, -2, 2, plot_points=500) Parmi les nombreuses options de la fonction plot, citons : plot_points (valeur par dfaut 200) : nombre minimal de points calculs ; xmin et xmax : bornes de lintervalle sur lequel est trace la fonction ; color : couleur du trac, un triplet RGB, une chane de caractres (par ex. blue ), ou une couleur HTML (par ex. #aaff0b ) ;

78

CHAP. 4. GRAPHIQUES

0.8 0.6 0.4 0.2 -2 -1.5 -1 -0.5 -0.2


Figure 4.1 Graphe de x x sin
1 . x

0.5

1.5

detect_poles (valeur par dfaut False) : permet de tracer ou non lasymptote verticale aux ples dune fonction ; alpha : transparence du trait ; thickness : paisseur du trait ; linestyle : nature du trait, trac en pointills ( : ), traits et pointills ( -. ), trait continu ( - ), qui est la valeur par dfaut. Pour visualiser le trac, on peut placer lobjet graphique dans une variable, disons g, puis utiliser la commande show, en prcisant par exemple les valeurs minimales et maximales de lordonne (g.show(ymin=-1, ymax=3)) ou alors en choisissant le rapport danit (g.show(aspect_ratio=1) pour un trac en repre orthonorm). La gure produite peut tre exporte grce la commande save vers dirents formats indiqus par les suxes .pdf, .png, .ps, .eps, .svg et .sobj : g.save(nom, aspect_ratio=1, xmin=-1, xmax=3, ymin=-1, ymax=3) A Pour inclure une telle gure dans un document L TEX laide de la commande includegraphics, on choisit lextension eps (PostScript encapsul) si le document est compil avec latex, et lextension pdf ( prfrer png, pour obtenir une meilleure rsolution) si le document est compil avec pdflatex. Traons sur un mme graphique la fonction sinus et ses premiers polynmes de Taylor en 0. sage: ....: sage: sage: sage: ....: ....: sage: def p(x, n): return(taylor(sin(x), x, 0, n)) xmax = 15 ; n = 15 g = plot(sin(x), x, -xmax, xmax) for d in range(n): g += plot(p(x, 2 * d + 1), x, -xmax, xmax,\ color=(1.7*d/(2*n), 1.5*d/(2*n), 1-3*d/(4*n))) g.show(ymin=-2, ymax=2)

On aurait galement pu eectuer une animation, pour observer comment le polynme de Taylor approche de mieux en mieux la fonction sinus lorsque le degr augmente. Si lon souhaite sauvegarder lanimation, il sut de lenregistrer au format gif.

4.1. COURBES EN 2D
2 1.5 1 0.5 -10 -5 -0.5 -1 -1.5 -2 5 10 -20 -10 4 3 2 1 -1 -2 -3 -4 10 20

79

Figure 4.2 Quelques polynmes de Taylor de sinus en 0.

sage: a = animate([[sin(x), taylor(sin(x), x, 0, 2*k+1)]\ ....: for k in range(0, 14)], xmin=-14, xmax=14,\ ....: ymin=-3, ymax=3, figsize=[8, 4]) sage: a.show(); a.save( chemin/animation.gif ) Revenons la fonction plot pour observer, par exemple, le phnomne de Gibbs. Traons la somme partielle dordre 20 de la srie de Fourier de la fonction crneau. sage: sage: sage: sage: sage: sage: sage: f2(x) = 1; f1(x) = -1 f = piecewise([[(-pi,0),f1],[(0,pi),f2]]) S = f.fourier_series_partial_sum(20,pi) g = plot(S, x, -8, 8, color= blue ) scie(x) = x - 2 * pi * floor((x + pi) / (2 * pi)) g += plot(scie(x) / abs(scie(x)), x, -8, 8, color= red ) g

1 0.5 -8 -6 -4 -2 -0.5 -1 2 4 6 8

Figure 4.3 Dcomposition de la fonction crneau en srie de Fourier.

Dans le code ci-dessus, f est une fonction par morceaux dnie sur [ ; ] laide de linstruction piecewise. Pour reprsenter le prolongement de f par 2 -priodicit, le plus simple est den chercher une expression valable pour tout rel (en loccurrence scie/abs(scie)). La somme des 20 premiers termes de la

80 srie de Fourier vaut : S= 4 sin(x) +

CHAP. 4. GRAPHIQUES

sin(3x) sin(5x) sin(19 ) + + + 3 5 19

4.1.2

Courbe paramtre

Les tracs de courbes paramtres (x = f (t), y = g (t)) sont raliss par la commande parametric_plot((f(t), g(t)), (t, a, b)) o [a, b] est lintervalle parcouru par le paramtre. Reprsentons par exemple la courbe paramtre dquations : 1 1 x(t) = cos(t) + cos(7t) + sin(17t), 2 3 1 1 y (t) = sin(t) + sin(7t) + cos(17t). 2 3 sage: sage: sage: sage: sage: t = var( t ) x = cos(t) + cos(7*t)/2 + sin(17*t)/3 y = sin(t) + sin(7*t)/2 + cos(17*t)/3 g = parametric_plot((x, y), (t, 0, 2*pi)) g.show(aspect_ratio=1)

1.5 1 0.5 -1.5 -1 -0.5 -0.5 -1 -1.5 0.5 1 1.5

Figure 4.4 Courbe paramtre dquation x(t) = cos(t) + sin(t) + 1 sin(7t) + 1 cos(17t). 2 3

1 2

cos(7t) +

1 3

sin(17t), y (t) =

4.1.3

Courbe en coordonnes polaires

Les tracs de courbes en coordonnes polaires = f () sont raliss par la commande polar_plot(rho(theta),(theta,a,b)) o [a, b] est lintervalle parcouru par le paramtre.

4.1. COURBES EN 2D

81

Reprsentons par exemple les conchodes de rosace dquation polaire () = 1 + e cos n lorsque n = 20/19 et e {2, 1/3}. sage: sage: sage: sage: t = var( t ); n = 20/19 g1 = polar_plot(1+2*cos(n*t),(t,0,n*36*pi),plot_points=5000) g2 = polar_plot(1+1/3*cos(n*t),(t,0,n*36*pi),plot_points=5000) g1.show(aspect_ratio=1); g2.show(aspect_ratio=1)

3 2 1 1

0.5

-3

-2

-1 -1 -2 -3

-1

-0.5 -0.5

0.5

-1

Figure 4.5 Rosaces dquation () = 1 + e cos n.

Exercice 12. Reprsenter la famille de conchodes de Pascal dquation polaire () = a + cos en faisant varier le paramtre a de 0 2 avec un pas de 0.1.

4.1.4

Courbe dnie par une quation implicite

Pour reprsenter une courbe donne par une quation implicite, on utilise la fonction implicit_plot(f(x, y), (x, a, b), (y, c, d)) ; cependant, on peut aussi utiliser la commande complex_plot qui permet de visualiser en couleur les lignes de niveau dune fonction deux variables. Reprsentons la courbe donne par lquation implicite C = z C , cos(z 4 ) = 1 . sage: sage: ....: sage: sage: sage: z = var( z ) g1 = complex_plot(abs(cos(z^4))-1, (-3,3), (-3,3), plot_points=400) f = lambda x, y : (abs(cos((x + I * y) ** 4)) - 1) g2 = implicit_plot(f, (-3, 3), (-3, 3), plot_points=400) g1.show(aspect_ratio=1); g2.show(aspect_ratio=1)

82
3 2 1

CHAP. 4. GRAPHIQUES

-3

-2

-1 -1 -2 -3 3 2 1

-3

-2

-1 -1 -2 -3

Figure 4.6 Courbe dnie par lquation

cos(z 4 ) = 1.

3 2

Voici un autre exemple de trac de fonction donne par une quation complexe : sage: f(z) = z^5+z-1+1/z sage: complex_plot(f,\ ....: (-3, 3), (-3, 3))
-3 -2 -1

1 1 -1 -2 -3 2 3

4.1. COURBES EN 2D

83

4.1.5

Trac de donnes

Pour tracer un diagramme en rectangles, on dispose de deux fonctions assez direntes. Tout dabord, la commande bar_chart prend en argument une liste dentiers et trace simplement des barres verticales dont la hauteur est donne par les lments de la liste (dans leur ordre dapparition dans la liste). Notons que loption width permet de choisir la largeur des rectangles. sage: bar_chart([randrange(15) for i in range(20)]) sage: bar_chart([x^2 for x in range(1,20)], width=0.2)
9 8 7 6 5 4 3 2 1 2 4 6 8 10 350 300 250 200 150 100 50 5 10 15

Figure 4.7 Diagrammes en rectangles.

En revanche, pour tracer lhistogramme des frquences dune donne alatoire partir dune liste de ottants, on utilise la fonction plot_histogram : les valeurs de la liste sont tries et rparties dans des intervalles (le nombre dintervalles tant x par la variable bins dont la valeur par dfaut vaut 50) ; la hauteur de la barre pour chaque intervalle tant gale la frquence correspondante. sage: liste = [10 + floor(10*sin(i)) for i in range(100)] sage: bar_chart(liste) sage: finance.TimeSeries(liste).plot_histogram(bins=20)

0.16 15 10 5 0.14 0.12 0.1 0.08 0.06 0.04 0.02 10 20 30 40 50 5 10 15

(a) Trac avec bar_chart.

(b) Trac avec plot_histogram.

Il est frquent que la liste statistique tudier soit stocke dans une feuille de calcul obtenue laide dun tableur. Le module csv de Python permet alors dimporter les donnes depuis un chier enregistr au format csv. Par exemple, supposons que lon souhaite tracer lhistogramme des notes dune classe se trouvant dans la colonne 3 du chier nomm ds01.csv. Pour extraire les notes de cette colonne, on utilise les instructions suivantes (en gnral les premires lignes

84

CHAP. 4. GRAPHIQUES

50 40 30 20 10 -60 -40 -20 -10 -20 -30 20 40

Figure 4.8 Marche alatoire.

comportent du texte do la ncessit de grer les erreurs ventuelles lors de la conversion en ottant grce linstruction try) : sage: sage: sage: sage: ....: ....: ....: ....: ....: ....: ....: ....: sage: import csv reader = csv.reader(open("ds01.csv")) notes = []; liste = [] for ligne in reader: 0.25 notes.append(ligne[3]) 0.2 for i in notes: 0.15 try: 0.1 f = float(i) 0.05 except ValueError: 0 2 4 6 pass else: liste.append(f) finance.TimeSeries(liste).plot_histogram(bins=20)

10

12

14

Pour tracer une liste de points relis (resp. un nuage de points), on utilise la commande line(p) (resp. point(p)), p dsignant une liste de listes deux lments donnant abscisse et ordonne des points tracer. Exemple. (Marche alatoire ) Partant dun point origine O, une particule se dplace dune longueur , intervalles de temps rguliers t, chaque fois dans une direction quelconque, indpendante des directions prcdentes. Reprsentons un exemple de trajectoire pour une telle particule. Le segment rouge relie la position initiale la position nale. sage: sage: sage: ....: ....: ....: sage: sage: from random import * n, l, x, y = 10000, 1, 0, 0; p = [[0, 0]] for k in range(n): theta = (2 * pi * random()).n(digits=5) x, y = x + l * cos(theta), y + l * sin(theta) p.append([x, y]) g1 = line([p[n], [0, 0]], color= red , thickness=2) g1 += line(p, thickness=.4); g1.show(aspect_ratio=1)

4.1. COURBES EN 2D

85

Exemple. (Suites quirparties ) tant donne une suite relle (un )nN , on construit la ligne polygonale dont les sommets successifs sont les points daxe zN =
n N

e2iun .

Si la suite est quirpartie modulo 1, la ligne brise ne sloigne pas trop rapidement de lorigine. On peut alors conjecturer la rgularit de la rpartition de la suite partir du trac de la ligne brise. Traons la ligne polygonale dans les cas suivants : un = n 2 et N = 200, un = n ln(n) 2 et N = 10000, un = E(n ln(n)) 2 et N = 10000 (o E dsigne la partie entire), un = pn 2 et N = 10000 (ici pn est le n-ime nombre premier). La gure 4.9 sobtient de la manire suivante (ici pour un = n 2) : sage: sage: sage: sage: sage: ....: sage: length = 200; n = var( n ) u = lambda n: n * sqrt(2) z = lambda n: exp(2 * I * pi * u(n)).n() vertices = [CC(0, 0)] for n in range(1, length): vertices.append(vertices[n - 1] + CC(z(n))) line(vertices).show(aspect_ratio=1)

On remarque que la courbe 4.9a est particulirement rgulire, ce qui permet de prvoir que lquirpartition de n 2 est de nature dterministe. Dans le cas de la suite un = n ln(n) 2, lexamen des valeurs prises donne limpression dun engendrement alatoire. Cependant, la courbe associe 4.9b est remarquablement bien structure. La courbe 4.9c prsente le mme type de structures que la deuxime. Enn, le trac de la courbe 4.9d fait apparatre la nature profondment dirente de la rpartition modulo 1/ 2 de la suite des nombres premiers : les spirales ont disparu et lallure ressemble la courbe que lon obtient dans le cas dune suite de nombres alatoires un (gure 4.8). Il semble donc que les nombres premiers occupent tout le hasard qui leur est imparti... Pour une interprtation dtaille des courbes obtenues, on se reportera au Que sais-je ? Les nombres premiers de Grald Tenenbaum et Michel Mends France [TMF00].
Exercice 13 (Trac des termes dune suite rcurrente). On considre la suite (un )nN dnie par : u0 = a, 1 n N, un+1 = u2 n 4 . Reprsenter graphiquement le comportement de la suite en construisant une liste forme des points [u0 , 0], [u0 , u1 ], [u1 , u1 ], [u1 , u2 ], [u2 , u2 ], . . . , avec a {0.4, 1.1, 1.3}.

86

CHAP. 4. GRAPHIQUES

0.6

60

0.4

40

0.2

20

-1

-0.8

-0.6

-0.4

-0.2 -0.2

-50

-40

-30

-20

-10 -20

10

20

-0.4
(a) Cas un = n 2. (b) Cas un = n ln(n) 2.

50 40 30 20 20 -10 -20 -30 -40


(c) Cas un = E(n ln(n)) 2. Figure 4.9 Suites quirparties. (d) Cas un = pn 2.

40 30 20 10 -80 -60 -40 -20

10 -30 -20 -10 -10 10 20

4.1. COURBES EN 2D

87

4.1.6

Trac de solution dquation direntielle

On peut combiner les commandes prcdentes pour tracer des solutions dquations ou de systmes direntiels. Pour rsoudre symboliquement une quation direntielle ordinaire, on utilise la fonction desolve dont ltude fait lobjet du chapitre 10. Pour rsoudre numriquement une quation direntielle, Sage nous fournit plusieurs outils : desolve_rk4 (qui utilise la mme syntaxe que la fonction desolve et qui sut pour rsoudre les quations direntielles ordinaires rencontres en licence), odeint (qui utilise le module SciPy) et enn ode_solver (qui appelle la bibliothque GSL dont lutilisation est dtaille dans la section 14.2). Les fonctions desolve_rk4 et odeint renvoient une liste de points quil est alors ais de tracer laide de la commande line ; cest celles que nous utiliserons dans cette section pour tracer des solutions numriques. Exemple. (quation direntielle linaire, du premier ordre, non rsolue ) Traons les courbes intgrales de lquation direntielle xy 2y = x3 . sage: x = var( x ); y = function( y ) sage: DE = x*diff(y(x), x) == 2*y(x) + x^3 sage: desolve(DE, [y(x),x]) (c + x)*x^2 sage: sol = [] sage: for i in srange(-2, 2, 0.2): ....: sol.append(desolve(DE, [y(x), x], ics=[1, i])) ....: sol.append(desolve(DE, [y(x), x], ics=[-1, i])) sage: g = plot(sol, x, -2, 2) sage: y = var( y ) sage: g += plot_vector_field((x, 2*y+x^3), (x,-2,2), (y,-1,1)) sage: g.show(ymin=-1, ymax=1) Pour diminuer le temps de calcul, il serait prfrable ici de saisir la main la solution gnrale de lquation et de crer une liste de solutions particulires (comme cela est fait dans la correction de lexercice 14) plutt que de rsoudre plusieurs fois de suite lquation direntielle avec des conditions initiales direntes. On aurait galement pu eectuer une rsolution numrique de cette quation ( laide de la fonction desolve_rk4) pour en tracer les courbes intgrales :

1 0.5 -2 -1.5 -1 -0.5 -0.5 -1 0.5 1 1.5 2 -2 -1.5 -1 -0.5

1 0.5 0.5 -0.5 -1 1 1.5 2

(a) Rsolution symbolique.

(b) Rsolution numrique.

Figure 4.10 Trac des courbes intgrales de xy 2y = x3 .

88

CHAP. 4. GRAPHIQUES

10 8 6 4 2 -4 -2 -2
Figure 4.11 Trac des courbes intgrales de y (t) + cos(y (t) t) = 0.

sage: sage: sage: sage: ....: ....: ....: ....: sage: sage: sage:

x = var( x ); y = function( y ) DE = x*diff(y(x), x) == 2*y(x) + x^3 g = Graphics() # cre un graphique vide for i in srange(-2, 2, 0.2): g += line(desolve_rk4(DE, y(x), ics=[1, i],\ step=0.05, end_points=[0,2])) g += line(desolve_rk4(DE, y(x), ics=[-1, i],\ step=0.05, end_points=[-2,0])) y = var( y ) g += plot_vector_field((x, 2*y+x^3), (x,-2,2), (y,-1,1)) g.show(ymin=-1, ymax=1)

Comme on le voit sur lexemple prcdent, la fonction desolve_rk4 prend en argument une quation direntielle (ou le membre de droite f de lquation crite sous forme rsolue y = f (y, x)), le nom de la fonction inconnue, la condition initiale, le pas et lintervalle de rsolution. Largument optionnel output permet de prciser la sortie de la fonction : la valeur par dfaut list renvoie une liste (ce qui est utile si on veut superposer des graphiques comme dans notre exemple), plot ache le trac de la solution et slope_field y ajoute le trac des pentes des courbes intgrales.
x Exercice 14. Tracer les courbes intgrales de lquation x2 y y = 0, pour 3 3 et 5 y 5.

Donnons prsent un exemple dutilisation de la fonction odeint du module SciPy. Exemple. (quation direntielle non linaire, rsolue, du premier ordre ) Traons les courbes intgrales de lquation y (t) + cos(y (t) t) = 0.

4.1. COURBES EN 2D sage: sage: sage: sage: ....: ....: sage: sage: ....: ....: sage: sage: sage: import scipy; from scipy import integrate f = lambda y, t: - cos(y * t) t = srange(0, 5, 0.1); p = Graphics() for k in srange(0, 10, 0.15): y = integrate.odeint(f, k, t) p += line(zip(t, flatten(y))) t = srange(0, -5, -0.1); q = Graphics() for k in srange(0, 10, 0.15): y = integrate.odeint(f, k, t) q += line(zip(t, flatten(y))) y = var( y ) v = plot_vector_field((1, -cos(x*y)), (x,-5,5), (y,-2,11)) g = p + q + v; g.show()

89

La fonction odeint prend en argument le second membre de lquation direntielle (crite sous forme rsolue), une ou plusieurs conditions initiales, et enn lintervalle de rsolution ; elle renvoie ensuite un tableau du type numpy.ndarray que lon aplatit laide de la commande flatten 1 dj vue au 3.3.2 et que lon runit avec le tableau t grce la commande zip avant deectuer le trac de la solution approche. Pour ajouter le champ des vecteurs tangents aux courbes intgrales, on a utilis la commande plot_vector_field. Exemple. (Modle proie-prdateur de Lokta-Volterra ) On souhaite reprsenter graphiquement lvolution dune population de proies et de prdateurs voluant suivant un systme dquations du type Lokta-Volterra : du = au buv, dt dv = cv + dbuv, dt o u dsigne le nombre de proies (par ex. des lapins), v le nombre de prdateurs (par ex. des renards). De plus, a, b, c, d sont des paramtres qui dcrivent lvolution des populations : a caractrise la croissance naturelle du nombre de lapins en labsence de renards, b la dcroissance du nombre de lapins due la prsence de prdateurs, c la dcroissance du nombre de renards en labsence de proies, enn d indique combien il faut de lapins pour quapparaisse un nouveau renard. sage: sage: sage: ....: sage: sage: sage: sage: import scipy; from scipy import integrate a, b, c, d = 1., 0.1, 1.5, 0.75 def dX_dt(X, t=0): # renvoie l augmentation des populations return [a*X[0] - b*X[0]*X[1], -c*X[1] + d*b*X[0]*X[1]] t = srange(0, 15, .01) # chelle de temps X0 = [10, 5] # conditions initiales : 10 lapins et 5 renards X = integrate.odeint(dX_dt, X0, t) # rsolution numrique lapins, renards = X.T # raccourci de X.transpose()

1. On aurait pu utiliser galement la fonction ravel de NumPy qui vite de crer un nouvel objet liste et donc optimise lutilisation de la mmoire.

90 sage: sage: sage: sage: sage:

CHAP. 4. GRAPHIQUES p = line(zip(t, lapins), color= red ) # trac du nombre de lapins p += text("Lapins",(12,37), fontsize=10, color= red ) p += line(zip(t, renards), color= blue ) # idem pour les renards p += text("Renards",(12,7), fontsize=10, color= blue ) p.axes_labels(["temps", "population"]); p.show(gridlines=True)

Les instructions ci-dessus tracent lvolution du nombre de lapins et de renards en fonction du temps (gure 4.12 gauche), et celles ci-dessous le champ de vecteurs (gure 4.12 droite) : sage: sage: sage: ....: ....: sage: sage: sage: ....: ....: sage:
population 40 35 30 25 20 15 10 5 0 2 4 6 8 10 Renards 12 14 temps Lapins

n = 11; L = srange(6, 18, 12 / n); R = srange(3, 9, 6 / n) CI = zip(L, R) # liste des conditions initiales def g(x,y): v = vector(dX_dt([x, y])) # pour un trac plus lisible, return v/v.norm() # on norme le champ de vecteurs x, y = var( x, y ) q = plot_vector_field(g(x, y), (x, 0, 60), (y, 0, 36)) for j in range(n): X = integrate.odeint(dX_dt, CI[j], t) # rsolution q += line(X, color=hue(.8-float(j)/(1.8*n))) # graphique q.axes_labels(["lapins","renards"]); q.show()

renards 35 30 25 20 15 10 5 10 20 30 40 50 60 lapins

Figure 4.12 tude dun systme proies-prdateurs.

Exercice 15 (Modle proie-prdateur). Refaire le graphe de gauche de la gure 4.12 en utilisant desolve_system_rk4 la place de odeint. Exercice 16 (Un systme direntiel autonome). Tracer les courbes intgrales du systme direntiel suivant : x = y, y = 0 .5 y x y 3 . Exercice 17 (coulement autour dun cylindre avec eet Magnus). On superpose un coulement simple autour dun cylindre de rayon a, un vortex de paramtre , ce qui modie la composante orthoradiale de vitesse. On se place dans un repre centr sur le cylindre, et on travaille en coordonnes cylindriques dans le plan z = 0, autrement dit en coordonnes polaires. Les composantes de la vitesse sont alors : vr = v0 cos() 1 a2 r2 et v = v0 sin() 1 + a2 r2 +2 av0 . r

4.1. COURBES EN 2D

91

Les lignes de courant (confondues avec les trajectoires, car lcoulement est stationnaire) sont parallles la vitesse. On cherche une expression paramtre des lignes de champs ; il faut alors rsoudre le systme direntiel : dr = vr dt et d v = . dt r

On utilise des coordonnes non dimensionnes, cest--dire rapportes a, rayon du cylindre, ce qui revient supposer a = 1. Tracer les lignes de courant de cet coulement pour {0.1, 0.5, 1, 1.25}. Lutilisation de leet Magnus a t propos pour mettre au point des systmes de propulsion composs de gros cylindres verticaux en rotation capables de produire une pousse longitudinale lorsque le vent est sur le ct du navire (ce fut le cas du navire Baden-Baden mis au point par Anton Flettner qui traversa lAtlantique en 1926).

4.1.7

Dveloppe dune courbe

On donne prsent un exemple de trac de dveloppe dun arc paramtr (on rappelle que la dveloppe est lenveloppe des normales ou, de manire quivalente, le lieu des centres de courbure de la courbe). Exemple. (Dveloppe de la parabole ) Trouvons lquation de la dveloppe de la parabole P dquation y = x2 /4 et traons sur un mme graphique la parabole P , quelques normales P et sa dveloppe. Pour dterminer un systme dquations paramtriques (x(t), y (t)) de lenveloppe dune famille de droites t dnies par des quations cartsiennes de la forme (t)X + (t)Y = (t), on exprime le fait que la droite t est tangente lenveloppe au point (x(t), y (t)) : (t)x(t) + (t)y (t) = (t), (t)x (t) + (t)y (t) = 0. (4.1) (4.2)

On drive lquation (4.1) et en combinant avec (4.2), on obtient le systme : (t) x(t) + (t) y (t) = (t), (t)x(t) + (t)y (t) = (t). (4.1) (4.3)

Dans notre cas, la normale (Nt ) la parabole P en M (t, t2 /4) a pour vecteur normal v = (1, t/2) (qui est le vecteur tangent la parabole) ; elle a donc pour quation : t3 t xt 1 = 0 x + y = t + , 2 y t /4 t/2 2 8 autrement dit, ((t), (t), (t)) = (1, t/2, t + t3 /8). On peut alors rsoudre le systme prcdent avec la fonction solve : sage: x, y, t = var( x, y, t ) sage: alpha(t) = 1; beta(t) = t / 2; gamma(t) = t + t^3 / 8 sage: env = solve([alpha(t) * x + beta(t) * y == gamma(t),\ ....: diff(alpha(t), t) * x + diff(beta(t), t) * y == \ ....: diff(gamma(t), t)], [x,y])

92 1 3 x = t3 , y = t2 + 2 4 4

CHAP. 4. GRAPHIQUES

Do une reprsentation paramtrique de lenveloppe des normales :


1 3 t , x(t) = 4 2 y (t) = 2 + 3 4t .

On peut alors eectuer le trac demand, en traant quelques normales la parabole (plus prcisment, on trace des segments [M, M + 18 n ] o M (u, u2 /4) est un point de P et n = (u/2, 1) un vecteur normal P ) : sage: sage: sage: ....: ....: sage: ....: sage: f(x) = x^2 / 4 p = plot(f, -8, 8, rgbcolor=(0.2,0.2,0.4)) # la parabole for u in srange(0, 8, 0.1): # normales la parabole p += line([[u, f(u)], [-8*u, f(u) + 18]], thickness=.3) p += line([[-u, f(u)], [8*u, f(u) + 18]], thickness=.3) p += parametric_plot((env[0][0].rhs(),env[0][1].rhs()),\ (t, -8, 8),color= red ) # trace la dveloppe p.show(xmin=-8, xmax=8, ymin=-1, ymax=12, aspect_ratio=1)

12 10 8 6 4 2 -8 -6 -4 -2 2 4 6 8

Figure 4.13 La dveloppe de la parabole.

Comme rappel plus haut, la dveloppe dune courbe est aussi le lieu de ses centres de courbures. laide de la fonction circle traons quelques cercles osculateurs la parabole. On rappelle que le centre de courbure en un point Mt = (x(t), y (t)) de la courbe a pour coordonnes : x = x + y x2+y2 , xy x y et y = y + x x2+y2 , xy x y

4.2. COURBES EN 3D et que le rayon de courbure en Mt vaut : R= sage: sage: sage: sage: sage: sage: sage: sage: sage: sage: ....: ....: sage: (x 2 + y 2 ) 2 . xy x y
3

93

t = var( t ); p = 2 x(t) = t; y(t) = t^2 / (2 * p); f(t) = [x(t), y(t)] df(t) = [x(t).diff(t), y(t).diff(t)] d2f(t) = [x(t).diff(t, 2), y(t).diff(t, 2)] T(t) = [df(t)[0] / df(t).norm(), df[1](t) / df(t).norm()] N(t) = [-df(t)[1] / df(t).norm(), df[0](t) / df(t).norm()] R(t) = (df(t).norm())^3 / (df(t)[0]*d2f(t)[1]-df(t)[1]*d2f(t)[0]) Omega(t) = [f(t)[0] + R(t)*N(t)[0], f(t)[1] + R(t)*N(t)[1]] g = parametric_plot(f(t), (t,-8,8), color= green ,thickness=2) for u in srange(.4, 4, .2): g += line([f(t=u), Omega(t=u)], color= red , alpha = .5) g += circle(Omega(t=u), R(t=u), color= blue ) g.show(aspect_ratio=1,xmin=-12,xmax=7,ymin=-3,ymax=12)

12 10 8 6 4 2 -10 -5 -2
Figure 4.14 Cercles osculateurs la parabole.

Le tableau 4.1 rsume les fonctions utilises dans cette section. On y signale de plus la commande text qui permet de placer une chane de caractre dans un graphique, ainsi que la commande polygon qui permet de tracer des polygones.

4.2

Courbes en 3D

On dispose de la commande plot3d(f(x,y),(x,a,b),(y,c,d)) pour le trac de surfaces en trois dimensions. La surface obtenue est alors visualise par dfaut

94

CHAP. 4. GRAPHIQUES

Type de trac Courbe reprsentative dune fonction Courbe paramtre Courbe dnie par une quation polaire Courbe dnie par une quation implicite Lignes de niveau dune fonction complexe Objet graphique vide Courbes intgrales dquation direntielle Diagramme en btonnets Diagramme des frquences dune srie statistique Trac dune ligne brise Trac dun nuage de points Cercle Polygone Texte plot parametric_plot polar_plot implicit_plot complex_plot Graphics() odeint, desolve_rk4 bar_chart plot_histogram line points circle polygon text

Tableau 4.1 Rcapitulatif des fonctions graphiques 2D.

grce lapplication Jmol ; cependant, on peut galement utiliser le Tachyon 3D Ray Tracer grce largument optionnel viewer= tachyon de la commande show. Voici un premier exemple de trac dune surface paramtre (gure 4.15) : sage: u, v = var( u, v ) sage: h = lambda u,v: u^2 + 2*v^2 sage: f = plot3d(h, (u,-1,1), (v,-1,1), aspect_ratio=[1,1,1])

Figure 4.15 La surface paramtre par (u, v ) u2 + 2v 2 .

La visualisation de la surface reprsentative dune fonction de deux variables permet de guider ltude dune telle fonction, comme nous allons le voir dans lexemple suivant. Exemple. (Une fonction discontinue dont les drives directionnelles existent partout ! ) tudier lexistence en (0, 0) des drives directionnelles et la continuit de lapplication f de R2 dans R dnie par : f (x, y ) =
x2 y x4 +y 2

si (x, y ) = (0, 0), si (x, y ) = (0, 0).

4.2. COURBES EN 3D

95

Pour H = cos sin , lapplication (t) = f (tH ) = f (t cos , t sin ) est drivable en t = 0 pour toute valeur de ; en eet,

sage: f(x, y) = x^2 * y / (x^4 + y^2) sage: t, theta = var( t, theta ) sage: limit(f(t * cos(theta), t * sin(theta)) / t, t=0) cos(theta)^2/sin(theta) Donc f admet en (0, 0) des drives directionnelles suivant nimporte quel vecteur. Pour mieux se reprsenter la surface reprsentative de f , on peut commencer par chercher quelques lignes de niveau ; par exemple la ligne de niveau associe la valeur 1 2 : sage: solve(f(x,y) == 1/2, y) [y == x^2] sage: a = var( a ); h = f(x, a*x^2).simplify_rational(); h a/(a^2 + 1) Le long de la parabole dquation y = ax2 prive de lorigine, f est constante et a a vaut f (x, ax2 ) = 1+ a2 . On trace alors la fonction h : a 1+a2 : sage: plot(h, a, -4, 4)

0.4 0.2 -4 -3 -2 -1 -0.2 -0.4 1 2 3 4

Figure 4.16 Une coupe verticale de la surface tudie.

La fonction h atteint son maximum en a = 1 et son minimum en a = 1. La restriction de f la parabole dquation y = x2 correspond la ligne de crte qui se trouve laltitude 1 2 ; quant la restriction de f la parabole dquation 1 y = x2 , elle correspond au fond du thalweg qui se trouve laltitude 2 . En conclusion, aussi proche que lon soit de (0, 0), on peut trouver des points en 1 lesquels f prend respectivement les valeurs 1 2 et 2 . Par consquent, la fonction nest pas continue lorigine. sage: p = plot3d(f(x,y),(x,-2,2),(y,-2,2),plot_points=[150,150]) On aurait galement pu tracer des plans horizontaux pour visualiser les lignes de niveau de cette fonction en excutant : sage: for i in range(1,4): ....: p += plot3d(-0.5 + i / 4, (x, -2, 2), (y, -2, 2),\ ....: color=hue(i / 10), opacity=.1)

96

CHAP. 4. GRAPHIQUES

Figure 4.17 La surface reprsentative de f : (x, y )

x2 y . x4 +y 2

Parmi les autres commandes de trac 3D, citons implicit_plot3d qui permet de tracer des surfaces dnies par une quation implicite de la forme f (x, y, z ) = 0. Traons par exemple la surface de Cassini (gure 4.18a) dnie par lquation 2 implicite : a2 + x2 + y 2 = 4 a2 x2 + z 4 . sage: x, y, z = var( x, y, z ); a = 1 sage: h = lambda x, y, z:(a^2 + x^2 + y^2)^2 - 4*a^2*x^2-z^4 sage: f = implicit_plot3d(h, (x,-3,3), (y,-3,3), (z,-2,2),\ ....: plot_points=100, adaptative=True) Enn donnons un exemple de trac de courbe dans lespace (gure 4.18b) laide de la commande line3d : sage: g1 = line3d([(-10*cos(t)-2*cos(5*t)+15*sin(2*t),\ ....: -15*cos(2*t)+10*sin(t)-2*sin(5*t),\ ....: 10*cos(3*t)) for t in srange(0,6.4,.1)],radius=.5)

(a) La surface de Cassini.

(b) Un nud dans lespace.

Figure 4.18 Surface et courbe dans lespace.

Domaines de calcul
Lcriture des mathmatiques sur papier ou au tableau noir requiert, de manire essentielle, la recherche dun bon compromis entre souplesse, lgret des notations et rigueur. Cela nest pas dirent pour lusage au quotidien dun systme de calcul. Sage essaye de laisser le choix de ce compromis lutilisateur, en particulier en permettant celui-ci de spcier, plus ou moins rigoureusement, le domaine de calcul : quelle est la nature des objets considrs, dans quel ensemble vivent-ils, quelles oprations peut-on leur appliquer ?

5.1

Sage est orient objet

Python et Sage utilisent fortement la programmation oriente objet. Mme si cela reste relativement transparent pour lutilisation ordinaire, il est utile den savoir un minimum, dautant que celle-ci est trs naturelle dans un contexte mathmatique.

5.1.1

Objets, classes et mthodes

La programmation oriente objet repose sur lide de modliser chaque entit physique ou abstraite que lon souhaite manipuler dans un programme par une construction du langage de programmation appele un objet . Le plus souvent, et cest le cas en Python, chaque objet est instance dune classe . Ainsi, le nombre rationnel 12/35 est modlis par un objet qui est une instance de la classe Rational : sage: o = 12/35 sage: print type(o)

98 <type sage.rings.rational.Rational >

CHAP. 5. DOMAINES DE CALCUL

Notons que cette classe est vraiment associe lobjet 12/35, et non la variable o qui le contient : sage: print type(12/35) <type sage.rings.rational.Rational > Prcisons les dnitions. Un objet est une portion de la mmoire de lordinateur qui contient linformation ncessaire pour reprsenter lentit quil modlise. La classe quant elle dnit deux choses : 1. la structure de donnes dun objet, cest--dire comment linformation est organise dans le bloc mmoire. Par exemple, la classe Rational spcie quun nombre rationnel comme 12/35 est reprsent par deux nombres entiers : son numrateur et son dnominateur ; 2. son comportement, et en particulier les oprations sur cet objet : par exemple comment on extrait le numrateur dun nombre rationnel, comment on calcule sa valeur absolue, comment on multiplie ou additionne deux nombres rationnels. Chacune de ces oprations est implante par une mthode (ici respectivement numer, abs, __mult__, __add__). Pour factoriser un nombre entier, on va donc appeler la mthode factor avec la syntaxe suivante 1 : sage: o = 720 sage: o.factor() 2^4 * 3^2 * 5 que lon peut lire comme : prendre la valeur de o et lui appliquer la mthode factor sans autre argument . Sous le capot, Python eectue le calcul suivant : sage: type(o).factor(o) 2^4 * 3^2 * 5 De gauche droite : demander la classe de o (type(o)) la mthode approprie de factorisation (type(o).factor), et lappliquer o . Notons au passage que lon peut appliquer une mthode une valeur sans passer par une variable : sage: 720.factor() 2^4 * 3^2 * 5 et donc en particulier enchaner les oprations, de la gauche vers la droite. Ici, on prend le numrateur dun nombre rationnel, que lon factorise ensuite : sage: o = 720 / 133 sage: o.numerator().factor() 2^4 * 3^2 * 5
1. Pour le confort de lutilisateur, Sage fournit aussi une fonction factor, de sorte que factor(o) est un raccourci pour o.factor(). Il en est de mme pour bon nombre de fonctions dusage courant, et il est tout fait possible dajouter ses propres raccourcis.

5.1. SAGE EST ORIENT OBJET

99

5.1.2

Objets et polymorphisme

En quoi cela nous concerne-t-il ? Tout dabord, presque toutes les oprations en Sage sont polymorphes, cest--dire quelles peuvent sappliquer dirents types dobjets. Ainsi, quelle que soit la nature de lobjet o que lon veut factoriser , on utilise la mme notation o.factor() (ou son raccourci factor(o)). Les oprations eectuer ne sont pourtant pas les mmes dans le cas dun entier et dun polynme ! Elles dirent dailleurs aussi selon que le polynme est coecients rationnels ou coecients dans un corps ni. Cest la classe de lobjet qui dtermine quelle version de factor sera nalement excute. De mme, calquant les notations mathmatiques usuelles, le produit de deux objets a et b peut toujours tre not a*b mme si lalgorithme utilis dans chaque cas est dirent 2 . Voici un produit de deux nombres entiers : sage: 3 * 7 21 un produit de deux nombres rationnels, obtenu par produit des numrateurs et dnominateurs puis rduction : sage: (2/3) * (6/5) 4/5 un produit de deux nombres complexes, utilisant la relation i2 = 1 : sage: (1 + I) * (1 - I) 2 des produits commutatifs formels de deux expressions : sage: (x + (x + 1)*(x sage: (x + (x + 1)*(x 2) * (x + 1) + 2) 1) * (x + 2) + 2)

Outre la simplicit de notation, cette forme de polymorphisme permet dcrire des programmes gnriques qui sappliquent tout objet admettant les oprations utilises (ici la multiplication) : sage: def puissance_quatre(a): ....: a = a * a ....: a = a * a ....: return a sage: puissance_quatre(2) 16 sage: puissance_quatre(3/2)
2. Pour une opration arithmtique binaire comme le produit, la procdure de slection de la mthode approprie est un peu plus complique que ce qui a t dcrit prcdemment. En eet, elle doit grer des oprations mixtes comme la somme 2 + 3/4 dun entier et dun nombre rationnel. En loccurrence, 2 sera converti en nombre rationnel 2/1 avant laddition. Les rgles qui servent choisir quels oprandes convertir, et comment, sappellent le modle de coercition .

100 81/16 sage: puissance_quatre(I) 1 sage: puissance_quatre(x+1) (x + 1)^4 sage: M = matrix([[0,-1],[1,0]]); M [ 0 -1] [ 1 0] sage: puissance_quatre(M) [1 0] [0 1]

CHAP. 5. DOMAINES DE CALCUL

5.1.3

Introspection

Les objets Python, et donc Sage, ont des fonctionnalits dintrospection . Cela signie que lon peut, lexcution, interroger un objet sur sa classe, ses mthodes, etc., et manipuler les informations obtenues via les constructions habituelles du langage de programmation. Ainsi, la classe dun objet o est ellemme un objet Python (presque) comme les autres, que lon peut rcuprer avec type(o) : sage: t = type(5/1); print t <type sage.rings.rational.Rational > sage: t == type(5) False Nous voyons ici que lexpression 5/1 construit le rationnel 5, qui est un objet dirent de lentier 5 ! Ce sont aussi les outils dintrospection qui permettent daccder laide en ligne spcique la factorisation des nombres entiers partir dun objet de type entier : sage: o = 720 sage: o.factor? ... Definition: o.factor(self, algorithm= pari , proof=None, ...) Docstring: Return the prime factorization of this integer as a formal Factorization object. ... voire au code source de cette fonction : sage: o.factor?? ... def factor(self, algorithm= pari , proof=None, ...) ... if algorithm == pari : ...

5.2. LMENTS, PARENTS, CATGORIES elif algorithm in [ kash , magma ]: ...

101

En passant au-dessus des dtails techniques, on distingue quici Sage dlgue le gros du calcul dautres logiciels (PARI, Kash, voire Magma). Dans le mme ordre dide, on peut utiliser la compltion automatique pour demander interactivement un objet o toutes les oprations que lon peut lui appliquer. Ici, il y en a beaucoup ; voici celles qui commencent par n : sage: o.n<tab> o.n o.next_prime o.numerator o.nbits o.next_probable_prime o.numerical_approx o.ndigits o.nth_root

Il sagit encore dune forme dintrospection.

5.2
5.2.1

lments, parents, catgories


lments et parents

Dans la section prcdente, nous avons vu la notion de classe dun objet. Dans la pratique, il est susant de savoir que cette notion existe ; on a rarement besoin de regarder explicitement le type dun objet. En revanche Sage introduit une contrepartie plus conceptuelle de cette notion que nous allons aborder maintenant : celle de parent dun objet. Supposons par exemple que lon veuille dterminer si un lment a est inversible. La rponse ne va pas seulement dpendre de llment lui-mme, mais aussi de lensemble A auquel il est considr appartenir (ainsi que son inverse potentiel). Par exemple, le nombre 5 nest pas inversible dans lensemble Z des entiers, son inverse 1/5 ntant pas un entier : sage: a = 5; a 5 sage: a.is_unit() False En revanche, il est inversible dans lensemble des rationnels : sage: a = 5/1; a 5 sage: a.is_unit() True Sage rpond diremment ces deux questions car, comme nous lavons vu dans la section prcdente, les lments 5 et 5/1 sont des instances de classes direntes. Dans certains systmes de calcul formel orients objets, tels MuPAD ou Axiom, lensemble X auquel x est considr appartenir (ici Z ou Q) est simplement modlis par la classe de x. Sage suit lapproche de Magma et modlise X par un objet supplmentaire associ x, appel son parent :

102 sage: parent(5) Integer Ring sage: parent(5/1) Rational Field

CHAP. 5. DOMAINES DE CALCUL

On peut retrouver ces deux ensembles avec les raccourcis : sage: ZZ Integer Ring sage: QQ Rational Field et les utiliser pour convertir aisment un lment de lun lautre lorsque cela a un sens : sage: QQ(5).parent() Rational Field sage: ZZ(5/1).parent() Integer Ring sage: ZZ(1/5) Traceback (most recent call last): ... TypeError: no conversion of this rational to integer Dune manire gnrale, la syntaxe P(x) o P est un parent tente de convertir lobjet x en un lment de P. Voici 1 en tant quentier 1 Z, en tant que nombre rationnel 1 Q, et en tant quapproximation ottante relle 1,0 R ou complexe 1,0 + 0,0i C : sage: ZZ(1), QQ(1), RR(1), CC(1) (1, 1, 1.00000000000000, 1.00000000000000)
Exercice 18. Quelle est la classe de lanneau des entiers relatifs Z ?

5.2.2

Constructions

Les parents tant eux-mmes des objets, on peut leur appliquer des oprations. Ainsi, on peut construire le produit cartsien Q2 : sage: cartesian_product([QQ, QQ]) The cartesian product of (Rational Field, Rational Field) retrouver Q comme corps des fractions de Z : sage: ZZ.fraction_field() Rational Field construire lanneau des polynmes en x coecients dans Z : sage: ZZ[ x ] Univariate Polynomial Ring in x over Integer Ring

5.3. DOMAINES DE CALCUL REPRSENTATION NORMALE

103

Par empilements successifs, on peut construire des structures algbriques complexes comme lespace des matrices 3 3 coecients polynomiaux sur un corps ni : sage: Z5 = GF(5); Z5 Finite Field of size 5 sage: P = Z5[ x ]; P Univariate Polynomial Ring in x over Finite Field of size 5 sage: M = MatrixSpace(P, 3, 3); M Full MatrixSpace of 3 by 3 dense matrices over Univariate Polynomial Ring in x over Finite Field of size 5 dont voici un lment : sage: M.random_element() [2*x^2 + 3*x + 4 4*x^2 + 2*x + 2 [ 3*x 2*x^2 + x + 3 [ 4*x^2 + 3 3*x^2 + 2*x + 4 4*x^2 + 2*x] 3*x^2 + 4*x] 2*x + 4]

5.2.3

Complment : catgories

Un parent na, en gnral, pas lui-mme un parent, mais une catgorie qui indique ses proprits : sage: QQ.category() Category of quotient fields De fait Sage sait que Q est un corps : sage: QQ in Fields() True et donc, par exemple, un groupe additif commutatif (voir gure 5.1) : sage: QQ in CommutativeAdditiveGroups() True Il en dduit que Q[x] est un anneau euclidien : sage: QQ[ x ] in EuclideanDomains() True Toutes ces proprits sont utilises pour calculer rigoureusement et plus ecacement sur les lments de ces ensembles.

5.3

Domaines de calcul reprsentation normale

Passons maintenant en revue quelques-uns des parents que lon trouve dans Sage. Nous avons observ en 2.1 limportance pour le calcul symbolique des formes normales, qui permettent de distinguer si deux objets sont mathmatiquement

104

CHAP. 5. DOMAINES DE CALCUL

elds euclidean domains principal ideal domains unique factorization domains gcd domains integral domains commutative rings rings rngs commutative additive groups semigroups semirings monoids domains division rings

commutative additive monoids commutative additive semigroups

magmas

additive magmas sets

sets with partial maps objects


Figure 5.1 Un petit morceau du graphe des catgories dans Sage.

5.3. DOMAINES DE CALCUL REPRSENTATION NORMALE

105

Quelques types de base de Python Entiers Python Flottants Python Boolens (vrai, faux ) Chanes de caractres int float bool str

Domaines numriques de base Entiers Z Rationnels Q Flottants prcision p Flottants complexes prcision p ZZ ou IntegerRing() QQ ou RationalField() Reals(p) ou RealField(p) Complexes(p) ou ComplexField(p)

Anneaux et corps nis Rsidus modulo n, Z/nZ Corps ni Fq Integers(n) ou IntegerModRing(n) GF(q) ou FiniteField(q)

Nombres algbriques Nombres algbriques Q Nombres algbriques rels Corps de nombres Q[x]/ p QQbar ou AlgebraicField() AA ou AlgebraicRealField() NumberField(p)

Calcul symbolique Matrices m n coecients dans A Polynmes A[x, y ] Sries A[[x]] Expressions symboliques MatrixSpace(A, m, n) A[ x,y ] ou PolynomialRing(A, x,y ) A[[ x ]] ou PowerSeriesRing(A, x ) SR

Tableau 5.1 Principaux domaines de calcul et parents.

gaux en comparant leurs reprsentations. Chacun des parents fondamentaux prsents ci-dessous correspond un domaine de calcul forme normale, cest-dire un ensemble dobjets mathmatiques qui admettent une forme normale. Cela permet Sage de reprsenter sans ambigut les lments de chacun de ces parents 3 .

5.3.1

Domaines de calcul lmentaires

Nous appelons domaines de calcul lmentaires les ensembles classiques de constantes ne faisant pas intervenir de variable : entiers, rationnels, nombres ottants, boolens, rsidus modulo n... Entiers. Les entiers sont reprsents en base deux (en interne) et en base dix ( lcran). Comme nous lavons vu, les entiers Sage sont des objets de classe Integer. Leur parent est lanneau Z :
3. La plupart des autres parents disponibles dans Sage correspondent des domaines de calcul forme normale, mais ce nest pas le cas de tous. Il arrive aussi que, pour des raisons decacit, Sage ne reprsente les lments sous forme normale que sur demande explicite.

106 sage: 5.parent() Integer Ring

CHAP. 5. DOMAINES DE CALCUL

Les entiers sont reprsents sous forme normale ; lgalit est donc facile tester. Aussi, pour pouvoir reprsenter des entiers sous forme factorise, la commande factor utilise une classe spcique : sage: print type(factor(4)) <class sage.structure.factorization_integer.IntegerFactorization > La classe Integer est propre Sage : par dfaut, Python utilise des entiers de type int. En gnral la conversion de lun vers lautre est automatique, mais il peut tre ncessaire dindiquer explicitement cette conversion par sage: int(5) 5 sage: print type(int(5)) <type int > ou inversement sage: Integer(5) 5 sage: print type(Integer(5)) <type sage.rings.integer.Integer > Rationnels. La proprit de forme normale stend aux nombres rationnels, lments de QQ, qui sont toujours reprsents sous forme rduite. Ainsi, dans la commande sage: factorial(99) / factorial(100) - 1 / 50 -1/100 les factorielles sont dabord values, puis la fraction 1/100 obtenue est mise sous forme irrductible. Sage construit ensuite le rationnel 1/50, eectue la soustraction, puis rduit nouveau le rsultat (il ny a rien faire en loccurrence). Flottants. Les nombres rels ne peuvent pas tre reprsents exactement. Leurs valeurs numriques approches sont reprsentes sous forme de nombres virgule ottante, appels aussi simplement ottants, prsents en dtail au chapitre 11. Dans Sage, les ottants sont exprims en base deux. Une consquence est que le ottant dnot par une constante dcimale comme 0.1 nest pas exactement gal 1/10, car 1/10 nest pas reprsentable exactement en base deux ! Chaque ottant a sa propre prcision. Le parent des ottants avec p bits signicatifs est not Reals(p). Celui des ottants la prcision par dfaut (p = 53) sappelle aussi RR. Comme dans le cas des entiers, les ottants Sage dirent de leurs analogues Python. Lorsquils interviennent dans une somme, un produit ou un quotient faisant intervenir par ailleurs des entiers ou rationnels, les ottants sont contagieux : toute lexpression est alors calcule en virgule ottante :

5.3. DOMAINES DE CALCUL REPRSENTATION NORMALE sage: 72/53 - 5/3 * 2.7 -3.14150943396227

107

De mme, lorsque largument dune fonction usuelle est un ottant, le rsultat est encore un ottant : sage: cos(1), cos(1.) (cos(1), 0.540302305868140) La mthode numerical_approx (ou son alias n) sert valuer numriquement les autres expressions. Un argument optionnel permet de prciser le nombre de chires signicatifs utiliss lors du calcul. Voici par exemple avec 50 chires signicatifs : sage: pi.n(digits=50) # variante: n(pi,digits=50) 3.1415926535897932384626433832795028841971693993751 Nombres complexes. De mme, les approximations en virgule ottante de nombres complexes prcision p sont lments de Complexes(p), ou CC la prcision par dfaut. On peut construire un ottant complexe et calculer son argument par sage: z = CC(1,2); z.arg() 1.10714871779409 Expressions symboliques complexes Lunit imaginaire i (note I ou i) dj rencontre dans les chapitres prcdents nest pas un lment de CC, mais une expression symbolique (voir 5.4.1) : sage: I.parent() Symbolic Ring On peut lutiliser pour noter un ottant complexe moyennant une conversion explicite : sage: (1.+2.*I).parent() Symbolic Ring sage: CC(1.+2.*I).parent() Complex Field with 53 bits of precision Dans le monde des expressions symboliques, les mthodes real, imag et abs donnent respectivement la partie relle, la partie imaginaire et le module dun nombre complexe : sage: z = 3 * exp(I*pi/4) sage: z.real(), z.imag(), z.abs().simplify_exp() (3/2*sqrt(2), 3/2*sqrt(2), 3)

108

CHAP. 5. DOMAINES DE CALCUL

Boolens. Les expressions logiques forment aussi un domaine de calcul forme normale, mais la classe des valeurs de vrit, ou boolens, est un type de base de Python sans parent Sage associ. Les deux formes normales sont True et False : sage: a, b, c = 0, 2, 3 sage: a == 1 or (b == 2 and c == 3) True Dans les tests et les boucles, les conditions composes laide des oprateurs or et and sont values de faon paresseuse de la gauche vers la droite. Ceci signie que lvaluation dune condition compose par or se termine aprs le premier prdicat de valeur True, sans valuer les termes placs plus droite ; de mme avec and et False. Ainsi le test ci-dessous dcrit la divisibilit a|b sur les entiers et ne provoque aucune erreur mme si a = 0 : sage: a = 0; b = 12; (a == 0) and (b == 0) or (a != 0) and (b%a == 0) Loprateur not est prioritaire sur and qui est lui-mme prioritaire sur or, les tests dgalit et de comparaison tant quant eux prioritaires sur tous les oprateurs boolens. Les deux tests suivants sont donc quivalents au prcdent : sage: ((a == 0) and (b == 0)) or ((a != 0) and (b%a == 0)) sage: a == 0 and b == 0 or not a == 0 and b%a == 0 En outre, Sage autorise les tests dencadrement et dgalits multiples de la mme faon quils sont crits en mathmatiques : x y < z t cod par x <= y < z <= t x=y=z=t x == y == z != t Dans les cas simples, ces tests sont eectus directement ; sinon il faut faire appel la commande bool pour forcer lvaluation : sage: x, y = var( x, y ) sage: bool( (x-y)*(x+y) == x^2-y^2 ) True Rsidus modulo n. Pour dnir un entier modulaire, on commence par construire son parent, lanneau Z/nZ : sage: Z4 = IntegerModRing(4); Z4 Ring of integers modulo 4 sage: m = Z4(7); m 3 Comme dans le cas des ottants, les calculs faisant intervenir m seront faits modulo 4 via des conversions automatiques. Ainsi, dans lexemple suivant, 3 et 1 sont automatiquement convertis en lments de Z/4Z : sage: 3 * m + 1 2

5.3. DOMAINES DE CALCUL REPRSENTATION NORMALE

109

Lorsque p est premier, on peut aussi choisir de construire Z/pZ en tant que corps : sage: Z3 = GF(3); Z3 Finite Field of size 3 Il sagit dans les deux cas de domaines reprsentation normale : les rductions modulo n ou p sont eectues automatiquement chaque cration dun lment. Les calculs dans les anneaux et les corps nis sont dtaills au chapitre 6.

5.3.2

Domaines composs

partir de constantes bien dnies, des classes dobjets symboliques faisant intervenir des variables et admettant une forme normale peuvent tre construites. Les plus importantes sont les matrices, les polynmes, les fractions rationnelles et les sries tronques (dveloppements limits). Les parents correspondants sont paramtrs par le domaine des coecients. Ainsi, par exemple, les matrices coecients entiers dirent des matrices coecients dans Z/nZ, et les rgles de calcul adquates sont appliques automatiquement, sans quil y ait besoin de faire appel explicitement une fonction de rduction modulo n. La partie II de ce livre est consacre principalement ces objets. Matrices. La forme normale dune matrice est obtenue lorsque tous ses coecients sont eux-mmes sous forme normale. Aussi, toute matrice sur un corps ou un anneau reprsentation normale est automatiquement sous forme normale : sage: sage: [ -5 [ 7 [ 2 a = matrix(QQ, [[1,2,3],[2,4,8],[3,9,27]]) (a^2 + 1) * a^(-1) 13/2 7/3] 1 25/3] 19/2 27]

Lappel la fonction matrix est un raccourci. En interne, Sage construit le parent correspondant, savoir lespace des matrices 3 3 coecients dans Q (qui est reprsentation normale), puis lutilise pour fabriquer la matrice : sage: M = MatrixSpace(QQ,3,3); M Full MatrixSpace of 3 by 3 dense matrices over Rational Field sage: a = M([[1,2,3],[2,4,8],[3,9,27]]) sage: (a^2 + 1) * a^(-1) [ -5 13/2 7/3] [ 7 1 25/3] [ 2 19/2 27] Les oprations sur les matrices symboliques sont dcrites au chapitre 8, lalgbre linaire numrique au chapitre 13.

110

CHAP. 5. DOMAINES DE CALCUL

Polynmes et fractions rationnelles. Tout comme les matrices, les polynmes de Sage connaissent le type de leurs coecients. Leurs parents sont les anneaux de polynmes comme Z[x] ou C[x, y, z ], prsents en dtail dans les chapitres 7 et 9 de ce livre, et que lon peut construire comme suit : sage: P = ZZ[ x ]; P Univariate Polynomial Ring in x over Integer Ring sage: F = P.fraction_field(); F Fraction Field of Univariate Polynomial Ring in x over Integer Ring sage: p = P(x+1) * P(x); p x^2 + x sage: p + 1/p (x^4 + 2*x^3 + x^2 + 1)/(x^2 + x) sage: parent(p + 1/p) Fraction Field of Univariate Polynomial Ring in x over Integer Ring Comme nous le verrons en 5.4.2, il ny a pas une reprsentation idale pour les polynmes et les fractions rationnelles. Les lments des anneaux de polynmes sont reprsents sous forme dveloppe. Ces anneaux sont donc reprsentation normale ds que les coecients sont eux-mmes dans un domaine de calcul reprsentation normale. Ces polynmes dirent des expressions polynomiales que nous avons rencontres au chapitre 2, qui nont pas de type bien dni de coecients ni de parent qui rete ce type. Celles-ci reprsentent une alternative aux vrais polynmes qui peut tre utile, par exemple, pour mlanger polynmes et autres expressions mathmatiques. Soulignons qu linverse de ce quil se passe avec les lments des anneaux de polynmes, quand on travaille avec ces expressions, il faut appeler explicitement une commande de rduction comme expand pour les mettre en forme normale. Sries. Les sries tronques sont des objets de la forme a0 + a1 x + a2 x2 + + an xn + O(xn+1 ) utiliss par exemple pour reprsenter des dveloppements limits et dont la manipulation avec Sage est dcrite en 7.5. Le parent des sries en x tronques prcision n, coecients dans A, est lanneau A[[x]], construit par PowerSeries Ring(A, x , n). Comme les polynmes, les sries tronques ont un analogue dans le monde des expressions symboliques. La commande de rduction en forme normale associe est series. sage: f = cos(x).series(x == 0, 6); 1 / f
1 1 4 2 6 1+( 1 2 )x + 24 x +O (x )

sage: (1 / f).series(x == 0, 6)
2 1+ 1 2x + 5 4 24 x

+ O x6

5.4. EXPRESSIONS VERSUS DOMAINES DE CALCUL

111

Nombres algbriques. Un nombre algbrique est dni comme racine dun polynme. Lorsque le degr du polynme est 5 ou plus, il nest, en gnral, pas possible den crire explicitement les racines laide des oprations +, , , /, . Cependant, de nombreux calculs sur les racines peuvent tre mens bien sans autre information que le polynme lui-mme. sage: k.<a> = NumberField(x^3 + x + 1); a^3; a^4+3*a -a - 1 -a^2 + 2*a La manipulation de nombres algbriques avec Sage nest pas traite en dtail dans ce livre, mais on en trouvera plusieurs exemples dans les chapitres 7 et 9.

5.4

Expressions versus domaines de calcul

Plusieurs approches sont donc possibles pour manipuler avec Sage des objets comme les polynmes. On peut soit les voir comme des expressions formelles particulires, comme nous lavons fait dans les premiers chapitres de ce livre, soit introduire un anneau de polynmes particulier et calculer avec ses lments. Pour conclure ce chapitre, nous dcrivons brivement le parent des expressions formelles, le domaine SR, puis nous illustrons travers quelques exemples limportance de contrler le domaine de calcul et les dirences entre les deux approches.

5.4.1

Les expressions comme domaine de calcul

Les expressions symboliques constituent elles-mmes un domaine de calcul ! Dans Sage, leur parent est lanneau symbolique : sage: parent(sin(x)) Symbolic Ring que lon peut aussi obtenir avec : sage: SR Symbolic Ring Les proprits de cet anneau sont assez oues ; il est commutatif : sage: SR.category() Category of commutative rings et les rgles de calcul font en gros lhypothse que toutes les variables symboliques sont valeur dans C. La forme des expressions que lon manipule dans SR (expressions polynomiales, rationnelles, trigonomtriques) ntant pas apparente dans leur classe ou leur parent, le rsultat dun calcul ncessite le plus souvent des transformations manuelles pour tre mis sous la forme dsire (voir 2.1), en utilisant par exemple expand, combine, collect et simplify. Pour bien utiliser ces fonctions, il faut savoir

112

CHAP. 5. DOMAINES DE CALCUL

quel type de transformations elles eectuent, quelles sous-classes 4 dexpressions formelles ces transformations sappliquent, et lesquelles de ces sous-classes constituent des domaines de calcul forme normale. Ainsi, lusage aveugle de la fonction simplify peut conduire des rsultats faux. Des variantes de simplify permettent alors de prciser la simplication eectuer.

5.4.2

Exemples : polynmes et formes normales

Construisons lanneau Q[x1 , x2 , x3 , x4 ] des polynmes en 4 variables : sage: R = QQ[ x1,x2,x3,x4 ]; R Multivariate Polynomial Ring in x1, x2, x3, x4 over Rational Field sage: x1, x2, x3, x4 = R.gens() Les lments de R sont automatiquement reprsents sous forme dveloppe : sage: x1 * (x2 - x3) x1*x2 - x1*x3 qui, comme nous lavons vu, est une forme normale. En particulier, le test zro dans R est immdiat : sage: (x1+x2)*(x1-x2) - (x1^2 - x2^2) 0 Ce nest pas toujours un avantage. Par exemple, si lon construit le dterminant de Vandermonde 1 i<j n (xi xj ) : sage: prod( (a-b) for (a,b) in Subsets([x1,x2,x3,x4],2) ) x1^3*x2^2*x3 - x1^2*x2^3*x3 - x1^3*x2*x3^2 + x1*x2^3*x3^2 + x1^2*x2*x3^3 - x1*x2^2*x3^3 - x1^3*x2^2*x4 + x1^2*x2^3*x4 + x1^3*x3^2*x4 - x2^3*x3^2*x4 - x1^2*x3^3*x4 + x2^2*x3^3*x4 + x1^3*x2*x4^2 - x1*x2^3*x4^2 - x1^3*x3*x4^2 + x2^3*x3*x4^2 + x1*x3^3*x4^2 - x2*x3^3*x4^2 - x1^2*x2*x4^3 + x1*x2^2*x4^3 + x1^2*x3*x4^3 - x2^2*x3*x4^3 - x1*x3^2*x4^3 + x2*x3^2*x4^3 on obtient 4! = 24 termes. La mme construction avec une expression reste sous forme factorise, et est beaucoup plus compacte et lisible : sage: x1, x2, x3, x4 = SR.var( x1, x2, x3, x4 ) sage: prod( (a-b) for (a,b) in Subsets([x1,x2,x3,x4],2) ) (x3 - x4)*(x2 - x4)*(x2 - x3)*(x1 - x4)*(x1 - x3)*(x1 - x2) De mme, une reprsentation factorise ou partiellement factorise permet des calculs de pgcd plus rapides. Mais il ne serait pas judicieux non plus de mettre automatiquement tout polynme sous forme factorise, mme sil sagit aussi dune forme normale, car la factorisation est coteuse en temps de calcul et rend compliques les additions. De manire gnrale, selon le type de calcul voulu, la reprsentation idale dun lment nest pas toujours sa forme normale. Cela amne les systmes de calcul
4. Au sens de familles, et non de classes dobjets Python.

5.4. EXPRESSIONS VERSUS DOMAINES DE CALCUL

113

formel un compromis avec les expressions. Un certain nombre de simplications basiques, comme la rduction des rationnels ou la multiplication par zro, y sont eectues automatiquement ; les autres transformations sont laisses linitiative de lutilisateur auquel des commandes spcialises sont proposes.

5.4.3

Exemple : factorisation des polynmes

Considrons la factorisation de lexpression polynomiale suivante : sage: x = var( x ) sage: p = 54*x^4+36*x^3-102*x^2-72*x-12 sage: factor(p) 6*(3*x + 1)^2*(x^2 - 2) Cette rponse est-elle satisfaisante ? Il sagit bien dune factorisation de p, mais son optimalit dpend fortement du contexte ! Pour le moment Sage considre p comme une expression symbolique, qui se trouve tre polynomiale. Il ne peut pas savoir si lon souhaite factoriser p en tant que produit de polynmes coecients entiers ou coecients rationnels (par exemple). Pour prendre le contrle, nous allons prciser dans quel ensemble (domaine de calcul) nous souhaitons considrer p. Pour commencer, nous allons considrer p comme un polynme coecients entiers. Nous dnissons donc lanneau R = Z[x] de ces polynmes : sage: R = ZZ[ x ]; R Univariate Polynomial Ring in x over Integer Ring Puis nous convertissons p dans cet anneau : sage: q = R(p); q 54*x^4 + 36*x^3 - 102*x^2 - 72*x - 12 lachage on ne voit pas de dirence, mais q sait quil est un lment de R : sage: parent(q) Univariate Polynomial Ring in x over Integer Ring Du coup, sa factorisation est sans ambigut : sage: factor(q) 2 * 3 * (3*x + 1)^2 * (x^2 - 2) On procde de mme sur le corps des rationnels : sage: R = QQ[ x ]; R Univariate Polynomial Ring in x over Rational Field sage: q = R(p); q 54*x^4 + 36*x^3 - 102*x^2 - 72*x - 12 sage: factor(q) (54) * (x + 1/3)^2 * (x^2 - 2)

114

CHAP. 5. DOMAINES DE CALCUL

Dans ce nouveau contexte, la factorisation est encore non ambigu, mais dirente de la prcdente. Cherchons maintenant une factorisation complte sur les nombres complexes. Une premire option est de sautoriser une approximation numrique des nombres complexes avec 16 bits de prcision : sage: R = ComplexField(16)[ x ]; R Univariate Polynomial Ring in x over Complex Field with 16 bits of precision sage: q = R(p); q 54.00*x^4 + 36.00*x^3 - 102.0*x^2 - 72.00*x - 12.00 sage: factor(q) (54.00) * (x - 1.414) * (x + 0.3333)^2 * (x + 1.414) Une autre est dagrandir un peu le corps des rationnels ; ici, on va ajouter sage: R = QQ[sqrt(2)][ x ]; R Univariate Polynomial Ring in x over Number Field in sqrt2 with defining polynomial x^2 - 2 sage: q = R(p); q 54*x^4 + 36*x^3 - 102*x^2 - 72*x - 12 sage: factor(q) (54) * (x - sqrt2) * (x + sqrt2) * (x + 1/3)^2 Enn, peut-tre souhaite-t-on que les coecients soient considrs modulo 5 ? sage: R = GF(5)[ x ]; R Univariate Polynomial Ring in x over Finite Field of size 5 sage: q = R(p); q 4*x^4 + x^3 + 3*x^2 + 3*x + 3 sage: factor(q) (4) * (x + 2)^2 * (x^2 + 3) 2.

5.4.4

Synthse

Dans les exemples prcdents, nous avons illustr comment lutilisateur peut contrler le niveau de rigueur dans ses calculs. Dun ct il peut utiliser les expressions symboliques. Ces expressions vivent dans lanneau SR. Elles orent de nombreuses mthodes (prsentes au chapitre 2) qui sappliquent bien certaines sous-classes dexpressions, telles que les expressions polynomiales. Reconnatre quune expression appartient telle ou telle classe permet de savoir quelles fonctions il est pertinent de lui appliquer. Un problme pour lequel cette reconnaissance est essentielle est celui de la simplication dexpressions. Cest autour de ce problme que sont dnies les principales classes dexpressions des systmes de calcul formel, et cest lapproche que nous privilgierons le plus souvent dans la suite de cet ouvrage. Dun autre ct, lutilisateur peut construire un parent qui va spcier explicitement le domaine de calcul. Cest particulirement intressant lorsque ce parent est

5.4. EXPRESSIONS VERSUS DOMAINES DE CALCUL

115

forme normale : cest--dire que deux objets lments sont mathmatiquement gaux si et seulement sils ont la mme reprsentation. Pour rsumer, la souplesse est lavantage principal des expressions : pas de dclaration explicite du domaine de calcul, ajout au vol de nouvelles variables ou fonctions symboliques, changement au vol du domaine de calcul (par exemple lorsque lon prend le sinus dune expression polynomiale), utilisation de toute la gamme des outils danalyse (intgration, etc.). Les avantages de la dclaration explicite du domaine de calcul sont ses vertus pdagogiques, souvent une plus grande rigueur 5 , la mise sous forme normale automatique (qui peut aussi tre un inconvnient !), ainsi que la possibilit de constructions avances qui seraient dlicates avec des expressions (calculs sur un corps ni ou une extension algbrique de Q, dans un anneau non commutatif, etc.).

5. Sage nest pas un systme de calcul certi ; il peut donc toujours y avoir un bogue informatique ; mais il ny aura pas dutilisation dhypothse implicite.

116

CHAP. 5. DOMAINES DE CALCUL

Deuxime partie

Algbre et calcul formel

Dieu a cr les nombres entiers, tout le reste est fabriqu par lhomme. Leopold Kronecker (1823 - 1891)

Corps nis et thorie lmentaire des nombres


Ce chapitre dcrit lutilisation de Sage en thorie lmentaire des nombres, pour manipuler des objets sur des anneaux ou corps nis (6.1), pour tester la primalit (6.2) ou factoriser un entier (6.3) ; enn nous discutons quelques applications (6.4).

6.1

Anneaux et corps nis

Les anneaux et corps nis sont un objet fondamental en thorie des nombres, et en calcul symbolique en gnral. En eet, de nombreux algorithmes de calcul formel se ramnent des calculs sur des corps nis, puis on exploite linformation obtenue via des techniques comme la remonte de Hensel ou la reconstruction par les restes chinois. Citons par exemple lalgorithme de Cantor-Zassenhaus pour la factorisation de polynme univari coecients entiers, qui commence par factoriser le polynme donn sur un corps ni.

6.1.1

Anneau des entiers modulo n

En Sage, lanneau Z/nZ des entiers modulo n se dnit laide du constructeur IntegerModRing (ou plus simplement Integers). Tous les objets construits partir de ce constructeur et leurs drivs sont systmatiquement rduits modulo n, et ont donc une forme canonique, cest--dire que deux variables reprsentant la mme valeur modulo n ont la mme reprsentation interne. Dans certains cas bien particuliers, il est plus ecace de retarder les rductions modulo n, par exemple si on multiplie des matrices avec de tels coecients ; on prfrera alors

120

CHAP. 6. CORPS FINIS ET THORIE DES NOMBRES

travailler avec des entiers, et eectuer les rductions modulo n la main via a % n. Attention, le module n napparat pas explicitement dans la valeur ache : sage: a = IntegerModRing(15)(3); b = IntegerModRing(17)(3); a, b (3, 3) sage: a == b False Une consquence est que si lon copie-colle des entiers modulo n, on perd linformation sur n. tant donne une variable contenant un entier modulo n, on retrouve linformation sur n via les mthodes base_ring ou parent, et la valeur de n via la mthode characteristic : sage: R = a.base_ring(); R Ring of integers modulo 15 sage: R.characteristic() 15 Les oprateurs de base (addition, soustraction, multiplication) sont surchargs pour les entiers modulo n, et appellent les fonctions correspondantes, de mme que les entiers sont automatiquement convertis, ds lors quun des oprandes est un entier modulo n : sage: a + a, a - 17, a * a + 1, a^3 (6, 1, 10, 12) Quant linversion 1/a mod n ou la division b/a mod n, Sage leectue quand elle est possible, sinon il renvoie une erreur ZeroDivisionError, i.e., quand a et n ont un pgcd non-trivial : sage: 1/(a+1) 4 sage: 1/a Traceback (most recent call last): ... ZeroDivisionError: Inverse does not exist. Pour obtenir la valeur de a en tant quentier partir du rsidu a mod n, on peut utiliser la mthode lift ou bien ZZ : sage: z = lift(a); y = ZZ(a); print y, type(y), y == z 3 <type sage.rings.integer.Integer > True Lordre additif de a modulo n est le plus petit entier k > 0 tel que ka = 0 mod n. Il vaut k = n/g o g = pgcd(a, n), et est donn par la mthode additive_order (on voit au passage quon peut aussi utiliser Mod ou mod pour dnir les entiers modulo n) : sage: [Mod(x,15).additive_order() for x in range(0,15)] [1, 15, 15, 5, 15, 3, 5, 15, 15, 5, 3, 15, 5, 15, 15]

6.1. ANNEAUX ET CORPS FINIS

121

Lordre multiplicatif de a modulo n, pour a premier avec n, est le plus petit entier k > 0 tel que ak = 1 mod n. (Si a a un diviseur commun p avec n, alors ak mod n est un multiple de p quel que soit k .) Si cet ordre multiplicatif gale (n), savoir lordre du groupe multiplicatif modulo n, on dit que a est un gnrateur de ce groupe. Ainsi pour n = 15, il ny a pas de gnrateur, puisque lordre maximal est 4 < 8 = (15) : sage: [[x, Mod(x,15).multiplicative_order()] ....: for x in range(1,15) if gcd(x,15) == 1] [[1, 1], [2, 4], [4, 2], [7, 4], [8, 4], [11, 2], [13, 4], [14, 2]] Voici un exemple avec n = p premier, o 3 est gnrateur : sage: p = 10^20 + 39; mod(2,p).multiplicative_order() 50000000000000000019 sage: mod(3,p).multiplicative_order() 100000000000000000038 Une opration importante sur Z/nZ est lexponentiation modulaire , qui consiste calculer ae mod n. Le crypto-systme RSA repose sur cette opration. Pour calculer ecacement ae mod n, les algorithmes les plus ecaces ncessitent de lordre de log e multiplications ou carrs modulo n. Il est crucial de rduire systmatiquement tous les calculs modulo n, au lieu de calculer dabord ae en tant quentier, comme le montre lexemple suivant : sage: n = 3^100000; a = n-1; e = 100 sage: %timeit (a^e) % n 5 loops, best of 3: 387 ms per loop sage: %timeit power_mod(a,e,n) 125 loops, best of 3: 3.46 ms per loop

6.1.2

Corps nis

Les corps nis 1 se dnissent laide du constructeur FiniteField (ou plus simplement GF). On peut aussi bien construire les corps premiers GF(p) avec p premier que les corps composs GF(q) avec q = pk , p premier et k > 1 un entier. Comme pour les anneaux, les objets crs dans un tel corps ont une forme canonique, par consquent une rduction est eectue chaque opration. Les corps nis jouissent des mmes proprits que les anneaux (6.1.1), avec en plus la possibilit dinverser un lment non nul : sage: R = GF(17); [1/R(x) for x in range(1,17)] [1, 9, 6, 13, 7, 3, 5, 15, 2, 12, 14, 10, 4, 11, 8, 16] Un corps non premier Fpk avec p premier et k > 1 est isomorphe lanneau quotient des polynmes de Fp [x] modulo un polynme f unitaire et irrductible de degr k . Dans ce cas, Sage demande un nom pour le gnrateur du corps, cest--dire la variable x :
1. En franais, le corps ni q lments est not usuellement Fq , alors quen anglais on utilise plutt GF(q ). On utilise ici la notation franaise pour dsigner le concept mathmatique, et la notation anglaise pour dsigner du code Sage.

122

CHAP. 6. CORPS FINIS ET THORIE DES NOMBRES

sage: R = GF(9,name= x ); R Finite Field in x of size 3^2 Ici, Sage a choisi automatiquement le polynme f : sage: R.polynomial() x^2 + 2*x + 2 Les lments du corps sont alors reprsents par des polynmes ak1 xk1 + + a1 x + a0 , o les ai sont des lments de Fp : sage: Set([r for r in R]) {0, 1, 2, x, x + 1, x + 2, 2*x, 2*x + 1, 2*x + 2} On peut aussi imposer Sage le polynme irrductible f : sage: Q.<x> = PolynomialRing(GF(3)) sage: R2 = GF(9, name= x , modulus=x^2+1); R2 Finite Field in x of size 3^2 Attention cependant, car si les deux instances R et R2 cres ci-dessus sont isomorphes F9 , lisomorphisme nest pas explicite : sage: p = R(x+1); R2(p) Traceback (most recent call last): ... TypeError: unable to coerce from a finite field other than the prime subfield

6.1.3

Reconstruction rationnelle

Le problme de la reconstruction rationnelle constitue une jolie application des calculs modulaires. tant donn un rsidu a modulo m, il sagit de trouver un petit rationnel x/y tel que x/y a mod m. Si on sait quun tel petit rationnel existe, au lieu de calculer directement x/y en tant que rationnel, on calcule x/y modulo m, ce qui donne le rsidu a, puis on retrouve x/y par reconstruction rationnelle. Cette seconde approche est souvent plus ecace, car on remplace des calculs rationnels faisant intervenir de coteux pgcds par des calculs modulaires. Lemme. Soient a, m N, avec 0 < a < m. Il existe au plus une paire dentiers x, y Z premiers entre eux tels que x/y a mod m avec 0 < |x|, y m/2. Il nexiste pas toujours de telle paire x, y , par exemple pour a = 2 et m = 5. Lalgorithme de reconstruction rationnelle est bas sur lalgorithme de pgcd tendu. Le pgcd tendu de m et a calcule une suite dentiers ai = i m + i a, o les entiers ai dcroissent, et les coecients i , i croissent en valeur absolue. Il sut donc de sarrter ds que |ai |, |i | m/2, et la solution est alors x/y = ai /i . Cet algorithme est disponible via la fonction rational_reconstruction de Sage, qui renvoie x/y lorsquune telle solution existe, et une erreur sinon : sage: rational_reconstruction(411,1000) -13/17

6.1. ANNEAUX ET CORPS FINIS sage: rational_reconstruction(409,1000) Traceback (most recent call last): ... ValueError: Rational reconstruction of 409 (mod 1000) does not exist.

123

Pour illustrer la reconstruction rationnelle, considrons le calcul du nombre harmonique Hn = 1 + 1/2 + + 1/n. Le calcul naf avec des nombres rationnels est le suivant : sage: def harmonic(n): ....: return add([1/x for x in range(1,n+1)]) Or nous savons que Hn peut scrire sous la forme pn /qn avec pn , qn entiers, o qn est le ppcm de 1, 2, . . . , n. On sait par ailleurs que Hn log n + 1, ce qui permet de borner pn . On en dduit la fonction suivante qui dtermine Hn par calcul modulaire et reconstruction rationnelle : sage: def harmonic_mod(n,m): ....: return add([1/x % m for x in range(1,n+1)]) sage: def harmonic2(n): ....: q = lcm(range(1,n+1)) ....: pmax = RR(q*(log(n)+1)) ....: m = ZZ(2*pmax^2) ....: m = ceil(m/q)*q + 1 ....: a = harmonic_mod(n,m) ....: return rational_reconstruction(a,m) La ligne m = ZZ(2*pmax^2) garantit que la reconstruction rationnelle va trouver p m/2, tandis que la ligne suivante garantit que m est premier avec x = 1, 2, . . . , n, sinon 1/x mod n provoquerait une erreur. sage: harmonic(100) == harmonic2(100) True Sur cet exemple, la fonction harmonic2 nest pas plus ecace que la fonction harmonic, mais elle illustre bien notre propos. Il nest pas toujours ncessaire de connatre une borne rigoureuse sur x et y , une estimation la louche sut si on peut vrier facilement par ailleurs que x/y est la solution cherche. On peut gnraliser la reconstruction rationnelle avec un numrateur x et un dnominateur y de tailles direntes (voir par exemple la section 5.10 du livre [vzGG03]).

6.1.4

Restes chinois

Une autre application utile des calculs modulaires est ce quon appelle communment les restes chinois . tant donns deux modules m et n premiers entre eux, soit x un entier inconnu tel que x a mod m et x b mod n. Alors le thorme des restes chinois permet de reconstruire de faon unique la valeur de x modulo le produit mn. En eet, on dduit de x a mod m que x scrit sous la forme x = a + m avec Z. En remplaant cette valeur dans x b mod n, on

124

CHAP. 6. CORPS FINIS ET THORIE DES NOMBRES

obtient 0 mod n, o 0 = (b a)/m mod n. Il en rsulte x = x0 + nm, o x0 = a + 0 m, et est un entier quelconque. On a dcrit ici la variante la plus simple des restes chinois . On peut galement considrer le cas de plusieurs moduli m1 , m2 , . . . , mk . La commande Sage pour trouver x0 partir de a, b, m, n est crt(a,b,m,n) : sage: a = 2; b = 3; m = 5; n = 7; lambda0 = (b-a)/m % n; a + lambda0 * m 17 sage: crt(2,3,5,7) 17 Reprenons lexemple du calcul de Hn . Calculons dabord Hn mod mi pour i = 1, 2, . . . , k , ensuite nous dduisons Hn mod (m1 mk ) par restes chinois, enn nous retrouvons Hn par reconstruction rationnelle : sage: def harmonic3(n): ....: q = lcm(range(1,n+1)) ....: pmax = RR(q*(log(n)+1)) ....: B = ZZ(2*pmax^2) ....: a = 0; m = 1; p = 2^63 ....: while m < B: ....: p = next_prime(p) ....: b = harmonic_mod(n,p) ....: a = crt(a,b,m,p) ....: m = m*p ....: return rational_reconstruction(a,m) sage: harmonic(100) == harmonic3(100) True La fonction crt de Sage fonctionne aussi quand les moduli m et n ne sont pas premiers entre eux. Soit g = gcd(m, n), il y a une solution si et seulement si a mod g b mod g : sage: crt(15,1,30,4) 45 sage: crt(15,2,30,4) Traceback (most recent call last): ... ValueError: No solution to crt problem since gcd(30,4) does not divide 15-2 Une application plus complexe des restes chinois est prsente dans lexercice 22.

6.2

Primalit

Tester si un entier est premier est une des oprations fondamentales dun logiciel de calcul symbolique. Mme si lutilisateur ne sen rend pas compte, de tels tests sont eectus plusieurs milliers de fois par seconde par le logiciel. Par

6.2. PRIMALIT

125

Commandes les plus utiles Anneau des entiers modulo n Corps ni q lments Test de pseudo-primalit Test de primalit IntegerModRing(n) GF(q ) is_pseudoprime(n) is_prime(n)

Tableau 6.1 Rcapitulatif.

exemple pour factoriser un polynme de Z[x] on commence par le factoriser dans Fp [x] pour un nombre premier p, il faut donc trouver un tel p. Deux grandes classes de tests de primalit existent. Les plus ecaces sont des tests de pseudo-primalit, et sont en gnral bass sur des variantes du petit thorme de Fermat, qui dit que si p est premier, alors tout entier 0 < a < p est un gnrateur du groupe multiplicatif (Z/pZ) , donc ap1 1 mod p. On utilise en gnral une petite valeur de a (2, 3, . . .) pour acclrer le calcul de ap1 mod p. Si ap1 1 mod p, p nest certainement pas premier. Si ap1 1 mod p, on ne peut rien conclure : on dit alors que p est pseudo-premier en base a. Lintuition est quun entier p qui est pseudo-premier pour plusieurs bases a de grandes chances dtre premier (voir cependant ci-dessous). Les tests de pseudo-primalit ont en commun que quand ils renvoient False, le nombre est certainement compos, par contre quand ils renvoient True, on ne peut rien conclure. La seconde classe est constitue des tests de vraie primalit. Ces tests renvoient toujours une rponse correcte, mais peuvent tre moins ecaces que les tests de pseudo-primalit, notamment pour les nombres qui sont pseudo-premiers en de nombreuses bases, et en particulier pour les nombres vraiment premiers. De nombreux logiciels ne fournissent quun test de pseudo-primalit, voire pire le nom de la fonction correspondante (isprime par exemple) laisse croire lutilisateur que cest un test de (vraie) primalit. Sage fournit deux fonctions distinctes : is_pseudoprime pour la pseudo-primalit, et is_prime pour la primalit : sage: p = previous_prime(2^400) sage: %timeit is_pseudoprime(p) 625 loops, best of 3: 1.07 ms per loop sage: %timeit is_prime(p) 5 loops, best of 3: 485 ms per loop Nous voyons sur cet exemple que le test de primalit est bien plus coteux ; quand cest possible, on prfrera is_pseudoprime. Certains algorithmes de primalit fournissent un certicat, qui peut tre vri indpendamment, souvent de manire plus ecace que le test lui-mme. Sage ne fournit pas de tel certicat dans la version actuelle, mais on peut en fabriquer un avec le thorme de Pocklington : Thorme. Soit n > 1 un entier tel que n 1 = F R, avec F n. Si pour tout facteur premier p de F , il existe a tel que an1 1 mod n et a(n1)/p 1 est premier avec n, alors n est premier.

126

CHAP. 6. CORPS FINIS ET THORIE DES NOMBRES

Soit par exemple n = 231 1. La factorisation de n 1 est 2 32 7 11 31 151 331. On peut prendre F = 151 331 ; a = 3 convient pour les deux facteurs p = 151 et p = 331. Il sut ensuite de prouver la primalit de 151 et 331. Ce test utilise de manire intensive lexponentiation modulaire. Nombres de Carmichael Les nombres de Carmichael sont des entiers composs qui sont pseudopremiers dans toutes les bases. Le petit thorme de Fermat ne permet donc pas de les distinguer des nombres premiers, quel que soit le nombre de bases essayes. Le plus petit nombre de Carmichael est 561 = 3 11 17. Un nombre de Carmichael a au moins trois facteurs premiers. En eet, supposons que n = pq soit un nombre de Carmichael, avec p, q premiers, p < q ; par dnition des nombres de Carmichael, on a pour tout 1 a < q lgalit an1 1 modulo n, et par suite modulo q , ce qui implique que n 1 est multiple de q 1. Lentier n est ncessairement de la forme q + q (q 1), puisquil est multiple de q , et n 1 est multiple de q 1, ce qui est incompatible avec n = pq puisque p < q . Si n = pqr, alors il sut que an1 1 mod p et de mme pour q et r, puisque par restes chinois on aura alors an1 1 mod n. Une condition susante est que n 1 soit multiple de p 1, q 1 et r 1 : sage: [560 % (x-1) for x in [3,11,17]] [0, 0, 0]

Exercice 19. crire une fonction Sage comptant les nombres de Carmichael n = pqr N , avec p, q, r premiers impairs distincts. Combien trouvez-vous pour N = 104 , 105 , 106 , 107 ? (Richard Pinch a compt 20138200 nombres de Carmichael infrieurs 1021 .)

Enn, pour itrer une opration sur des nombres premiers dans un intervalle, il vaut mieux utiliser la construction prime_range, qui construit une table via un crible, plutt quune boucle avec next_probable_prime ou next_prime : sage: def count_primes1(n): ....: return add([1 for p in range(n+1) if is_prime(p)]) sage: %timeit count_primes1(10^5) 5 loops, best of 3: 674 ms per loop La fonction est plus rapide en utilisant is_pseudoprime au lieu de is_prime : sage: def count_primes2(n): ....: return add([1 for p in range(n+1) if is_pseudoprime(p)]) sage: %timeit count_primes2(10^5) 5 loops, best of 3: 256 ms per loop Sur cet exemple il vaut mieux utiliser une boucle qui vite de construire une liste de 105 lments, et l encore is_pseudoprime est plus rapide que is_prime :

6.3. FACTORISATION ET LOGARITHME DISCRET sage: def count_primes3(n): ....: s = 0; p = 2 ....: while p <= n: s += 1; p = next_prime(p) ....: return s sage: %timeit count_primes3(10^5) 5 loops, best of 3: 49.2 ms per loop sage: def count_primes4(n): ....: s = 0; p = 2 ....: while p <= n: s += 1; p = next_probable_prime(p) ....: return s sage: %timeit count_primes4(10^5) 5 loops, best of 3: 48.6 ms per loop Litrateur prime_range est quant lui bien plus rapide : sage: def count_primes5(n): ....: s = 0 ....: for p in prime_range(n): s += 1 ....: return s sage: %timeit count_primes5(10^5) 125 loops, best of 3: 2.67 ms per loop

127

6.3

Factorisation et logarithme discret

On dit quun entier a est un carr ou rsidu quadratique modulo n sil existe x, 0 x < n, tel que a x2 mod n. Sinon, on dit que a est un non-rsidu quadratique modulo n. Lorsque n = p est premier, ce test peut se dcider ecacement grce au calcul du symbole de Jacobi de a et p, not (a|p), qui peut prendre les valeurs {1, 0, 1}, o (a|p) = 0 signie que a est multiple de p, et (a|p) = 1 (respectivement (a|p) = 1) signie que a est (respectivement nest pas) un carr modulo p. La complexit du calcul du symbole de Jacobi (a|n) est essentiellement la mme que celle du calcul du pgcd de a et n, savoir O(M ( ) log ) o est la taille de n, et M ( ) est le cot du produit de deux entiers de taille . Cependant toutes les implantations du symbole de Jacobi voire du pgcd nont pas cette complexit (a.jacobi(n) calcule (a|n)) : sage: p = (2^42737+1)//3; a = 3^42737 sage: %timeit a.gcd(p) 125 loops, best of 3: 4.3 ms per loop sage: %timeit a.jacobi(p) 25 loops, best of 3: 26.1 ms per loop Lorsque n est compos, trouver les solutions de x2 a mod n est aussi dicile que factoriser n. Toutefois le symbole de Jacobi, qui est relativement facile calculer, donne une information partielle. En eet, si (a|n) = 1, il ny a pas de solution, car une solution vrie ncessairement (a|p) = 1 pour tous les facteurs premiers p de n, donc (a|n) = 1.

128

CHAP. 6. CORPS FINIS ET THORIE DES NOMBRES

Le logarithme discret. Soit n un entier positif, g un gnrateur du groupe multiplicatif modulo n et a premier avec n, 0 < a < n. Par dnition du fait que g est un gnrateur, il existe un entier x tel que g x = a mod n. Le problme du logarithme discret consiste trouver un tel entier x. La mthode log permet de rsoudre ce problme : sage: p = 10^10+19; a = mod(17,p); a.log(2) 6954104378 sage: mod(2,p)^6954104378 17 Les meilleurs algorithmes connus pour calculer un logarithme discret sont de mme ordre de complexit en fonction de la taille de n que ceux pour factoriser n. Cependant limplantation actuelle en Sage du logarithme discret est peu ecace : sage: p = 10^20+39; a = mod(17,p) sage: %time r = a.log(3) CPU times: user 89.63 s, sys: 1.70 s, total: 91.33 s Suites aliquotes La suite aliquote associe un entier positif n est la suite (sk ) dnie par rcurrence : s0 = n et sk+1 = (sk ) sk , o (sk ) est la somme des diviseurs de sk , i.e., sk+1 est la suite des diviseurs propres de sk , cest--dire sans sk lui-mme. On arrte litration lorsque sk = 1 alors sk1 est premier ou lorsque la suite (sk ) dcrit un cycle. Par exemple en partant de n = 30 on obtient : 30, 42, 54, 66, 78, 90, 144, 259, 45, 33, 15, 9, 4, 3, 1. Lorsque le cycle est de longueur un, on dit que lentier correspondant est parfait, par exemple 6 = 1 + 2 + 3 et 28 = 1 + 2 + 4 + 7 + 14 sont parfaits. Lorsque le cycle est de longueur deux, on dit que les deux entiers en question sont amicaux, comme 220 et 284. Lorsque le cycle est de longueur trois ou plus, les entiers formant ce cycle sont dits sociables.
Exercice 20. Calculer la suite aliquote commenant par 840, acher les 5 premiers et 5 derniers lments, et tracer le graphe de log10 sk en fonction de k (on pourra utiliser la fonction sigma).

6.4
6.4.1

Applications
La constante

La constante est une gnralisation en dimension deux de la constante dEuler. Elle est dnie comme suit :
n

= lim

k=2

1 2 log n , rk

(6.1)

6.4. APPLICATIONS

129

2 o rk est le rayon du plus petit disque du plan ane R contenant au moins 2 k points de Z . Par exemple r2 = 1/2, r3 = r4 = 2/2, r5 = 1, r6 = 5/2, r7 = 5/4, r8 = r9 = 2 :

Exercice 21 (Constante de Masser-Gramain). 1. crire une fonction qui prend en entre un entier positif k, et renvoie le rayon rk et le centre (xk , yk ) dun plus petit disque contenant au moins k points de Z2 . On admettra rk < k/ . m 2. crire une fonction dessinant le cercle de centre (xk , yk ) et de rayon rk , avec les k points de Z2 inclus, comme ci-dessus. 3. En utilisant lencadrement (k 6) + 2 2 k1 < rk < , (6.2)

calculer une approximation de avec une erreur borne par 0.3.

6.4.2 Calcul dintgrale multiple via reconstruction rationnelle


Cette application est inspire de larticle [Bea09]. Soient k et n1 , n2 , . . . , nk des entiers positifs ou nuls. On veut calculer lintgrale I=
V nk 1 n2 xn 1 x2 xk dx1 dx2 . . . dxk ,

o le domaine dintgration est dni par V = {x1 x2 xk 0, x1 + + xk 1}. Par exemple pour k = 2, n1 = 3, n2 = 5, on obtient la valeur
1/ 2

I=
x2 =0

1x2 x1 =x2

5 x3 1 x2 dx1 dx2 =

13 . 258048

130

CHAP. 6. CORPS FINIS ET THORIE DES NOMBRES

Exercice 22. Sachant que I est un nombre rationnel, mettre au point un algorithme utilisant la reconstruction rationnelle et/ou les restes chinois pour calculer I . On implantera cet algorithme en Sage et on lappliquera au cas o [n1 , . . . , n31 ] = [9, 7, 8, 11, 6, 3, 7, 6, 6, 4, 3, 4, 1, 2, 2, 1, 1, 1, 2, 0, 0, 0, 3, 0, 0, 0, 0, 1, 0, 0, 0].

Polynmes
Ce chapitre est consacr aux polynmes une indtermine et aux objets apparents, essentiellement les fractions rationnelles et les sries formelles. Nous allons y voir tout dabord comment eectuer avec Sage des manipulations telles que la division euclidienne de polynmes, la dcomposition en polynmes irrductibles, la recherche de racines ou la dcomposition en lments simples de fractions rationnelles. Ceci en tenant compte de lanneau ou du corps o vivent les coecients des polynmes considrs : Sage nous permet de calculer dans les anneaux de polynmes A[x], leurs quotients A[x]/ P (x) , les corps de fractions rationnelles K (x) ou encore les anneaux de sries formelles A[[x]] pour toute une gamme danneaux de base. Mais les oprations sur les polynmes ont des applications plus inattendues. Comment deviner automatiquement le terme suivant de la suite 1, 1, 2, 3, 8, 11, 39...? Par exemple, grce lapproximation de Pad des fractions rationnelles, prsente en section 7.4.3 ! Comment dvelopper aisment en srie les solutions de lquation exf (x) = f (x) ? Rponse en section 7.5.3. Nous supposons en gnral que le lecteur a lhabitude de manipuler les polynmes et fractions rationnelles au niveau dun cours de premire anne duniversit. Nous abordons cependant aussi quelques sujets plus avancs. (Comment prouver que les solutions de lquation x5 x 1 ne sexpriment pas par radicaux ? Il sut de calculer son groupe de Galois comme expliqu en section 7.3.4.) Les passages correspondants ne sont pas utiliss dans le reste du livre, et le lecteur peut les sauter sans dommage. Enn, ce chapitre donne une poigne dexemples de manipulation de nombres algbriques et de nombres p-adiques. Les polynmes plusieurs indtermines font quant eux lobjet du chapitre 9.

132

CHAP. 7. POLYNMES

7.1
7.1.1

Anneaux de polynmes
Introduction

Nous avons vu au chapitre 2 comment eectuer des calculs sur des expressions formelles , lments de lanneau symbolique SR. Quelques-unes des mthodes applicables ces expressions, par exemple degree, sont destines aux polynmes : sage: x = var( x ); p = (2*x+1)*(x+2)*(x^4-1) sage: print p, "est de degr", p.degree(x) (x + 2)*(2*x + 1)*(x^4 - 1) est de degr 6 Dans certains systmes de calcul formel, dont Maple et Maxima, reprsenter les polynmes comme des expressions formelles particulires est la manire habituelle de les manipuler. limage dAxiom, Magma ou MuPAD, Sage permet aussi de traiter les polynmes de faon plus algbrique, et sait calculer dans des anneaux comme Q[x] ou Z/4Z [x, y, z ]. Ainsi, pour reproduire lexemple prcdent en travaillant dans un anneau de polynmes bien dtermin, on aecte la variable Python x lindtermine de lanneau des polynmes en x coecients rationnels, donne par polygen(QQ, x ), au lieu de la variable symbolique x renvoye 1 par var( x ) : sage: x = polygen(QQ, x ); p = (2*x+1)*(x+2)*(x^4-1) sage: print p, "est de degr", p.degree() 2*x^6 + 5*x^5 + 2*x^4 - 2*x^2 - 5*x - 2 est de degr 6 Observons que le polynme est automatiquement dvelopp. Les polynmes algbriques sont toujours reprsents sous forme normale. Cest une dirence cruciale par rapport aux polynmes de SR. En particulier, lorsque deux polynmes sont mathmatiquement gaux, leur reprsentation informatique est la mme, et une comparaison coecient par coecient sut tester lgalit. Les fonctionnalits de calcul sur les polynmes algbriques sont beaucoup plus tendues et performantes que celles sur les expressions polynomiales.

7.1.2

Construction danneaux de polynmes

En Sage, les polynmes, comme beaucoup dautres objets algbriques, sont en gnral coecients dans un anneau commutatif. Cest le point de vue que nous adoptons, mais la plupart de nos exemples concernent des polynmes sur un corps. Dans tout le chapitre, les lettres A et K dsignent respectivement un anneau commutatif et un corps quelconques. La premire tape pour mener un calcul dans une structure algbrique R est souvent de construire R elle-mme. On construit Q[x] par sage: R = PolynomialRing(QQ, x ) sage: x = R.gen()
1. Une petite dirence : alors que var( x ) a le mme eet que x = var( x ) en utilisation interactive, polygen(QQ, x ) sans aectation ne change pas la valeur de la variable Python x.

7.1. ANNEAUX DE POLYNMES

133

Manipulation des anneaux de polynmes, R = A[x] construction (repr. dense) ex. Z[x], Q[x], R[x], Z/nZ[x] construction (repr. creuse) accs lanneau de base A accs la variable x tests (intgre, nthrien...) R.<x> = A[] ou R.<x> = PolynomialRing(A, x ) ZZ[ x ], QQ[ x ], RR[ x ], Integers(n)[ x ] R.<x> = PolynomialRing(A, x , sparse=True) R.base_ring() R.gen() ou R.0 R.is_integral_domain(), R.is_noetherian(), ...

Tableau 7.1 Anneaux de polynmes.

Le x qui apparat sur la premire ligne est une chane de caractres, le nom de lindtermine, ou gnrateur de lanneau. Le x de la deuxime ligne est une variable Python dans laquelle on rcupre le gnrateur ; employer le mme nom facilite la lecture du code. Lobjet ainsi stock dans la variable x reprsente le polynme x Q[x]. Il a pour parent (le parent dun objet Sage est la structure algbrique do il est issu , voir 5.1) lanneau QQ[ x ] : sage: x.parent() Univariate Polynomial Ring in x over Rational Field Le polynme x Q[x] est considr comme dirent la fois des polynmes identit x A[x] danneau de base A = Q et de ceux, comme t Q[t], dont lindtermine porte un autre nom. Lexpression PolynomialRing(QQ, t ) scrit aussi QQ[ t ]. On combine souvent cette abrviation avec la construction S.<g> = ... , qui aecte simultanment une structure la variable S et son gnrateur la variable g. La construction de lanneau Q[x] et de son indtermine se rduit alors R.<x> = QQ[ x ], ou mme simplement R.<x> = QQ[] en sous-entendant la variable x. La forme x = polygen(QQ, x ) vue en introduction quivaut sage: x = PolynomialRing(QQ, x ).gen() Signalons en passant que lon peut choisir entre plusieurs reprsentations en mmoire lorsque lon construit un anneau de polynmes. Les dirences entre reprsentations seront discutes en 7.6.
Exercice 23 (Variables et indtermines). 1. Comment dnir x et y pour observer les rsultats suivants ? sage: x^2 + 1 y^2 + 1 sage: (y^2 + 1).parent() Univariate Polynomial Ring in x over Rational Field 2. Aprs les instructions sage: Q.<x> = QQ[]; p = x + 1; x = 2; p = p + x quelle est la valeur de p ?

134 Polynmes coecients polynomiaux

CHAP. 7. POLYNMES

Nous pouvons dnir en Sage des anneaux de polynmes coecients dans nimporte quel anneau commutatif, y compris un autre anneau de polynmes. Mais attention, les anneaux du type A[x][y ] construits suivant ce procd sont distincts des vritables anneaux de polynmes plusieurs indtermines comme A[x, y ]. Ces derniers, prsents au chapitre 9, sont mieux adapts aux calculs courants. En eet, travailler dans A[x][y ][. . . ] fait souvent jouer aux indtermines des rles trop dissymtriques. Cependant, on souhaite parfois justement privilgier une variable en voyant les autres comme des paramtres. La mthode polynomial des polynmes multivaris permet disoler une variable, un peu comme la mthode collect des expressions. Voici par exemple comment calculer le polynme rciproque dun polynme donn par rapport une de ses indtermines : sage: R.<x,y,z,t> = QQ[]; p = (x+y+z*t)^2 sage: p.polynomial(t).reverse() (x^2 + 2*x*y + y^2)*t^2 + (2*x*z + 2*y*z)*t + z^2 Ici, p.polynomial(t) cre un polynme en la seule indtermine t et coecients dans QQ[x,y,z], auquel on applique ensuite la mthode reverse. Les autres conversions entre A[x, y, . . . ] et A[x][y ][. . . ] fonctionnent comme on sy attend : sage: sage: y^2 + sage: x^3 + sage: y^2 + x = polygen(QQ); y = polygen(QQ[x], y ) p = x^3 + x*y + y + y^2; p (x + 1)*y + x^3 q = QQ[ x,y ](p); q x*y + y^2 + y QQ[ x ][ y ](q) (x + 1)*y + x^3

7.1.3

Polynmes

Cration et arithmtique de base. Aprs linstruction R.<x> = QQ[], les expressions construites partir de x et des constantes rationnelles par les oprations + et * sont des lments de Q[x]. Par exemple, dans p = x + 2, Sage dtermine automatiquement que la valeur de la variable x et lentier 2 peuvent tous deux sinterprter comme des lments de Q[x]. La routine daddition des polynmes de Q[x] est donc appele ; elle fabrique et renvoie le polynme x + 2 Q[x]. Une autre faon de crer un polynme consiste numrer ses coecients : sage: def rook_polynomial(n, var= x ): ....: return ZZ[var]([binomial(n, k)^2 * factorial(k) ....: for k in (0..n) ]) La fonction ci-dessus fabrique des polynmes o le coecient de xk sinterprte comme le nombre de faons de placer k tours sur un chiquier n n sans quelles

7.1. ANNEAUX DE POLYNMES

135

Accs aux donnes, oprations syntaxiques indtermine x coecient de xk coecient dominant degr liste des coecients liste des coecients non nuls dictionnaire degr coecient tests (unitaire, constant...) p.variables(), p.variable_name() p[k] p.leading_coefficient() p.degree() p.coeffs() p.coefficients() p.dict() p.is_monic(), p.is_constant(), ...

Arithmtique de base oprations p + q , p q , p q , pk substitution x := a drive p + q, p - q, p * q, p^k p(a) ou p.subs(a) p.derivative() ou diff(p)

Transformations transformation des coecients changement danneau de base A[x] B [x] polynme rciproque p.map_coefficients(f) p.change_ring(B) ou B[ x ](p) p.reverse()

Tableau 7.2 Oprations de base sur les polynmes p, q A[x].

se menacent, do son nom. Les parenthses aprs ZZ[var] servent convertir de force un objet donn en un lment de cet anneau. La conversion dune liste [a0 , a1 , . . . ] en lment de ZZ[ x ] renvoie le polynme a0 + a1 x + Z[x]. Vue densemble des oprations sur les polynmes. Les lments dun anneau de polynmes sont reprsents par des objets Python de la classe Polynomial ou de classes drives. Les principales oprations 2 disponibles sur ces objets sont rsumes dans les tableaux 7.2 7.5. Ainsi, on rcupre le degr dun polynme en appelant sa mthode degree. De mme, p.subs(a) ou simplement p(a) donne la valeur de p au point a, mais sert aussi calculer la compose p a lorsque a est lui-mme un polynme, et plus gnralement valuer un polynme de A[x] en un lment dune A-algbre : sage: p = R.random_element(degree=4) # un polynme au hasard sage: p -4*x^4 - 52*x^3 - 1/6*x^2 - 4/23*x + 1 sage: p.subs(x^2) -4*x^8 - 52*x^6 - 1/6*x^4 - 4/23*x^2 + 1 sage: p.subs(matrix([[1,2],[3,4]]))
2. Il y en a beaucoup dautres. Ces tableaux omettent les fonctionnalits trop pointues, les variantes plus spcialises de mthodes mentionnes, et de nombreuses mthodes communes tous les lments danneaux , voire tous les objets Sage, qui ne prsentent pas dintrt particulier sur les polynmes. Notons cependant que les mthodes spcialises (par exemple p.rescale(a), quivalent p(a*x)) sont souvent plus ecaces que les mthodes plus gnrales qui peuvent les remplacer.

136 [-375407/138 -273931/69] [ -273931/46 -598600/69]

CHAP. 7. POLYNMES

Nous reviendrons sur le contenu des deux derniers tableaux dans les sections 7.2.1 et 7.3. Changement danneau. La liste exacte des oprations disponibles, leur eet et leur ecacit dpendent fortement de lanneau de base. Par exemple, les polynmes de ZZ[ x ] possdent une mthode content qui renvoie leur contenu, cest--dire le pgcd de leurs coecients ; ceux de QQ[ x ] non, lopration tant triviale. La mthode factor existe quant elle pour tous les polynmes mais dclenche une exception NotImplementedError pour un polynme coecients dans SR ou dans Z/4Z. Cette exception signie que lopration nest pas disponible dans Sage pour ce type dobjet bien quelle ait un sens mathmatiquement. Il est donc trs utile de pouvoir jongler avec les dirents anneaux de coecients sur lesquels on peut considrer un mme polynme. Applique un polynme de A[x], la mthode change_ring renvoie son image dans B [x], quand il y a une faon naturelle de convertir les coecients. La conversion est souvent donne par un morphisme canonique de A dans B : notamment, change_ring sert tendre lanneau de base pour disposer de proprits algbriques supplmentaires. Ici par exemple, le polynme p est irrductible sur les entiers, mais se factorise sur R : sage: x = polygen(QQ) sage: p = x^2 - 16*x + 3 sage: p.factor() x^2 - 16*x + 3 sage: p.change_ring(RDF).factor() (x - 15.8102496759) * (x - 0.189750324093) Le domaine RDF est en fait celui des ottants machine , prsent au chapitre 11. La factorisation obtenue nest quapproche ; elle ne sut pas retrouver exactement coup sr le polynme de dpart. Pour reprsenter les racines relles de polynmes coecients entiers dune manire qui permet les calculs exacts, on utilise le domaine AA des nombres algbriques rels. Nous verrons quelques exemples dans les sections suivantes. La mme mthode change_ring permet de rduire un polynme de Z[x] modulo un nombre premier : sage: p.change_ring(GF(3)) x^2 + 2*x Inversement, si B A et si les coecients de p sont en fait dans B , cest aussi change_ring que lon utilise an de ramener p dans B [x]. Itration. Plus gnralement, on a parfois besoin dappliquer une transformation tous les coecients dun polynme. La mthode map_coefficients est l pour cela. Applique un polynme p A[x] avec comme paramtre une fonction f , elle renvoie le polynme obtenu en appliquant f chacun des coecients non nuls de p. Le plus souvent, f est une fonction anonyme introduite

7.2. ARITHMTIQUE EUCLIDIENNE

137

Divisibilit et division euclidienne test de divisibilit p | q multiplicit dun diviseur q k | p division euclidienne p = qd + r pseudo-division ak p = qd + r plus grand commun diviseur plus petit commun multiple pgcd tendu g = up + vq restes chinois c a mod p, c b mod q p.divides(q) k = p.valuation(q) q, r = p.quo_rem(d) ou q = p//d, r = p%d q, r, k = p.pseudo_divrem(d) p.gcd(q), gcd([p1, p2, p3]) p.lcm(q), lcm([p1, p2, p3]) g, u, v = p.xgcd(q) ou xgcd(p, q) c = crt(a, b, p, q)

Divers interpolation p(xi ) = yi contenu de p Z[x] p = R.lagrange_polynomial([(x1,y1), ...]) p.content()

Tableau 7.3 Arithmtique des polynmes.

par la construction lambda (voir 3.3.2). Voici par exemple comment calculer le conjugu dun polynme coecients complexes : sage: sage: x^3 + sage: x^3 QQi.<myI> = QQ[I] # myi est le i de QQi, I celui de SR R.<x> = QQi[]; p = (x + 2*myI)^3; p 6*I*x^2 - 12*x - 8*I p.map_coefficients(lambda z: z.conjugate()) 6*I*x^2 - 12*x + 8*I

Dans le cas prsent, on peut aussi crire p.map_coefficients(conjugate), car conjugate(z) a le mme eet que z.conjugate pour z Q[i]. Appeler explicitement une mthode de lobjet z est plus sr : le code fonctionne ainsi avec tous les objets dots dune mthode conjugate(), et seulement ceux-l.

7.2

Arithmtique euclidienne

Aprs la somme et le produit, les oprations les plus lmentaires sont ici la division euclidienne et le calcul de plus grand commun diviseur. Les oprateurs et mthodes correspondants (tableau 7.3) rappellent ceux sur les entiers. Bien souvent cependant, ces oprations sont caches par une couche dabstraction mathmatique supplmentaire : quotient danneaux (7.2.2) o chaque opration arithmtique contient une division euclidienne implicite, fractions rationnelles (7.4) dont la normalisation passe par des calculs de pgcd...

7.2.1

Divisibilit

Divisions. La division euclidienne fonctionne sur un corps, et plus gnralement sur un anneau commutatif si le coecient dominant du diviseur est inversible, puisque ce coecient est le seul lment de lanneau de base par lequel il est ncessaire de diviser lors du calcul :

138

CHAP. 7. POLYNMES

Oprations sur les anneaux de polynmes Les parents des objets polynmes, les anneaux A[x], sont eux-mmes des objets Sage part entire. Voyons rapidement quoi ils peuvent servir. Une premire famille de mthodes permet de construire des polynmes remarquables, den tirer au hasard, ou encore dnumrer des familles de polynmes, ici ceux de degr exactement 2 sur F2 : sage: list(GF(2)[ x ].polynomials(of_degree=2)) [x^2, x^2 + 1, x^2 + x, x^2 + x + 1] Nous ferons appel quelques-unes de ces mthodes dans les exemples des sections suivantes pour construire les objets sur lesquels travailler. Le chapitre 15 explique de faon plus gnrale comment numrer les lments densembles nis avec Sage. Deuximement, le systme connat quelques faits de base propos de chaque anneau de polynmes. On peut tester si un objet donn est un anneau, sil est nthrien : sage: A = QQ[ x ] sage: A.is_ring() and A.is_noetherian() True ou encore si Z est sous-anneau de Q[x] et pour quelles valeurs de n lanneau Z/nZ est intgre : sage: ZZ.is_subring(A) True sage: [n for n in range(20) ....: if Integers(n)[ x ].is_integral_domain()] [0, 2, 3, 5, 7, 11, 13, 17, 19] Ces possibilits reposent largement sur le systme de catgories de Sage (voir aussi 5.2.3). Les anneaux de polynmes sont membres dun certain nombre de catgories , comme la catgorie des ensembles, celle des anneaux euclidiens, et bien dautres : sage: R.categories() [Category of euclidean domains, Category of principal ideal domains, ... Category of sets with partial maps, Category of objects] Cela rete que tout anneau de polynmes est aussi un ensemble, un anneau euclidien, et ainsi de suite. Le systme peut ainsi transfrer automatiquement aux anneaux de polynmes les proprits gnrales des objets de ces direntes catgories.

7.2. ARITHMTIQUE EUCLIDIENNE sage: R.<t> = Integers(42)[]; (t^20-1) % (t^5+8*t+7) 22*t^4 + 14*t^3 + 14*t + 6

139

Lorsque le coecient dominant nest pas inversible, on peut encore dnir une pseudo-division euclidienne : soient A un anneau commutatif, p, d A[x], et a le coecient dominant de d. Alors il existe deux polynmes q, r A[x], avec deg r < deg d, et un entier k deg p deg d + 1 tels que ak p = qd + r. La pseudo-division euclidienne est donne par la mthode pseudo_divrem. Pour eectuer une division exacte, on utilise galement loprateur de quotient euclidien //. En eet, diviser par un polynme non constant avec / renvoie un rsultat de type fraction rationnelle (voir 7.4), ou choue lorsque cela na pas de sens : sage: ((t^2+t)//t).parent() Univariate Polynomial Ring in t over Ring of integers modulo 42 sage: (t^2+t)/t Traceback (most recent call last): ... TypeError: self must be an integral domain.
Exercice 24. Usuellement, en Sage, les polynmes de Q[x] sont reprsents sur la base monomiale (xn )nN . Les polynmes de Tchebyche Tn , dnis par Tn (cos ) = cos(n), constituent une famille de polynmes orthogonaux et donc une base de Q[x]. Les premiers polynmes de Tchebyche sont sage: x = polygen(QQ); [chebyshev_T(n, x) for n in (0..4)] [1, x, 2*x^2 - 1, 4*x^3 - 3*x, 8*x^4 - 8*x^2 + 1] crire une fonction qui prend en entre un lment de Q[x] et renvoie les coecients de sa dcomposition sur la base (Tn )nN . Exercice 25 (Division suivant les puissances croissantes). Soient n N et u, v A[x], avec v (0) inversible. Alors il existe un unique couple (q, r) de polynmes de A[x] avec deg q n tel que u = qv + xn+1 r. crire une fonction qui calcule q et r par un analogue de lalgorithme de division euclidienne. Comment faire ce mme calcul le plus simplement possible, laide de fonctions existantes ?

PGCD. Sage sait calculer le pgcd de polynmes sur un corps, grce la structure euclidienne de K [x], mais aussi sur certains autres anneaux, dont les entiers : sage: S.<x> = ZZ[]; p = 2*(x^10-1)*(x^8-1) sage: p.gcd(p.derivative()) 2*x^2 - 2 On peut prfrer lexpression plus symtrique gcd(p,q), qui donne le mme rsultat que p.gcd(q). Elle est cependant un peu moins naturelle en Sage car ce nest pas un mcanisme gnral : la routine appele par gcd(p,q) est une fonction de deux arguments dnie manuellement dans le code source de Sage

140

CHAP. 7. POLYNMES

et qui appelle son tour p.gcd. Seules quelques mthodes usuelles ont ainsi une fonction associe. Le pgcd tendu (en anglais extended gcd ), cest--dire le calcul dune relation de Bzout g = pgcd(p, q ) = ap + bq, g, p, q, a, b K [x] est fourni quant lui par p.xgcd(q) : sage: R.<x> = QQ[]; p = x^5-1; q = x^3-1 sage: print "le pgcd est %s = (%s)*p + (%s)*q" % p.xgcd(q) le pgcd est x - 1 = (-x)*p + (x^3 + 1)*q La mthode xgcd existe aussi pour les polynmes de ZZ[ x ], mais attention : lanneau Z[x] ntant pas principal, le rsultat nest pas en gnral une relation de Bzout !

7.2.2

Idaux et quotients

Idaux de A[x]. Les idaux des anneaux de polynmes, et les quotients par ces idaux, sont reprsents par des objets Sage construits partir de lanneau de polynmes par les mthodes ideal et quo. Le produit dun tuple de polynmes par un anneau de polynmes est interprt comme un idal : sage: R.<x> = QQ[] sage: J1 = (x^2 - 2*x + 1, 2*x^2 + x - 3)*R; J1 Principal ideal (x - 1) of Univariate Polynomial Ring in x over Rational Field On peut multiplier les idaux, et rduire un polynme modulo un idal : sage: J2 = R.ideal(x^5 + 2) sage: ((3*x+5)*J1*J2).reduce(x^10) 421/81*x^6 - 502/81*x^5 + 842/81*x - 680/81 Le polynme rduit demeure dans ce cas un lment de QQ[ x ]. Une autre possibilit consiste construire le quotient par un idal et y projeter des lments. Le parent du projet est alors lanneau quotient. La mthode lift des lments du quotient sert les relever dans lanneau de dpart. sage: B = R.quo((3*x+5)*J1*J2) # quo nomme automatiquement xbar sage: B(x^10) # le gnrateur de B image de x 421/81*xbar^6 - 502/81*xbar^5 + 842/81*xbar - 680/81 sage: B(x^10).lift() 421/81*x^6 - 502/81*x^5 + 842/81*x - 680/81 Si K est un corps, lanneau K [x] est principal : les idaux sont reprsents dans les calculs par un gnrateur, et tout ceci nest gure quun langage plus algbrique pour les oprations vues en 7.2.1. Son principal mrite est que les anneaux quotients peuvent aisment tre utiliss dans de nouvelles constructions, ici celle de F5 [t]/ t2 + 3 [x] : sage: R.<t> = GF(5)[]; R.quo(t^2+3)[ x ].random_element()

7.3. FACTORISATION ET RACINES

141

Construction didaux et danneaux quotients Q = R/J idal u, v, w rduction de p modulo J anneau quotient R/J , R/ p anneau quotient pour obtenir Q corps de nombres isomorphe R.ideal(u, v, w) ou (u, v, w)*R J.reduce(p) ou p.mod(J) R.quo(J), R.quo(p) Q.cover_ring() Q.number_field()

lments de K [x]/ p relev (section de R R/J ) polynme minimal polynme caractristique matrice trace u.lift() u.minpoly() u.charpoly() u.matrix() u.trace()

Tableau 7.4 Idaux et quotients.

(3*tbar + 1)*x^2 + (2*tbar + 3)*x + 3*tbar + 4 Sage permet aussi de construire des idaux danneaux non principaux comme Z[x], mais les oprations disponibles sont alors limites sauf dans le cas des polynmes plusieurs indtermines sur un corps, qui font lobjet du chapitre 9.
Exercice 26. On dnit la suite (un )nN par les conditions initiales un = n + 7 pour 0 n < 1000 et la relation de rcurrence linaire un+1000 = 23un+729 5un+2 + 12un+1 + 7un (n 0).

Calculer les cinq derniers chires de u1010000 . Indication : on pourra sinspirer de lalgorithme de 3.2.4. Mais celui-ci prend trop de temps quand lordre de la rcurrence est lev. Introduire un quotient danneau de polynmes judicieux an dviter ce problme.

Extensions algbriques. Un cas particulier important est le quotient de K [x] par un polynme irrductible pour raliser une extension algbrique de K . Les corps de nombres, extensions nies de Q, sont reprsents par des objets NumberField distincts des quotients de QQ[ x ]. Lorsque cela a un sens, la mthode number_field dun quotient danneau de polynmes renvoie le corps de nombres correspondant. Linterface des corps de nombres, plus riche que celle des anneaux quotients, dpasse le cadre de ce livre. Les corps nis composs Fpk , raliss comme extensions algbriques des corps nis premiers Fp , sont quant eux dcrits en 6.1.

7.3

Factorisation et racines

Un troisime niveau aprs les oprations lmentaires et larithmtique euclidienne concerne la dcomposition des polynmes en produit de facteurs irrductibles, ou factorisation. Cest peut-tre ici que le calcul formel est le plus utile !

142

CHAP. 7. POLYNMES

7.3.1

Factorisation

Test dirrductibilit. Sur le plan algbrique, la question la plus simple concernant la factorisation dun polynme est si celui-ci scrit comme produit de deux facteurs non triviaux, ou au contraire est irrductible. Naturellement, la rponse dpend de lanneau de base. La mthode is_irreducible indique si un polynme est irrductible dans son anneau parent. Par exemple, le polynme 3x2 6 est irrductible sur Q, mais pas sur Z (pourquoi ?) : sage: R.<x> = QQ[]; p = 3*x^2 - 6 sage: p.is_irreducible(), p.change_ring(ZZ).is_irreducible() (True, False) Factorisation. Dcomposer en facteurs premiers un entier de plusieurs centaines ou milliers de chires est un problme trs dicile. Factoriser un polynme de degr 1000 sur Q ou Fp ne demande en revanche que quelques secondes de temps processeur 3 : sage: p = QQ[ x ].random_element(degree=1000) sage: %timeit p.factor() 5 loops, best of 3: 32.2 s per loop Ici sarrte donc la similitude algorithmique entre polynmes et entiers que nous avons pu observer dans les sections prcdentes. Tout comme le test dirrductibilit, la factorisation a lieu sur lanneau de base du polynme. Par exemple, la factorisation dun polynme sur les entiers est constitue dune partie constante, elle-mme dcompose en facteurs premiers, et dun produit de polynmes primitifs, cest--dire dont les coecients sont premiers entre eux : sage: x = polygen(ZZ); p = 54*x^4+36*x^3-102*x^2-72*x-12 sage: p.factor() 2 * 3 * (3*x + 1)^2 * (x^2 - 2) Sage permet de factoriser sur des anneaux varis rationnels, complexes (approchs), corps nis et corps de nombres notamment : sage: for A in [QQ, ComplexField(16), GF(5), QQ[sqrt(2)]]: ....: print A, ":"; print A[ x ](p).factor() Rational Field : (54) * (x + 1/3)^2 * (x^2 - 2) Complex Field with 16 bits of precision : (54.00) * (x - 1.414) * (x + 0.3333)^2 * (x + 1.414) Finite Field of size 5 : (4) * (x + 2)^2 * (x^2 + 3) Number Field in sqrt2 with defining polynomial x^2 - 2 : (54) * (x - sqrt2) * (x + sqrt2) * (x + 1/3)^2
3. Dun point de vue thorique, on sait factoriser dans Q[x] en temps polynomial, et dans Fp [x] en temps polynomial probabiliste, alors que lon ignore sil est possible de factoriser les entiers en temps polynomial.

7.3. FACTORISATION ET RACINES

143

Factorisation test dirrductibilit factorisation factorisation sans carr partie sans carr p/ pgcd(p, p ) p.is_irreducible() p.factor() p.squarefree_decomposition() p.radical() Racines racines dans A, dans D racines relles racines complexes isolation des racines relles isolation des racines complexes rsultant discriminant groupe de Galois (p irrductible) p.roots(), p.roots(D) p.roots(RR), p.real_roots() p.roots(CC), p.complex_roots() p.roots(RIF), p.real_root_intervals() p.roots(CIF) p.resultant(q) p.discriminant() p.galois_group()

Tableau 7.5 Factorisation et racines.

Le rsultat dune dcomposition en facteurs irrductibles nest pas un polynme (puisque les polynmes sont toujours sous forme normale, cest--dire dvelopps !), mais un objet f de type Factorization. On peut rcuprer le i-me facteur avec f[i], et on retrouve le polynme par f.expand(). Les objets Factorization disposent aussi de mthodes comme gcd et lcm qui ont le mme sens que pour les polynmes mais oprent sur les formes factorises. Dcomposition sans carr. Malgr sa bonne complexit thorique et pratique, la factorisation complte dun polynme est une opration complexe. La dcomposition sans carr constitue une forme plus faible de factorisation, beaucoup plus facile obtenir quelques calculs de pgcd susent et qui apporte dj beaucoup dinformation. r i Soit p = i=1 pm K [x] un polynme dcompos en produit de facteurs i irrductibles sur un corps K de caractristique nulle. On dit que p est sans carr (en anglais squarefree ) si tous les facteurs pi sont de multiplicit mi = 1, cest--dire si les racines de p dans une clture algbrique de K sont simples. Une dcomposition sans carr est une factorisation en produit de facteurs sans carr deux deux premiers entre eux :
2 s p = f1 f2 . . . fs

fm =
mi =m

pi .

La dcomposition sans carr spare donc les facteurs irrductibles de p par multiplicit. La partie sans carr f1 . . . fs = p1 . . . pr de p est le polynme racines simples qui a les mmes racines que p aux multiplicits prs.

7.3.2

Recherche de racines

Le calcul des racines dun polynme admet de nombreuses variantes, suivant que lon cherche des racines relles, complexes, ou dans un autre domaine, exactes

144

CHAP. 7. POLYNMES

ou approches, avec ou sans multiplicits, de faon garantie ou heuristique... La mthode roots dun polynme renvoie par dfaut les racines du polynme dans son anneau de base, sous la forme dune liste de couples (racine, multiplicit) : sage: R.<x> = ZZ[]; p = (2*x^2-5*x+2)^2 * (x^4-7); p.roots() [(2, 2)] Avec un paramtre, roots(D) renvoie les racines dans le domaine D, ici les racines rationnelles, puis des approximations des racines -adiques pour = 19 : sage: p.roots(QQ) [(2, 2), (1/2, 2)] sage: p.roots(Zp(19, print_max_terms=3)) [(2 + 6*19^10 + 9*19^11 + ... + O(19^20), 1), (7 + 16*19 + 17*19^2 + ... + O(19^20), 1), (10 + 9*19 + 9*19^2 + ... + O(19^20), 1), (10 + 9*19 + 9*19^2 + ... + O(19^20), 1), (12 + 2*19 + 19^2 + ... + O(19^20), 1), (2 + 13*19^10 + 9*19^11 + ... + O(19^20), 1)] Cela fonctionne pour une grande varit de domaines, avec une ecacit variable. En particulier, choisir pour D le corps des nombres algbriques QQbar ou celui des algbriques rels AA permet de calculer de faon exacte les racines complexes ou relles dun polynme coecients rationnels : sage: racines = p.roots(AA); racines [(-1.626576561697786?, 1), (0.500000000000000?, 2), (1.626576561697786?, 1), (2.000000000000000?, 2)] Sage jongle de faon transparente pour lutilisateur entre diverses reprsentations des nombres algbriques. Lune consiste par exemple coder chaque Q via son polynme minimal coupl un encadrement susamment prcis pour distinguer des autres racines. Ainsi, malgr leur achage, les racines renvoyes ne sont pas de simples valeurs approches. Elles peuvent tre rutilises dans des calculs exacts : sage: a = racines[0][0]^4; a.simplify(); a 7 Ici, on a lev la premire des racines trouves la puissance quatrime, puis forc Sage simplier susamment le rsultat pour rendre manifeste quil sagit de lentier 7. Une variante de la rsolution exacte consiste simplement isoler les racines, cest--dire calculer des intervalles contenant chacun exactement une racine, en passant comme domaine D celui des intervalles rels RIF ou complexes CIF. Parmi les autres domaines utiles dans le cas dun polynme coecients rationnels, citons RR, CC, RDF, CDF, qui correspondent tous des racines approches, cherches numriquement, ainsi que les corps de nombres QQ[alpha]. Les mthodes spciques real_roots, complex_roots et (pour certains anneaux de base) real_root_intervals orent des options supplmentaires ou donnent des rsultats lgrement dirents des appels correspondant roots. La recherche et lisolation de racines numriques sont traites plus en dtail en 12.2.

7.3. FACTORISATION ET RACINES

145

7.3.3

Rsultant

Sur tout anneau factoriel, lexistence dun facteur commun non constant deux polynmes se caractrise par lannulation de leur rsultant Res(p, q ), qui est un polynme en leurs coecients. Un intrt majeur du rsultant par rapport au pgcd est quil se spcialise bien par morphismes danneaux. Par exemple, les polynmes x 12 et x 20 sont premiers entre eux dans Z[x], mais lannulation de leur rsultant sage: x = polygen(ZZ); (x-12).resultant(x-20) -8 modulo n montre quils ont une racine commune dans Z/nZ si et seulement n divise 8. m n Soient p = i=0 pi xi et q = i=0 qi xi deux polynmes non constants de A[x], avec pm , qn = 0. Le rsultant de p et q est dni par pm .. . .. . pm Res(p, q ) = qn q0 .. . qn p0 .. . ..

. p0 . . .. (7.1)

q0

Cest le dterminant, dans des bases convenables, de lapplication linaire An1 [x] Am1 [x] Am+n1 [x] u, v up + vq o Ak [x] A[x] dsigne le sous-module des polynmes de degr au plus k . Si p et q sont scinds, leur rsultant scrit aussi en fonction des dirences de leurs racines :
m Res(p, q ) = pn m qn i,j

(i j ),

p = pm (x 1 ) . . . (x m ) q = qn (x 1 ) . . . (x n ).

La proprit de spcialisation mentionne plus haut se dduit de la dnition (7.1) : si : A A est un morphisme danneaux dont lapplication p et q ne fait pas chuter leurs degrs, autrement dit tel que (pm ) = 0 et (qn ) = 0, alors on a Res((p), (q )) = (Res(p, q )). Ainsi, (Res(p, q )) sannule lorsque (p) et (q ) ont un facteur commun. Nous avons vu un exemple de ce phnomne un peu plus haut, avec pour la projection canonique de Z dans Z/nZ.

146

CHAP. 7. POLYNMES

Mais lutilisation la plus commune du rsultant concerne le cas o lanneau de base est lui-mme un anneau de polynmes : p, q A[x] avec A = K [a1 , . . . , ak ]. En particulier, soient 1 , . . . , k K , et considrons la spcialisation : B [a1 , . . . , ak ] K q (a1 , . . . , ak ) q (1 , . . . , k ). On voit alors que le rsultant Res(p, q ) sannule en (1 , . . . , k ) si et seulement si les spcialisations (p), (q ) K [x] ont un facteur commun, sous rserve que lun des termes dominants de p et q soit dirent de zro en (1 , . . . , k ). Par exemple, le discriminant de p est dni par disc(p) = (1)d(d1)/2 Res(p, p )/pm . Cette dnition gnralise les discriminants classiques des polynmes de degr deux ou trois : sage: R.<a,b,c,d> = QQ[]; x = polygen(R); p = a*x^2+b*x+c sage: p.resultant(p.derivative()) -a*b^2 + 4*a^2*c sage: p.discriminant() b^2 - 4*a*c sage: (a*x^3 + b*x^2 + c*x + d).discriminant() b^2*c^2 - 4*a*c^3 - 4*b^3*d + 18*a*b*c*d - 27*a^2*d^2 Comme le discriminant de p est, une normalisation prs, le rsultant de p et de sa drive, il sannule si et seulement si p a une racine multiple.

7.3.4

Groupe de Galois

Le groupe de Galois dun polynme irrductible p Q[x] est un objet algbrique qui dcrit certaines symtries des racines de p. Il sagit dun objet central de la thorie des quations algbriques. Notamment, lquation p(x) = 0 est rsoluble par radicaux, cest--dire que ses solutions sexpriment partir des coecients de p au moyen des quatre oprations et de lextraction de racine n-ime, si et seulement si le groupe de Galois de p est rsoluble. Sage permet de calculer les groupes de Galois des polynmes coecients rationnels de degr modr, et deectuer toutes sortes doprations sur les groupes obtenus. Tant la thorie de Galois que les fonctionnalits de thorie des groupes de Sage dpassent le cadre de ce livre. Bornons-nous appliquer sans plus dexplications le thorme de Galois sur la rsolubilit par radicaux. Le calcul suivant 4 montre que les racines de x5 x 1 ne sexpriment pas par radicaux : sage: x = polygen(QQ); G = (x^5 - x - 1).galois_group(); G Transitive group number 5 of degree 5
4. Ce calcul ncessite une table de groupes nis qui ne fait pas partie de linstallation de base de Sage, mais que lon peut tlcharger et installer automatiquement par la commande install_package("database_gap") (il peut tre ncessaire de redmarrer Sage aprs linstallation).

7.4. FRACTIONS RATIONNELLES sage: G.is_solvable() False

147

Il sagit dun des exemples les plus simples dans ce cas, puisque les polynmes de degr infrieur ou gal 4 sont toujours rsolubles par radicaux, de mme videmment que ceux de la forme x5 a. En examinant les gnrateurs de G vu comme un groupe de permutations, on reconnat que G S5 , ce que lon vrie facilement : sage: G.gens() [(1,2,3,4,5), (1,2)] sage: G.is_isomorphic(SymmetricGroup(5)) True

7.4
7.4.1

Fractions rationnelles
Construction et proprits lmentaires

La division de deux polynmes (sur un anneau intgre) produit une fraction rationnelle. Son parent est le corps des fractions de lanneau de polynmes, qui peut sobtenir par Frac(R) : sage: x = polygen(RR); r = (1 + x)/(1 - x^2); r.parent() Fraction Field of Univariate Polynomial Ring in x over Real Field with 53 bits of precision sage: r (x + 1.00000000000000)/(-x^2 + 1.00000000000000) On observe que la simplication nest pas automatique. Cest parce que RR est un anneau inexact, cest--dire dont les lments sinterprtent comme des approximations dobjets mathmatiques. La mthode reduce met la fraction sous forme rduite. Elle ne renvoie pas de nouvel objet, mais modie la fraction rationnelle existante : sage: r.reduce(); r 1.00000000000000/(-x + 1.00000000000000) Sur un anneau exact, en revanche, les fractions rationnelles sont automatiquement rduites. Les oprations sur les fractions rationnelles sont analogues celles sur les polynmes. Celles qui ont un sens dans les deux cas (substitution, drive, factorisation...) sutilisent de la mme faon. Le tableau 7.6 numre quelques autres mthodes utiles. La dcomposition en lments simples et surtout la reconstruction rationnelle mritent quelques explications.

7.4.2

Dcomposition en lments simples

Sage calcule la dcomposition en lments simples dune fraction rationnelle a/b de Frac(K[ x ]) partir de la factorisation de b dans K[ x ]. Il sagit donc

148

CHAP. 7. POLYNMES

Fractions rationnelles corps des fractions K (x) numrateur dnominateur simplication (modie r) dcomposition en lments simples reconstruction rationnelle de s mod m Frac(K[ x ]) r.numerator() r.denominator() r.reduce() r.partial_fraction_decomposition() s.rational_reconstruct(m)

Sries tronques anneau A[[t]] anneau A((t)) coecient [xk ] f (x) troncature prcision drive, primitive (nulle en 0) oprations usuelles f , exp f , ... rciproque (f g = g f = x) solution de y = ay + b PowerSeriesRing(A, x , default_prec=n) LaurentSeriesRing(A, x , default_prec=n) f[k] x + O(x^n) f.prec() f.derivative(), f.integral() f.sqrt(), f.exp(), ... g = f.reversion() a.solve_linear_de(precision, b)

Tableau 7.6 Objets construits partir des polynmes.

de la dcomposition en lments simples sur K . Le rsultat est form dune partie polynomiale p et dune liste de fractions rationnelles dont les dnominateurs sont des puissances de facteurs irrductibles de b : sage: R.<x> = QQ[]; r = x^10 / ((x^2-1)^2 * (x^2+3)) sage: poly, parts = r.partial_fraction_decomposition() sage: poly x^4 - x^2 + 6 sage: for part in parts: part.factor() (17/32) * (x - 1)^-2 * (x - 15/17) (-17/32) * (x + 1)^-2 * (x + 15/17) (-243/16) * (x^2 + 3)^-1 On a ainsi obtenu la dcomposition en lments simples sur les rationnels r= (x2
17 x 15 17 x 15 243 x10 32 32 = x4 x2 + 6 + 32 + 32 + 2 16 . 2 2 2 2 1) (x + 3) (x 1) (x + 1) x +3

Il nest pas dicile de voir que cest aussi la dcomposition de r sur les rels. Sur les complexes en revanche, le dnominateur du dernier terme nest pas irrductible, et donc la fraction rationnelle peut encore se dcomposer. On peut calculer la dcomposition en lments simples sur les rels ou les complexes numriquement : sage: C = ComplexField(15) sage: Frac(C[ x ])(r).partial_fraction_decomposition() (x^4 - x^2 + 6.000, [(0.5312*x - 0.4688)/(x^2 - 2.000*x + 1.000), 4.384*I/(x - 1.732*I), (-4.384*I)/(x + 1.732*I), (-0.5312*x - 0.4688)/(x^2 + 2.000*x + 1.000)])

7.4. FRACTIONS RATIONNELLES

149

La dcomposition exacte sur C sobtient de la mme faon, en remplaant C par QQbar. En faisant le calcul sur AA, on aurait la dcomposition sur les rels mme quand toutes les racines relles du dnominateur ne sont pas rationnelles.

7.4.3

Reconstruction rationnelle

Un analogue de la reconstruction rationnelle prsente en 6.1.3 existe pour les polynmes coecients dans A = Z/nZ. tant donns m, s A[x], la commande sage: s.rational_reconstruct(m, dp, dq) calcule lorsque cest possible des polynmes p, q A[x] tels que qs p mod m, deg p dp , deg q dq . Restreignons-nous pour simplier au cas o n est premier. Une telle relation avec q et m premiers entre eux entrane p/q = s dans A[x]/ m , do le nom de reconstruction rationnelle. Le problme de reconstruction rationnelle se traduit par un systme linaire sur les coecients de p et q , et un simple argument de dimension montre quil admet une solution non triviale ds que dp + dq deg m 1. Il ny a pas toujours de solution avec q et m premiers entre eux (par exemple, les solutions de p qx mod x2 avec deg p 0, deg q 1 sont les multiples constants de (p, q ) = (0, x)), mais rational_reconstruct cherche en priorit les solutions q premires avec m. Approximants de Pad. Le cas m = xn est appel approximation de Pad. Un approximant de Pad de type (k, n k ) dune srie formelle f K [[x]] est une fraction rationnelle p/q K (x) telle que deg p k 1, deg q n k , q (0) = 1, et p/q = f + O(xn ). On a alors p/q f mod xn . Commenons par un exemple purement formel. Les commandes suivantes calculent un approximant de Pad de la srie f = i=0 (i + 1)2 xi coecients dans Z/101Z : sage: A = Integers(101); R.<x> = A[] sage: f6 = sum( (i+1)^2 * x^i for i in (0..5) ); f6 36*x^5 + 25*x^4 + 16*x^3 + 9*x^2 + 4*x + 1 sage: num, den = f6.rational_reconstruct(x^6, 1, 3); num/den (100*x + 100)/(x^3 + 98*x^2 + 3*x + 100) En dveloppant nouveau en srie la fraction rationnelle trouve, on observe que non seulement les dveloppements concident jusqu lordre 6, mais le terme suivant aussi est juste ! sage: S = PowerSeriesRing(A, x , 7); S(num)/S(den) 1 + 4*x + 9*x^2 + 16*x^3 + 25*x^4 + 36*x^5 + 49*x^6 + O(x^7) En eet, f est elle-mme une fraction rationnelle : on a f = (1 + x)/(1 x)3 . Le dveloppement tronqu f6, accompagn de bornes sur les degrs du numrateur et du dnominateur, sut la reprsenter sans ambigut. De ce point de vue, le calcul dapproximants de Pad est linverse du dveloppement en srie des fractions rationnelles : il permet de repasser de cette reprsentation alternative la reprsentation habituelle comme quotient de deux polynmes.

150

CHAP. 7. POLYNMES

3 2 1 -6 -4 -2 -1 -2 -3 2 4 6
type (4, 2) type (8, 4) type (12, 6)

Figure 7.1 La fonction tangente et quelques approximants de Pad sur [2, 2 ].

Un exemple analytique. Historiquement, les approximants de Pad ne sont pas ns de ce genre de considrations formelles, mais de la thorie de lapproximation des fonctions analytiques. En eet, les approximants de Pad du dveloppement en srie dune fonction analytique approchent souvent mieux la fonction que les troncatures de la srie. Quand le degr du dnominateur est assez grand, ils peuvent mme fournir de bonnes approximations mme en-dehors du disque de convergence de la srie. On dit parfois quils avalent les ples . La gure 7.1, qui montre la convergence des approximants de type (2k, k ) de la fonction tangente au voisinage de 0, illustre ce phnomne. Bien que rational_reconstruct soit limit aux polynmes sur Z/nZ, il est possible de sen servir pour calculer des approximants de Pad coecients rationnels, et aboutir cette gure. Le plus simple est de commencer par eectuer la reconstruction rationnelle modulo un nombre premier assez grand : sage: x = var( x ); s = tan(x).taylor(x, 0, 20) sage: p = previous_prime(2^30); ZpZx = Integers(p)[ x ] sage: Qx = QQ[ x ] sage: num, den = ZpZx(s).rational_reconstruct(ZpZx(x)^10,4,5) sage: num/den (1073741779*x^3 + 105*x)/(x^4 + 1073741744*x^2 + 105) puis de relever la solution trouve. La fonction suivante relve un lment a de Z/pZ en un entier de valeur absolue au plus p/2. sage: def lift_sym(a): ....: m = a.parent().defining_ideal().gen() ....: n = a.lift() ....: if n <= m // 2: return n ....: else: return n - m On obtient : sage: Qx(map(lift_sym, num))/Qx(map(lift_sym, den))

7.5. SRIES FORMELLES (-10*x^3 + 105*x)/(x^4 - 45*x^2 + 105)

151

Lorsque les coecients cherchs sont trop grands pour cette technique, on peut faire le calcul modulo plusieurs premiers, et appliquer le thorme chinois an de retrouver une solution coecients entiers, comme expliqu en 6.1.4. Une autre possibilit est de calculer une relation de rcurrence coecients constants satisfaite par les coecients de la srie. Ce calcul est presque quivalent celui dun approximant de Pad (voir exercice 27), mais la fonction berlekamp_massey de Sage permet de le faire sur un corps quelconque. Systmatisons un peu le calcul prcdent, en crivant une fonction qui calcule directement lapproximant coecients rationnels, sous des hypothses susamment favorables : sage: def mypade(pol, n, k): ....: x = ZpZx.gen(); ....: n,d = ZpZx(pol).rational_reconstruct(x^n, k-1, n-k) ....: return Qx(map(lift_sym, n))/Qx(map(lift_sym, d)) Il ny a plus alors qu appeler plot sur les rsultats de cette fonction (convertis en lments de SR, car plot ne permet pas de tracer directement le graphe dune fraction rationnelle algbrique ) pour obtenir le graphique de la gure 7.1 : sage: add( ....: plot(expr, -2*pi, 2*pi, ymin=-3, ymax=3, ....: linestyle=sty, detect_poles=True, aspect_ratio=1) ....: for (expr, sty) in [ ....: (tan(x), - ), ....: (SR(mypade(s, 4, 2)), : ), ....: (SR(mypade(s, 8, 4)), -. ), ....: (SR(mypade(s, 12, 6)), -- ) ]) Les exercices suivants prsentent deux autres applications classiques de la reconstruction rationnelle.
Exercice 27. 1. Montrer que si (un )nN satisfait une rcurrence linaire coecients constants, la srie formelle u z n est une fraction rationnelle. nN n Comment sinterprtent le numrateur et le dnominateur ? 2. Deviner les termes suivants de la suite 1, 1, 2, 3, 8, 11, 34, 39, 148, 127, 662, 339, 3056, 371, 14602, 4257, . . . , en utilisant rational_reconstruct. Retrouver le rsultat laide de la fonction berlekamp_massey. Exercice 28 (Interpolation de Cauchy). Trouver une fraction rationnelle r = p/q F17 (x) telle que r(0) = 1, r(1) = 0, r(2) = 7, r(3) = 5, avec p de degr minimal.

7.5

Sries formelles

Une srie formelle est une srie entire vue comme une simple suite de coecients, sans considration de convergence. Plus prcisment, si A est un anneau

152

CHAP. 7. POLYNMES

commutatif, on appelle sries formelles (en anglais formal power series ) dind termine x coecients dans A les sommes formelles n=0 an xn o (an ) est une suite quelconque dlments de A. Munies des oprations daddition et de multiplication naturelles

an xn +
n=0 n=0

bn x n =
n=0

(an + bn )xn , ai bj xn ,
n=0 i+j =n

an xn
n=0 n=0

bn xn =

les sries formelles forment un anneau not A[[x]]. Dans un systme de calcul formel, ces sries sont utiles pour reprsenter des fonctions analytiques dont on na pas dcriture exacte. Comme toujours, lordinateur fait les calculs, mais cest lutilisateur de leur donner un sens mathmatique. lui par exemple de sassurer que les sries quil manipule sont convergentes. Les sries formelles interviennent aussi abondamment en combinatoire, en tant que sries gnratrices. Nous verrons un exemple de ce type en 15.1.2.

7.5.1

Oprations sur les sries tronques

Lanneau de sries formelles Q[[x]] sobtient par sage: R.<x> = PowerSeriesRing(QQ) ou en abrg R.<x> = QQ[[]] 5 . Les lments de A[[ x ]] sont des sries tronques, cest--dire des objets de la forme f = f0 + f1 x + + fn1 xn1 + O(xn ). Ils jouent le rle dapproximations des sries mathmatiques innies, tout comme les lments de RR reprsentent des approximations de rels. Lanneau A[[ x ]] est donc un anneau inexact. Chaque srie possde son propre ordre de troncature 6 , et la prcision est suivie automatiquement au cours des calculs : sage: R.<x> = QQ[[]] sage: f = 1 + x + O(x^2); g = x + 2*x^2 + O(x^4) sage: f + g 1 + 2*x + O(x^2) sage: f * g x + 3*x^2 + O(x^3) Il existe des sries de prcision innie, qui correspondent exactement aux polynmes :
5. Ou partir de Q[x], par QQ[ x ].completion( x ). 6. Dun certain point de vue, cest la principale dirence entre un polynme modulo xn et une srie tronque lordre n : les oprations sur ces deux sortes dobjets sont analogues, mais les lments de A[[x]]/ xn ont, eux, tous la mme prcision .

7.5. SRIES FORMELLES sage: (1 + x^3).prec() +Infinity

153

Une prcision par dfaut est utilise quand il est ncessaire de tronquer un rsultat exact. Elle se rgle la cration de lanneau, ou ensuite par la mthode set_default_prec : sage: R.<x> = PowerSeriesRing(Reals(24), default_prec=4) sage: 1/(1 + RR.pi() * x)^2 1.00000 - 6.28319*x + 29.6088*x^2 - 124.025*x^3 + O(x^4) Tout cela entrane quil nest pas possible de tester lgalit mathmatique de deux sries. Cest une dirence conceptuelle importante entre celles-ci et les autres classes dobjets vues dans ce chapitre. Sage considre donc deux lments de A[[ x ]] comme gaux ds quils concident jusqu la plus faible de leurs prcisions : sage: R.<x> = QQ[[]] sage: 1 + x + O(x^2) == 1 + x + x^2 + O(x^3) True Attention : cela implique par exemple que le test O(x^2) == 0 renvoie vrai, puisque la srie nulle a une prcision innie. Les oprations arithmtiques de base sur les sries fonctionnent comme sur les polynmes. On dispose aussi de quelques fonctions usuelles, par exemple f.exp() lorsque f (0) = 0, ainsi que des oprations de drivation et dintgration. Ainsi, un dveloppement asymptotique quand x 0 de 1 exp x2 est donn par sage: (1/(1+x)).sqrt().integral().exp() / x^2 + O(x^4) x^-2 + x^-1 + 1/4 + 1/24*x - 1/192*x^2 + 11/1920*x^3 + O(x^4) Ici, mme si seuls quatre termes apparaissent dans le rsultat, chaque opration est eectue la prcision par dfaut 20, qui sut largement pour obtenir un reste nal en O(x4 ). Pour obtenir plus de vingt termes, il faudrait augmenter la prcision des calculs intermdiaires. Cet exemple montre aussi que si f, g K[[x]] et g (0) = 0, le quotient f /g renvoie un objet srie de Laurent formelle. Contrairement aux sries de Laurent de lanalyse complexe, de la forme n= an xn , les sries de Laurent formelles n sont des sommes du type n=N an x , avec un nombre ni de termes dexposant ngatif. Cette restriction est ncessaire pour donner un sens au produit de deux sries formelles : sans celle-ci, chaque coecient du produit sexprime comme une somme de srie innie.
x 0

1 dt 1+t

154

CHAP. 7. POLYNMES

7.5.2

Dveloppement de solutions dquations

Face une quation direntielle dont les solutions exactes sont trop compliques calculer ou exploiter une fois calcules, ou tout simplement qui nadmet pas de solution en forme close, un recours frquent consiste chercher des solutions sous forme de sries. On commence habituellement par dterminer les solutions de lquation dans lespace des sries formelles, et si ncessaire, on conclut ensuite par un argument de convergence que les solutions formelles construites ont un sens analytique. Sage peut tre dune aide prcieuse pour la premire tape. Considrons par exemple lquation direntielle y (x) = 1 + x2 y (x) + exp(x), y (0) = 1.

Cette quation admet une unique solution en srie formelle, dont on peut calculer les premiers termes par sage: (1+x^2).sqrt().solve_linear_de(prec=6, b=x.exp()) 1 + 2*x + 3/2*x^2 + 5/6*x^3 + 1/2*x^4 + 7/30*x^5 + O(x^6) De plus, le thorme de Cauchy dexistence de solutions dquations direntielles linaires coecients analytiques assure que cette srie converge pour |x| < 1 : sa somme fournit donc une solution analytique sur le disque unit complexe. Cette approche nest pas limite aux quations direntielles. Lquation fonctionnelle exf (x) = f (x) est plus complique, ne serait-ce que parce quelle nest pas linaire. Mais cest une quation de point xe, nous pouvons essayer de raner une solution (formelle) par itration : sage: sage: sage: ....: ....: 1 + x 1 + x 1 + x 1 + x 1 + x S.<x> = PowerSeriesRing(QQ, default_prec=5) f = S(1) for i in range(5): f = (x*f).exp() print f + 1/2*x^2 + 1/6*x^3 + 1/24*x^4 + O(x^5) + 3/2*x^2 + 5/3*x^3 + 41/24*x^4 + O(x^5) + 3/2*x^2 + 8/3*x^3 + 101/24*x^4 + O(x^5) + 3/2*x^2 + 8/3*x^3 + 125/24*x^4 + O(x^5) + 3/2*x^2 + 8/3*x^3 + 125/24*x^4 + O(x^5)

Que se passe-t-il ici ? Les solutions de exf (x) = f (x) dans Q[[x]] sont les points xes de la transformation : f exf . Si une suite ditrs de la forme n (a) converge, sa limite est ncessairement solution de lquation. Inversement, posons f (x) = n=0 fn xn , et dveloppons en srie les deux membres : il vient

fn xn =
n=0 k=0

1 x fj xj k! j =0

=
n=0 k=0

1 k!

fj1 fj2 . . . fjk

xn .

(7.2)

j1 ,...,jk N j1 ++jk =nk

7.5. SRIES FORMELLES

155

Peu importent les dtails de la formule ; lessentiel est que fn se calcule en fonction des coecients prcdents f0 , . . . , fn1 , comme on le voit en identiant les coecients des deux membres. Chaque itration de fournit donc un nouveau terme correct.
Exercice 29. Calculer le dveloppement limit lordre 15 de tan x au voisinage de zro partir de lquation direntielle tan = 1 + tan2 .

7.5.3

Sries paresseuses

Le phnomne de point xe motive lintroduction dune autre sorte de sries formelles appeles sries paresseuses (en anglais lazy ). Ce ne sont pas des sries tronques, mais bien des sries innies ; ladjectif paresseux signie que les coecients ne sont calculs que quand ils sont explicitement demands. En contrepartie, on ne peut reprsenter que des sries dont on sait calculer les coecients : essentiellement, des combinaisons de sries de base et certaines solutions dquations pour lesquelles existent des relations comme (7.2). Par exemple, la srie paresseuse lazy_exp dnie par sage: L.<x> = LazyPowerSeriesRing(QQ) sage: lazy_exp = x.exponential(); lazy_exp O(1) est un objet qui contient dans sa reprsentation interne toutes les informations ncessaires pour calculer le dveloppement en srie de exp x nimporte quel ordre. Elle sache initialement comme O(1) car aucun coecient na encore t calcul. Tenter daccder au coecient de x5 dclenche le calcul, et les coecients calculs sont alors mmoriss : sage: lazy_exp[5] 1/120 sage: lazy_exp 1 + x + 1/2*x^2 + 1/6*x^3 + 1/24*x^4 + 1/120*x^5 + O(x^6) Reprenons lexemple de lquation exf (x) = f (x) pour voir comment il se traite avec des sries paresseuses. Nous pouvons dabord essayer de reproduire le calcul fait plus haut dans lanneau QQ[[ x ]] : sage: sage: ....: ....: ....: 1 + x 1 + x 1 + x 1 + x 1 + x f = L(1) # la srie paresseuse constante 1 for i in range(5): f = (x*f).exponential() f.compute_coefficients(5) # force le calcul des print f # premiers coefficients + 1/2*x^2 + 1/6*x^3 + 1/24*x^4 + 1/120*x^5 + O(x^6) + 3/2*x^2 + 5/3*x^3 + 41/24*x^4 + 49/30*x^5 + O(x^6) + 3/2*x^2 + 8/3*x^3 + 101/24*x^4 + 63/10*x^5 + O(x^6) + 3/2*x^2 + 8/3*x^3 + 125/24*x^4 + 49/5*x^5 + O(x^6) + 3/2*x^2 + 8/3*x^3 + 125/24*x^4 + 54/5*x^5 + O(x^6)

156

CHAP. 7. POLYNMES

Les dveloppements obtenus sont bien sr les mmes que prcdemment 7 . Mais la valeur de f chaque itration est maintenant une srie innie, dont on peut calculer des coecients la demande. Toutes ces sries intermdiaires sont conserves en mmoire. Le calcul de chacune dentre elles est automatiquement pouss la prcision requise de manire fournir, par exemple, le coecient de x7 dans le dernier itr lorsque lon tente dy accder : sage: f[7] 28673/630 Avec le code de la 7.5.2, laccs f[7] aurait provoqu une erreur, lindice 7 tant suprieur lordre de troncature de la srie f. Cependant, la valeur renvoye par f[7] nest que le coecient de x7 dans litr 5 (1), et non dans la solution. La force des sries paresseuses est la possibilit de passer directement la limite, en codant f elle-mme comme une srie paresseuse : sage: from sage.combinat.species.series import LazyPowerSeries sage: f = LazyPowerSeries(L, name= f ) sage: f.define((x*f).exponential()) sage: f.coefficients(8) [1, 1, 3/2, 8/3, 125/24, 54/5, 16807/720, 16384/315] Ce qui faisait marcher le calcul itratif est la relation (7.2). En coulisses, Sage dduit de la dnition rcursive f.define((x*f).exponential()) une formule du mme genre, qui permet de calculer les coecients par rcurrence.

7.6

Reprsentation informatique des polynmes

Un mme objet mathmatique le polynme p, coecients dans A peut se coder sur ordinateur de faons trs direntes. Si le rsultat mathmatique dune opration sur p est bien sr indpendant de la reprsentation, il en va autrement du comportement des objets Sage correspondants. Le choix de la reprsentation inue sur les oprations possibles, la forme exacte de leurs rsultats, et particulirement lecacit des calculs. Reprsentation dense et reprsentation creuse. Il existe deux faons principales de reprsenter les polynmes. En reprsentation dense, les coecients de n p = i=0 pi xi sont stocks dans un tableau [p0 , . . . , pn ] index par les exposants. Une reprsentation creuse ne stocke que les coecients non nuls : le polynme est cod par un ensemble de paires exposant-coecient (i, pi ), regroupes dans une liste, ou mieux, dans un dictionnaire index par les exposants (voir 3.3.9). Pour des polynmes qui sont eectivement denses, cest--dire dont la plupart des coecients sont non nuls, la reprsentation dense occupe moins de mmoire et
7. On constate cependant que Sage emploie parfois des conventions incohrentes : la mthode qui sappelait exp pour les sries tronques sappelle ici exponential, et compute_ coefficients(5) calcule les coecients jusqu lordre 5 inclus tandis que default_prec=5 donnait des sries tronques aprs le coecient de x4 .

7.6. REPRSENTATION INFORMATIQUE DES POLYNMES

157

permet des calculs plus rapides. Elle conomise le stockage des exposants et des structures de donnes internes du dictionnaire : ne reste que le strict ncessaire, les coecients. De plus, laccs un lment ou litration sur les lments sont plus rapides dans un tableau que dans un dictionnaire. Inversement, la reprsentation creuse permet de calculer ecacement sur des polynmes qui ne tiendraient mme pas en mmoire en reprsentation dense : sage: R = PolynomialRing(ZZ, x , sparse=True) sage: p = R.cyclotomic_polynomial(2^50); p, p.derivative() (x^562949953421312 + 1, 562949953421312*x^562949953421311) Comme lillustre lexemple prcdent, la reprsentation est une caractristique de lanneau de polynmes, que lon choisit sa construction. Le polynme dense x Q[x] et le polynme creux x Q[x] nont donc pas le mme 8 parent. La reprsentation par dfaut des polynmes une indtermine est dense. Loption sparse=True de PolynomialRing sert construire un anneau de polynmes creux. Certains dtails de reprsentation varient de plus suivant la nature des coecients des polynmes. Il en va de mme du code utilis pour eectuer les oprations fondamentales. Sage ore en eet, outre une implmentation gnrique des polynmes qui fonctionne sur tout anneau commutatif, plusieurs variantes optimises pour un type particulier de coecients. Celles-ci apportent quelques fonctionnalits supplmentaires, et surtout sont considrablement plus ecaces que la version gnrique. Elles sappuient pour cela sur des bibliothques externes spcialises, par exemple flint ou ntl dans le cas de Z[x]. Pour mener bien de trs gros calculs, il est crucial de travailler autant que possible dans des anneaux de polynmes disposant dimplmentations ecaces. La page daide ache par p? pour un polynme p indique quelle implmentation il utilise. Le choix de limplmentation dcoule le plus souvent de ceux de lanneau de base et de la reprsentation. Loption implementation de PolynomialRing permet de prciser une implmentation quand plusieurs choix sont possibles. Expressions symboliques. Les expressions symboliques dcrites dans les chapitres 1 et 2 (cest--dire les lments de SR) fournissent une troisime reprsentation des polynmes. Elles constituent un choix naturel quand un calcul mle polynmes et expressions plus complexes, comme cest souvent le cas en analyse. Mais la souplesse de reprsentation quelles orent est parfois utile mme dans un 10 contexte plus algbrique. Par exemple, le polynme (x + 1)10 , une fois dvelopp, est dense, mais il nest pas ncessaire (ni souhaitable !) de le dvelopper pour le driver ou lvaluer numriquement. Attention cependant : contrairement aux polynmes algbriques, les polynmes symboliques (de SR) ne sont pas rattachs un anneau de coecients particulier et ne sont pas manipuls sous forme canonique. Un mme polynme a un grand nombre dcritures direntes, entre lesquelles cest lutilisateur dexpliciter
8. Pourtant, QQ[ x ] == PolynomialRing(QQ, x , sparse=True) renvoie vrai : les deux parents sont gaux, car ils reprsentent le mme objet mathmatique. Naturellement, le test correspondant avec is renvoie faux.

158 Un peu de thorie

CHAP. 7. POLYNMES

Pour tirer le meilleur parti des oprations rapides sur les polynmes, il est bon davoir une ide de leur complexit algorithmique. En voici un bref aperu lintention du lecteur connaissant un peu dalgorithmique. Nous nous limitons au cas des polynmes denses. Additions, soustractions et autres manipulations directes des coecients se font facilement en temps linaire en les degrs des polynmes en jeu. Leur rapidit en pratique dpend donc essentiellement de la possibilit daccder rapidement aux coecients, et donc de la structure de donnes. Lopration cruciale est la multiplication. En eet, non seulement cest une opration arithmtique de base, mais aussi dautres oprations utilisent des algorithmes dont la complexit dpend essentiellement de celle de la multiplication. Par exemple, on peut calculer la division euclidienne de deux polynmes de degr au plus n pour le cot de O(1) multiplications, ou encore leur pgcd pour celui de O(log n) multiplications. Bonne nouvelle : on sait multiplier les polynmes en temps presque linaire. Prcisment, la meilleure complexit connue sur un anneau quelconque est de O(n log n log log n) oprations dans lanneau de base. Elle repose sur des gnralisations du clbre algorithme de Schnhage-Strassen, qui atteint la mme complexit pour la multiplication dentiers. En comparaison, la mthode que lon utilise la main pour multiplier les polynmes demande un nombre doprations de lordre de n2 . Les algorithmes de multiplication rapide sont comptitifs en pratique pour les polynmes de degr susamment grand, de mme que les mthodes qui en drivent pour la division. Les bibliothques sur lesquelles sappuie Sage pour certains types de coecients font appel ce genre dalgorithmes avancs : cest ainsi que Sage est capable de travailler ecacement avec des polynmes de degr astronomique sur certains anneaux de coecients.

les conversions ncessaires. Dans le mme ordre dides, le domaine SR regroupe toutes les expressions symboliques, sans distinction entre les polynmes et les autres, mais on peut tester explicitement si une expression symbolique f est polynomiale en une variable x par f.is_polynomial(x).

Mathematics is the art of reducing any problem to linear algebra. William Stein

Algbre linaire
Ce chapitre traite de lalgbre linaire exacte et symbolique, cest--dire sur des anneaux propres au calcul formel, tels que Z, des corps nis, des anneaux de polynmes... Lalgbre linaire numrique est traite quant elle au chapitre 13. Nous prsentons les constructions sur les matrices et leurs espaces ainsi que les oprations de base (8.1), puis les dirents calculs possibles sur ces matrices, regroups en deux thmes : ceux lis llimination de Gauss et aux transformations par quivalence gauche (8.2.1 et 8.2.2), et ceux lis aux valeurs et espaces propres et aux transformations de similitude (8.2.3). On peut trouver dans les ouvrages de Gantmacher [Gan90], de von zur Gathen et Gerhard [vzGG03], de Lombardi et Journadi [LA04] un traitement approfondi des notions abordes dans ce chapitre.

8.1
8.1.1

Constructions et manipulations lmentaires


Espaces de vecteurs, de matrices

De la mme faon que pour les polynmes, les vecteurs et les matrices sont manipuls comme des objets algbriques appartenant un espace. Si les coecients appartiennent un corps K , cest un espace vectoriel sur K ; sils appartiennent un anneau, cest un K -module libre. On construit ainsi lespace M2,3 (Z) et lespace vectoriel (F32 )3 par sage: MS = MatrixSpace(ZZ,2,3); MS Full MatrixSpace of 2 by 3 dense matrices over Integer Ring sage: VS = VectorSpace(GF(3^2, x ),3); VS

160

CHAP. 8. ALGBRE LINAIRE

Espaces de matrices construction construction (mat. creuses) anneau de base K extension de lanneau changement de lanneau groupe engendr base de lespace MS = MatrixSpace(K, nrows, ncols) MS = MatrixSpace(K, nrows, ncols, sparse = True) MS.base_ring() MS.base_extend(B) MS.change_ring(B) MatrixGroup([A,B]) MS.basis() ou MS.gens() Construction de matrices matrice nulle matrice avec coecients matrice identit matrice alatoire bloc de Jordan matrice par blocs MS() ou MS.zero() ou matrix(K,nrows,ncols) MS([1,2,3,4] ou matrix(K,2,2,[1,2,3,4]) ou matrix(K,[[1,2],[3,4]]) MS.one() ou MS.identity_matrix() ou identity_matrix(K,n) MS.random_element() ou random_matrix(K,nrows,ncols) jordan_block(x,n) block_matrix([A,1,B,0]) ou block_diagonal_matrix Manipulations de base accs un coecient accs une ligne, colonne accs aux colonnes paires sous-matrices A[2,3] A[-1,:], A[:,2] A[:,0:8:2] A[3:4,2:5], A[:,2:5], A[:4,2:5] A.matrix_from_rows([1,3]), A.matrix_from_columns([2,5]), A.matrix_from_rows_and_columns([1,3],[2,5]) A.submatrix(i,j,nrows,ncols) A.stack(B) A.augment(B)

concatnation par lignes concatnation par colonnes

Tableau 8.1 Constructeurs de matrices et de leurs espaces.

Vector space of dimension 3 over Finite Field in x of size 3^2 Un systme gnrateur pour ces espaces est donn par la base canonique ; elle peut tre obtenue indiremment par les mthodes MS.gens() ou MS.basis(). sage: MatrixSpace(ZZ,2,3).basis() 1 0 0 , 0 1 0 , 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1

Groupes de matrices. On pourra par ailleurs dnir des sous-groupes de lespace total des matrices. Ainsi le constructeur MatrixGroup([A,B,...]) renvoie le groupe engendr par les matrices passes en argument, qui doivent tre inversibles. sage: A = matrix(GF(11), 2, 2, [1,0,0,2]) sage: B = matrix(GF(11), 2, 2, [0,1,1,0]) sage: MG = MatrixGroup([A,B])

8.1. CONSTRUCTIONS ET MANIPULATIONS LMENTAIRES sage: MG.cardinality() 200 sage: identity_matrix(GF(11),2) in MG True

161

Le groupe gnral linaire de degr n sur un corps K , not GLn (K ), est le groupe form par les matrices n n inversibles de Mn,n (K ). Il se construit naturellement en Sage avec la commande GL(n,K). Le groupe spcial linaire SLn (K ) des lments de GLn (K ) de dterminant 1 se construit avec la commande SL(n,K).

8.1.2

Construction des matrices et des vecteurs

Les matrices et les vecteurs peuvent naturellement tre gnrs comme des lments dun espace en fournissant la liste des coecients en arguments. Pour les matrices, ceux-ci seront lus par ligne : sage: MS = MatrixSpace(ZZ,2,3); A = MS([1,2,3,4,5,6]); A 1 2 3 4 5 6 Le constructeur vide MS() renvoie une matrice nulle, tout comme la mthode MS.zero(). Plusieurs constructeurs spcialiss permettent de produire les matrices usuelles, comme random_matrix, identity_matrix, jordan_block (voir tableau 8.1). En particulier on pourra construire des matrices et des vecteurs avec les constructeurs matrix et vector, sans devoir construire lespace associ pralablement. Par dfaut une matrice est construite sur lanneau des entiers Z et a pour dimensions 0 0. sage: a = matrix(); a.parent() Full MatrixSpace of 0 by 0 dense matrices over Integer Ring On peut naturellement spcier un domaine pour les coecients ainsi que les dimensions, pour crer ainsi une matrice nulle, ou remplie dune liste de coecients passe en argument. sage: a = matrix(GF(8, x ),3,4); a.parent() Full MatrixSpace of 3 by 4 dense matrices over Finite Field in x of size 2^3 Le constructeur matrix accepte aussi comme argument des objets admettant une transformation naturelle en matrice. Ainsi, il peut tre utilis pour obtenir la matrice dadjacence dun graphe, sous la forme dune matrice coecients dans Z. sage: g = graphs.PetersenGraph() sage: m = matrix(g); m; m.parent() [0 1 0 0 1 1 0 0 0 0] [1 0 1 0 0 0 1 0 0 0] [0 1 0 1 0 0 0 1 0 0] [0 0 1 0 1 0 0 0 1 0]

162 [1 0 [1 0 [0 1 [0 0 [0 0 [0 0 Full 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 0 0 0 1 0 1 1 0 0 0 1 0 1 1 MatrixSpace

CHAP. 8. ALGBRE LINAIRE 0 1] 1 0] 1 1] 0 1] 0 0] 0 0] of 10 by 10 dense matrices over Integer Ring

Matrices par blocs. Pour construire une matrice par blocs partir de sousmatrices, on peut utiliser la fonction block_matrix. sage: sage: 1 3 2 6 A = matrix([[1,2],[3,4]]) block_matrix([[A,-A],[2*A, A^2]]) 2 1 2 4 3 4 4 7 10 8 15 22

La structure est carre par blocs par dfaut mais le nombre de blocs ligne ou colonne peut tre spci par les arguments optionnels ncols et nrows. Lorsque cela est possible, un coecient comme 0 ou 1 est interprt comme un bloc diagonal (ici zro ou identit) de dimension approprie. sage: sage: 1 0 0 0 A = matrix([[1,2,3],[4,5,6]]) block_matrix([1,A,0,0,-A,2], ncols=3) 0 1 2 3 0 0 1 4 5 6 0 0 0 1 2 3 2 0 0 4 5 6 0 2

Pour le cas particulier des matrices diagonales par blocs, on passe simplement la liste des blocs diagonaux au constructeur block_diagonal_matrix. sage: sage: 1 0 0 0 0 A = matrix([[1,2,3],[0,1,0]]) block_diagonal_matrix(A, A.transpose()) 2 3 0 0 1 0 0 0 0 0 1 0 0 0 2 1 0 0 3 0

La structure par blocs nest quune commodit dachage, et Sage traite la matrice comme toute autre matrice. On peut par ailleurs dsactiver cet achage en ajoutant largument subdivide=False au constructeur block_matrix.

8.1.3

Manipulations de base et arithmtique sur les matrices

Indices et accs aux coecients. Laccs aux coecients ainsi qu des sous-matrices extraites se fait de faon unie par loprateur crochet A[i,j],

8.1. CONSTRUCTIONS ET MANIPULATIONS LMENTAIRES

163

selon les conventions usuelles de Python. Les indices de ligne i et de colonne j peuvent tre des entiers (pour laccs des coecients) ou des intervalles sous la forme 1:3 (on rappelle que par convention, en Python les indices commencent 0, et les intervalles sont toujours inclusifs pour la borne infrieure et exclusifs pour la borne suprieure). Lintervalle : sans bornes correspond la totalit des indices possibles dans la dimension considre. La notation a:b:k permet daccder aux indices compris entre a et b 1 par pas de k . Enn, les indices ngatifs sont aussi valides, et permettent de parcourir les indices partir de la n. Ainsi A[-2,:] correspond lavant dernire ligne. Laccs ces sous-matrices se fait aussi bien en lecture quen criture. On peut par exemple modier une colonne donne de la faon suivante : sage: sage: 0 3 6 A = matrix(3,3,range(9)) A[:,1] = vector([1,1,1]); A 1 2 1 5 1 8

Lindice de pas k peut aussi tre ngatif, indiquant un parcours par valeurs dcroissantes. sage: A[::-1], A[:,::-1], A[::2,-1] 6 1 8 2 1 0 3 1 5 , 5 1 3 , 2 8 0 1 2 8 1 6

Extraction de sous-matrices. Pour extraire une matrice partir dune liste dindices de ligne ou de colonne non ncessairement contigus, on utilise les mthodes A.matrix_from_rows, A.matrix_from_columns, ou dans le cas gnral la mthode A.matrix_from_rows_and_columns. sage: A = matrix(ZZ,4,4,range(16)); A 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 sage: A.matrix_from_rows_and_columns([0,2,3],[1,2]) 1 2 9 10 13 14 Pour extraire une sous-matrice de lignes et de colonnes contigus, on pourra aussi utiliser la mthode submatrix(i,j,m,n) formant la sous-matrice de dimension m n dont le coecient suprieur gauche se trouve en position (i, j ).

164

CHAP. 8. ALGBRE LINAIRE

Plongements et extensions. Lorsque lon veut plonger un espace de matrices dans lespace des matrices de mme dimension mais coecients dans une extension de lanneau de base, on pourra utiliser la mthode base_extend de lespace de matrice. Cette opration nest toutefois valide que pour les oprations dextension de corps ou danneau. Pour eectuer le changement de lanneau de base suivant un morphisme (lorsquil existe), on utilise plutt la mthode change_ring. sage: MS = MatrixSpace(GF(3),2,3) sage: MS.base_extend(GF(9, x )) Full MatrixSpace of 2 by 3 dense matrices over Finite Field in x of size 3^2 sage: MS = MatrixSpace(ZZ,2,3) sage: MS.change_ring(GF(3)) Full MatrixSpace of 2 by 3 dense matrices over Finite Field of size 3 Mutabilit et mise en cache. Les objets reprsentant les matrices sont par dfaut mutables, cest--dire que lon peut librement en modier leurs membres (ici leurs coecients) aprs leur construction. Si on souhaite protger la matrice contre les modications, on utilise la fonction A.set_immutable(). Il est alors toujours possible den tirer des copies mutables par la fonction copy(A). noter que le mcanisme de mise en cache des rsultats calculs (tels que le rang, le dterminant...) reste toujours fonctionnel, quel que soit ltat de mutabilit.

8.1.4

Oprations de base sur les matrices

Les oprations arithmtiques sur les matrices se font avec les oprateurs usuels +,-,*,^. Linverse dune matrice A peut scrire aussi bien A^-1 que ~A. Lorsque a est un scalaire et A une matrice, lopration a*A correspond la multiplication externe de lespace de matrices. Pour les autres oprations o un scalaire a est fourni en lieu et place dune matrice (par exemple lopration a+A), il est considr comme la matrice scalaire correspondante aIn si a = 0 et les dimensions le permettent. Le produit lment par lment de deux matrices seectue avec lopration elementwise_product.

8.2

Calculs sur les matrices

En algbre linaire, les matrices peuvent tre utilises pour reprsenter aussi bien des familles de vecteurs, des systmes dquations linaires, des applications linaires ou des sous-espaces. Ainsi, le calcul dune proprit comme le rang dune famille, la solution dun systme, les espaces propres dune application linaire, ou la dimension dun sous-espace se ramnent des transformations sur ces matrices rvlant cette proprit. Ces transformations correspondent des changements de base, vus au niveau matriciel comme des transformations dquivalence : B = P AQ1 , o P et Q sont des matrices inversibles. Deux matrices sont dites quivalentes sil existe une telle

8.2. CALCULS SUR LES MATRICES

165

Oprations de base transpose, conjugue produit externe somme, produit, puissance k-ime, inverse A.tranpose(), A.conjugate() a*A A + B, A * B, A^k, A^-1 ou

~A

Tableau 8.2 Oprations de base et arithmtique sur les matrices.

transformation pour passer de lune lautre. On peut ainsi former des classes dquivalence pour cette relation, et lon dnit des formes normales, permettant de caractriser de manire unique chaque classe dquivalence. Dans ce qui suit, nous prsentons lessentiel des calculs sur les matrices disponibles avec Sage, sous langle de deux cas particuliers de ces transformations : Les transformations dquivalence gauche, de la forme B = U A, qui rvlent les proprits caractristiques pour les familles de vecteurs, telles que le rang (nombre de vecteurs linairement indpendants), le dterminant (volume du paralllpipde dcrit par la famille de vecteurs), le prol de rang (premier sous-ensemble de vecteurs formant une base), . . . Llimination de Gauss est loutil central pour ces transformations, et la forme chelonne rduite (forme de Gauss-Jordan dans un corps ou forme de Hermite dans Z) est la forme normale. En outre, ces transformations servent la rsolution des systmes linaires. Les transformations de similitude, de la forme B = U AU 1 , qui rvlent les proprits caractristiques des matrices reprsentant des endomorphismes, comme les valeurs propres, les espaces propres, les polynmes minimal et caractristique, . . . La forme de Jordan ou la forme de Frobenius, selon les domaines de calcul, seront les formes normales pour ces transformations. La forme de Gram-Schmidt est une autre dcomposition base sur les transformations dquivalence gauche, transformant une matrice en un ensemble de vecteurs orthogonaux.

8.2.1

limination de Gauss, forme chelonne

limination de Gauss et quivalence gauche. Llimination de Gauss est lune des oprations fondamentales en algbre linaire car elle permet daccder une reprsentation de la matrice la fois plus adapte au calcul, comme la rsolution de systmes, et rvlant certaines de ses proprits fondamentales, comme le rang, le dterminant, le prol de rang, etc. Les oprations de base pour llimination sont les oprations lmentaires sur les lignes : permutation de deux lignes : Li Lj , ajout dun multiple dune ligne une autre : Li Li + sLj . Au niveau matriciel, ces transformations correspondent la multiplication gauche respectivement par les matrices de transposition Ti,j et par les matrices

166

CHAP. 8. ALGBRE LINAIRE

limination de Gauss et applications transvection sur les lignes transvection sur les colonnes transposition de lignes, colonnes forme de Gauss-Jordan, immuable forme de Gauss-Jordan en place facteurs invariants forme normale de Smith dterminant, rang mineurs dordre k prol de rang en colonne, en ligne rsolution de systme gauche (t x A = b) rsolution de systme droite (Ax = b) espace image noyau gauche noyau droite noyau dans lanneau de base add_multiple_of_row(i,j,s) add_multiple_of_column(i,j,s) swap_rows(i1,i2), swap_columns(j1,j2) echelon_form echelonize elementary_divisors smith_form det, rank minors(k) pivots, pivot_rows b/A ou A.solve_left(b) A\b ou A.solve_right(b) image kernel ou left_kernel right_kernel integer_kernel

Dcomposition spectrale polynme minimal polynme caractristique itrs de Krylov gauche valeurs propres vecteurs propres gauche, droite espaces propres gauche, droite diagonalisation bloc de Jordan Ja,k minimal_polynomial ou minpoly characteristic_polynomial ou charpoly maxspin(v) eigenvalues eigenvectors_left, eigenvectors_right eigenspaces_left, eigenspaces_right eigenmatrix_left, eigenmatrix_right jordan_block(a,k)

Tableau 8.3 Calculs sur les matrices.

de transvection Ci,j,s , donnes par :


i j

1 .. . 0 .. 1 . 0 .. . 1 1

1 .. . 1 .. . 1 .. . s

i . j

Ti,j

, Ci,j,s =

Ces matrices ont toutes pour dterminant 1 ou 1. Ainsi toute multiplication gauche par un produit de ces matrices peut tre vue comme un changement de base prservant les volumes et donc en particulier le dterminant (au signe prs). En Sage, lopration de transvection est eectue par la mthode add_multiple_of_row(i,j,s), et celle de transposition par la mthode swap_rows(i,j).

8.2. CALCULS SUR LES MATRICES

167

x1 . tant donn un vecteur colonne x = . . dont la k -ime composante xk xm est inversible, on dnit la transformation de Gauss comme la composition des xi transvections Ci,k, i pour i = k + 1 . . . m, avec i = x (peu importe lordre k tant donn quelles commutent). La matrice correspondante est la suivante : 1 .. . = 1
k+1 k+2

Gx,k = Ck+1,k,

k+1

Cm,k,

..

..

. . .

..

k . 1

Une transformation de Gauss Gx,k a pour eet dliminer les coecients du vecteur situs sous le coecient pivot xk : x1 x1 . . . . . . xk xk Gx,k xk+1 = 0 . . . . . . . xm 0 Pour une matrice A = [ai,j ] de dimension m n, lalgorithme du pivot de Gauss procde alors itrativement, de la colonne gauche la colonne droite. En supposant que les k 1 premires colonnes ont dj t traites, fournissant p k 1 pivots, la k -ime est alors traite de la faon suivante : trouver la premire composante inversible ai,k de la colonne Ck sur une ligne i > p. On lappelle le pivot. Si aucun pivot nest trouv, passer la colonne suivante. Appliquer la transposition Ti,p+1 sur les lignes pour placer le pivot en position (p + 1, k ). Appliquer la transformation de Gauss Gx,p+1 , x tant la nouvelle colonne Ck . Cet algorithme transforme la matrice A en une matrice triangulaire suprieure. Plus prcisment elle aura une forme chelonne, cest--dire telle que le premier coecient non nul de chaque ligne se trouve plus droite que celui de la ligne prcdente ; de plus, toutes les lignes nulles se trouvent regroupes en bas de la matrice. Voici un exemple de droulement de cet algorithme. sage: a = matrix(GF(7),4,3,[6,2,2,5,4,4,6,4,5,5,1,3]); a

168

CHAP. 8. ALGBRE LINAIRE

6 5 6 5

2 4 4 1

2 4 5 3

sage: u = copy(identity_matrix(GF(7),4)); u[1:,0] = -a[1:,0]/a[0,0] sage: u, u*a 6 2 2 1 0 0 0 5 1 0 0 0 0 0 6 0 1 0 , 0 2 3 0 4 6 5 0 0 1 sage: v sage: b 1 0 0 0 = copy(identity_matrix(GF(7),4)); v.swap_rows(1,2) = v*u*a; v, b 6 2 2 0 0 0 0 1 0 , 0 2 3 1 0 0 0 0 0 0 4 6 0 0 1

sage: w = copy(identity_matrix(GF(7),4)) sage: w[2:,1] = -b[2:,1]/b[1,1]; w, w*b 6 2 2 1 0 0 0 0 1 0 0 0 2 3 0 0 1 0 , 0 0 0 0 0 0 0 5 0 1 limination de Gauss-Jordan. La transformation de Gauss-Jordan est similaire celle de Gauss, en ajoutant Gx,k les transvections correspondant aux lignes dindice i < k ; cela revient liminer les coecients dune colonne au-dessus et au-dessous du pivot. Si de plus on divise chaque ligne par son pivot, on obtient alors une forme chelonne dite rduite encore appele forme de Gauss-Jordan. Pour toute classe dquivalence de matrices, il existe une unique matrice sous cette forme ; il sagit donc dune forme normale. Dfinition. Une matrice est dite sous forme chelonne rduite si : toutes les lignes nulles sont en bas de la matrice, le coecient non nul le plus gauche de chaque ligne non nulle, appel le pivot, est un 1, et est situ droite du pivot de la ligne prcdente, les pivots sont les seuls coecients non nuls au sein de leur colonne. Thorme. Pour toute matrice A de dimension m n coecients dans un corps, il existe une unique matrice R de dimension m n sous forme chelonne rduite et une matrice inversible U de dimension m m telles que U A = R. Il sagit de la dcomposition de Gauss-Jordan.

8.2. CALCULS SUR LES MATRICES

169

En Sage, la forme chelonne rduite est donne par les mthodes echelonize et echelon_form. La premire remplace la matrice initiale par sa forme chelonne rduite alors que la deuxime renvoie une matrice immuable sans modier la matrice initiale. sage: A = matrix(GF(7),4,5,[4,4,0,2,4,5,1,6,5,4,1,1,0,1,0,5,1,6,6,2]) sage: A, A.echelon_form() 4 4 0 2 4 1 0 5 0 3 5 1 6 5 4 0 1 2 0 6 1 1 0 1 0 , 0 0 0 1 5 5 1 6 6 2 0 0 0 0 0 Plusieurs variantes de llimination de Gauss sinterprtent sous la forme de direntes dcompositions matricielles, parfois utiles pour le calcul : les dcompositions A = LU pour les matrices gnriques, A = LU P pour les matrices rgulires, A = LSP , A = LQU P ou A = P LU Q pour les matrices de rang quelconque. Les matrices L sont triangulaires infrieures (valeurs nulles au-dessus de la diagonale principale, en anglais Lower triangular ), U triangulaires suprieures (Upper triangular ), et les matrices P, Q sont des permutations. Si ces variantes sont algorithmiquement moins coteuses que la forme chelonne rduite, elles norent pas lavantage de fournir une forme normale. Forme chelonne dans les anneaux euclidiens. Dans un anneau euclidien, les coecients non nuls ne sont pas ncessairement inversibles, et llimination de Gauss consisterait donc choisir le premier lment inversible de la colonne courante pour pivot. Ainsi certaines colonnes non nulles peuvent ne pas contenir de pivot et llimination nest alors plus possible. Il est cependant toujours possible de dnir une transformation unimodulaire liminant le coecient de tte dune ligne avec celui dune autre, grce lalgorithme dEuclide tendu. a Soit A = et soit g = pgcd(a, b). Soient u et v les coecients de Bzout b fournis par lalgorithme dEuclide tendu appliqu a et b (tels que g = ua + vb), et s = b/g, t = a/g tels que u s v t a b g = 0 .

u v = 1. s t Par ailleurs, comme pour Gauss-Jordan, on peut toujours ajouter des multiples de la ligne pivot aux lignes suprieures an de rduire leurs coecients dans la mme colonne modulo le pivot g . Cette opration eectue itrativement sur toutes les colonnes de la matrice produit la forme normale de Hermite. Cette transformation est unimodulaire car det Dfinition. Une matrice est dite sous forme de Hermite si ses lignes nulles sont en bas,

170

CHAP. 8. ALGBRE LINAIRE

le coecient non nul le plus gauche de chaque ligne, appel le pivot, se trouve droite de celui de la ligne suprieure, tous les coecients au-dessus du pivot sont rduits modulo le pivot. Thorme. Pour toute matrice A de dimension m n coecients dans un anneau euclidien, il existe une unique matrice H de dimension m n sous forme de Hermite et une matrice U unimodulaire, de dimension m m, telles que U A = H. Dans le cas dun corps, la forme de Hermite correspond la forme chelonne rduite, ou forme de Gauss-Jordan. En eet, dans ce cas, tous les pivots sont inversibles, chaque ligne peut tre divise par son pivot, et les coecients au-dessus de celui-ci peuvent tre nouveau limins par des transformations de Gauss, produisant ainsi une forme chelonne rduite. En Sage, il ny a donc quune seule mthode : echelon_form, qui renvoie soit la forme de Hermite, soit la forme chelonne rduite, selon que la matrice est coecients dans un anneau ou dans un corps. Par exemple, pour une matrice coecients dans Z, on obtient les deux formes chelonnes direntes, selon que le domaine de base soit Z ou Q : sage: ....: 1 0 0 0 sage: 1 0 0 0 a = matrix(ZZ, 4, 6, [2,1,2,2,2,-1,1,2,-1,2,1,-1,2,1,-1,\ -1,2,2,2,1,1,-1,-1,-1]); a.echelon_form() 2 0 5 4 1 3 0 2 6 7 0 1 3 3 0 0 0 6 9 3 a.base_extend(QQ).echelon_form() 5 11 0 0 0 2 6 8 1 0 0 3 3 3 3 0 1 0 2 2 1 3 0 0 1 2 2

Pour les matrices sur Z, la forme normale de Hermite est aussi accessible par la fonction hermite_form. Pour obtenir la matrice de passage U telle que U A = H , on peut utiliser loption transformation=True. sage: A = matrix(ZZ,4,5,[4,4,0,2,4,5,1,6,5,4,1,1,0,1,0,5,1,6,6,2]) sage: H, U = A.echelon_form(transformation=True); H, U 1 1 0 0 2 0 1 1 1 0 4 6 0 4 0 1 5 0 , 0 0 0 1 2 0 1 0 1 0 0 0 0 0 1 2 4 2 Facteurs invariants et forme normale de Smith. Si lon sautorise liminer plus avant la forme de Hermite par des transformations unimodulaires droite (i.e., sur les colonnes), on peut alors obtenir une forme diagonale canonique, appele forme normale de Smith. Ses coecients diagonaux sont appels les facteurs invariants (en anglais elementary divisors ) de la matrice. Ils sont totalement ordonns pour la divisibilit (i.e., si | si+1 ).

8.2. CALCULS SUR LES MATRICES

171

Thorme. Pour toute matrice A de dimension m n et coecients dans un anneau principal, il existe des matrices unimodulaires U et V de dimension m m et n n et une unique matrice m n diagonale S telles que S = U AV . Les coecients si = Si,i pour i {1, . . . , min(m, n)} vrient si | si+1 et sont appels les facteurs invariants de A. En Sage, la mthode elementary_divisors renvoie la liste des facteurs invariants. On peut par ailleurs calculer la forme normale de Smith ainsi que les matrices de passages U et V par la commande smith_form. sage: A = matrix(ZZ, 4, 5,\ ....: [-1,-1,-1,-2,-2,-2,1,1,-1,2,2,2,2,2,-1,2,2,2,2,2]) sage: S,U,V = A.smith_form(); S,U,V 0 2 1 5 0 1 0 0 0 0 1 0 0 0 1 0 1 1 1 1 0 0 1 0 0 0 0 0 0 0 0 0 1 , 0 0 3 0 0 , 2 1 0 0 1 2 0 5 0 0 0 0 6 0 0 0 2 1 0 1 0 2 0 sage: A.elementary_divisors() [1, 1, 3, 6] sage: S == U*A*V True Rang, prol de rang et pivots. Llimination de Gauss rvle de nombreux invariants de la matrice, tels que son rang et son dterminant (qui peut tre lu comme le produit des pivots). Ils sont accessibles par les fonctions det et rank. Ces valeurs seront mises en cache, et ne seront donc pas recalcules lors dun deuxime appel. Plus gnralement, la notion de prol de rang est trs utile, lorsque lon considre la matrice comme une squence de vecteurs. Dfinition. Le prol de rang par colonne dune matrice m n A de rang r est la squence de r indices lexicographiquement minimale, telle que les colonnes correspondantes dans A sont linairement indpendantes. Le prol de rang se lit directement sur la forme chelonne rduite, comme la squence des indices des pivots. Il est calcul par la fonction pivots. Lorsque la forme chelonne rduite a dj t calcule, le prol de rang est aussi mmoris dans le cache, et peut tre obtenu sans calcul supplmentaire. Le prol de rang par ligne se dnit de manire similaire, en considrant la matrice comme une squence de m vecteurs ligne. Il sobtient par la commande pivot_rows ou comme sous-produit de la forme chelonne rduite de la matrice transpose. sage: sage: 1 0 0 0 B = matrix(GF(7),5,4,[4,5,1,5,4,1,1,1,0,6,0,6,2,5,1,6,4,4,0,2]) B.transpose().echelon_form() 0 5 0 3 1 2 0 6 0 0 1 5 0 0 0 0

172

CHAP. 8. ALGBRE LINAIRE

sage: B.pivot_rows() (0, 1, 3) sage: B.transpose().pivots() == B.pivot_rows() True

8.2.2

Rsolution de systmes ; image et base du noyau

Rsolution de systmes. Un systme linaire peut tre reprsent par une matrice A et un vecteur b soit droite : Ax = b, soit gauche : t x A = b. Les fonctions solve_right et solve_left eectuent leur rsolution. On peut aussi utiliser de faon quivalente les oprateurs A\b et b/A. Lorsque le systme est donn par une matrice coecients dans un anneau, la rsolution est systmatiquement eectue dans le corps des fractions de cet anneau (e.g., Q pour Z ou K (X ) pour K [X ]). On verra plus loin comment la rsolution peut tre faite dans lanneau lui-mme. Le membre de droite dans lgalit du systme peut tre aussi bien un vecteur quune matrice (ce qui correspond rsoudre plusieurs systmes linaires simultanment, avec la mme matrice). Les matrices des systmes peuvent tre rectangulaires et les systmes peuvent admettre une unique, aucune ou une innit de solutions. Dans ce dernier cas, les fonctions solve renvoient lune de ces solutions, en mettant zro les composantes correspondant aux colonnes linairement dpendantes du systme. sage: R.<x> = PolynomialRing(GF(5), x ) sage: A = random_matrix(R,2,3); A 3x2 + x x 2 + 2x 2 x + x + 2 2x + 4x + 3
2

2x2 + 2 x + 4x + 3
2

sage: b = random_matrix(R,2,1); b 4x2 + 1 3x2 + 2x sage: A.solve_right(b) 3


4x +2x+4 3x3 +2x2 +2x 3x2 +4x+3 x3 +4x2 +4x

sage: A.solve_right(b) == A\b True Image et noyau. Interprte comme une application linaire , une matrice A de dimension m n dnit deux sous-espaces vectoriels de K m et K n , respectivement limage et le noyau de . Limage est lensemble des vecteurs de K m obtenus par combinaisons linaires des colonnes de A. Il sobtient par la fonction image qui renvoie un espace vectoriel dont la base est sous forme chelonne rduite.

8.2. CALCULS SUR LES MATRICES

173

Le noyau est le sous-espace vectoriel de K n des vecteurs x tels que Ax = 0. Obtenir une base de ce sous-espace sert en particulier dcrire lensemble des solutions dun systme linaire, lorsque celui-ci en possde une innit : si x est une solution de Ax = b et V le noyau de A, alors lensemble des solutions scrit simplement x + V . Il sobtient par la fonction right_kernel qui renvoie lespace vectoriel ainsi quune base mise sous forme chelonne rduite. On peut naturellement aussi dnir le noyau gauche (lensemble des x dans K m tels que t x A = 0), qui correspond au noyau droite de la transpose de A (i.e., ladjoint de ). Il sobtient avec la fonction left_kernel. Par convention, la fonction kernel renvoie le noyau gauche. De plus les bases sont donnes comme des matrices de vecteurs lignes dans les deux cas. sage: a = matrix(QQ,3,5,[2,2,-1,-2,-1,2,-1,1,2,-1/2,2,-2,-1,2,-1/2]) sage: a.image() Vector space of degree 5 and dimension 3 over Rational Field Basis matrix: [ 1 0 0 1/4 -11/32] [ 0 1 0 -1 -1/8] [ 0 0 1 1/2 1/16] sage: a.right_kernel() Vector space of degree 5 and dimension 2 over Rational Field Basis matrix: [ 1 0 0 -1/3 8/3] [ 0 1 -1/2 11/12 2/3] La notion de noyau se gnralise naturellement au cas o les coecients ne sont plus dans un corps ; il sagit alors dun module libre. En particulier, pour une matrice dnie dans un corps de fractions, on obtiendra le noyau dans lanneau de base par la commande integer_kernel. Par exemple, pour une matrice coecients dans Z, plonge dans lespace vectoriel des matrices coecients dans Q, on pourra calculer aussi bien son noyau comme un sous-espace vectoriel de Qm ou comme un module libre de Zm . sage: a = matrix(ZZ,5,3,[1,1,122,-1,-2,1,-188,2,1,1,-10,1,-1,-1,-1]) sage: a.kernel() Free module of degree 5 and rank 2 over Integer Ring Echelon basis matrix: [ 1 979 -11 -279 811] [ 0 2079 -22 -569 1488] sage: b = a.base_extend(QQ) sage: b.kernel() Vector space of degree 5 and dimension 2 over Rational Field Basis matrix: [ 1 0 -121/189 -2090/189 6949/63] [ 0 1 -2/189 -569/2079 496/693] sage: b.integer_kernel() Free module of degree 5 and rank 2 over Integer Ring Echelon basis matrix:

174 [ [ 1 979 -11 -279 811] 0 2079 -22 -569 1488]

CHAP. 8. ALGBRE LINAIRE

8.2.3

Valeurs propres, forme de Jordan et transformations de similitude

Lorsque lon interprte une matrice carre comme un oprateur linaire (un endomorphisme), elle nen est que la reprsentation dans une base donne. Tout changement de base correspond une transformation de similitude B = U 1 AU de la matrice. Les deux matrices A et B sont alors dites semblables. Ainsi les proprits de loprateur linaire, qui sont indpendantes de la base, sont rvles par ltude des invariants de similitude de la matrice. Parmi ces invariants, les plus simples sont le rang et le dterminant. En eet les matrices U et U 1 tant inversibles, le rang de U 1 AU gale le rang de A. De plus det(U 1 AU ) = det(U 1 ) det(A) det(U ) = det(U 1 U ) det(A) = det(A). De la mme faon, le polynme caractristique de la matrice A, dni par A (x) = det(xId A) est aussi invariant par transformation de similitude : det(xId U 1 AU ) = det(U 1 (xId A)U ) = det(xId A). Par consquent, les valeurs caractristiques dune matrice, dnies comme les racines du polynme caractristique dans son corps de dcomposition, sont donc aussi des invariants de similitude. Par dnition, un scalaire est une valeur propre dune matrice A sil existe un vecteur non nul u tel que Au = u. Lespace propre associ une valeur propre est lensemble des vecteurs u tels que Au = u. Cest un sous-espace vectoriel dni par E = Ker(Id A). Les valeurs propres concident avec les valeurs caractristiques : det(Id A) = 0 dim(Ker(Id A)) 1 u = 0, u Au = 0.

Ces deux points de vue correspondent respectivement lapproche algbrique et gomtrique des valeurs propres. Dans le point de vue gomtrique, on sintresse laction de loprateur linaire A sur les vecteurs de lespace avec plus de prcision que dans le point de vue algbrique. En particulier on distingue les notions de multiplicit algbrique, correspondant lordre de la racine dans le polynme caractristique, de la multiplicit gomtrique, correspondant la dimension du sous-espace propre associ la valeur propre. Pour les matrices diagonalisables, ces deux notions sont quivalentes. Dans le cas contraire, la multiplicit gomtrique est toujours infrieure la multiplicit algbrique. Le point de vue gomtrique permet de dcrire plus en dtail la structure de la matrice. Par ailleurs, il donne des algorithmes beaucoup plus rapides pour le calcul des valeurs et espaces propres, et des polynmes caractristique et minimal. Espaces invariants cycliques, et forme normale de Frobenius. Soit A une matrice n n sur un corps K et u un vecteur de K n . La famille de vecteurs u, Au, A2 u, . . . , An u, appele suite de Krylov, est lie (comme famille de n + 1

8.2. CALCULS SUR LES MATRICES

175

vecteurs en dimension n). Soit d tel que Ad u soit le premier vecteur de la squence linairement dpendant avec ses prdcesseurs u, Au, . . . , Ad1 u. On crira
d1

Ad u =
i=0

i Ai u
d1

cette relation de dpendance linaire. Le polynme A,u (x) = xd i=0 i xi , qui vrie A,u (A)u = 0 est donc un polynme unitaire annulateur de la suite de Krylov et de degr minimal. On lappelle le polynme minimal du vecteur u (sous entendu, relativement la matrice A). Lensemble des polynmes annulateurs de u forme un idal de K [X ], engendr par A,u . Le polynme minimal de la matrice A est dni comme le polynme unitaire A (x) de plus petit degr annulant la matrice A : A (A) = 0. En particulier, en appliquant A (A) au vecteur u, on constate que A est un polynme annulateur de la suite de Krylov. Il est donc ncessairement un multiple du polynme minimal de u. On peut en outre montrer (cf. exercice 30) quil existe un vecteur u tel que A,u = A . (8.1) Lorsque le vecteur u est choisi alatoirement, la probabilit quil satisfasse lquation (8.1) est dautant plus grande que la taille du corps est grande (on peut n montrer quelle est au moins de 1 |K | ).
Exercice 30. Montrons quil existe toujours un vecteur u dont le polynme minimal concide avec le polynme minimal de la matrice. 1. Soit (e1 , . . . , en ) une base de lespace vectoriel. Montrer que A concide avec le ppcm des A,ei . 2. Dans le cas particulier o A est une puissance dun polynme irrductible, montrer quil existe un indice i0 tel que A = A,ei0 . 3. Montrer que si les polynmes minimaux i = A,ei et j = A,ej des vecteurs ei et ej sont premiers entre eux, alors A,ei +ej = i j . 4. Montrer que si A = P1 P2 o P1 et P2 sont premiers entre eux, alors il existe des vecteurs x1 = 0 et x2 = 0 tels que Pi soit le polynme minimal de xi . mk 1 5. Conclure en utilisant la factorisation en polynmes irrductibles A = m 1 . . . k . 0 0 3 0 0 1 0 6 0 0 6. Illustration : soit A = 0 1 5 0 0 une matrice dans GF(7). Calculer les 0 0 0 0 5 0 0 0 1 5 degrs du polynme minimal de A, et des polynmes minimaux des vecteurs de la base canonique u = e1 et v = e4 , ainsi que de u + v . On peut se servir de la fonction maxspin(u) applique la transpose de A, qui renvoie la squence maximale des itrs de Krylov dun vecteur u.

Soit P = xk + i=0 i xi un polynme unitaire de degr k . La matrice compagnon associe au polynme P est la matrice k k dnie par 0 0 1 1 CP = . . .. . . . 1 k1

k1

176

CHAP. 8. ALGBRE LINAIRE

Cette matrice a la proprit davoir P pour polynme minimal et caractristique. Elle joue ainsi un grand rle dans le calcul des polynmes minimal et caractristique. Proposition. Soit Ku la matrice forme par les d premiers itrs de Krylov dun vecteur u. Alors AKu = Ku CA,u Ainsi, lorsque d = n, la matrice Ku est carre dordre n et inversible. Elle 1 dnit une transformation de similitude Ku AKu = CA,u rduisant la matrice A une matrice compagnon. Or cette transformation prserve le dterminant, et donc le polynme caractristique ; on pourra ainsi lire directement les coecients du polynme minimal et caractristique (ici identiques) sur la matrice compagnon. sage: ....: sage: sage: sage: 0 1 0 0 A = matrix(GF(97), 4, 4,\ [86,1,6,68,34,24,8,35,15,36,68,42,27,1,78,26]) e1 = identity_matrix(GF(97),4)[0] U = matrix(A.transpose().maxspin(e1)).transpose() F = U^-1*A*U; F 0 0 83 0 0 77 1 0 20 0 1 10

sage: K.<x> = GF(97)[] sage: P = x^4-sum(F[i,3]*x^i for i in range(4)); P x4 + 87x3 + 77x2 + 20x + 14 sage: P == A.charpoly() True Dans le cas gnral (d n) les vecteurs itrs u, . . . , Ad1 u forment une base dun sous-espace I invariant sous laction de la matrice A (i.e., tel que AI I ). Comme chacun de ces vecteurs est obtenu cycliquement en appliquant la matrice A au vecteur prcdent, on lappelle aussi sous-espace cyclique. La dimension maximale dun tel sous-espace est le degr du polynme minimal de la matrice. Il est engendr par les itrs de Krylov du vecteur construit dans lexercice 30, quon notera u 1 . On lappelle le premier sous-espace invariant. Ce premier espace invariant admet un espace supplmentaire V . En calculant modulo le premier espace invariant, cest--dire en considrant que deux vecteurs sont gaux si leur dirence appartient au premier sous-espace invariant, on peut dnir un second sous-espace invariant pour les vecteurs dans cet espace supplmentaire ainsi quun polynme minimal qui est appel le second invariant de similitude. On obtiendra alors une relation de la forme : A Ku 1 Ku = Ku 2 1 Ku 2 C1 C2 ,

8.2. CALCULS SUR LES MATRICES

177

o 1 , 2 sont les deux premiers invariants de similitude, et Ku , Ku sont les 1 2 matrices de Krylov correspondant aux deux espaces cycliques engendrs par les vecteurs u 1 et u2 . . . . K u Itrativement, on construit une matrice K = Ku carre, inver1 k sible, telle que C1 .. K 1 AK = (8.2) . . Ck Comme chaque u i on en dduit que i | i1 i est annul par les j pour j pour tout 2 i k , autrement dit, la suite des i est totalement ordonne pour la division. On peut montrer que pour toute matrice, il existe une unique squence de polynmes invariants 1 , . . . , k . Ainsi la matrice diagonale par blocs Diag(C1 , . . . , Ck ), semblable la matrice A et rvlant ces polynmes, est une forme normale, appele forme rationnelle canonique, ou forme normale de Frobenius. Thorme (Forme normale de Frobenius).Toute matrice carre A dans un C1 .. corps est semblable une unique matrice F = , avec i+1 | i . Ck pour tout i < k . Daprs lquation (8.2), il apparat quon peut lire les bases des sous-espaces invariants sur la matrice de passage K . Remarque. Le thorme de Cayley-Hamilton nonce que le polynme caractristique annule sa matrice : A (A) = 0. Il se montre simplement, aprs lintroduction de cette forme normale de Frobenius. En eet, A (x) = =
i=1

det(xId A) = det(K ) det(xId F ) det(K 1 )


k k

det(xId Ci ) =
i=1

i (x).

Ainsi, le polynme minimal 1 est un diviseur du polynme caractristique, qui est donc annulateur de la matrice A. En Sage, on pourra calculer la forme normale de Frobenius dans Q de matrices coecients dans Z avec la mthode frobenius 1 : sage: A = matrix(ZZ,8,[[6,0,-2,4,0,0,0,-2],[14,-1,0,6,0,-1,-1,1],\ ....: [2,2,0,1,0,0,1,0],[-12,0,5,-8,0,0,0,4],\ ....: [0,4,0,0,0,0,4,0],[0,0,0,0,1,0,0,0],\ ....: [-14,2,0,-6,0,2,2,-1],[-4,0,2,-4,0,0,0,4]]) sage: A.frobenius()
1. Cest une lgre aberration de linterface actuelle du logiciel : alors que la forme de Frobenius est dnie pour toute matrice dans un corps, Sage ne permet de la calculer que pour les matrices coecients dans Z, en eectuant implicitement le plongement dans Q.

178 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 4 4 1 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 4 0 1 0 0 0 0 0 0 0 0 2

CHAP. 8. ALGBRE LINAIRE

On peut obtenir par ailleurs la liste de polynmes invariants en passant 1 en argument. Pour obtenir linformation sur les espaces invariants associs, on passe largument 2 qui produira la matrice de passage K . Elle fournit une base de lespace total, dcompose en la somme directe des espaces invariants. sage: A.frobenius(1) x4 x2 4x 4, x3 x2 4, x 2 sage: F,K = A.frobenius(2) sage: K 1 15 3 1 1 2 16 64 128 5 13 15 0 64 128 256 0 9 11 7 0 0 128 128 128 0 5 7 0 128 0 256 1 5 17 0 1 64 16 32 1 5 31 0 0 32 64 128 5 1 1 128 0 0 32 64 5 0 0 1 1 2 4 sage: K^-1*F*K == A True Ces rsultats sous-entendent que la matrice A coecients dans Z a t plonge dans son corps de fractions Q. Pour tudier laction de la matrice A sur le module libre Zn , et la dcomposition du module quelle engendre, on utilise la fonction decomposition ; cependant son tude dpasse le cadre de cet ouvrage. Facteurs invariants et invariants de similitude. Une proprit importante relie les invariants de similitude et les facteurs invariants vus dans la section 8.2.1. Thorme. Les invariants de similitude dune matrice A coecients dans un corps correspondent aux facteurs invariants de sa matrice caractristique xId A. La preuve de ce rsultat dpasse le cadre de cet ouvrage et nous nous contentons de lillustrer sur lexemple prcdent. sage: S.<x> = QQ[] sage: B = x*identity_matrix(8) - A

7 64 17 128 1 32 7 128 1 32 17 64 15 64 1 2

23 64 7 128
5 128 1 64 31 32 1 64 1 64 1 2

43 128 53 256 5 32 9 256 21 64 21 128 21 128 21 4

8.2. CALCULS SUR LES MATRICES sage: B.elementary_divisors() 1, 1, 1, 1, 1, x 2, x3 x2 4, x4 x2 4x 4 sage: A.frobenius(1) x4 x2 4x 4, x3 x2 4, x 2

179

Valeurs propres, vecteurs propres. Si lon dcompose le polynme minimal m1 ms en facteurs irrductibles, 1 = 1 . . . s , alors tous les facteurs invariants mi,1 mi,s scrivent sous la forme i = 1 . . . s , avec des multiplicits mi,j mj . On montre que lon peut alors trouver une transformation de similitude qui change chaque bloc compagnon Ci de la forme de Frobenius en un bloc diagonal Diag(Cmi,1 , . . . , Cmi,s ). Cette variante de la forme de Frobenius, que lon appelle s 1 forme intermdiaire, est toujours forme de blocs compagnons, mais cette fois correspondant chacun une puissance dun polynme irrductible. Cm1,1 1 .. . m1,s Cs m2,1 C 1 F = (8.3) .. . .. . Cmk,1 1 .. . Lorsquun facteur irrductible i est de degr 1 et de multiplicit 1, son bloc compagnon est une matrice 1 1 sur la diagonale et correspond ainsi une valeur propre. Lorsque le polynme minimal est scind et sans carr, la matrice est donc diagonalisable. On obtiendra les valeurs propres par la mthode eigenvalues. La liste des vecteurs propres droite (respectivement gauche) associs leur valeur propre et sa multiplicit est donne par la mthode eigenvectors_right (respectivement eigenvectors_left). Enn les espaces propres, ainsi que leur base de vecteurs propres, sont fournis par les mthodes eigenspaces_right et eigenspaces_left. sage: A = matrix(GF(7),4,[5,5,4,3,0,3,3,4,0,1,5,4,6,0,6,3]) sage: A.eigenvalues() [4, 1, 2, 2] sage: A.eigenvectors_right() [(4, [ (1, 5, 5, 1) ], 1), (1, [ (0, 1, 1, 4) ], 1), (2, [ (1, 3, 0, 1),

180

CHAP. 8. ALGBRE LINAIRE

(0, 0, 1, 1) ], 2)] sage: A.eigenspaces_right() [ (4, Vector space of degree 4 and dimension 1 over Finite Field of size 7 User basis matrix: [1 5 5 1]), (1, Vector space of degree 4 and dimension 1 over Finite Field of size 7 User basis matrix: [0 1 1 4]), (2, Vector space of degree 4 and dimension 2 over Finite Field of size 7 User basis matrix: [1 3 0 1] [0 0 1 1]) ] De faon plus concise, la mthode eigenmatrix_right renvoie le couple form par la matrice diagonalise et la matrice de ses vecteurs propres droite. (La mthode eigenmatrix_left fait de mme avec les vecteurs propres gauche.) sage: A.eigenmatrix_right() 1 0 4 0 0 0 0 1 0 0 5 1 0 0 2 0 , 5 1 1 4 0 0 0 2 1 3 0 1 0 0 1 1

Forme de Jordan. Lorsque le polynme minimal est scind mais ayant des facteurs avec des multiplicits suprieures 1, la forme intermdiaire (8.3) nest pas diagonale. On montre alors quil nexiste pas de transformation de similitude la rendant diagonale, la matrice initiale nest donc pas diagonalisable. On peut en revanche la trigonaliser, cest--dire la rendre triangulaire suprieure, telle que les valeurs propres apparaissent sur la diagonale. Parmi les direntes matrices triangulaires possibles, la plus rduite de toutes est la forme normale de Jordan. Un bloc de Jordan J,k , associ la valeur propre et lordre k , est la matrice J,k de dimensions k k donne par 1 .. . . .. J,k = . 1 Cette matrice joue un rle similaire celui des blocs compagnons, en rvlant plus prcisment la multiplicit dune valeur propre. En eet, son polynme caractristique vaut J,k = (X )k . De plus son polynme minimal vaut aussi

8.2. CALCULS SUR LES MATRICES

181

J,k = (X )k , en eet, il est ncessairement un multiple de P = X . Or la matrice 0 1 .. .. . . P (J,k ) = 0 1 0 est nilpotente dordre k , do J,k = J,k = (X )k . La forme normale de Jordan correspond la forme intermdiaire (8.3), o les blocs compagnons des m j i,j ont t remplacs par les blocs de Jordan Jj ,mi,j (on rappelle que, le polynme minimal tant scind, les j scrivent sous la forme X j ). Ainsi lorsque son polynme minimal est scind, toute matrice est semblable une matrice de Jordan de la forme J1 ,m1,1 .. . Js ,m1,s J1 ,m2,1 .. (8.4) J = . . .. . J1 ,mk,1 .. . En particulier, dans tout corps algbriquement clos, comme C, la forme de Jordan dune matrice est toujours dnie. En Sage, le constructeur jordan_block(a,k) produit le bloc de Jordan Ja,k . On obtiendra la forme normale de Jordan par la mthode jordan_form. Loption transformation=True permet dobtenir la matrice de transformation U telle que U 1 AU est sous forme de Jordan. sage: sage: 3 0 0 0 A = matrix(ZZ,4,[3,-1,0,-1,0,2,0,-1,1,-1,2,0,1,-1,-1,3]) A.jordan_form() 0 0 0 3 0 0 0 2 1 0 0 2

sage: J,U = A.jordan_form(transformation=True) sage: U^-1*A*U == J True La forme de Jordan est unique une permutation des blocs de Jordan prs. Selon les ouvrages, on peut imposer ou non que leur ordre dapparition sur la diagonale respecte lordre des polynmes invariants, comme dans lquation (8.4). On remarque dans lexemple ci-dessus que Sage ne respecte pas cet ordre, puisque le premier polynme invariant (le polynme minimal) est le polynme (X 3)(X 2)2 .

182

CHAP. 8. ALGBRE LINAIRE

Forme normale primaire. Pour tre complet, il faut mentionner une dernire forme normale qui gnralise la forme de Jordan dans le cas quelconque o le polynme minimal nest pas scind. Pour un polynme irrductible P de degr k , on dnit le bloc de Jordan de multiplicit m comme la matrice JP,m de dimension km km vriant CP B .. .. . . JP,m = CP B CP o B est la matrice k k dont le seul coecient non nul est Bk,1 = 1, et CP est la matrice compagnon associe au polynme P (8.2.3). On note que si P = X , on retrouve la notion de bloc de Jordan associ la valeur propre . On montre de faon similaire que les polynmes minimal et caractristique de cette matrice valent JP,m = JP,m = P m . Ainsi on montre quil existe une transformation de similitude remplaant chaque bloc compagnon Cmi,j de la forme intermdiaire (8.3) en un bloc de Jordan Jj ,mi,j . La matrice ainsi forme est appele la forme primaire ou encore la deuxime forme de Frobenius. Il sagit l encore dune forme normale, cest--dire unique une permutation des blocs diagonaux prs. Lunicit de ces formes normales permet en particulier de tester si deux matrices sont semblables, et par la mme occasion de produire une matrice de passage entre lune et lautre.
Exercice 31. crire un programme qui dtermine si deux matrices A et B sont semblables et renvoie la matrice U de passage telle que A = U 1 BU (on pourra renvoyer None dans le cas o les matrices ne sont pas semblables).
j

Systmes polynomiaux
Ce chapitre prolonge les deux prcdents. Les objets sont des systmes dquations plusieurs variables, comme ceux du chapitre 8. Ces quations, dans la ligne du chapitre 7, sont polynomiales. Par rapport aux polynmes une seule indtermine, ceux plusieurs indtermines prsentent une grande richesse mathmatique mais aussi des dicults nouvelles, lies notamment au fait que lanneau K [x1 , . . . , xn ] nest pas principal. La thorie des bases de Grbner fournit des outils pour contourner cette limitation. Au nal, on dispose de mthodes puissantes pour tudier les systmes polynomiaux, avec dinnombrables applications qui couvrent des domaines varis. Une bonne partie du chapitre ne prsuppose que des connaissances de base sur les polynmes plusieurs indtermines. Certains passages sont cependant du niveau dun cours dalgbre commutative de L3 ou M1. Pour une introduction moins allusive et en franais la thorie mathmatique des systmes polynomiaux, accessible au niveau licence, le lecteur pourra se reporter au chapitre [FSED09] de Faugre et Safey El Din. On trouvera un traitement plus avanc dans le livre de Elkadi et Mourrain [EM07]. Enn, en anglais cette fois, le livre de Cox, Little et OShea [CLO07] est la fois accessible et fort complet.

9.1
9.1.1

Polynmes plusieurs indtermines


Les anneaux A[x1 , . . . , xn ]

Nous nous intressons ici aux polynmes plusieurs indtermines, dits aussi anglicisme commun dans le domaine du calcul formel multivaris. Comme pour les autres structures algbriques disponibles dans Sage, avant de pouvoir construire des polynmes, il nous faut dnir une famille dindtermines

184

CHAP. 9. SYSTMES POLYNOMIAUX

vivant toutes dans un mme anneau. La syntaxe est pratiquement la mme quen une variable (cf. 7.1.1) : sage: R = PolynomialRing(QQ, x,y,z ) sage: x,y,z = R.gens() # donne le n-uplet des indtermines ou en abrg : sage: R.<x,y,z> = QQ[] (ou encore R = QQ[ x,y,z ]). Le constructeur PolynomialRing permet aussi de crer une famille dindtermines de mme nom, avec des indices entiers : sage: R = PolynomialRing(QQ, x , 10) Placer le n-uplet renvoy par gens lui-mme dans la variable x permet alors daccder naturellement lindtermine xi par x[i] : sage: x = R.gens() sage: sum(x[i] for i in xrange(5)) x0 + x1 + x2 + x3 + x4 Lordre des variables est signicatif. La comparaison par == de QQ[ x,y ] et QQ[ y,x ] renvoie faux, et un mme polynme vu comme lment de lun ou de lautre sache diremment : sage: def test_poly(ring, deg=3): ....: monomials = Subsets( ....: flatten([(x,)*deg for x in (1,) + ring.gens()]), ....: deg, submultiset=True) ....: return add(mul(m) for m in monomials) sage: x^3 + sage: y^3 + sage: True test_poly(QQ[ x^2*y + x*y^2 test_poly(QQ[ y^2*x + y*x^2 test_poly(QQ[ x,y ]) + y^3 + x^2 + x*y + y^2 + x + y + 1 y,x ]) + x^3 + y^2 + y*x + x^2 + y + x + 1 x,y ]) == test_poly(QQ[ y,x ])

Exercice 32. Expliquer le fonctionnement de la fonction test_poly dnie cidessus.

Plus largement, crire les polynmes sous forme canonique demande de choisir une faon dordonner les termes de la somme. Les trier par degr simpose naturellement quand il ny a quune indtermine, mais dans le cas des polynmes multivaris, aucun ordre sur les monmes ne couvre tous les besoins. Sage permet donc de choisir entre plusieurs ordres, grce loption order de PolynomialRing. Par exemple, lordre not deglex range les monmes par degr total, puis par ordre lexicographique des degrs des indtermines en cas dgalit : sage: test_poly(PolynomialRing(QQ, x,y , order= deglex )) x^3 + x^2*y + x*y^2 + y^3 + x^2 + x*y + y^2 + x + y + 1

9.1. POLYNMES PLUSIEURS INDTERMINES

185

Construction danneaux de polynmes anneau A[x, y ] anneau A[x0 , . . . , xn1 ] anneau A[x0 , x1 , . . . , y0 , y1 , . . . ] n-uplet des gnrateurs 1er, 2e... gnrateur indtermines de R = A[x, y ][z ][. . . ] conversion A[x1 , x2 , y ] A[x1 , x2 ][y ] PolynomialRing(A, x,y ) ou A[ x,y ] PolynomialRing(A, x , n) InfinitePolynomialRing(A, [ x , y ]) R.gens() R.0, R.1, ... R.variable_names_recursive() p.polynomial(y)

Accs aux coecients support, coecients non nuls coecient dun monme degr(s) total, en x, partiels monme/coecient/terme de tte p.exponents(), p.coefficients() p[x^2*y] ou p[2,1] p.degree(), p.degree(x), p.degrees() p.lm(), p.lc(), p.lt()

Oprations de base transformation des coecients drive partielle d/dx valuation p(x, y )|x=a,y=b homognisation dnominateur commun (p Q[x, y, . . . ]) p.map_coefficients(f) p.derivative(x) p.subs(x=a, y=b) ou p(x=a, y=b) p.homogenize() p.denominator()

Tableau 9.1 Polynmes plusieurs indtermines.

Les principaux ordres disponibles sont dcrits plus en dtail en 9.3.1. Nous verrons que le choix de lordre nest pas quune question dachage, mais exerce une inuence sur certains calculs.
Exercice 33. Dnir lanneau Q[x2 , x3 , . . . , x37 ] dont les indtermines sont indexes par les nombres premiers infrieurs 40, ainsi que des variables x2, x3, . . ., x37 pour accder aux indtermines.

Il peut enn savrer utile, dans quelques cas, de manipuler des polynmes plusieurs indtermines en reprsentation rcursive, cest--dire comme lments dun anneau de polynmes coecients eux-mmes polynomiaux (voir encadr page 134).

9.1.2

Polynmes

Tout comme les polynmes en une variable sont de classe Polynomial, ceux en plusieurs variables (dans les anneaux avec un nombre ni dindtermines) sont de classe MPolynomial 1 . Pour les anneaux de base usuels (comme Z, Q ou Fq ), ils sappuient sur le logiciel Singular, un systme de calcul formel spcialis dans les calculs rapides sur les polynmes. Dans les autres cas, Sage se rabat sur une implmentation gnrique beaucoup plus lente.
1. Contrairement Polynomial, cette classe nest pas accessible directement depuis la ligne de commande : il faut utiliser son nom complet. Par exemple, on peut tester si un objet est de type polynme multivari par isinstance(p, sage.rings.polynomial.multi_polynomial. MPolynomial).

186 Les anneaux A[(xn , yn , . . . )nN ]

CHAP. 9. SYSTMES POLYNOMIAUX

Il arrive que lon ne sache pas, au dbut dun calcul, combien de variables seront ncessaires. Cela rend lutilisation de PolynomialRing assez pnible : il faut commencer calculer dans un premier domaine, puis ltendre et convertir tous les lments chaque fois que lon souhaite introduire une nouvelle variable. Les anneaux de polynmes en une innit dindtermines orent une structure de donnes plus souple. Leurs lments peuvent contenir des variables prises dans une ou plusieurs familles innies dindtermines. Chaque gnrateur de lanneau correspond non pas une seule variable, mais une famille de variables indexes par les entiers naturels : sage: R.<x,y> = InfinitePolynomialRing(ZZ, order= lex ) sage: p = mul(x[k] - y[k] for k in range(2)); p x_1*x_0 - x_1*y_0 - x_0*y_1 + y_1*y_0 sage: p + x[100] x_100 + x_1*x_0 - x_1*y_0 - x_0*y_1 + y_1*y_0 On revient un anneau de polynmes PolynomialRing usuel grce la mthode polynomial, qui renvoie limage dun lment dun Infinite PolynomialRing dans un anneau susamment grand pour contenir tous les lments de lanneau une innit de variables manipuls jusque-l. Lanneau obtenu nest gnralement pas le plus petit avec cette proprit. En contrepartie de cette souplesse, ces anneaux sont moins ecaces que les anneaux PolynomialRing. Par ailleurs, leurs idaux ne se substituent pas ceux des anneaux de polynmes usuels pour les calculs sur les systmes polynomiaux, sujet central du prsent chapitre.

Les polynmes plusieurs indtermines sont toujours cods en reprsentation creuse 2 . Pourquoi ce choix ? Un polynme dense n variables de degr total d d compte n+ monmes : pour n = d = 10, cela fait 184 756 coecients stocker ! d Il est donc trs dicile de manipuler de gros polynmes denses comme on le fait en une variable. Par ailleurs, mme quand les polynmes sont denses, les supports (les positions des monmes non nuls) rencontrs en pratique ont des formes varies. Or, si par exemple un polynme n variables dense jusquau degr total d 1 est reprsent par un tableau rectangulaire d d, pour d grand, seul un coecient sur n! environ est non nul. Au contraire, la reprsentation creuse par dictionnaire sadapte la forme du support ainsi dailleurs qu lordre sur les monmes.
2. La reprsentation rcursive (voir encadr page 134) fournit cependant une forme de polynmes multivaris partiellement denses. Dans la reprsentation en mmoire dun polynme de A[x][y ], chaque coecient de y k occupe (en rgle gnrale) un espace proportionnel son degr en x, quoi il faut ajouter une place proportionnelle au degr en y pour le polynme lui-mme.

9.1. POLYNMES PLUSIEURS INDTERMINES

187

9.1.3

Oprations de base

Fixons un peu de terminologie. Soit R = A[x1 , . . . , xn ] un anneau de polynmes. n 1 2 On appelle monme une expression de la forme x 1 x2 xn , cest--dire un produit dindtermines, et on le note en abrg x . Le n-uplet dentiers = (1 , 2 , . . . , n ) est lexposant du monme x . Un terme est un monme multipli par un lment de A, son coecient. Puisque la faon dordonner leurs termes nest pas unique, les lments de R nont pas, en tant quobjets mathmatiques, de coecient dominant. Mais une fois un ordre choisi la construction de lanneau, il est possible et utile de dnir un monme de tte, le plus gauche dans lordre dcriture. Les mthodes lm (pour leading monomial ), lc (leading coecient ) et lt (leading term ) dun polynme plusieurs indtermines renvoient respectivement son monme de tte, le coecient de celui-ci, et le terme quils constituent : sage: R.<x,y,z> = QQ[] sage: p = 7*y^2*x^2 + 3*y*x^2 + 2*y*z + x^3 + 6 sage: p.lt() 7*x^2*y^2 Les oprations arithmtiques +, - et *, de mme que les mthodes dict, coefficients, et bien dautres, sutilisent comme leurs analogues en une seule variable. Parmi les petites dirences, loprateur crochets [] dextraction dun coecient accepte comme paramtre soit un monme, soit son exposant : sage: p[x^2*y] == p[(2,1,0)] == p[2,1,0] == 3 True De mme, lvaluation ncessite de donner des valeurs toutes les variables ou de prciser celles substituer : sage: p(0, 3, -1) 0 sage: p.subs(x = 1, z = x^2+1) 2*x^2*y + 7*y^2 + 5*y + 7 La mthode subs peut aussi substituer un nombre quelconque de variables en une fois, voir sa documentation pour des exemples dusages avancs. Le degr se dcline quant lui en degr total et degrs partiels : sage: print "total={d} (en x)={dx} partiels={ds}"\ ....: .format(d=p.degree(), dx=p.degree(x), ds=p.degrees()) total=4 (en x)=3 partiels=(3, 2, 1) Dautres constructions subissent des adaptations videntes, par exemple, la mthode derivative prend en paramtre la variable par rapport laquelle driver.

9.1.4

Arithmtique

Au-del des oprations syntaxiques et arithmtiques lmentaires, les fonctions disponibles dans Sage sont en gnral limites aux polynmes sur un corps, et

188

CHAP. 9. SYSTMES POLYNOMIAUX

parfois sur Z ou Z/nZ. Pour la suite de ce chapitre, et sauf mention contraire explicite, nous nous placerons sur un corps. La division euclidienne des polynmes na de sens quen une variable. En Sage, la mthode quo_rem et les oprateurs associs // et % restent pourtant dnis pour les polynmes multivaris. La division avec reste quils calculent vrie (p//q)*q + (p%q) == p et concide avec la division euclidienne lorsque p et q ne dpendent que dune variable, mais ce nest pas elle-mme une division euclidienne et elle na rien de canonique. Elle savre tout de mme utile lorsque la division est exacte ou lorsque le diviseur est un monme. Dans les autres cas, on prfrera quo_rem et ses variantes la mthode mod, dcrite en 9.2.3, qui rduit un polynme modulo un idal en tenant compte du choix dordre monomial de lanneau : sage: sage: ....: (-x + sage: 2*y^2 R.<x,y> = QQ[]; p = x^2 + y^2; q = x + y print("({quo})*({q}) + ({rem}) == {p}".format( \ quo=p//q, q=q, rem=p%q, p=p//q*q+p%q)) y)*(x + y) + (2*x^2) == x^2 + y^2 p.mod(q) # n est PAS quivalent p%q

Les mthodes divides, gcd, lcm ou encore factor ont le mme sens quen une seule variable. Faute de division euclidienne, les premires ne sont pas disponibles pour des coecients de nimporte quel type ; mais elles fonctionnent sur divers corps usuels, par exemple les corps de nombres : sage: R.<x,y> = QQ[exp(2*I*pi/5)][] sage: (x^10 + y^5).gcd(x^4 - y^2) x^2 + y sage: (x^10 + y^5).factor() (x^2 + (a^2)*y) * (x^2 + (a)*y) * (x^2 + (a^3)*y) * (x^2 + (-a^3 - a^2 - a - 1)*y) * (x^2 + y)

9.2

Systmes polynomiaux et idaux

Nous abordons prsent le sujet central de ce chapitre. Les sections 9.2.1 et 9.2.2 orent un panorama des manires de trouver et de comprendre les solutions dun systme dquations polynomiales avec laide de Sage. La section 9.2.3 est consacre aux idaux associs ces systmes. Les sections suivantes reviennent de faon plus dtaille sur les outils dlimination algbrique et de rsolution de systmes.

9.2.1

Un premier exemple

Considrons une variante du systme polynomial de la section 2.2, 2 x yz = 18 xy 3 z = 24 xyz 4 = 6.

(9.1)

9.2. SYSTMES POLYNOMIAUX ET IDAUX

189

Oprations sur les polynmes plusieurs indtermines divisibilit p | q factorisation pgcd, ppcm test p sans facteur carr rsultant Resx (p, q ) p.divides(q) p.factor() p.gcd(q), p.lcm(q) p.is_squarefree() p.resultant(q, x)

Tableau 9.2 Arithmtique.

La fonction solve() de Sage ne nous avait permis de trouver les solutions que numriquement. Voyons maintenant comment Sage parvient rsoudre le systme de faon exacte, et, avec un peu daide de lutilisateur, trouver des formes closes simples pour toutes les solutions 3 . numrer les solutions. Commenons par traduire le problme en termes plus algbriques, en construisant lidal de Q[x, y, z ] engendr par les quations : sage: R.<x,y,z> = QQ[] sage: J = R.ideal(x^2 * y * z - 18, ....: x * y^3 * z - 24, ....: x * y * z^4 - 6) Comme nous le verrons dans la section 9.2.3, la commande suivante nous permet de vrier que lidal J est de dimension zro, cest--dire que le systme (9.1) possde un nombre ni de solutions dans C3 : sage: J.dimension() 0 Ceci tabli, le premier rexe est dutiliser la mthode variety, qui calcule toutes les solutions du systme. Sans paramtre, elle donne les solutions dans le corps de base de lanneau de polynmes : sage: J.variety() [{y: 2, z: 1, x: 3}] La solution (3, 2, 1) dj trouve est donc lunique solution rationnelle. Ltape suivante est dnumrer les solutions complexes. An de le faire de faon exacte, nous travaillons dans le corps des nombres algbriques. Nous retrouvons les 17 solutions : sage: V = J.variety(QQbar) sage: len(V) 17 Explicitement, les trois dernires ont lallure suivante : sage: V[-3:]
3. Le propos tant dillustrer les outils de rsolution de systmes polynomiaux, nous ngligeons la possibilit de ramener (9.1) des quations linaires en passant au logarithme !

190

CHAP. 9. SYSTMES POLYNOMIAUX

[{z: 0.9324722294043558? - 0.3612416661871530?*I, y: -1.700434271459229? + 1.052864325754712?*I, x: 1.337215067329615? - 2.685489874065187?*I}, {z: 0.9324722294043558? + 0.3612416661871530?*I, y: -1.700434271459229? - 1.052864325754712?*I, x: 1.337215067329615? + 2.685489874065187?*I}, {z: 1, y: 2, x: 3}] Chaque point solution est donn par un dictionnaire dont les cls sont les gnrateurs de QQbar[ x,y,z ] (et non de QQ[ x,y,z ], do un petit dtour pour y accder ci-dessous), et les valeurs associes, les coordonnes du point. Hors celle de la solution rationnelle identie prcdemment, les premires coordonnes sont toutes des nombres algbriques de degr 16 : sage: (xx, yy, zz) = QQbar[ x,y,z ].gens() sage: [ pt[xx].degree() for pt in V ] [16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 1] Calculer avec les solutions et identier leur structure. Nous avons obtenu une reprsentation exacte des solutions complexes du systme (9.1), mais cette reprsentation nest pas franchement explicite. Ce nest pas grave : disposer des coordonnes comme lments de QQbar sut poursuivre les calculs exacts dessus. Par exemple, il nest pas dicile de voir que si (x, y, z ) est solution du systme (9.1), alors (|x|, |y |, |z |) aussi. Construisons lensemble des (|x|, |y |, |z |) pour (x, y, z ) solution : sage: Set(tuple(abs(pt[i]) for i in (xx,yy,zz)) for pt in V) {(3, 2, 1)} Toutes les valeurs de x (resp. y , z ) sont donc de mme module. Mieux, on peut vrier que la substitution (x, y, z ) (x, 9 y, 6 z ) o = e2i/17 (9.2)

laisse le systme invariant. En particulier, les dernires coordonnes des solutions sont exactement les racines dix-septimes de lunit, ce dont on sassure nouveau grce la possibilit de calculer exactement sur les nombres algbriques : sage: w = QQbar.zeta(17); w # racine primitive de 1 0.9324722294043558? + 0.3612416661871530?*I sage: Set(pt[zz] for pt in V) == Set(w^i for i in range(17)) True Les solutions du systme sont donc les triplets (3, 2 9 , 6 ) pour 17 = 1. Voil qui est plus parlant !
Exercice 34. Chercher les solutions relles (et non seulement rationnelles) de (9.1), pour vrier directement quil ny a que (3, 2, 1). Retrouver la substitution (9.2), y compris la valeur 17 pour lordre de comme racine de lunit, par un calcul avec Sage.

9.2. SYSTMES POLYNOMIAUX ET IDAUX

191

Nous aurions pu arriver au mme rsultat en examinant les polynmes minimaux des coordonnes des points de V . On observe en eet quune mme coordonne a le mme polynme minimal pour tous les points solutions autres que (3, 2, 1). Le polynme minimal commun de leur troisime coordonne nest autre que le polynme cyclotomique 17 : sage: set(pt[zz].minpoly() for pt in V[:-1]) set([x^16 + x^15 + x^14 + x^13 + x^12 + x^11 + x^10 + x^9 + x^8 + x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x + 1]) Ceux des premire et deuxime coordonnes sont respectivement 316 17 (x/3) et 216 17 (x/2). Des formules closes. Une expression explicite des solutions est donc possible en ayant recours la notation exponentielle des complexes : sage: def polar_form(z): ....: rho = z.abs(); rho.simplify() ....: theta = 2 * pi * z.rational_argument() ....: return (SR(rho) * exp(I*theta)) sage: [tuple(polar_form(pt[i]) for i in [xx,yy,zz]) for pt in V[-3:]] [(3*e^(-6/17*I*pi), 2*e^(14/17*I*pi), e^(-2/17*I*pi)), (3*e^(6/17*I*pi), 2*e^(-14/17*I*pi), e^(2/17*I*pi)), (3, 2, 1)] Naturellement, si nous avions eu lide dcrire les lments de V en notation exponentielle, cela aurait su conclure. Simplier le systme. Une approche dirente est possible. Plutt que de chercher les solutions, essayons de calculer une forme plus simple du systme luimme. Les outils fondamentaux quore Sage pour ce faire sont la dcomposition triangulaire et les bases de Grbner. Nous verrons plus loin ce quils calculent exactement ; essayons dj de les utiliser sur cet exemple : sage: J.triangular_decomposition() [Ideal (z^17 - 1, y - 2*z^10, x - 3*z^3) of Multivariate Polynomial Ring in x, y, z over Rational Field] sage: J.transformed_basis() [z^17 - 1, -2*z^10 + y, -3*z^3 + x] On obtient dans un cas comme dans lautre le systme quivalent z 17 = 1 y = 2z 10 x = 3z 3 ,

soit V = {(3 3 , 2 10 , ) | 17 = 1}. Cest un reparamtrage immdiat de la description compacte des solutions trouve manuellement plus haut.

192

CHAP. 9. SYSTMES POLYNOMIAUX

9.2.2

Quest-ce que rsoudre ?

Un systme polynomial qui possde des solutions en a souvent une innit. Lquation toute simple x2 y = 0 admet une innit de solutions dans Q2 , sans parler de R2 ou C2 . Il nest donc pas question de les numrer. Le mieux quon puisse faire est dcrire lensemble des solutions aussi explicitement que possible , cest--dire en calculer une reprsentation dont on puisse facilement extraire des informations intressantes. La situation est analogue celle des systmes linaires, pour lesquels (dans le cas homogne) une base du noyau du systme est une bonne description de lespace des solutions. Dans le cas particulier o les solutions sont en nombre ni il devient possible de les calculer . Mais mme dans ce cas, cherche-t-on numrer les solutions dans Q, ou encore dans un corps ni Fq ? trouver des approximations numriques des solutions relles ou complexes ? Ou encore, comme dans lexemple de la section prcdente, reprsenter ces dernires laide de nombres algbriques, cest--dire par exemple calculer les polynmes minimaux de leurs coordonnes ? Ce mme exemple illustre que dautres reprsentations de lensemble des solutions peuvent tre bien plus parlantes quune simple liste de points, surtout quand les solutions sont nombreuses. Ainsi, les numrer nest pas forcment la chose la plus pertinente faire mme quand cest possible. In ne, on ne cherche pas tant calculer les solutions qu calculer avec les solutions, pour en dduire ensuite, suivant le problme, les informations auxquelles on sintresse vraiment. La suite de ce chapitre explore dirents outils utiles pour ce faire.

9.2.3

Idaux et systmes

Si s polynmes p1 , . . . , ps K [x] sannulent en un point x coordonnes dans K ou dans une extension de K , tout lment de lidal quils engendrent sannule aussi en x. Il est donc naturel dassocier au systme polynomial p1 (x) = p2 (x) = = ps (x) = 0 lidal J = p1 , . . . , ps K [x]. Deux systmes polynomiaux qui engendrent le mme idal sont quivalents au sens o ils ont les mmes solutions. Si L est un corps contenant K , on appelle sous-varit algbrique de Ln associe J lensemble VL (J ) = {x Ln | p J, p(x) = 0} = {x Ln | p1 (x) = = ps (x) = 0} des solutions coordonnes dans L du systme. Des idaux dirents peuvent avoir la mme varit associe. Par exemple, les quations x = 0 et x2 = 0 admettent la mme unique solution dans C, alors que lon a x2 x . Ce que lidal engendr par un systme polynomial capture est plutt la notion intuitive de solutions avec multiplicits . Ainsi, les deux systmes suivants expriment chacun lintersection du cercle unit et dune courbe dquation x2 y 2 = 1, runion de deux hyperboles quila-

9.2. SYSTMES POLYNOMIAUX ET IDAUX

193

1 0.5 -1 -0.5 -0.5 -1


(a) (S1 )

1 0.5 0.5 1 -1 -0.5 -0.5 -1


(b) (S2 )

0.5 1

sage: opts = { axes :True, gridlines :True, frame :False, ....: aspect_ratio :1, axes_pad :0, fontsize :8, ....: xmin :-1.3, xmax :1.3, ymin :-1.3, ymax :1.3} sage: (ideal(J.0).plot() + ideal(J.1).plot()).show(**opts)
Figure 9.1 Intersection de deux courbes planes, voir systmes (9.3).

tres (voir gure 9.1) : (S1 ) x2 + y 2 = 1 16 x2 y 2 = 1 (S2 ) x2 + y 2 = 1 4 x2 y 2 = 1. (9.3)

Le systme (S1 ) possde huit solutions dans C, toutes coordonnes relles. Quand on le dforme en (S2 ) en faisant varier le paramtre , les deux solutions sur chaque branche de lhyperbole se rapprochent jusqu tre confondues. Le systme (S2 ) na plus que quatre solutions, chacune en un certain sens de multiplicit deux . En diminuant encore , il ny aurait plus de solution relle, mais huit solutions complexes. Calcul modulo un idal. Comme dans le cas des polynmes une seule indtermine, Sage permet de dnir des idaux 4 J K [x], des anneaux quotients K [x]/J , et de calculer naturellement avec les lments de ces anneaux quotients. Lidal J1 associ (S1 ) se construit par : sage: R.<x,y> = QQ[] sage: J = R.ideal(x^2 + y^2 - 1, 16*x^2*y^2 - 1) On peut ensuite eectuer le quotient de K [x] par J1 , y projeter des polynmes, calculer avec les classes dquivalence modulo J1 , et les remonter en des reprsentants :
4. Attention : les objets InfinitePolynomialRing ont aussi une mthode ideal, mais celle-ci na pas le mme sens que pour les anneaux de polynmes usuels. (Un idal quelconque de K [(xn )nN ] na aucune raison dtre niment engendr !) La suite du chapitre ne sapplique pas ces objets.

194 sage: ybar2 = R.quo(J)(y^2) sage: [ybar2^i for i in range(3)] [1, ybar^2, ybar^2 - 1/16] sage: ((ybar2 + 1)^2).lift() 3*y^2 + 15/16

CHAP. 9. SYSTMES POLYNOMIAUX

Il y a ici une dicult thorique. Les lments de K [x]/J sont reprsents sous forme normale, ce qui est ncessaire pour pouvoir tester lgalit de deux lments. Or cette forme normale nest pas vidente dnir, pour la raison dj mentionne en 9.1.4 : la division dun reprsentant dune classe dquivalence p + J par un gnrateur principal de J , utilise pour calculer dans K [x]/J , na pas danalogue direct en plusieurs variables. Bornons-nous pour linstant admettre quil existe nanmoins une forme normale, qui dpend de lordre sur les lments choisi la construction de lanneau et repose sur un systme de gnrateurs de J particulier appel base de Grbner. La section 9.3 la n de ce chapitre est consacre dnir les bases de Grbner et montrer comment on peut les utiliser dans les calculs. Sage calcule automatiquement des bases de Grbner lorsque cest ncessaire ; mais ces calculs sont parfois trs coteux, en particulier quand le nombre de variables est grand, de sorte que calculer dans un anneau quotient peut tre dicile. Revenons lutilisation de Sage. Lorsque p J , la commande p.lift(J) crit p comme combinaison linaire coecients polynomiaux des gnrateurs de J : sage: u = (16*y^4 - 16*y^2 + 1).lift(J); u [16*y^2, -1] sage: u[0]*J.0 + u[1]*J.1 16*y^4 - 16*y^2 + 1 Pour un polynme quelconque, lexpression p.mod(J) donne la forme normale de p modulo J , vue comme lment de K [x] : sage: (y^4).mod(J) y^2 - 1/16 Attention : si J.reduce(p) est quivalent p.mod(J), en revanche, la variante p.reduce([p1, p2, ...]) renvoie un reprsentant de p + J qui nest pas forcment la forme normale (voir 9.3.2) : sage: (y^4).reduce([x^2 + y^2 - 1, 16*x^2*y^2 - 1]) y^4 En combinant p.mod(J) et p.lift(J), on peut dcomposer un polynme p en une combinaison linaire coecients polynomiaux de gnrateurs de J , plus un reste qui est nul si et seulement si p J . Radical dun idal et solutions. Le point essentiel de la correspondance entre idaux et varits est le thorme des zros de Hilbert, ou Nullstellensatz . une clture algbrique de K . Soit K n lenThorme (Nullstellensatz ). Soient p1 , . . . , ps K [x], et soit Z K semble des zros communs des pi . Un polynme p K[x] sannule identiquement sur Z si et seulement sil existe un entier k tel que pk p1 , . . . , ps .

9.2. SYSTMES POLYNOMIAUX ET IDAUX

195

Idaux idal p1 , p2 R somme, produit, puissance intersection I J quotient I : J = {p | pJ I} radical J rduction modulo J section de R R/J anneau quotient R/J idal homognis R.ideal(p1, p2) ou (p1, p2)*R I + J, I * J, I^k I.intersection(J) I.quotient(J) J.radical() J.reduce(p) ou p.mod(J) p.lift(J) R.quo(J) J.homogenize()

Quelques idaux prdnis irrelevant ideal x1 , . . . , xn idal jacobien p/xi i racines cycliques (9.11) quations de corps xq i = xi R.irrelevant_ideal() p.jacobian_ideal() sage.rings.ideal.Cyclic(R) sage.rings.ideal.FieldIdeal(GF(q)[ x1,x2 ])

Tableau 9.3 Idaux.

Ce rsultat donne un critre algbrique pour tester si un systme polynomial admet des solutions. Le polynme constant 1 sannule identiquement sur Z si et seulement si Z est vide, donc le systme p1 (x) = = ps (x) = 0 a des solutions si et seulement si lidal p1 , . . . , ps ne contient pas 1. Par exemple, les dans K cercles de rayon 1 centrs en (0, 0) et en (4, 0) ont une intersection complexe : sage: 1 in ideal(x^2+y^2-1, (x-4)^2+y^2-1) False En revanche, en ajoutant la condition x = y , le systme na plus de solution. On peut donner une preuve triviale vrier quil est alors contradictoire en exhibant comme certicat une combinaison des quations qui se rduit 1 = 0 si elles sont satisfaites. Le calcul sage: R(1).lift(ideal(x^2+y^2-1, (x-4)^2+y^2-1, x-y)) [-1/28*y + 1/14, 1/28*y + 1/14, -1/7*x + 1/7*y + 4/7] fournit dans notre cas la relation 1 (y + 2)(x2 + y 2 1) + (y + 2) (x 4)2 + y 2 1 28 + (4x + 4y + 16)(x y ) = 1. En termes didaux, le Nullstellensatz arme que lensemble des polynmes qui sannulent identiquement sur la varit VK (J ) associe un idal J est le radical de cet idal, dni par J = {p K [x] | k N, pk J }. On a V ( J ) = V (J )

196

CHAP. 9. SYSTMES POLYNOMIAUX

mais intuitivement, le passage au radical oublie les multiplicits . Ainsi, lidal J1 est son propre radical (on dit quil est radical), tandis que lidal J2 associ (S2 ) vrie J2 J2 : sage: J1 = (x^2 + y^2 - 1, 16*x^2*y^2 - 1)*R sage: J2 = (x^2 + y^2 - 1, 4*x^2*y^2 - 1)*R sage: J1.radical() == J1 True sage: J2.radical() Ideal (2*y^2 - 1, 2*x^2 - 1) of Multivariate Polynomial Ring in x, y over Rational Field sage: 2*y^2 - 1 in J2 False Systmes, idaux et cryptographie Des modules spciques, sage.rings.polynomial.multi_polynomial_ sequence et sage.crypto.mq, orent des outils pour manipuler les systmes polynomiaux en tenant compte de la forme particulire des quations, et non seulement de lidal quelles engendrent. Cela est utile pour travailler avec de gros systmes structurs, comme ceux issus de la cryptographie. Le module sage.crypto dnit aussi plusieurs systmes polynomiaux associs des constructions cryptographiques classiques.

Oprations sur les idaux. Il est aussi possible de calculer sur les idaux eux-mmes. Rappelons que la somme de deux idaux est dnie par I + J = {p + q | p I et q J } = I J . Elle correspond gomtriquement lintersection des varits : V (I + J ) = V (I ) V (J ). Ainsi, lidal J1 associ (S1 ) scrit comme la somme de C = x2 + y 2 1 et H = 16 x2 y 2 1 , qui dnissent respectivement le cercle et la double hyperbole. En Sage : sage: C = ideal(x^2 + y^2 - 1); H = ideal(16*x^2*y^2 - 1) sage: C + H == J1 True Ce test dgalit sappuie lui aussi sur un calcul de base de Grbner. De mme, lintersection, le produit et le quotient didaux satisfont I J = {p | p I et p J } I J = pq | p I, q J I : J = {p | pJ I } V (I J ) = V (I ) V (J ) V (I J ) = V (I ) V (J ) V (I : J ) = V (I ) \ V (J )

9.2. SYSTMES POLYNOMIAUX ET IDAUX

197

dsigne ici et se calculent comme indiqu dans le tableau 9.3. La notation X la fermeture de Zariski de X , cest--dire la plus petite sous-varit algbrique contenant X . Par exemple, la courbe de la gure 9.1a est lensemble des zros des polynmes de C H , et le quotient (C H ) : 4xy 1 correspond la runion du cercle avec une des deux hyperboles : sage: CH = C.intersection(H).quotient(ideal(4*x*y-1)); CH Ideal (4*x^3*y + 4*x*y^3 + x^2 - 4*x*y + y^2 - 1) of Multivariate Polynomial Ring in x, y over Rational Field sage: CH.gen(0).factor() (4*x*y + 1) * (x^2 + y^2 - 1) En revanche, la courbe obtenue en retirant V (H ) un nombre ni de points nest pas une sous-varit algbrique, de sorte que : sage: H.quotient(C) == H True Dimension. tout idal de J K [x] est aussi associe une dimension qui correspond intuitivement la dimension maximale des composantes de la varit V (J ) sur un corps algbriquement clos 5 . On a par exemple : sage: [J.dimension() for J in [J1, J2, C, H, H*J2, J1+J2]] [0, 0, 1, 1, 1, -1] En eet, V (J1 ) et V (J2 ) sont formes dun nombre ni de points, V (C ) et V (H ) sont des courbes, V (H J2 ) est runion de courbes et de points isols, et V (J1 + J2 ) est vide. Les systmes de dimension zro, cest--dire ceux qui engendrent un idal de dimension zro, ou encore (pour les systmes coecients rationnels) qui ne possdent quun nombre ni de solutions, auront une importance particulire dans la suite du chapitre puisque ce sont ceux que lon peut rsoudre le plus explicitement.

9.2.4

limination

liminer une variable dans un systme dquations, cest trouver des consquences , ou mieux toutes les consquences du systme indpendantes de cette variable. Autrement dit, il sagit de trouver des quations vries par toute solution, mais qui ne font pas intervenir la variable limine, ce qui les rend souvent plus faciles analyser. Par exemple, on peut liminer x du systme linaire 2x + y 2z = 0 2x + 2y + z = 1 (9.4)

en retranchant la premire quation la deuxime. Il vient y + 3z = 1, ce qui montre que tout triplet (x, y, z ) solution de (9.4) est de la forme (x, 1 3z, z ).
5. Nous donnons en 9.3.3 une dnition plus rigoureuse, mais pas forcment plus clairante. Voir les rfrences mentionnes en dbut de chapitre pour un traitement plus satisfaisant.

198

CHAP. 9. SYSTMES POLYNOMIAUX

Systmes polynomiaux gnraux : limination, gomtrie idal dlimination J A[z, t] K [x, y, z, t] rsultant Resx (p, q ) dimension genre J.elimination_ideal(x, y) p.resultant(q, x) J.dimension() J.genus()

Dimension zro (ensemble ni de solutions) solutions dans L K dimension sur K du quotient base du quotient dcomposition triangulaire J.variety(L) J.vector_space_dimension() J.normal_basis() J.triangular_decomposition()

Tableau 9.4 Rsolution de systmes polynomiaux.

On peut ensuite vrier que toute solution partielle (1 3z, z ) stend en une 1 (unique) solution ( 5z2 , 1 3z, z ) de (9.4). Cela illustre que lalgorithme du pivot de Gauss rsout les systmes linaires par limination, contrairement par exemple aux formules de Cramer. Idaux dlimination. Dans le contexte des systmes polynomiaux, les consquences des quations p1 (x) = = ps (x) = 0 sont les lments de lidal p1 , . . . , ps . Si J est un idal de K [x1 , . . . , xn ], on appelle k -ime idal dlimination de J lensemble Jk = J K [xk+1 , . . . , xn ] (9.5) des lments de J qui ne font intervenir que les n k dernires variables. Cest un idal de K [xk+1 , . . . , xn ]. En Sage, la mthode elimination_ideal prend la liste des variables liminer. Attention : elle ne renvoie pas Jk K [xk+1 , . . . , xn ], mais lidal Jk de K [x1 , . . . , xn ] engendr par celui-ci. Dans le cas du systme linaire (9.4), on trouve sage: R.<x,y,z> = QQ[] sage: J = ideal(2*x+y-2*z, 2*x+2*y+z-1) sage: J.elimination_ideal(x) Ideal (y + 3*z - 1) of Multivariate Polynomial Ring in x, y, z over Rational Field sage: J.elimination_ideal([x,y]) Ideal (0) of Multivariate Polynomial Ring in x, y, z over Rational Field Mathmatiquement, ces rsultats sinterprtent ainsi : on a J Q[y, z ] = y + 3z 1 Q[y, z ] et J Q[z ] = Q[z ], cest--dire Q[z ] J . (En eet, lidal 0 correspond au systme rduit la seule quation triviale 0 = 0, dont tout polynme est solution.) Ce nest certes pas une faon recommandable de rsoudre les systmes linaires : les outils spciques discuts au chapitre 8 sont bien plus ecaces ! Pour un exemple un peu moins trivial, reprenons le systme (S1 ) de la section 9.2.3 (voir gure 9.1a) :

9.2. SYSTMES POLYNOMIAUX ET IDAUX sage: J1.gens() [x^2 + y^2 - 1, 16*x^2*y^2 - 1]

199

Llimination de y fournit un idal de Q[x] donc principal engendr par un polynme g dont les racines sont les abscisses 2 2 des huit solutions de (S1 ) : sage: g = J1.elimination_ideal(y).gens(); g [16*x^4 - 16*x^2 + 1] sage: SR(g[0]).solve(SR(x)) # rsout par radicaux [x == -1/2*sqrt(sqrt(3) + 2), x == 1/2*sqrt(sqrt(3) + 2), x == -1/2*sqrt(-sqrt(3) + 2), x == 1/2*sqrt(-sqrt(3) + 2)] En rinjectant chacune des valeurs de x trouves dans (S1 ), on obtient un systme (redondant) dquations en y seulement qui permet de calculer les deux valeurs de y correspondantes. liminer = projeter. Lexemple prcdent illustre que llimination de y dun systme correspond gomtriquement la projection de la varit solution sur un hyperplan dquation y = constante. Mais considrons maintenant sparment les idaux C = x2 + y 2 1 et H = 16 x2 y 2 1 dont J1 est la somme, et nouveau, liminons y : sage: C.elimination_ideal(y).gens() [0] sage: H.elimination_ideal(y).gens() [0] Concernant C , rien de bien surprenant. Le cercle {(x, y ) R2 | x2 + y 2 = 1} se projette certes sur [1; 1], mais il est clair que nimporte quelle valeur de x peut tre rinjecte dans lunique quation x2 + y 2 1 = 0 et que lquation en y obtenue a des solutions complexes. Ce que traduit llimination de y dans C est la projection sur la premire coordonne du cercle complexe {(x, y ) C2 | x2 + y 2 = 1}, qui est C tout entier. La situation de H est un petit peu plus complique. Lquation 16 x2 y 2 = 1 na pas de solution, mme complexe, pour x = 0. On a cette fois VC (H Q[x]) = C (VC (H )) = C \ {0}. 3

En eet, le projet de lhyperbole, C \ {0}, nest pas une sous-varit algbrique. Moralit : llimination correspond bien la projection (sur un corps algbriquement clos), mais elle ne calcule pas le projet exact dune varit ane, seulement la fermeture de Zariski de celui-ci.

200

CHAP. 9. SYSTMES POLYNOMIAUX

Figure 9.2 Une portion de la courbe en (x, y, t) dnie par (9.6) et sa projection sur le plan t = 0.

Applications : un peu de gomtrie plane. Si X Ck est donn par une paramtrisation rationnelle X = { f1 (t), f2 (t), . . . , fk (t) }, f1 , . . . , fk Q(t1 , . . . , tn ),

trouver une quation implicite pour X revient projeter la partie de Ck+n dnie par les quations xi = fi (t) sur le sous-espace (x1 , . . . , xk ) Ck . Cest un problme dlimination. Considrons la paramtrisation classique du cercle x= 1 t2 1 + t2 y= 2t 1 + t2 (9.6)

associe lexpression de (sin , cos ) en fonction de tan(/2). Elle se traduit par des relations polynomiales qui dnissent un idal de Q[x, y, t] : sage: R.<x,y,t> = QQ[] sage: Param = R.ideal((1-t^2)-(1+t^2)*x, 2*t-(1+t^2)*y) liminons t : sage: Param.elimination_ideal(t).gens() [x^2 + y^2 - 1] On obtient une quation du cercle. On peut remarquer que cette quation sannule en (x, y ) = (1, 0), bien que la paramtrisation (9.6) natteigne pas ce point, car le cercle priv dun point nest pas une sous-varit algbrique. Un autre exemple : traons quelques-uns des cercles (Ct ) dquation Ct : x2 + (y t)2 = t2 + 1 2 (9.7)

au moyen des commandes Sage (voir gure 9.3) : sage: R.<x,y,t> = QQ[] sage: eq = x^2 + (y-t)^2 - 1/2*(t^2+1)

9.2. SYSTMES POLYNOMIAUX ET IDAUX

201

2.4 1.6 0.8 0 -0.8 -1.6 -2.4 -1.8-1.2-0.6 0 0.6 1.2 1.8

2.4 1.6 0.8 0 -0.8 -1.6 -2.4 -1.8-1.2-0.6 0 0.6 1.2 1.8

Figure 9.3 Une famille de cercles et son enveloppe.

sage: fig = add((eq(t=k/5)*QQ[x,y]).plot() for k in (-15..15)) sage: fig.show(aspect_ratio=1, xmin=-2, xmax=2, ymin=-3, ymax=3) On voit apparatre lenveloppe de la famille de cercles (Ct ), une courbe limite tangente tous les Ct , que lon peut dcrire informellement comme lensemble des points dintersection de cercles inniment proches de la famille. Plus prcisment, si f est une fonction direntiable et si la courbe Ct a pour quation f (x, y, t) = 0 pour tout t, lenveloppe de (Ct ) est lensemble des (x, y ) tels que f t, f (x, y, t) = 0 et (x, y, t) = 0. (9.8) t Dans le cas des cercles (9.7), la fonction f (x, y, t) est un polynme. Leur enveloppe est le projet sur le plan (x, y ) des solutions de (9.8), donc on peut en dterminer une quation par le calcul didal dlimination suivant : sage: env = ideal(eq, eq.derivative(t)).elimination_ideal(t) sage: env.gens() [2*x^2 - 2*y^2 - 1] Il ny a plus qu tracer la courbe trouve : sage: env.change_ring(QQ[x,y]).plot() Rsultant et limination. Les oprations dlimination des exemples prcdents sappuient implicitement sur des bases de Grbner calcules automatiquement par Sage. Mais nous avons rencontr auparavant dans ce livre un autre outil dlimination : le rsultant. Considrons deux polynmes non constants p, q K [x1 , . . . , xn , y ]. On note Resy (p, q ) le rsultant de p et q vus comme des polynmes en une indtermine y

202 Ingalits

CHAP. 9. SYSTMES POLYNOMIAUX

Considrons un triangle de sommets A = (0, 0), B = (1, 0) et C = (x, y ). Supposons les angles BAC et CBA gaux, et tentons de prouver par le calcul = que le triangle est alors isocle. En introduisant le paramtre t = tan A tan B , la situation est code par les quations y = tx = t(1 x), et il sagit de montrer quelles entranent x2 + y 2 = (1 x)2 + y 2 . Avec Sage, on obtient : sage: R.<x,y,t> = QQ[] sage: J = (y-t*x, y-t*(1-x))*R sage: (x^2+y^2) - ((1-x)^2+y^2) in J False Et pour cause : lorsque x = y = t = 0, les hypothses sont satisfaites, mais la conclusion est fausse ! Gomtriquement, on doit exclure le cas des triangles plats, qui peuvent avoir deux angles gaux sans tre isocles. Comment coder, disons, la contrainte t = 0 ? Lastuce est dintroduire une variable auxiliaire u, et dimposer tu = 1. Le calcul devient : sage: R.<x,y,t,u> = QQ[] sage: J = (y-t*x, y-t*(1-x), t*u-1)*R sage: (x^2+y^2) - ((1-x)^2+y^2) in J True et lon a cette fois le rsultat attendu. Observons en passant que lon peut forcer plusieurs expressions la fois ne pas sannuler avec une seule variable auxiliaire, via une quation du type t1 t2 tn u = 1.

coecients dans K [x1 , . . . , xn ]. Nous avons vu en 7.3.3 que cest un polynme de K [x1 , . . . , xn ] qui sannule en u K n si et seulement si p(u1 , . . . , un , y ) et q (u1 , . . . , un , y ) (qui sont deux polynmes de K [y ]) ont un zro commun, sauf peuttre lorsque les coecients dominants (en y ) de p et q sannulent eux-mmes en u. On peut dire un petit peu plus : en fait, Resy (p, q ) engendre lidal dlimination 6 p, q K [x1 , . . . , xn ]. Ainsi, tous les calculs dlimination que nous avons faits entre deux polynmes peuvent tre remplacs par des rsultants. Par exemple, lquation de lenveloppe des cercles (9.7) est sage: eq.derivative(t).resultant(eq, t) x^2 - y^2 - 1/2
6. Les points dannulation des coecients dominants o la proprit de spcialisation du rsultant ne tient pas sont ceux ajouts par le passage la fermeture de Zariski lors de la projection.

9.2. SYSTMES POLYNOMIAUX ET IDAUX

203

Nous nous en tiendrons ici au cas de deux polynmes. Il est possible dutiliser le rsultant ou des gnralisations du rsultant pour des problmes dlimination plus gnraux, mais la thorie est plus complique, et les outils correspondants ne sont pas encore disponibles dans Sage.

9.2.5

Systmes de dimension zro

On peut traiter bien des problmes partir du seul calcul didaux dlimination, et Sage nore gure dautre outil bote noire pour rsoudre des systmes polynomiaux gnraux. La situation est dirente en ce qui concerne les systmes de dimension zro. Un idal J K [x] est dit de dimension zro lorsque le quotient K [x]/J est un espace vectoriel de dimension nie. Sur un corps algbriquement clos, cela quivaut dire que la varit V (J ) est forme dun nombre ni de points. Ainsi, les systmes (9.1) et (9.3) engendrent des idaux de dimension zro on dit aussi quils sont eux-mmes de dimension zro. En revanche, lidal (x2 +y 2 )(x2 +y 2 +1) de Q[x, y ] est de dimension 1 bien que sa seule solution relle soit (0, 0) : sage: R.<x,y> = QQ[] sage: ((x^2 + y^2)*(x^2 + y^2 + 1)*R).dimension() 1 Les systmes de dimension zro se rsolvent de faon plus explicite que ce quautorisent les outils gnraux de la section prcdente. Nous avons dj vu plusieurs de ces possibilits luvre sur lexemple de la section 9.2.1. numrer les solutions. Tout dabord, le fait de navoir quun nombre ni de solutions permet de les numrer, exactement ou approximativement. Lexpression Sage J.variety(L) sert calculer la varit VL (J ). Elle dclenche une erreur si J nest pas de dimension zro. Par dfaut, elle cherche les solutions du systme coordonnes dans le corps de base de lanneau de polynmes ambiant. Par exemple, la sous-varit de Qn dnie par J1 est vide : sage: J1 = (x^2 + y^2 - 1, 16*x^2*y^2 - 1)*R sage: J1.variety() [] Mais tout comme la mthode roots des polynmes une seule indtermine, variety fonctionne pour toutes sortes de domaines L. Le plus important pour nous ici est le corps des nombres algbriques. On peut en eet montrer que les solutions dun systme de dimension zro coecients dans K sont coordonnes dans la clture algbrique de K . Ainsi, il est possible de calculer exactement la varit complexe VC (J ) = VQ (J ) associe un idal J Q[x] : sage: J1.variety(QQbar)[0:2] [{y: -0.9659258262890683?, x: -0.2588190451025208?}, {y: -0.9659258262890683?, x: 0.2588190451025208?}]
Exercice 35. Montrer que les solutions de (S1 ) sont coordonnes dans Q[ et les exprimer par radicaux. 2 3]

204

CHAP. 9. SYSTMES POLYNOMIAUX

Dcomposition triangulaire. En interne, J.variety(L) passe par le calcul dune dcomposition triangulaire de lidal J . Cette dcomposition est intressante en elle-mme car elle donne parfois une description de la varit V (J ) plus commode pour la suite des calculs, voire plus facile interprter que la sortie de variety (voir 9.2.1), particulirement quand les solutions sont nombreuses. Un systme polynomial est dit triangulaire sil est de la forme d 1 1 1 p1 (x1 ) := xd + + a1,0 = 0 1 + a1,d1 1 x1 d2 2 1 p2 (x1 , x2 ) := x2 + a2,d2 1 (x1 ) xd + + a ( x ) = 0 2,0 1 2 . . . dn 1 n pn (x1 , . . . , xn ) := xd + = 0 n + an,dn 1 (x1 , . . . , xn1 ) xn autrement dit si chaque polynme pi ne fait intervenir que les variables x1 , . . . , xi et est unitaire en la variable xi . Quand un systme de dimension zro est de cette forme, sa rsolution se ramne un nombre ni de rsolutions dquations polynomiales une seule variable : il sut de trouver les racines x1 de p1 , les reporter dans p2 , chercher alors les racines x2 de ce dernier, et ainsi de suite. Cette stratgie fonctionne que lon cherche les solutions exactement ou numriquement. Tout systme nest pas quivalent un systme triangulaire. Soit par exemple J lidal dni par : sage: sage: sage: sage: sage: ....: ....: sage: R.<x,y> = PolynomialRing(QQ, order= lex ) C = ideal(x^2+y^2-1) D = ideal((x+y-1)*(x+y+1)) J = C + D

En image (voir gure 9.4) : opts = { axes aspect_ratio ymin :-1.3, show(C.plot() :True, gridlines :True, frame :False, :1, axes_pad :0, xmin :-1.3, xmax :1.3, ymax :1.3, fontsize : 8} + D.plot(), figsize=[2,2], **opts)

La varit V (J ) contient deux points dabscisse 0 mais un seul point dabscisse 1, et de mme, un point dordonne 1 contre deux dordonne nulle. Lidal J ne peut donc tre dcrit par un systme triangulaire. On peut montrer en revanche que tout idal de dimension zro scrit comme intersection nie didaux engendrs par des systmes triangulaires. La mthode triangular_decomposition calcule une telle dcomposition : sage: J.triangular_decomposition() [Ideal (y, x^2 - 1) of Multivariate Polynomial Ring in x, y over Rational Field, Ideal (y^2 - 1, x) of Multivariate Polynomial Ring in x, y over Rational Field] Gomtriquement, on obtient une reprsentation de la varit V (J ) comme runion de varits associes des systmes plus simples, et souvent assez simples pour constituer une bonne description des solutions.

9.2. SYSTMES POLYNOMIAUX ET IDAUX

205

1 0.5 -1 -0.5 -0.5 -1


x2 + y 2 1, (x + y 1)(x + y + 1)

1 0.5 0.5 1 -1 -0.5 -0.5 -1


x2 + y 2 1, (x + 2y 1)(x + 2y + 1)

0.5 1

Figure 9.4 Dans chacun des deux cas, la varit associe lidal J du texte est lintersection dun cercle et de la runion de deux droites.

Quelques dicults. On peut lgitimement se demander quel est lintrt de la dcomposition triangulaire pour numrer les solutions. Aprs tout, face un systme de dimension zro, il est toujours possible de trouver un polynme une seule variable dont les racines soient exactement les premires coordonnes des solutions, par un calcul didal dlimination. En reportant ses racines dans le systme dquations, on diminue le nombre de variables, ce qui permet ditrer le procd jusqu avoir compltement rsolu le systme. Mais la remonte dans le systme en propageant les rsultats partiels peut tre dlicate. Modions un peu le systme prcdent : sage: D = ideal((x+2*y-1)*(x+2*y+1)); J = C + D sage: J.variety() [{y: -4/5, x: 3/5}, {y: 0, x: -1}, {y: 0, x: 1}, {y: 4/5, x: -3/5}] sage: [T.gens() for T in J.triangular_decomposition()] [[y, x^2 - 1], [25*y^2 - 16, 4*x + 3*y]] La forme de la dcomposition triangulaire ne change pas : pour chacune des composantes, on dispose dune quation en y seulement, et dune seconde quation qui permet dexprimer x en fonction de y . liminons donc x, pour avoir de mme une quation en y seul, en loccurrence le produit des deux prcdentes : sage: Jy = J.elimination_ideal(x); Jy.gens() [25*y^3 - 16*y] Il ny a plus qu reporter les racines de cette quation dans les quations qui dnissent lidal J pour trouver x. Avec la premire quation, x2 + y 2 1 = 0, il vient : sage: ys = QQ[ y ](Jy.0).roots(); ys [(4/5, 1), (0, 1), (-4/5, 1)] sage: QQ[ x ](J.1(y=ys[0][0])).roots() [(-3/5, 1), (-13/5, 1)]

206

CHAP. 9. SYSTMES POLYNOMIAUX

Lune des deux valeurs obtenues est correcte on a (3/5, 4/5) V (J ) mais lautre ne correspond aucune solution : il faut tester les valeurs trouves au moyen de la seconde quation de dpart, (x + 2y 1)(x + 2y + 1), pour lliminer. Le problme se corse si lon rsout les quations univaries numriquement, ce qui est parfois ncessaire en raison du cot des oprations sur les nombres algbriques : sage: ys = CDF[ y ](Jy.0).roots(); ys [(-0.8, 1), (0.0, 1), (0.8, 1)] sage: [CDF[ x ](p(y=ys[0][0])).roots() for p in J.gens()] [[(-0.6 - 1.30624677741e-16*I, 1), (0.6 + 1.30624677741e-16*I, 1)], [(0.6 - 3.13499226579e-16*I, 1), (2.6 + 3.13499226579e-16*I, 1)]] Ici, en reportant y 0,8 dans les deux gnrateurs de J , on trouve deux valeurs de x proches de 0,6. Comment sassurer que ce sont des approximations de la coordonne x dune mme solution exacte (x, y ) (0,6, 0, 8), et non des racines parasites comme dans lexemple prcdent ? Ces phnomnes samplient quand le nombre de variables et dquations augmente. Quand le systme est triangulaire en revanche, il ny a chaque tape de remonte quune quation considrer, et comme elle est toujours unitaire, les approximations numriques naectent pas le nombre de solutions. Continuons dans la mme veine. Pour le systme suivant, J.variety() calcule (exactement) une dcomposition triangulaire de J , puis cherche numriquement les solutions relles du ou des systmes obtenus. Cela donne une unique solution relle : sage: R.<x,y> = QQ[]; J = ideal([ x^7-(100*x-1)^2, y-x^7+1 ]) sage: J.variety(RDF) [{y: 396340.890167, x: 26.612261084}] En menant le calcul exactement jusquau bout, on voit pourtant quil existe trois solutions relles, et que la valeur de x dans la solution trouve numriquement est compltement fausse : sage: J.variety(AA) [{x: 0.00999999900000035?, y: -0.999999999999990?}, {x: 0.01000000100000035?, y: -0.999999999999990?}, {x: 6.305568998641385?, y: 396340.8901665450?}] Moralit : la dcomposition triangulaire nest pas une panace, et ne dispense pas dtre prudent dans linterprtation des rsultats de calculs approchs. Il existe un grand nombre dautres mthodes pour paramtrer et approcher les solutions de systmes de dimension zro, plus ou moins adaptes suivant les problmes, qui ne sont pas implmentes dans Sage. Lexercice 36 donne un aperu de certaines ides utilises. Algbre quotient. Les quotients par des idaux de dimension zro sont beaucoup plus maniables que les quotients danneaux de polynmes en gnral, car les

9.3. BASES DE GRBNER Mathmatiques avances

207

Sage dispose aussi dun grand nombre de fonctions dalgbre commutative et de gomtrie algbrique qui dpassent largement le niveau de ce livre. Le lecteur intress est invit explorer la documentation des idaux de polynmes ainsi que celle du module sage.schemes. Dautres fonctionnalits encore sont accessibles travers les interfaces aux logiciels spcialiss Singular, CoCoA et Macaulay2.

calculs dans lalgbre quotient se ramnent de lalgbre linaire en dimension nie. Si J K [x] est un idal de dimension zro, la dimension dimK K [x]/J de lalgbre quotient en tant que K -espace vectoriel est une borne sur le nombre de points de V (J ). (En eet, pour tout u V (J ), il existe un polynme coecients dans K qui vaut 1 en u et 0 en tout autre point de V (J ). Deux tels polynmes ne peuvent pas tre quivalents modulo J .) On peut penser cette dimension comme le nombre de solutions avec multiplicits du systme dans la clture algbrique de K . Par exemple, nous avons relev que les quatre solutions du systme (S2 ) introduit en 9.2.3 sont chacune la double intersection de deux courbes. Cela explique que lon ait : sage: len(J2.variety(QQbar)), J2.vector_space_dimension() (4, 8) La mthode normal_basis calcule une liste de monmes dont les projections dans K [x]/J forment une base : sage: J2.normal_basis() [x*y^3, y^3, x*y^2, y^2, x*y, y, x, 1] La base renvoye dpend de lordre sur les termes choisi la construction de lanneau de polynmes ; nous la dcrivons plus prcisment en 9.3.3.
Exercice 36. Soit J un idal de dimension zro de Q[x, y ]. Soit x le polynme caractristique de lapplication linaire mx : Q[x, y ]/J p+J Q[x, y ]/J xp + J.

Calculer x dans le cas J = J2 = x2 + y 2 1, 4x2 y 2 1 . Montrer que toute racine de x est labscisse dun point de la varit VC (J ).

9.3

Bases de Grbner

Nous avons jusquici utilis les fonctionnalits dlimination algbrique et de rsolution de systmes polynomiaux quore Sage comme des botes noires. Cette section introduit quelques-uns des outils mathmatiques et algorithmiques sous-jacents. Le but est la fois dy recourir directement et de faire un usage avis des fonctions de plus haut niveau prsentes auparavant.

208

CHAP. 9. SYSTMES POLYNOMIAUX


Principaux ordres monomiaux, avec lexemple de Q[x, y, z ] lex x < x 1 < 1 ou (1 = 1 et 2 < 2 ) ou . . . ou (1 = 1 , . . . , n1 = n1 et n < n ) x3 > x2 y > x2 z > x2 > xy 2 > xyz > xy > xz 2 > xz > x > y 3 > y 2 z > y 2 > yz 2 > yz > y > z 3 > z 2 > z > 1 invlex x < x n < n ou (n = n et n1 < n1 ) ou . . . ou (n = n , . . . , 2 = 2 et 1 < 1 ) z 3 > yz 2 > xz 2 > z 2 > y 2 z > xyz > yz > x2 z > xz > z > y 3 > xy 2 > y 2 > x2 y > xy > y > x3 > x2 > x > 1 deglex x < x || < | | ou (|| = | | et x <lex x ) x3 > x2 y > x2 z > xy 2 > xyz > xz 2 > y 3 > y 2 z > yz 2 > z 3 > x2 > xy > xz > y 2 > yz > z 2 > x > y > z > 1 degrevlex x < x || < | | ou (|| = | | et x >invlex x ) x3 > x2 y > xy 2 > y 3 > x2 z > xyz > y 2 z > xz 2 > yz 2 > z 3 > x2 > xy > y 2 > xz > yz > z 2 > x > y > z > 1 Construction dordres monomiaux

objet reprsentant un ordre prdni sur n variables ordre matriciel : x <M x M <lex M blocs : x y < x y <1 ou ( = et <2 )

TermOrder( nom , n) TermOrder(M) T1 + T2

Tableau 9.5 Ordres monomiaux.

Les techniques employes par Sage pour les calculs sur les idaux et llimination reposent sur la notion de base de Grbner. On peut voir celle-ci, entre autres, comme une extension plusieurs indtermines de la reprsentation par gnrateur principal des idaux de K [x]. Le problme central de cette section est de dnir et calculer une forme normale pour les lments des algbres quotients de K [x]. Notre point de vue reste celui de lutilisateur : nous dnissons les bases de Grbner, montrons comment en obtenir avec Sage et quoi cela peut servir, mais nous nabordons pas les algorithmes utiliss pour faire le calcul.

9.3.1

Ordres monomiaux

Un ordre monomial ou ordre admissible (global) est un ordre total sur les monmes x dun anneau de polynmes K [x] qui satisfait x < x = x+ < x+ et = 0 = 1 < x (9.9)

pour tous exposants , , . De faon quivalente, on peut considrer < comme un ordre sur les exposants Nn ou encore sur les termes c x . Les monme de tte, coecient de tte et terme de tte dun polynme p (voir 9.1.3) pour lordre monomial ambiant sont ceux de plus grand exposant ; on les note respectivement lm p, lc p et lt p. La premire des conditions (9.9) exprime une contrainte de compatibilit avec la multiplication : le produit par un monme x ne change pas lordre. La seconde

9.3. BASES DE GRBNER

209

impose que < soit un bon ordre, cest--dire quil nexiste pas de suite innie strictement dcroissante de monmes. Remarquons que le seul ordre admissible sur K [x] est lordre usuel xn > xn1 > > 1. Nous avons vu en 9.1.1 que Sage permet de slectionner un ordre lors de la dnition dun anneau de polynmes via des constructions comme sage: R.<x,y,z,t> = PolynomialRing(QQ, order= lex ) Le tableau 9.5 recense les principaux ordres admissibles prdnis 7 : lex est lordre lexicographique des exposants, invlex lordre lexicographique des exposants lus de droite gauche, et deglex range les monmes par degr total puis par ordre lexicographique. La dnition de degrevlex est un peu plus complique : les monmes sont rangs par degr total, puis dans lordre lexicographique dcroissant des exposants lus partir de la droite. Cet ordre surprenant est pourtant celui adopt par dfaut quand on omet loption order, car il est plus ecace que les autres pour certains calculs. On choisit gnralement (mais pas toujours !) conjointement lordre des variables de lanneau et celui des monmes de sorte que x1 > x2 > > xn , et lon parle alors souvent, par exemple, de lordre lex tel que x > y > z plutt que de lordre lex sur K [x, y, z ] . Les ordres prdnis lex, deglex et degrevlex obissent cette convention ; quant lordre invlex sur K [x, y, z ], cest aussi lordre lex tel que z > y > x, cest--dire celui sur K [z, y, x].

9.3.2

Division par une famille de polynmes

Un ordre monomial < tant x, soit G = {g1 , g2 , . . . , gs } un ensemble ni de polynmes de K [x]. On note G = g1 , g2 , . . . , gs lidal de K [x] engendr par G. La division dun polynme p K [x] par G est un analogue multivari de la division euclidienne dans K [x]. Comme cette dernire, elle associe p un reste, donn en Sage par lexpression p.reduce(G), qui est un polynme plus petit appartenant la mme classe dquivalence modulo G : sage: ((x+y+z)^2).reduce([x-t, y-t^2, z^2-t]) 2*z*t^2 + 2*z*t + t^4 + 2*t^3 + t^2 + t Le reste est obtenu en retranchant p, tant que cest possible, des multiples dlments de G dont le terme de tte sannule avec un terme de p lors de la soustraction. la dirence du cas univari, il arrive que lon puisse annuler ainsi un terme de p, mais pas celui de tte : on demande donc seulement dannuler un terme le plus grand possible au sens de lordre monomial.
7. Sage admet aussi des ordres (dits locaux ) dans lesquels 1 est le plus grand des monmes au lieu dtre le plus petit. Par exemple, dans lordre neglex sur Q[x, y, z ], on a 1 > z > z 2 > z 3 > y > yz > yz 2 > y 2 > y 2 z > y 3 > x > xz > xz 2 > xy > xyz > xy 2 > x2 > x2 z > x2 y > x3 . Les ordres locaux ne sont pas des ordres admissibles au sens de la dnition (9.9), et nous ne les utilisons pas dans ce livre, mais le lecteur intress pourra complter le tableau 9.5 en utilisant la fonction test_poly dnie en 9.1.1.

210

CHAP. 9. SYSTMES POLYNOMIAUX

Formellement, pour p K [x], notons ltG p le terme de p dexposant maximal divisible par un terme de tte dlment de G. Appelons rduction lmentaire toute transformation de la forme pp = p c x g, o g G et ltG p = c x lt g. (9.10) Une rduction lmentaire prserve la classe dquivalence de p modulo G , et fait disparatre le plus grand monme de p quelle aecte : on a p p G et ltG p < ltG p. Comme < est un bon ordre, il nest pas possible dappliquer un polynme une innit de rductions lmentaires successives. Toute suite de rductions lmentaires se termine donc sur un polynme qui ne peut plus tre rduit, qui est le reste de la division. Observons que ce procd gnralise des mthodes familires dlimination la fois pour les polynmes une indtermine et pour les systmes linaires. Sil ny a quune seule variable, la division dun polynme p par un singleton G = {g } se rduit exactement la division euclidienne de p par g . Dans lautre cas extrme de polynmes en plusieurs indtermines mais dont tous les monmes sont de degr 1, elle devient identique lopration lmentaire de rduction de la mthode de Gauss-Jordan. Mais contrairement ce quil se passe dans ces cas particuliers, en gnral, le reste dpend du choix des rductions lmentaires. (On dit que le systme de rgles de rcriture (9.10) nest pas conuent.) Ainsi, changer lordre dans lequel on donne les lments de G conduit dans lexemple suivant des choix de rductions dirents : sage: sage: sage: y^3 sage: y^2 R.<x,y> = PolynomialRing(QQ, order= lex ) (g, h) = (x-y, x-y^2); p = x*y - x p.reduce([g, h]) # deux rductions par h y^2 p.reduce([h, g]) # deux rductions par g y

Quand bien mme les lments de G seraient considrs dans un ordre dterministe (de faon rendre le rsultat unique pour p et G donns), comment sassurer, par exemple, que la suite de rductions lmentaires de p par {g, h} choisie dcouvrira la relation suivante qui montre que p g, h ? sage: p - y*g + h 0

9.3.3

Bases de Grbner

Les limitations de la division multivarie expliquent la dicult mentionne en 9.2.3 obtenir une forme normale pour les lments des algbres K [x]/J : diviser par les gnrateurs de lidal ne sut pas... Du moins en gnral ! Car il existe des systmes de gnrateurs particuliers pour lesquels la division est conuente, et calcule une forme normale. Ces systmes sappellent des bases de Grbner, ou bases standard.

9.3. BASES DE GRBNER

211

x xy , x y , x y, x
4 3 3 4 5

z x3 , xy 2 z, xz 2

Figure 9.5 Escaliers didaux engendrs par des monmes.

x x + y 1, 16 x y 1
2 2 2 2

x 16 x y 1
2 2 2 2

x x + y 1, (x + y )2 1

Figure 9.6 Escaliers didaux de Q[x, y ] rencontrs dans ce chapitre. Dans ces trois cas, lescalier et la position des gnrateurs sont les mmes pour les ordres lex, deglex et degrevlex.

x lex(x, y )

x invlex(x, y ) = lex(y, x) degrevlex(x, y )

Figure 9.7 Escaliers de lidal xy + x + y 2 + 1, x2 y + xy 2 + 1 Q[x, y ] relativement dirents ordres monomiaux.

Sur chaque schma, la zone grise correspond aux termes de tte des lments de lidal. Les carrs noirs donnent la position des gnrateurs utiliss pour le dcrire.

212

CHAP. 9. SYSTMES POLYNOMIAUX

Escaliers. Une faon plaisante dapprhender les bases de Grbner passe par la notion descalier dun idal. Attachons chaque polynme non nul de K [x1 , . . . , xn ] au point de Nn donn par son exposant de tte, et dessinons la partie E Nn ainsi occupe par un idal J (voir gures 9.5 9.7). Le dessin obtenu (qui dpend de lordre monomial) est en forme descalier : en eet, on a + Nn E pour tout E . Les lments de J \{0} sont dans la zone grise, au-dessus de lescalier ou sa frontire. Les points strictement sous lescalier correspondent exclusivement des polynmes de K [x] \ J , mais tous les polynmes de K [x] \ J ne sont pas sous lescalier. Par exemple, dans un polynme de x3 , xy 2 z, xz 2 , tout monme, de tte ou non, est multiple dun des polynmes x3 , xy 2 z et xz 2 . Les monmes de tte sont donc exactement les x y z vriant lune des ingalits (, , ) (3, 0, 0), (, , ) (1, 2, 1) ou (, , ) (1, 0, 2) composante par composante (gure 9.5). Un polynme dont lexposant de tte ne satisfait pas ces conditions, par exemple x2 + xz 2 si lordre ambiant est lordre lexicographique avec x > y > z , ne peut appartenir lidal. Certains polynmes comme x3 + x ne sont pas non plus dans lidal malgr un monme de tte au-dessus de lescalier. La situation est analogue pour tout idal engendr par des monmes. Pour un idal quelconque, la structure de lescalier ne se lit pas facilement sur les gnrateurs. Ainsi, en notant 1 , . . . , s les exposants de tte des gnrateurs, s on a i=1 ( i + Nn ) E dans tous les exemples des gures 9.6 et 9.7 sauf le deuxime. On peut cependant montrer que E scrit toujours comme runion dun nombre ni densembles de la forme + Nn , cest--dire intuitivement que lescalier na quun nombre ni de coins. Ce rsultat est parfois appel lemme de Dickson. Bases de Grbner. Une base de Grbner est simplement une famille de gnrateurs qui capture la forme de lescalier, et plus prcisment qui compte un polynme chaque coin de celui-ci. Dfinition. Une base de Grbner dun idal J K [x] relativement un ordre monomial < est une partie nie G de J telle que pour tout p J non nul, il existe g G dont le monme de tte (pour lordre <) lm g divise lm p. Tester si les gnrateurs par lesquels est dni un idal forment une base de Grbner se fait en Sage avec la mthode basis_is_groebner. Nous avons dj observ que tout ensemble de monmes est une base de Grbner : sage: R.<x,y> = PolynomialRing(QQ, order= lex ) sage: R.ideal(x*y^4, x^2*y^3, x^4*y, x^5).basis_is_groebner() True En revanche, le systme {x2 + y 2 1, 16 x2 y 2 1} qui code lintersection du cercle et des hyperboles de la gure 9.1a nest pas une base de Grbner : sage: R.ideal(x^2+y^2-1, 16*x^2*y^2-1).basis_is_groebner() False Daprs la forme de lescalier (gure 9.6), il lui manque pour cela un polynme de J1 de monme de tte y 4 .

9.3. BASES DE GRBNER

213

Largument fond sur le lemme de Dickson esquiss ci-dessus montre que tout idal admet des bases de Grbner 8 . Calculons des bases de Grbner de J1 et des autres idaux dont les escaliers sont reprsents gure 9.6. Dans le cas de J1 , il vient : sage: R.ideal(x^2+y^2-1, 16*x^2*y^2-1).groebner_basis() [x^2 + y^2 - 1, y^4 - y^2 + 1/16] On voit apparatre comme prvu les monmes de tte x2 et y 4 . Leur prsence explique la faon dont lescalier se referme sur les axes, dont nous verrons quelle est caractristique des systmes de dimension zro. Concernant la double hyperbole seule, on trouve : sage: R.ideal(16*x^2*y^2-1).groebner_basis() [x^2*y^2 - 1/16] cest--dire un multiple du gnrateur. De faon gnrale, tout singleton est une base de Grbner. Le troisime exemple montre quune base de Grbner peut ncessiter plus de polynmes quun systme de gnrateurs quelconque : sage: R.ideal(x^2+y^2-1, (x+y)^2-1).groebner_basis() [x^2 + y^2 - 1, x*y, y^3 - y] Du fait de la simplicit des exemples prcdents, ces trois bases de Grbner ne dpendent pas ou peu de lordre monomial. Il en va bien diremment en gnral. La gure 9.7 reprsente les escaliers associs un mme idal de Q[x, y ] pour trois ordres monomiaux classiques. Des bases de Grbner correspondantes sont : sage: R_lex.<x,y> = PolynomialRing(QQ, order= lex ) sage: J_lex = (x*y+x+y^2+1, x^2*y+x*y^2+1)*R_lex; J_lex.gens() [x*y + x + y^2 + 1, x^2*y + x*y^2 + 1] sage: J_lex.groebner_basis() [x - 1/2*y^3 + y^2 + 3/2, y^4 - y^3 - 3*y - 1] sage: R_invlex = PolynomialRing(QQ, x,y , order= invlex ) sage: J_invlex = J_lex.change_ring(R_invlex); J_invlex.gens() [y^2 + x*y + x + 1, x*y^2 + x^2*y + 1] sage: J_invlex.groebner_basis() [y^2 + x*y + x + 1, x^2 + x - 1] sage: R_drl = PolynomialRing(QQ, x,y , order= degrevlex ) sage: J_drl = J_lex.change_ring(R_drl); J_drl.gens() [x*y + y^2 + x + 1, x^2*y + x*y^2 + 1] sage: J_drl.groebner_basis() [y^3 - 2*y^2 - 2*x - 3, x^2 + x - 1, x*y + y^2 + x + 1]
8. On peut voir ce rsultat comme une version eective du thorme de nthrianit de Hilbert, qui arme que les idaux de K [x] sont engendrs par un nombre ni dlments. Une preuve classique de ce thorme rappelle fortement la construction dune base de Grbner pour lordre lexicographique.

214

CHAP. 9. SYSTMES POLYNOMIAUX

Rduction division multivarie de p par G gnrateurs inter-rduits p.reduce(G) J.interreduced_basis() Bases de Grbner test de base de Grbner base de Grbner (rduite) changement dordre pour lex changement dordre R1 R2 J.basis_is_groebner() J.groebner_basis() J.transformed_basis() J.transformed_basis( fglm , other_ring=R2)

Tableau 9.6 Bases de Grbner.

La base de Grbner pour lordre lex met en vidence la rgle de rcriture x = 1 3 3 2 2 y y 2 , grce laquelle on peut exprimer les lments de lalgbre quotient en fonction de la seule variable y . La forme allonge de lescalier correspondant rete cette possibilit. De mme, la base de Grbner pour lordre invlex indique quon peut liminer les puissances de y via lgalit y 2 = xy x 1. Nous y reviendrons la n de la section suivante.

9.3.4

Proprits des bases de Grbner

Les bases de Grbner servent implmenter les oprations tudies dans la section 9.2. On les utilise notamment an de calculer des formes normales pour les idaux danneaux de polynmes et les lments des quotients par ces idaux, dliminer des variables dans les systmes polynomiaux, ou encore de dterminer des caractristiques des solutions telles que leur dimension. Division par une base de Grbner. La division par une base de Grbner G dun polynme de G ne peut sarrter sur un lment non nul de G . Cest une consquence immdiate de la dnition : en eet, un tel lment serait au-dessus de lescalier associ G , donc encore divisible par G. Tout lment de G se rduit donc zro dans la division par G. En particulier, une base de Grbner dun idal J engendre J . De mme, la division dun polynme p / J par une base de Grbner de J ne peut sarrter que sur un polynme sous lescalier , or deux polynmes distincts sous lescalier appartiennent des classes dquivalence distinctes modulo J (puisque leur dirence est encore sous lescalier ). La division par une base de Grbner fournit donc une forme normale pour les lments du quotient K [x]/J , et ce, indpendamment de lordre dans lequel on eectue les rductions lmentaires. La forme normale dune classe dquivalence p + J est son unique reprsentant situ sous lescalier ou nul. Cest cette forme normale que calculent les oprations dans lalgbre quotient prsentes en 9.2.3. Pour poursuivre lexemple de la gure 9.7, la rduction sage: p = (x + y)^5 sage: J_lex.reduce(p)

9.3. BASES DE GRBNER 17/2*y^3 - 12*y^2 + 4*y - 49/2 se dcompose en un calcul de base de Grbner suivi dune division : sage: p.reduce(J_lex.groebner_basis()) 17/2*y^3 - 12*y^2 + 4*y - 49/2 Le rsultat dune projection dans le quotient est essentiellement le mme : sage: R_lex.quo(J_lex)(p) 17/2*ybar^3 - 12*ybar^2 + 4*ybar - 49/2

215

Naturellement, changer dordre monomial donne lieu un choix de forme normale dirent : sage: R_drl.quo(J_drl)(p) 5*ybar^2 + 17*xbar + 4*ybar + 1 Les monmes qui apparaissent dans la forme normale correspondent aux points sous lescalier. Ainsi, lidal J est de dimension zro si et seulement si le nombre de points sous son escalier est ni, et ce nombre de points est la dimension du quotient K [x]/J . Dans ce cas, la base que renvoie la mthode normal_basis dcrite en 9.2.5 est simplement lensemble des monmes sous lescalier pour lordre monomial ambiant : sage: [y^3, sage: [x*y, sage: [y^2, J_lex.normal_basis() y^2, y, 1] J_invlex.normal_basis() y, x, 1] J_drl.normal_basis() y, x, 1]

Remarquons en passant que le nombre de monmes sous lescalier est indpendant de lordre monomial. Dimension. Nous sommes maintenant arms pour donner une dnition de la dimension dun idal dans le cas gnral : J est de dimension d lorsque le nombre de points sous lescalier correspondant des monmes de degr total au plus t est de lordre de td quand t . Par exemple, lidal 16 x2 y 2 1 (gure 9.6) est de dimension 1 : sage: ideal(16*x^2*y^2-1).dimension() 1 En eet, le nombre de monmes m sous lescalier tels que degx m + degy m t est gal 4t 2 pour t 3. De mme, les deux idaux de la gure 9.5 sont respectivement de dimension 1 et de dimension 2. On peut montrer que la valeur de la dimension ne dpend pas de lordre monomial, et correspond hors dgnrescences la dimension gomtrique de la varit associe lidal.

216

CHAP. 9. SYSTMES POLYNOMIAUX

Bases rduites. Un ensemble ni de polynmes qui contient une base de Grbner est lui-mme une base de Grbner, donc un idal non nul a une innit de bases de Grbner. Une base de Grbner G = {g1 , . . . , gs } est dite rduite lorsque les coecients de tte des gi valent tous 1 (et 0 / G) ; et aucun des gi nest rductible par le reste de la base G \ {gi } au sens des rgles (9.10). ordre monomial x, chaque idal admet une unique base de Grbner rduite. Par exemple, la base de Grbner rduite de lidal 1 est le singleton {1}, quel que soit lordre. Les bases de Grbner rduites fournissent donc une forme normale pour les idaux de K [x]. Une base de Grbner rduite est minimale au sens o, si on lui enlve un quelconque lment, ce qui reste nest plus un systme de gnrateurs de lidal. Concrtement, elle comporte exactement un polynme par coin de lescalier. Elle peut se calculer partir dune base de Grbner quelconque G en remplaant chaque lment g G par son reste dans la division par G \ {g }, et ainsi de suite tant que cest possible. Cest ce que fait la mthode interreduced_basis. Les polynmes qui se rduisent zro sont eacs. limination. Les ordres lexicographiques jouissent de la proprit fondamentale suivante : si G est une base de Grbner pour lordre lexicographique de J K [x1 , . . . , xn ], alors les G K [xk+1 , . . . , xn ] sont des bases de Grbner des idaux dlimination 9 J K [xk+1 , . . . , xn ]. Une base de Grbner lexicographique se dcompose en blocs dont le dernier ne dpend que de xn , lavant-dernier de xn et xn1 , et ainsi de suite 10 : sage: R.<t,x,y,z> = PolynomialRing(QQ, order= lex ) sage: J = R.ideal(t+x+y+z-1, t^2-x^2-y^2-z^2-1, t-x*y) sage: [u.polynomial(u.variable(0)) for u in J.groebner_basis()] [t + x + y + z - 1, (y + 1)*x + y + z - 1, (z - 2)*x + y*z - 2*y - 2*z + 1, (z - 2)*y^2 + (-2*z + 1)*y - z^2 + z - 1] Dans cet exemple, le dernier polynme de la base ne dpend que de y et z . Viennent auparavant un bloc de deux polynmes en x, y et z , et en premier un polynme qui fait intervenir toutes les variables. Les idaux dlimination successifs sy lisent immdiatement. Nous avons vu cependant (9.2.5) que ces derniers ne fournissent pas une description parfaite de lidal. Ici, le bloc des polynmes en z seul est vide, donc toute valeur de z sauf peut-tre un nombre ni apparat comme dernire coordonne dune solution. On est tent dexprimer les valeurs de y possibles
9. Pour un k donn, cest vrai plus gnralement de tout ordre tel que i k < j = xi > xj . Un ordre qui satisfait une proprit de ce type est dit par blocs (voir aussi tableau 9.5). 10. Cest donc une forme triangulaire du systme form par les gnrateurs de lidal, quoiquen un sens plus faible que celui dni en 9.2.5 : on ne peut pas dire grand-chose a priori sur le nombre de polynmes de chaque bloc ou leurs termes de tte.

9.3. BASES DE GRBNER

217

pour chaque z grce la dernire quation. Elles sont au nombre de deux, sauf pour z = 2, pour lequel seul y = 1 convient. Ce nest quen passant lquation prcdente que lon voit que le choix z = 2 est contradictoire. Inversement, nouveau daprs la dernire quation, y = 1 implique z = 2, donc est exclu. Il savre donc nalement quaucun des coecients de tte des polynmes (crits en leur variable principale respective, comme dans la sortie Sage ci-dessus) ne sannule pour z = 2.
Exercice 37 (Relations trigonomtriques). crire (sin )6 comme un polynme en u() = sin + cos et v () = sin(2) + cos(2).

9.3.5

Calcul

Nous renvoyons le lecteur intress par les algorithmes de calcul de bases de Grbner aux rfrences [CLO07, FSED09, EM07] mentionnes en introduction. En complment, le module sage.rings.polynomial.toy_buchberger de Sage ore une implmentation pdagogique de lalgorithme de Buchberger et de dirents algorithmes lis, qui suit de prs leur description thorique. Changement dordre Les bases de Grbner les plus intressantes ne sont pas les plus faciles calculer : souvent, lordre degrevlex est le moins coteux, mais on lit plus dinformations utiles sur une base de Grbner lexicographique. Par ailleurs, on a occasionnellement besoin de bases de Grbner dun mme idal pour plusieurs ordres dirents. Cela motive lintroduction, en plus des algorithmes de calcul de base de Grbner gnraux, dalgorithmes dits de changement dordre. Ceux-ci calculent une base de Grbner pour un ordre monomial partir dune base de Grbner du mme idal pour un ordre dirent. Ils sont souvent plus ecaces que ceux qui partent dun systme de gnrateurs quelconques. Ainsi, une stratgie souvent fructueuse pour obtenir une base de Grbner lexicographique consiste commencer par en calculer une pour lordre degrevlex, puis appliquer une mthode de changement dordre. Sage fait cela automatiquement dans certains cas. La mthode transformed_basis permet de calculer la main des bases de Grbner par changement dordre, quand lidal est de dimension zro ou si lordre cible est lex. Au besoin, elle commence par calculer une base de Grbner pour lordre attach lanneau de polynmes. Retenons toutefois que le calcul dune base de Grbner est une opration coteuse en temps de calcul comme en mmoire, voire trs coteuse dans les cas dfavorables. La mthode groebner_basis admet dailleurs de nombreuses options 11 qui permettent lutilisateur expert de choisir manuellement un algorithme de calcul de base de Grbner en fonction des caractristiques du problme.
11. Pour plus de dtails, voir sa page daide ainsi que celles des mthodes internes de lidal concern, dont le nom commence par _groebner_basis.

218

CHAP. 9. SYSTMES POLYNOMIAUX Considrons les idaux Cn (K ) K [x0 , . . . , xn1 ] dnis par : C2 (K ) = x0 + x1 , x0 x1 1 C3 (K ) = x0 + x1 + x2 , x0 x1 + x0 x2 + x1 x2 , x0 x1 x2 1 . . .
k

(9.11)

Cn (K ) =
iZ/nZ j =0

n2

xi+j

k=0

+ x 0 x n1 1 ,

et accessibles en Sage par des commandes telles que : sage: from sage.rings.ideal import Cyclic sage: Cyclic(QQ[ x,y,z ]) Ideal (x + y + z, x*y + x*z + y*z, x*y*z - 1) of Multivariate Polynomial Ring in x, y, z over Rational Field Ce sont des problmes de test classiques pour valuer les performances doutils de rsolution des systmes polynomiaux. Sur une machine o Sage met moins dune seconde calculer la base de Grbner rduite de C6 (Q) : sage: def C(R, n): return Cyclic(PolynomialRing(R, x , n)) sage: %time len(C(QQ, 6).groebner_basis()) CPU times: user 0.25 s, sys: 0.01 s, total: 0.26 s Wall time: 0.97 s 45 le calcul de celle de C7 (Q) ne se termine pas en une douzaine dheures, et utilise plus de 3 Go de mmoire. dfaut de pouvoir calculer la base de Grbner sur les rationnels, essayons de remplacer Q par un corps ni Fp . Lide, habituelle en calcul formel, est de limiter le cot des oprations sur les coecients : celles sur les lments de Fp prennent un temps constant, tandis que le nombre de chires des rationnels a tendance crotre violemment au l des calculs. On choisit p susamment petit pour que les calculs dans Fp puissent tre faits directement sur des entiers machine. Il ne doit cependant pas tre trop petit, de sorte que la base de Grbner sur Fp ait des chances de partager une bonne partie de la structure de celle sur Q. Par exemple, avec un p convenable, la base de Grbner de C6 (Fp ) a le mme nombre dlments que celle de C6 (Q) : sage: p = previous_prime(2^30) sage: len(C(GF(p), 6).groebner_basis()) 45 En augmentant la taille du systme traiter, on voit que linuence du corps des coecients sur le temps de calcul est loin dtre ngligeable : les cas n = 7 et n = 8 deviennent faisables sans problme. sage: %time len(C(GF(p), 7).groebner_basis())

9.3. BASES DE GRBNER CPU times: user 3.71 s, sys: 0.00 s, total: 3.71 s Wall time: 3.74 s 209 sage: %time len(C(GF(p), 8).groebner_basis()) CPU times: user 104.30 s, sys: 0.07 s, total: 104.37 s Wall time: 104.49 s 372

219

Ces exemples illustrent aussi un autre phnomne important : la sortie dun calcul de base de Grbner peut tre beaucoup plus grosse que lentre. Ainsi, le dernier calcul ci-dessus montre que toute base de Grbner, rduite ou non, de C8 (Fp ) (avec cette valeur de p) pour lordre degrevlex compte au moins 372 lments, alors que C8 est engendr par seulement 8 polynmes.

220

CHAP. 9. SYSTMES POLYNOMIAUX

Pour rsoudre cette quation direntielle, regardez-la jusqu ce que la solution vienne delle-mme. George Plya (1887 - 1985)

quations direntielles et suites dnies par une relation de rcurrence


10.1
10.1.1

10

quations direntielles
Introduction

Si la mthode de George Plya semble peu ecace, on peut faire appel Sage mme si le domaine de la rsolution formelle des quations direntielles demeure une faiblesse de nombreux logiciels de calcul. Sage est en pleine volution cependant et progresse chaque version un peu plus en largissant son spectre de rsolution. On peut, si on le souhaite, invoquer Sage an dobtenir une tude qualitative : en eet, ses outils numriques et graphiques guideront lintuition. Cest lobjet de la section 14.2 du chapitre consacr au calcul numrique. Des outils dtude graphique des solutions sont donns la section 4.1.6. Des mthodes de rsolution laide de sries se trouvent la section 7.5.2. On peut prfrer rsoudre les quations direntielles exactement. Sage peut alors parfois y aider en donnant directement une rponse formelle comme nous le verrons dans ce chapitre. Dans la plupart des cas, il faudra passer par une manipulation savante de ces quations pour aider Sage. Il faudra veiller garder en tte que la solution attendue dune quation direntielle est une fonction drivable sur un certain intervalle mais que Sage, lui, manipule des expressions sans domaine de dnition. La machine aura donc besoin dune intervention humaine pour aller vers une solution rigoureuse.

222

CHAP. 10. QUATIONS DIFFRENTIELLES ET RCURRENCES

Nous tudierons dabord les gnralits sur les quations direntielles ordinaires dordre 1 et quelques cas particuliers comme les quations linaires, les quations variables sparables, les quations homognes, une quation dpendant dun paramtre (10.1.2) ; puis de manire plus sommaire les quations dordre 2 ainsi quun exemple dquation aux drives partielles (10.1.3). Nous terminerons par lutilisation de la transforme de Laplace (10.1.4) et enn la rsolution de certains systmes direntiels (10.1.5). On rappelle quune quation direntielle ordinaire (parfois note EDO, ou ODE en anglais) est une quation faisant intervenir une fonction (inconnue) dune seule variable, ainsi quune ou plusieurs drives, successives ou non, de la fonction. Dans lquation y (x) + x y (x) = sin(x) la fonction inconnue y est appele la variable dpendante et la variable x (par rapport laquelle y varie) est appele la variable indpendante . Une quation aux drives partielles (note parfois EDP, ou PDE en anglais) fait intervenir plusieurs variables indpendantes ainsi que les drives partielles de la variable dpendante par rapport ces variables indpendantes. Sauf mention contraire, on considrera dans ce chapitre des fonctions dune variable relle.

10.1.2

quations direntielles ordinaires dordre 1


F (x, y (x), y (x)) = 0.

Commandes de base. On voudrait rsoudre une EDO dordre 1 :

On commence par dnir une variable x et une fonction y dpendant de cette variable : sage: x = var( x ) sage: y = function( y , x) On utilise ensuite : sage: desolve(equation, variable,ics = ..., ivar = ..., ....: show_method = ..., contrib_ode = ...) o : equation est lquation direntielle. Lgalit est symbolise par ==. Par exemple lquation y = 2y + x scrit diff(y,x) == 2*y+x ; variable est le nom de la variable dpendante, cest--dire la fonction y dans y = 2y + x ; ics est un argument optionnel qui permet dindiquer des conditions initiales. Pour une quation du premier ordre, on donne une liste [x0 ,y0 ], pour les quations du second ordre cest [x0 ,y0 ,x1 ,y1 ] ou [x0 ,y0 ,y0 ] ; ivar est un argument optionnel qui permet de prciser la variable indpendante, cest--dire x dans y = 2y + x. Cet argument doit absolument tre prcis en cas dquations dpendant de paramtres comme par exemple y = ay + bx + c ;

10.1. QUATIONS DIFFRENTIELLES

223

show_method est un argument optionnel x False par dfaut. Dans le cas contraire, il demande Sage de prciser la mthode de rsolution utilise. Les termes anglais renvoys peuvent tre linear, separable, exact, homogeneous, bernoulli, generalized homogeneous. Sage renvoie alors une liste dont le premier argument est la solution et le deuxime la mthode ; contrib_ode est un argument optionnel par dfaut x False. Dans le cas contraire, desolve pourra soccuper des quations de Riccati, Lagrange, Clairaut et dautres cas pathologiques. quations du premier ordre pouvant tre rsolues directement par Sage. Nous allons tudier dans cette section comment rsoudre avec Sage les quations linaires, les quations variables sparables, les quations de Bernoulli, les quations homognes, les quations exactes, ainsi que les quations de Riccati, Lagrange et Clairaut. quations linaires. Il sagit dquations du type : y + P (x)y = Q(x), o P et Q sont des fonctions continues sur des intervalles donns. Exemple : y + 3y = ex . sage: x = var( x ); y = function( y , x) sage: desolve(diff(y,x) + 3*y == exp(x), y, show_method=True) [1/4*(4*c + e^(4*x))*e^(-3*x), linear ] quations variables sparables. Il sagit dquations du type : P (x) = y Q(y ), o P et Q sont des fonctions continues sur des intervalles donns. Exemple : yy = x. sage: desolve(y*diff(y,x) == x, y, show_method=True) [1/2*y(x)^2 == 1/2*x^2 + c, separable ] Attention ! Sage parfois ne reconnat pas les quations variables sparables et les traite comme des quations exactes. Exemple : y = ex+y . sage: desolve(diff(y,x) == exp(x+y), y, show_method=True) [-(e^(x + y(x)) + 1)*e^(-y(x)) == c, exact ] quations de Bernoulli. Il sagit dquations du type : y + P (x)y = Q(x)y , o P et Q sont des fonctions continues sur des intervalles donns et 0, 1 . Exemple : y y = xy 4 . sage: desolve(diff(y,x)-y == x*y^4, y, show_method=True)

224

CHAP. 10. QUATIONS DIFFRENTIELLES ET RCURRENCES

[e^x/(-1/3*(3*x - 1)*e^(3*x) + c)^(1/3), bernoulli ] quations homognes. Il sagit dquations du type : y = P (x, y ) , Q(x, y )

o P et Q sont des fonctions homognes de mme degr sur des intervalles donns. Exemple : x2 y = y 2 + xy + x2 . sage: desolve(x^2*diff(y,x) == y^2+x*y+x^2, y, show_method=True) [c*x == e^(arctan(y(x)/x)), homogeneous ] Les solutions ne sont pas donnes de manire explicite. Nous verrons plus loin comment se dbrouiller dans certains cas. quations exactes. Il sagit dquations du type : f f dx + dy, x y avec f une fonction de deux variables direntiable. cos(y )2x 2 2 Exemple : y = y +x sin(y ) avec f = x x cos y + y /2. sage: desolve(diff(y,x) == (cos(y)-2*x)/(y+x*sin(y)), y, ....: show_method=True) [x^2 - x*cos(y(x)) + 1/2*y(x)^2 == c, exact ] Ici encore, les solutions ne sont pas donnes de manire explicite. quations de Riccati. Il sagit dquations du type : y = P (x)y 2 + Q(x)y + R(x), o P , Q et R sont des fonctions continues sur des intervalles donns. 1 1 Exemple : y = xy 2 + x y x 2. Il faut dans ce cas xer loption contrib_ode True pour que Sage cherche des solutions avec des mthodes plus complexes. sage: desolve(diff(y,x) == x*y^2+y/x-1/x^2, y, ....: contrib_ode=True, show_method=True)[1] riccati quations de Lagrange et de Clairaut. Lorsque lquation est de la forme y = xP (y ) + Q(y ) o P et Q sont de classe C 1 sur un certain intervalle, on parle dquation de Lagrange. Lorsque P est lidentit, on parle dquation de Clairaut. Exemple : y = xy y 2 . sage: desolve(y == x*diff(y,x)-diff(y,x)^2, y, ....: contrib_ode=True, show_method=True) [[y(x) == -c^2 + c*x, y(x) == 1/4*x^2], clairault ]

10.1. QUATIONS DIFFRENTIELLES quation linaire. Rsolvons par exemple y + 2y = x2 2x + 3 :

225

sage: x = var( x ); y = function( y , x) sage: DE = diff(y,x)+2*y == x**2-2*x+3 sage: desolve(DE, y) -1/4*(2*(2*x - 1)*e^(2*x) - (2*x^2 - 2*x + 1)*e^(2*x) - 4*c - 6*e^(2*x))*e^(-2*x) Ordonnons un peu tout a avec la commande expand : sage: desolve(DE, y).expand() c*e^(-2*x) + 1/2*x^2 - 3/2*x + 9/4 On prendra donc lhabitude dutiliser desolve(...).expand(). Quelle est la mthode utilise ? sage: desolve(DE, y, show_method=True)[1] linear Ajoutons des conditions initiales, par exemple x(0) = 1 : sage: desolve(DE, y, ics=[0,1]).expand() 1/2*x^2 - 3/2*x - 5/4*e^(-2*x) + 9/4 quations variables sparables. tudions lquation y log(y ) = y sin(x) : sage: x = var( x ); y = function( y , x) sage: desolve(diff(y,x)*log(y) == y*sin(x), y, show_method=True) [1/2*log(y(x))^2 == c - cos(x), separable ] Sage est daccord avec nous : cest bien une quation variables sparables. Prenons lhabitude de nommer nos solutions pour pouvoir les rutiliser par la suite : sage: ed = desolve(diff(y,x)*log(y) == y*sin(x), y); ed 1/2*log(y(x))^2 == c - cos(x)
1 Ici, y (x) nest pas donn de faon explicite : 2 log2 y (x) = c cos(x). On peut demander une expression de y (x) en utilisant solve. On fera attention la nature de ed et de y :

sage: solve(ed, y) [y(x) == e^(-sqrt(2*c - 2*cos(x))), y(x) == e^(sqrt(2*c - 2*cos(x)))] Il faudra tout de mme faire attention ce sqrt(2c - 2cos(x)) mme si Sage ne nous met pas tout de suite en garde : on veillera donc choisir par la suite c 1. Pour avoir lallure des courbes des solutions, il nous faut rcuprer le membre de droite de chaque solution avec la commande rhs(). Par exemple, pour obtenir le membre de droite de la premire solution en remplaant c par 5 : sage: solve(ed, y)[0].subs_expr(c==5).rhs()

226

CHAP. 10. QUATIONS DIFFRENTIELLES ET RCURRENCES

Traceback (most recent call last): ... NameError: name c is not defined En eet, nous navons pas dni c : cest Sage qui la introduit. Pour accder c, nous pouvons utiliser variables() qui donne la liste des variables dune expression : sage: ed.variables() (c, x) Seules c et x sont considres comme des variables car y a t dni comme une fonction de la variable x. On accde donc c avec ed.variables()[0] : sage: c = ed.variables()[0] sage: solve(ed, y)[0].subs_expr(c == 5).rhs() e^(-sqrt(-2*cos(x) + 10)) Autre exemple, pour avoir le trac de la premire solution avec c = 2 : sage: plot(solve(ed, y)[0].subs_expr(c == 2).rhs(), x, -3, 3) et on obtient :

0.24 0.22 0.2 0.18 0.16 0.14 0.12 0.1 -3 -2 -1 0 1 2 3

Pour avoir plusieurs courbes (voir gure 10.1), on utilise une boucle : sage: P = Graphics() sage: for k in range(1,20,2): ....: P += plot(solve(ed, y)[0].subs_expr(c==1+k/4).rhs(), x, -3, 3) On aurait pu avoir laspect correspondant aux deux solutions en eectuant une double boucle : sage: P = Graphics() sage: for j in [0,1]: ....: for k in range(1,10,2): ....: f = solve(ed,y)[j].subs_expr(c==2+0.25*k).rhs() ....: P += plot(f, x, -3, 3)

10.1. QUATIONS DIFFRENTIELLES

227

0.25 0.2 0.15 0.1 0.05 -3 -2 -1 0 1 2 3

Figure 10.1 Quelques solutions de y log(y ) = y sin(x).

sage: P mais la dirence dchelle entre les solutions ne permet plus de distinguer les courbes correspondant la premire solution :

25 20 15 10 5 -3 -2 -1 1 2 3

Exercice 38 (quations direntielles variables sparables). Rsolvez dans R les quations variables sparables suivantes : 1. (E1 ) : yy = sin(x) ; 2. (E2 ) : y =
sin(x) . cos(y )

1+y 2

quations homognes. On veut rsoudre lquation homogne xy = y + y 2 + x2 . Cest bien une quation homogne car on peut lcrire dy y+ = dx y 2 + x2 N (y, x) = , x M (y, x)

228

CHAP. 10. QUATIONS DIFFRENTIELLES ET RCURRENCES

or N (ky, kx) = kN (y, x) et M (ky, kx) = kM (y, x). Il sut donc deectuer le changement de variable vriant y (x) = x u(x) pour tout rel x pour obtenir une quation variables sparables. sage: u = function( u ,x) sage: y = x*u sage: DE = x*diff(y,x) == y + sqrt(x**2 + y**2) On applique le changement de variables dans lquation direntielle de dpart. Lquation ntant pas dnie en 0, on va la rsoudre sur ]0, +[ et sur ] , 0[. Travaillons dabord sur ]0, +[ : sage: assume(x>0) sage: desolve(DE, u) x == c*e^(arcsinh(x^2*u(x)/sqrt(x^4))) On nobtient pas u de manire explicite. Pour y remdier, on va utiliser une commande Maxima : ev comme valuer, avec loption logarc=True qui indique que les fonctions trigonomtriques hyperboliques inverses seront converties laide de logarithmes. Ensuite on va pouvoir exprimer u laide de la commande solve de Sage : sage: S = desolve(DE,u)._maxima_().ev(logarc=True).sage().solve(u); S [u(x) == -(sqrt(u(x)^2 + 1)*c - x)/c] Ici, S est une liste constitue dune quation ; S[0] sera donc lquation elle-mme. Lquation nest cependant toujours pas rsolue explicitement. Nous allons aider un peu Sage en lui demandant de rsoudre lquation quivalente c2 (u2 + 1) = (x uc)2 , via les commandes : sage: solu = (x-S[0]*c)^2; solu (c*u(x) - x)^2 == (u(x)^2 + 1)*c^2 sage: sol = solu.solve(u); sol [u(x) == -1/2*(c^2 - x^2)/(c*x)] Il ne reste plus qu revenir y : sage: y(x) = x*sol[0].rhs(); y(x) -1/2*(c^2 - x^2)/c Nous obtenons bien les solutions sous forme explicite : y ( x) = x2 c2 . 2c

Il ne reste plus qu tracer les solutions sur ]0, +[ en faisant attention prendre des constantes c non nulles : sage: P = Graphics()

10.1. QUATIONS DIFFRENTIELLES sage: for k in range(-19,19,2): ....: P += plot(y(x).subs_expr(c == 1/k), x, 0, 3) sage: P

229

80 60 40 20 -20 -40 -60 -80 0.5 1 1.5 2 2.5 3

Exercice 39 (quations direntielles homognes). Rsolvez dans R lquation homogne suivante : (E5 ) : xyy = x2 + y 2 .

Une quation paramtres : le modle de Verhulst. Le taux relatif de croissance dune population est une fonction linairement dcroissante de la population. Pour ltudier, on peut tre amen rsoudre une quation de la forme : y = ay by 2 , avec a et b des paramtres rels positifs. sage: x = var( x ); y = function( y , x); a, b = var( a, b ) sage: DE = diff(y,x) - a*y == -b*y**2 sage: sol = desolve(DE,[y,x]); sol -(log(b*y(x) - a) - log(y(x)))/a == c + x Nous nobtenons pas y explicitement. Essayons de lisoler avec solve : sage: Sol = solve(sol, y)[0]; Sol log(y(x)) == (c + x)*a + log(b*y(x) - a) Nous navons toujours pas de solution explicite. Nous allons regrouper les termes gauche et simplier cette expression laide de simplify_log() : sage: Sol(x) = Sol.lhs()-Sol.rhs(); Sol(x) -(c + x)*a - log(b*y(x) - a) + log(y(x)) sage: Sol = Sol.simplify_log(); Sol(x) -(c + x)*a + log(y(x)/(b*y(x) - a)) sage: solve(Sol, y)[0].simplify() y(x) == a*e^(a*c + a*x)/(b*e^(a*c + a*x) - 1)

230

CHAP. 10. QUATIONS DIFFRENTIELLES ET RCURRENCES

10.1.3

quations dordre 2

quations linaires coecients constants. Rsolvons maintenant une quation du second ordre linaire coecients constants, par exemple : y + 3y = x2 7x + 31. On utilise la mme syntaxe que pour les quations dordre 1, la drive seconde de y par rapport x sobtenant avec diff(y,x,2). sage: x = var( x ); y = function( y , x) sage: DE = diff(y,x,2)+3*y == x^2-7*x+31 sage: desolve(DE, y).expand() k1*sin(sqrt(3)*x) + k2*cos(sqrt(3)*x) + 1/3*x^2 - 7/3*x + 91/9 Ajoutons des conditions initiales, par exemple y (0) = 1 et y (0) = 2 : sage: desolve(DE, y, ics=[0,1,2]).expand() 1/3*x^2 + 13/9*sqrt(3)*sin(sqrt(3)*x) - 7/3*x - 82/9*cos(sqrt(3)*x) + 91/9 ou bien y (0) = 1 et y (1) = 0 : sage: desolve(DE, y, ics=[0,1,-1,0]).expand() 1/3*x^2 - 7/3*x - 82/9*sin(sqrt(3)*x)*cos(sqrt(3))/sin(sqrt(3)) + 115/9*sin(sqrt(3)*x)/sin(sqrt(3)) - 82/9*cos(sqrt(3)*x) + 91/9 cest--dire 1 2 7 82 sin( 3x) cos( 3) 115 sin( 3x) 82 91 + x x cos( 3x) + . 3 3 9 9 9 sin( 3) 9 sin( 3) Rsolution dune EDP : lquation de la chaleur. tudions la clbre quation de la chaleur. La temprature z se rpartit dans une tige rectiligne homogne de longueur selon lquation (o x est labscisse le long de la tige, et t le temps) : 2z z (x, t) = C (x, t). x2 t On tudiera cette quation pour : t R+ , z (0, t) = 0 z ( , t) = 0 x ]0; [, z (x, 0) = 1.

On va chercher des solutions ne sannulant pas sous la forme : z (x, t) = f (x)g (t). Cest la mthode de sparation des variables. sage: x, t = var( x, t ); f = function( f ,x); g = function( g ,t) sage: z = f*g sage: eq(x,t) = diff(z,x,2) == diff(z,t); eq(x,t) g(t)*D[0, 0](f)(x) == f(x)*D[0](g)(t)

10.1. QUATIONS DIFFRENTIELLES Lquation devient donc : g (t) d2 f (x) dg (t) = f (x) . 2 dx dt

231

Divisons par f (x)g (t), suppos non nul : sage: eqn = eq/z; eqn(x,t) D[0, 0](f)(x)/f(x) == D[0](g)(t)/g(t) On obtient alors une quation o chaque membre ne dpend que dune variable : 1 d2 f (x) 1 dg (t) = . 2 f (x) dx g (t) dt Chaque membre ne peut donc qutre constant. Sparons les quations et introduisons une constante k : sage: k = var( k ) sage: eq1(x,t) = eqn(x,t).lhs() == k; eq2(x,t) = eqn(x,t).rhs() == k Rsolvons sparment les quations en commenant par la deuxime : sage: g(t) = desolve(eq2(x,t),[g,t]); g(t) c*e^(k*t) donc g (t) = cekt avec c une constante. Pour la premire, nous ny arrivons pas directement : sage: desolve(eq1,[f,x]) Traceback (most recent call last): ... TypeError: ECL says: Maxima asks: Is k positive, negative, or zero? Utilisons assume : sage: assume(k>0); desolve(eq1,[f,x]) k1*e^(sqrt(k)*x) + k2*e^(-sqrt(k)*x) cest--dire f (x) = k1 ex
k

+ k2 ex

10.1.4

Transforme de Laplace

La transforme de Laplace permet de convertir une quation direntielle avec des conditions initiales en quation algbrique et la transforme inverse permet ensuite de revenir la solution ventuelle de lquation direntielle. Pour mmoire, si f est une fonction dnie sur R en tant identiquement nulle sur ]; 0[, on appelle transforme de Laplace de f la fonction F dnie, sous certaines conditions, par :
+

L f (x) = F (s) =
0

esx f (x) dx.

232

CHAP. 10. QUATIONS DIFFRENTIELLES ET RCURRENCES

On obtient facilement les transformes de Laplace des fonctions polynomiales, trigonomtriques, exponentielles, etc. Ces transformes ont des proprits fort intressantes, notamment concernant la transforme dune drive : si f est continue par morceaux sur R+ alors L f (x) = sL f (x) f (0), et si f satisfait les conditions imposes sur f : L f (x) = s2 L f (x) sf (0) f (0). Exemple. On veut rsoudre lquation direntielle y 3y 4y = sin(x) en utilisant la transforme de Laplace avec les conditions initiales y (0) = 1 et y (0) = 1. Alors : L (y 3y 4y ) = L (sin(x)) , cest--dire : (s2 3s 4)L(y ) sy (0) y (0) + 3y (0) = L(sin(x)). Si on a oubli les tables des transformes de Laplace des fonctions usuelles, on peut utiliser Sage pour retrouver la transforme du sinus : sage: x, s = var( x, s ); f = function( f ,x) sage: f(x) = sin(x); f.laplace(x,s) x |--> 1/(s^2 + 1) Ainsi on obtient une expression de la transforme de Laplace de y : L(y ) = 1 s4 + . (s2 3s 4)(s2 + 1) s2 3s 4

Utilisons alors Sage pour obtenir la transforme inverse : sage: X(s) = 1/(s^2-3*s-4)/(s^2+1) + (s-4)/(s^2-3*s-4) sage: X(s).inverse_laplace(s, x) 9/10*e^(-x) + 1/85*e^(4*x) - 5/34*sin(x) + 3/34*cos(x) Si lon veut moiti tricher , on peut dcomposer X (s) en lments simples dabord : sage: X(s).partial_fraction() 1/34*(3*s - 5)/(s^2 + 1) + 1/85/(s - 4) + 9/10/(s + 1) et il ne reste plus qu lire une table dinverses. On peut cependant utiliser directement la bote noire desolve_laplace qui donnera directement la solution : sage: x = var( x ); y = function( y ,x) sage: eq = diff(y,x,x) - 3*diff(y,x) - 4*y - sin(x) == 0 sage: desolve_laplace(eq, y) 1/10*(8*y(0) - 2*D[0](y)(0) - 1)*e^(-x) + 1/85*(17*y(0) + 17*D[0](y)(0) + 1)*e^(4*x) - 5/34*sin(x) + 3/34*cos(x) sage: desolve_laplace(eq, y, ics=[0,1,-1]) 9/10*e^(-x) + 1/85*e^(4*x) - 5/34*sin(x) + 3/34*cos(x)

10.1. QUATIONS DIFFRENTIELLES

233

10.1.5

Systmes direntiels linaires

Un exemple simple de systme direntiel linaire du premier ordre. On veut rsoudre le systme direntiel suivant : y (x) = A y (x) y (0) = c avec 2 A = 2 0 On crit : sage: x = var( x ); y1 = function( y1 , x) sage: y2 = function( y2 , x); y3 = function( y3 , x) sage: y = vector([y1, y2, y3]) sage: A = matrix([[2,-2,0],[-2,0,2],[0,2,2]]) sage: system = [diff(y[i], x) - (A * y)[i] for i in range(3)] sage: desolve_system(system, [y1, y2, y3], ics=[0,2,1,-2]) [y1(x) == e^(-2*x) + e^(4*x), y2(x) == 2*e^(-2*x) - e^(4*x), y3(x) == -e^(-2*x) - e^(4*x)] Pour les conditions initiales, la syntaxe est : ics = [x0,y1(x0),y2(x0),y3(x0)]. Avec une matrice de valeurs propres complexes. A= Avec Sage : sage: x = var( x ); y1 = function( y1 , x); y2 = function( y2 , x) sage: y = vector([y1,y2]) sage: A = matrix([[3,-4],[1,3]]) sage: system = [diff(y[i], x) - (A * y)[i] for i in range(2)] sage: desolve_system(system, [y1, y2], ics=[0,2,0]) [y1(x) == 2*e^(3*x)*cos(2*x), y2(x) == e^(3*x)*sin(2*x)] soit : y1 (x) = 2 cos(2x)e3x y2 (x) = sin(2x)e3x . 3 1 4 , 3 c= Prenons cette fois 2 . 0 2 0 2 0 2 , 2 y1 (x) y (x) = y2 (x) , y3 (x) 2 c = 1 . 2

234

CHAP. 10. QUATIONS DIFFRENTIELLES ET RCURRENCES On veut rsoudre le systme :

Un systme du second ordre.

y1 (x) 2y1 (x) + 6y2 (x) y1 (x) 3y2 (x) = 0 y2 (x) + 2y1 (x) 6y2 (x) y1 (x) + y2 (x) = 0. On se ramne un systme du premier ordre en posant u = (u1 , u2 , u3 , u4 ) = (y1 , y2 , y1 , y2 ). On a alors : u1 u 2 u 3 u4 = u3 = u4 = 2u1 6u2 + u3 + 3u4 = 2u1 + 6u2 + u3 u4 ,

cest--dire u (x) = A u(x) avec

0 0 A= 2 2

0 0 6 6

1 0 0 1 . 1 3 1 1

Avec Sage : sage: sage: sage: sage: sage: sage: x = var( x ); u1 = function( u1 , x); u2 = function( u2 , x) u3 = function( u3 , x); u4 = function( u4 , x) u = vector([u1,u2,u3,u4]) A = matrix([[0,0,1,0],[0,0,0,1],[2,-6,1,3],[-2,6,1,-1]]) system = [diff(u[i], x) - (A*u)[i] for i in range(4)] sol = desolve_system(system, [u1, u2, u3, u4])

On ne retiendra que les deux premires composantes car ce sont y1 et y2 qui nous intressent, cest--dire u1 et u2 : sage: sol[0] u1(x) == 1/24*(2*u1(0) - 6*u2(0) - u3(0) + 3*u4(0))*e^(-4*x) + 1/12*(2*u1(0) - 6*u2(0) + 5*u3(0) + 3*u4(0))*e^(2*x) + 3/4*u1(0) + 3/4*u2(0) - 3/8*u3(0) - 3/8*u4(0) sage: sol[1] u2(x) == -1/12*(2*u1(0) - 6*u2(0) - u3(0) - 3*u4(0))*e^(2*x) - 1/24*(2*u1(0) - 6*u2(0) - u3(0) + 3*u4(0))*e^(-4*x) + 1/4*u1(0) + 1/4*u2(0) - 1/8*u3(0) - 1/8*u4(0) ce qui peut se rsumer, avec un bon sens de lobservation, : y1 (x) = k1 e2x + k2 e4x + 3k3 y2 (x) = k4 e2x k2 e4x + k3 avec k1 , k2 , k3 et k4 des paramtres dpendant des conditions initiales.

10.2. SUITES DFINIES PAR UNE RELATION DE RCURRENCE

235

quations direntielles Dclaration de variable Dclaration de fonction Rsolution dune quation Rsolution dun systme Conditions initiales 1er ordre Conditions initiales 2e ordre Conditions initiales pour les systmes Variable indpendante Mthode de rsolution Appel des mthodes particulires x=var( x ) y=function( y ,x) desolve(equation, y, <options>) desolve_system([eq1, ...], [y1, ...], <options>) [x0 , y (x0 )] [x0 , y (x0 ), x1 , y (x1 )] [x0 , y (x0 ), y (x0 )] [x0 , y1 (x0 ), y2 (x0 ), ...] ivar=x show_method=True contrib_ode=True

Transformes de Laplace Transforme dune fonction f : x f (x) Transforme inverse de X (s) Rsolution via la transformation de Laplace f.laplace(x,s) X(s).inverse_laplace(s,x) desolve_laplace(equation,fonction)

Commandes diverses Expression de la drive premire Forme dveloppe dune expression Variables intervenant dans une expression Substitution dune variable Membre de droite dune quation Membre de gauche dune quation diff(y,x) expr.expand() expr.variables() expr.subs_expr(var==val) equation.rhs() equation.lhs()

Tableau 10.1 Commandes utiles pour la rsolution dquations direntielles.

10.2
10.2.1

Suites dnies par une relation de rcurrence


Suites dnies par un+1 = f (un )

Dnition de la suite. Considrons une suite dnie par une relation un+1 = f (un ) avec u0 = a. On peut dnir la suite naturellement laide dun algorithme rcursif. Prenons par exemple une suite logistique (suite dnie par une rcurrence de la forme xn+1 = rxn (1 xn )) : f : x 3.83 x 1 x 100 000 et u0 = 20 000.

Celle-ci peut se dnir en Sage par : sage: x = var( x ); f = function( f ,x) sage: f(x) = 3.83*x*(1 - x/100000) sage: def u(n): ....: if n==0: return(20000) ....: else: return f(u(n-1)) On peut prfrer une dnition itrative :

236

CHAP. 10. QUATIONS DIFFRENTIELLES ET RCURRENCES

sage: def v(n): ....: V = 20000; ....: for k in [1..n]: ....: V = f(V) ....: return V Reprsentation graphique. donnes (k, uk ) : On peut demander de tracer les points de coor-

sage: def nuage(u,n): ....: L = [[0,u(0)]]; ....: for k in [1..n]: ....: L += [[k,u(k)]] ....: points(L).show() partir du dessin suivant, on conjecture lexistence de trois valeurs dadhrence : sage: nuage(u,50)

90000 80000 70000 60000 50000 40000 30000 20000 0 10 20 30 40 50

On aurait pu prfrer la reprsentation faisant intervenir la premire bissectrice et la courbe reprsentative de f . Celle-ci nexistant pas nativement dans Sage, nous allons construire une petite procdure qui eectuera le travail : sage: def escargot(f,x,u0,n,xmin,xmax): ....: u = u0 ....: P = plot(x, x, xmin, xmax, color= gray ) ....: for i in range(n): ....: P += line([[u,u],[u,f(u)],[f(u),f(u)]], color = red ) ....: u = f(u) ....: P += f.plot(x, xmin, xmax, color= blue ) # Courbe de f ....: P.show() Par exemple, avec la mme suite : sage: f(x) = 3.83*x*(1 - x/100000)

10.2. SUITES DFINIES PAR UNE RELATION DE RCURRENCE sage: escargot(f,x,20000,100,0,100000) on observe galement les trois valeurs dadhrence :

237

1e5

8e4 6e4 4e4 2e4 2e4


10.2.2

4e4

6e4

8e4

1e5

Suites rcurrentes linaires


ak un+k + ak1 un+k1 + + a1 un+1 + a0 un = 0

Sage traite les suites du type :

avec (ai )0 i k une famille de scalaires. Par exemple, considrons la suite : u0 = 1, u1 = 1, un+2 = 3 1 un+1 un . 2 2

Dans la version 5.9 de Sage, la fonction bien connue rsolve nest pas accessible directement. Il faut aller la chercher dans SymPy, ce qui entrane certains dsagrments comme les changements de syntaxe pour dclarer les variables. Voici par exemple le prambule ncessaire la dnition de la suite : sage: from sympy import Function, Symbol sage: u = Function( u ); n = Symbol( n , integer=True) Il faut ensuite dnir la relation linaire sous la forme ak un+k + + a0 un = 0 : sage: f = u(n+2)-(3/2)*u(n+1)+(1/2)*u(n) On invoque enn rsolve en observant bien comment sont dclares les conditions initiales : sage: from sympy import rsolve sage: rsolve(f, u(n), {u(0):-1,u(1):1}) 3 - 4*2**(-n) cest--dire un = 3
1 2n2 .

238

CHAP. 10. QUATIONS DIFFRENTIELLES ET RCURRENCES

Remarque. Attention certaines limitations de rsolve. Par exemple, pour les suites rcurrentes linaires dordre 2, un rsultat correct nest obtenu que si lquation caractristique admet deux racines relles distinctes comme dans lexemple prcdent. Sinon, Sage exprime la solution laide du symbole de Pochhammer (RisingFactorial(x,n)) ce qui est peu exploitable.

10.2.3

Suites rcurrentes avec second membre

Sage traite aussi des suites du type : ak (n)un+k + ak1 (n)un+k1 + + a1 (n)un+1 + a0 (n)un = f (n) avec (ai )0 i k une famille de fonctions polynomiales en n et f qui peut tre une fonction polynomiale, rationnelle ou hypergomtrique de n. Selon la nature de f (n), la commande sera dirente : rsolve_poly si f est polynomiale ; rsolve_ratio si f est rationnelle ; rsolve_hyper si f est hypergomtrique. On dnit les ai (n) sous forme dune liste [a0 (n), . . . , ak1 (n), ak (n)]. Par exemple, pour tudier la complexit du tri fusion, on est amen tudier la suite : un+1 = 2un + 2n+2 , Le calcul donne sage: from sympy import rsolve_hyper sage: n = Symbol( n , integer=True) sage: rsolve_hyper([-2,1],2**(n+2),n) 2**n*C0 + 2**(n + 2)*(C0 + n/2) or u0 = 0 donne C0=0 donc un = n 2n+1 . u0 = 0.

Troisime partie

Calcul numrique

Nombres virgule ottante

11

Dans les chapitres suivants, les nombres virgule ottante sont au cur des calculs ; il convient de les tudier car leur comportement suit des rgles prcises. Comment reprsenter des nombres rels en machine ? Comme ces nombres ne peuvent pas en gnral tre cods avec une quantit nie dinformation, ils ne sont pas toujours reprsentables sur un ordinateur : il faut donc les approcher avec une quantit de mmoire nie. Un standard sest dgag autour dune approximation des nombres rels avec une quantit xe dinformation : la reprsentation virgule ottante. Dans ce chapitre, on trouve : une description sommaire des nombres virgule ottante et des dirents types de ces nombres disponibles dans Sage, et la dmonstration de quelquesunes de leurs proprits. Quelques exemples montreront certaines des dicults quon rencontre en calculant avec les nombres virgule ottante, quelques astuces pour arriver parfois les contourner, en esprant dvelopper chez le lecteur une prudence bien ncessaire ; en conclusion, nous essayons de donner quelques proprits que doivent possder les mthodes numriques pour pouvoir tre utilises avec ces nombres. Pour aller plus loin, le lecteur pourra consulter les documents [BZ10] et [Gol91] (disponibles sur le web) ou le livre [MBdD+ 10].

11.1
11.1.1

Introduction
Dnition

Un ensemble F (, r, m, M ) de nombres virgule ottante est dni par quatre paramtres : une base 2, un nombre de chires r et deux entiers relatifs m et

242

CHAP. 11. NOMBRES VIRGULE FLOTTANTE

M . Les lments de F (, r, m, M ) sont les nombres de la forme x = (1)s 0.d1 d2 . . . dr j , o les chires di sont des nombres entiers qui vrient 0 di < pour i > 1 et 0 < d1 < . Le nombre de chires r est la prcision ; lindicateur de signe s vaut 0 ou 1 ; lexposant j est compris entre les deux entiers m et M , et 0.d1 d2 . . . dr est la mantisse.

11.1.2

Proprits, exemples

La normalisation 0 < d1 < garantit que tous les nombres ont la mme quantit de chires signicatifs. On remarque que la valeur zro nest pas reprsentable avec la convention d1 > 0 : zro admet une reprsentation spciale. titre dexemple, le nombre not 0.028 en base 10 (reprsentation virgule xe), sera reprsent par 0.28 101 (sous rserve bien sr que r 2 et m 1 M ). La base 2 tant bien adapte la reprsentation binaire des ordinateurs, sera gal 2 dans les dirents ensembles de nombres ottants proposs par Sage, et nous nous placerons donc toujours dans ce cadre dans la suite de ce chapitre. Pour donner un exemple, 0.101 21 reprsente la valeur 5/4 dans lensemble F (2, 3, 1, 2). Comme la seule valeur possible de d1 pour = 2 est d1 = 1, il peut tre omis dans une implantation machine et, toujours dans lensemble F (2, 3, 1, 2), 5/4 pourra par exemple tre cod en machine avec les 5 bits : 00110, o le premier chire gauche reprsentera le signe +, les 2 chires suivants (01) la mantisse (101), et les deux derniers chires droite lexposant (00 codant la valeur 1 de lexposant, 01 la valeur 0, etc.). Il doit tre bien vident pour le lecteur que les ensembles F (, r, m, M ) dcrivent seulement un sous-ensemble ni des nombres rels. Pour reprsenter un nombre rel x qui se situe entre deux nombres conscutifs de F (, r, m, M ), il faut une application appele arrondi qui dnisse quel nombre approchera x : on peut prendre le nombre le plus proche de x, mais dautres choix sont possibles ; la norme impose que larrondi laisse F (, r, m, M ) invariant. Lensemble des nombres reprsentables est born, et les ensembles de nombres ottants contiennent les valeurs exceptionnelles +, qui reprsentent non seulement les innis (comme 1/0) mais aussi toutes les valeurs suprieures au plus grand nombre positif reprsentable (ou infrieures au plus petit nombre ngatif reprsentable), ainsi que des valeurs reprsentant des oprations indnies comme 0/0.

11.1.3

Normalisation

Aprs quelques ttonnements, la ncessit dune norme sest fait sentir, an que des programmes identiques fournissent les mmes rsultats sur des machines direntes. Depuis 1985, la norme IEEE 754 dnit plusieurs ensembles de nombres, dont, entre autres, des nombres stocks sur 64 bits ( double prcision ) : le signe

11.2. LES NOMBRES FLOTTANTS

243

s est cod sur 1 bit, la mantisse sur 53 bits (dont 52 seulement sont stocks), et lexposant sur 11 bits. Les nombres sont de la forme : (1)s 0.d1 d2 . . . d53 2j 1023 . Ils correspondent au type double du langage C.

11.2

Les nombres ottants

Sage fournit deux sortes de nombres ottants : 1. Les nombres ottants double prcision dcrits en 11.1.3 : ce sont les nombres fournis par le processeur de lordinateur ; dans Sage ces nombres appartiennent la classe RDF : sage: xrdf = RDF(3.0) 2. Des nombres virgule ottante de prcision arbitraire : chaque instance de la classe RealField dnit un ensemble de nombres virgule ottante de prcision donne (et ventuellement avec un mode darrondi donn : voir 11.3.2). Pour dclarer un nombre x100 avec une prcision de 100 bits, on crira par exemple : sage: R100 = RealField(100) # prcision : 100 bits. sage: x100 = R100(3/8); x100 0.37500000000000000000000000000 Les nombres de lensemble RealField(p) sont de la forme (1)s 0.d1 d2 . . . dp 2e , avec s {0, 1} ; la mantisse comporte p chires binaires, et e peut avoir 30 bits (ou plus sur certaines machines). On peut laisser implicite la prcision : sage: Rdefaut = RealField() # prcision par dfaut de 53 bits sage: xdefaut = Rdefaut(2/3) et on peut tester la prcision de tous les nombres virgule ottante avec la mthode prec() : sage: xrdf.prec() 53 sage: x100.prec() 100 sage: xdefaut.prec() 53 Ainsi, les nombres de lensemble RealField() et ceux de lensemble RDF ont la mme prcision, mais RealField() accepte des exposants bien plus grands. Lensemble RealField() avec la prcision de 53 bits est le type par dfaut des nombres rels de Sage :

244

CHAP. 11. NOMBRES VIRGULE FLOTTANTE

sage: x = 1.0; print type(x) <type sage.rings.real_mpfr.RealLiteral > sage: x.prec() 53 Ici, real_mpfr.RealLiteral indique que lensemble de nombres auquel appartient x est implant avec la bibliothque GNU MPFR. Rappelons que le type dun nombre est dni automatiquement par le second membre lors dune aectation : sage: sage: sage: sage: sage: sage: sage: sage: sage: x x x x x x x R x = = = = = = = = = 1.0 # 0.1e+1 # 1 # RDF(1) # RDF(1.) # RDF(0.1e+1) # 4/3 # RealField(20) R(1) # x appartient RealField() idem : x appartient RealField() x est entier x est un flottant double prcision machine idem : x est un flottant double prcision idem x est un nombre rationnel x est un flottant de prcision 20 bits

et des conversions naturelles des nombres rationnels sont eectues : sage: RDF(8/3) 2.66666666667 sage: R100 = RealField(100); R100(8/3) 2.6666666666666666666666666667 ainsi que des conversions entre nombres appartenant des ensembles de nombres virgule ottante dirents : sage: x = R100(8/3) sage: R = RealField(); R(x) 2.66666666666667 sage: RDF(x) 2.66666666667 Les dirents ensembles de nombres virgule ottante contiennent aussi les valeurs particulires +0, -0, +infinity, -infinity, et NaN : sage: 1.0/0.0 +infinity sage: RDF(1)/RDF(0) +infinity sage: RDF(-1.0)/RDF(0.) -infinity La valeur NaN est attribue aux rsultats indnis : sage: 0.0/0.0 NaN sage: RDF(0.0)/RDF(0.0) NaN

11.3. PROPRITS DES NOMBRES VIRGULE FLOTTANTE


x 10 1010 103 1 103 1010 1030
30

245

R2(x).ulp() 3.9e-31 2.9e-11 0.00049 0.50 510. 4.3e9 3.2e29

RDF(x).ulp() 8.75811540203e-47 6.46234853557e-27 1.08420217249e-19 1.11022302463e-16 5.68434188608e-14 9.53674316406e-07 7.03687441777e+13

R100(x).ulp() 1.2446030555722283414288128108e-60 9.1835496157991211560057541970e-41 1.5407439555097886824447823541e-33 1.5777218104420236108234571306e-30 8.0779356694631608874161005085e-28 1.3552527156068805425093160011e-20 1.0000000000000000000000000000

Tableau 11.1 Distances entre ottants.

11.2.1

Quel type de nombres choisir ?

Les ottants de prcision arbitraire permettent de calculer avec une prcision trs grande, alors que la prcision est xe pour les nombres RDF. En contrepartie les calculs avec les nombres RealField(n) font appel la bibliothque logicielle GNU MPFR, alors que pour les nombres RDF, les calculs sont eectus par larithmtique ottante du processeur, qui est beaucoup plus rapide. On donne en 13.2.10 une comparaison o lecacit des nombres ottants machine se conjugue avec lutilisation de bibliothques optimises pour ces nombres. Notons que, parmi les mthodes de calcul numrique quon rencontrera dans les chapitres suivants, nombreuses sont celles qui utilisent uniquement les nombres ottants RDF et, quoiquon fasse, convertiront toujours les nombres virgule ottante dans ce format. R2, un ensemble de ottants jouets. Les ottants de prcision arbitraire, outre quils sont irremplaables pour des calculs en grande prcision, permettent de dnir une classe de ottants qui, parce quils sont trs peu prcis, montrent de manire caricaturale les proprits des nombres virgule ottante : lensemble R2 des nombres de prcision 2 bits : sage: R2 = RealField(2)

11.3
11.3.1

Quelques proprits des nombres virgule ottante


Des ensembles pleins de trous

Dans chaque ensemble de nombres virgule ottante, la mthode ulp() (unit in the last place ) donne la taille de lintervalle sparant chaque nombre du nombre reprsentable le plus proche (dans la direction oppose de celle de zro) : sage: x2 = R2(1.); x2.ulp() 0.50 sage: xr = 1.; xr.ulp() 2.22044604925031e-16

246

CHAP. 11. NOMBRES VIRGULE FLOTTANTE

Le lecteur pourra vrier facilement la valeur donne pour x2.ulp(). Le tableau 11.1 donne la taille de lintervalle sparant un nombre x ou plus exactement R(x) o R est lensemble considr de son voisin le plus proche (dans la direction oppose de celle de zro) pour dirents ensembles de nombres (R100 est lensemble RealField(100)), et direntes valeurs de x. Comme on peut facilement le prvoir, la taille des trous sparant deux nombres conscutifs crot avec la taille des nombres.
Exercice 40 (une valeur un peu surprenante). Montrer que R100(1030 ).ulp() vaut bien 1.0000000000000000000000000000.

11.3.2

Larrondi

Comment approcher un nombre qui nest pas reprsentable dans un ensemble de nombres virgule ottante ? On peut dnir larrondi de direntes manires : vers le nombre reprsentable le plus proche : cest ainsi que lon procde dans lensemble RDF, et cest le comportement par dfaut des ensembles de nombres crs par RealField. Pour un nombre situ gale distance de deux nombres reprsentables, on arrondit la mantisse paire la plus proche ; en direction de ; RealField(p,rnd=RNDD) fournira ce comportement, avec une prcision de p bits ; en direction de zro ; exemple : RealField(p,rnd=RNDZ) ; en direction de + ; exemple : RealField(p,rnd=RNDU).

11.3.3

Quelques proprits

Larrondi ncessaire aux ensembles de nombres virgule ottante cause de nombreux eets pernicieux. Explorons-en quelques-uns. Un phnomne dangereux. Connu en anglais sous le nom de catastrophic cancellation , il sagit de la perte de prcision qui rsulte de la soustraction de deux nombres voisins ; plus exactement, il sagit dune amplication des erreurs : sage: a = 10000.0; b = 9999.5; c = 0.1; c 0.100000000000000 sage: a1 = a+c # on perturbe a sage: a1-b 0.600000000000364 Ici lerreur c introduite sur a rend le calcul de la dirence imprcis (les 3 dernires dcimales sont fausses). Application : calcul des racines dun trinme du second degr. Mme la rsolution dune quation du second degr ax2 + bx + c = 0 peut poser des problmes. Considrons le cas a = 1, b = 104 , c = 1 : sage: a = 1.0; b = 10.0^4; c = 1.0 sage: delta = b^2-4*a*c

11.3. PROPRITS DES NOMBRES VIRGULE FLOTTANTE sage: x = (-b-sqrt(delta))/(2*a); y = (-b+sqrt(delta))/(2*a) sage: x, y (-9999.99990000000, -0.000100000001111766) La somme des racines calcules est juste, mais pas le produit : sage: x+y+b/a 0.000000000000000 sage: x*y-c/a 1.11766307320238e-9

247

Lerreur est due au phnomne de catastrophic cancellation qui se manifeste quand on ajoute -b et sqrt(delta) lors du calcul de y. Ici, on peut rcuprer une meilleure approximation de y : sage: y = (c/a)/x; y -0.000100000001000000 sage: x+y+b/a 0.000000000000000 On remarque que, du fait de larrondi, la somme des racines reste correcte. Le lecteur pourra envisager tous les cas possibles pour le choix de a, b et c pour se convaincre que lcriture dun programme numriquement robuste pour le calcul des racines dun trinme du second degr est loin dtre simple. Les ensembles de nombres ottants ne sont pas des groupes pour laddition. En eet, laddition ny est pas associative. Utilisons lensemble R2 (avec 2 bits de prcision) : sage: x1 = R2(1/2); x2 = R2(4); x3 = R2(-4) sage: x1, x2, x3 (0.50, 4.0, -4.0) sage: x1+(x2+x3) 0.50 sage: (x1+x2)+x3 0.00 Nous pouvons en dduire que les dirents arrangements possibles des calculs dans un programme ne sont pas sans importance sur le rsultat ! Rcurrences, suites de nombres virgule ottante. Considrons 1 la rcurrence un+1 = 4un 1. Si u0 = 1/3, la suite est stationnaire : ui = 1/3 pour tout i. sage: x = RDF(1/3) sage: for i in range(1,100): x = 4*x-1; print x
1. Merci Marc Delglise (Institut Camille Jordan, Lyon) pour cet exemple.

248 0.333333333333 0.333333333333 0.333333333333 ... -1.0 -5.0 -21.0 -85.0 -341.0 -1365.0 -5461.0 -21845.0 ...

CHAP. 11. NOMBRES VIRGULE FLOTTANTE

La suite calcule diverge ! On peut remarquer que ce comportement est assez naturel car il sagit dun phnomne classique dinstabilit : toute erreur sur u0 , est multiplie par 4 chaque itration, et nous savons que larithmtique ottante introduit des erreurs qui vont donc tre amplies chaque itration. Calculons maintenant la rcurrence un+1 = 3un 1, avec u0 = 1/2. On sattend au mme rsultat : la suite, si elle est exactement calcule, est constante, mais toute erreur sera multiplie par 3 chaque pas. sage: x = RDF(1/2) sage: for i in range(1,100): x = 3*x-1; print x 0.5 0.5 0.5 ... 0.5 Cette fois-ci, la suite calcule reste constante ! Comment expliquer ces deux comportements dirents ? Regardons la reprsentation binaire de u0 dans chaque cas. Dans le premier cas (un+1 = 4un 1, u0 = 1/3), on a : 1 1 = 3 4

i=0

1 1 = i 4 4

i=0

1 , 22i

et donc 1/3 nest pas reprsentable exactement dans les ensembles de nombres virgule ottante dont nous disposons (avec = 2), quelle que soit leur prcision. Le lecteur est invit refaire le calcul prcdent dans un ensemble de grande prcision, par exemple RealField(1000) pour vrier que la suite calcule diverge toujours. Notons que si on remplace dans le premier programme la ligne sage: x = RDF(1/3) par sage: x = 1/3

11.3. PROPRITS DES NOMBRES VIRGULE FLOTTANTE

249

alors les calculs seectuent dans lensemble des nombres rationnels et les itrs successifs vaudront toujours 1/3. Dans le deuxime cas (un+1 = 3un 1, u0 = 1/2), u0 et 3/2 scrivent respectivement 0.1 et 1.1 en base 2 ; ils sont donc reprsentables exactement, sans arrondi, dans les divers ensembles de nombres ottants. Le calcul est donc exact, et la suite reste constante. Lexercice suivant montre quune suite programme dans un ensemble de nombres virgule ottante peut converger vers une limite fausse.
Exercice 41 (exemple d Jean-Michel Muller). On considre la rcurrence suivante (cf. [MBdD+ 10, p. 9]) : un = 111 1130 3000 + . un1 un1 un2

On peut montrer que la solution gnrale est de la forme : un = 100n+1 + 6n+1 + 5n+1 . 100n + 6n + 5n

1. On choisit u0 = 2 et u1 = 4 : quelles sont les valeurs de , et ? Vers quelle limite converge la suite ? 2. Programmer le calcul de la suite (toujours avec u0 = 2 et u1 = 4) dans lensemble RealField() (ou dans RDF). Que peut-on constater ? 3. Expliquer ce comportement. 4. Eectuer le mme calcul dans un ensemble de grande prcision, par exemple RealField(5000). Commenter le rsultat. 5. La suite est dnie dans Q. La programmer dans lensemble des nombres rationnels et commenter le rsultat.

Les nombres ottants et la sommation des sries numriques. On considre une srie numrique relle de terme gnral un positif. Le calcul des m sommes partielles i=0 ui dans un ensemble de nombres virgule ottante va tre perturb par les erreurs darrondi. Le lecteur pourra samuser montrer que, si un tend vers 0 quand n tend vers linni, et si les sommes partielles restent dans lintervalle des nombres reprsentables, alors, partir dun certain rang m, m la suite i=0 ui calcule avec arrondi est stationnaire (cf. [Sch91]). Bref, dans le monde des nombres ottants, la vie est simple : les sries dont le terme gnral positif tend vers 0 convergent, condition que les sommes partielles ne croissent pas trop ! Regardons cela avec la srie harmonique (divergente) de terme un = 1/n : sage: def sumharmo(P): ....: RFP = RealField(P) ....: y = RFP(1.); x = RFP(0.); n = 1 ....: while x <> y: ....: y = x; x += 1/n; n += 1 ....: return P, n, x Testons cette procdure avec direntes valeurs de la prcision P :

250 sage: sumharmo(2) (2, 5, 2.0) sage: sumharmo(20) (20, 131073, 12.631)

CHAP. 11. NOMBRES VIRGULE FLOTTANTE

Le lecteur pourra vrier avec une feuille de papier et un crayon que, dans notre ensemble R2 de ottants jouets, la procdure converge bien en 5 itrations vers la valeur 2.0. videmment le rsultat dpend de la prcision p, et le lecteur pourra aussi vrier (toujours avec son crayon...) que pour n > p , la somme calcule est stationnaire. Attention toutefois : avec la prcision par dfaut de 53 bits, et en eectuant 109 oprations par seconde, il faudra 253 /109 /3600 heures, soit environ 104 jours, pour atteindre la valeur stationnaire ! Amliorer le calcul de certaines rcurrences. Moyennant quelques prcautions, il est possible damliorer certains rsultats : voici un exemple utile. Il est frquent de rencontrer des rcurrences de la forme : yn+1 = yn + n , o les nombres n sont petits en valeur absolue par rapport aux nombres yn : penser par exemple lintgration des quations direntielles de la mcanique cleste pour la simulation du systme solaire, o de grandes valeurs (des distances, des vitesses) subissent de trs petites perturbations, en temps long [HLW02]. Mme si on peut calculer avec prcision les termes n , les erreurs darrondi lors des additions yn+1 = yn + n vont introduire des erreurs considrables. Prenons par exemple la suite dnie par y0 = 1013 , 0 = 1 et n+1 = an avec a = 1 108 . Voici la programmation habituelle, nave, du calcul de yn : sage: def iter(y,delta,a,n): ....: for i in range(0,n): ....: y += delta ....: delta *= a ....: return y Avec les valeurs rationnelles que nous avons choisies pour y0 , 0 et a, nous pouvons calculer la valeur exacte des itrs avec Sage : sage: def exact(y,delta,a,n): ....: return y+delta*(1-a^n)/(1-a) Calculons prsent 100 000 itrs avec les nombres virgule ottante RDF (par exemple), et comparons le rsultat la valeur exacte : sage: sage: sage: sage: exact y0 = RDF(10^13); delta0 = RDF(1); a = RDF(1-10^(-8)); n = 100000 ii = iter(y0,delta0,a,n) s = exact(10^13,1,1-10^(-8),n) print "exact - sommation classique:", s-ii - sommation classique: -45.5

Voici maintenant lalgorithme de la sommation compense :

11.3. PROPRITS DES NOMBRES VIRGULE FLOTTANTE sage: def sumcomp(y,delta,e,n,a): ....: for i in range(0,n): ....: b = y ....: e += delta ....: y = b+e ....: e += (b-y) ....: delta = a*delta # nouvelle valeur de delta ....: return y

251

Pour comprendre son comportement, regardons le schma ci-dessous (on suit ici les prsentations de Higham [Hig93] et[HLW02]), o les botes reprsentent les mantisses des nombres. La position des botes reprsente lexposant (plus la bote est gauche, plus lexposant est grand) : b = yn b1 b2 e1 e 0 n e = e + n yn+1 = b + e 1 1 b2 + 1 2 e1 + 2

b1

e = e + (b yn+1 ) e1 + 2 0 Lerreur darrondi est accumule dans e, et on constate quaucun des chires de n nest perdu, tandis quavec la manire nave de procder, les bits nots 2 disparaissent du calcul. Eectuons nouveau le calcul de 100 000 itrs, avec la mthode de la sommation compense : sage: c = sumcomp(y0,delta0,RDF(0.0),n,a) sage: print "exact-sommation compensee:", s-c exact-sommation compensee: -0.001953125 Lerreur absolue est de 45.5 avec lalgorithme naf, et de 0.0019 avec la sommation compense ! Au passage, observons que pour les erreurs relatives on obtient 4.549 1012 avec la sommation nave, et 1.95 1016 avec la sommation compense.

11.3.4

Nombres ottants complexes

Sage propose deux familles de nombres complexes reprsents en machine par des couples de nombres virgule ottante appartenant aux ensembles prcdemment rencontrs : 1. Les nombres complexes double prcision ComplexDoubleField (ou de manire abrge CDF). Ce sont les nombres de la forme x + i y o x et y sont chacun des nombres ottants double prcision . On cre les nombres ainsi : sage: x = CDF(2,1.); x 2.0 + 1.0*I sage: y = CDF(20,0); y

252 20.0 ou bien :

CHAP. 11. NOMBRES VIRGULE FLOTTANTE

sage: z = ComplexDoubleElement(2.,1.); z 2.0 + 1.0*I 2. Les nombres ottants complexes de prcision arbitraire ComplexField. Ce sont les nombres de la forme x + i y , o x et y ont la mme prcision de p bits. Une instance de la classe ComplexField cre un ensemble de prcision donne (53 par dfaut) : sage: C = ComplexField(); C(2,3) 2.00000000000000 + 3.00000000000000*I sage: C100 = ComplexField(100); C100(2,3) 2.0000000000000000000000000000 + 3.0000000000000000000000000000*I Bien entendu, les calculs avec ces dirents ensembles posent les mmes problmes darrondi que ceux avec les nombres rels virgule ottante.

11.3.5

Mthodes

Nous avons dj vu les mthodes prec et ulp. Les dirents ensembles de nombres rencontrs ici fournissent un grand nombre de mthodes. Donnons quelques exemples : des mthodes qui renvoient des constantes. Exemples : sage: R200 = RealField(200); R200.pi() 3.1415926535897932384626433832795028841971693993751058209749 sage: R200.euler_constant() 0.57721566490153286060651209008240243104215933593992359880577 des fonctions trigonomtriques sin, cos, arcsin, arccos, etc. Exemple : sage: x = RDF.pi()/2; x.cos() # approximation flottante de zero! 6.12323399574e-17 sage: x.cos().arccos() - x 0.0 les logarithmes (log, log10, log2, etc.), les fonctions trigonomtriques hyperboliques et leurs inverses (sinh, arcsinh, cosh, arccosh, etc.). des fonctions spciales (gamma, j0, j1, jn(k), etc.). Le lecteur consultera la documentation de Sage pour avoir une liste complte des trs nombreuses mthodes disponibles. Rappelons que cette liste peut tre obtenue en ligne de la manire suivante : sage: x = 1.0; x.<tab> Pour chaque mthode on obtient sa dnition, ses paramtres ventuels et un exemple dutilisation en tapant (ici pour la fonction dEuler (x)) : sage: x.gamma?

11.4. EN GUISE DE CONCLUSION

253

Ensembles de nombres ottants Nombres rels de prcision p bits Nombres ottants machine Nombres complexes de prcision p bits Nombres complexes machine RealField(p) RDF ComplexField(p) CDF

Tableau 11.2 Rcapitulatif des ensembles de nombres ottants.

11.4

En guise de conclusion

Les mthodes numriques implantes dans Sage, quon trouvera dcrites dans les chapitres suivants, ont toutes t tudies thoriquement ; leur analyse numrique consiste, entre autres, tudier la convergence des mthodes itratives, lerreur introduite en simpliant un problme pour le rendre calculable, mais aussi le comportement des calculs en prsence de perturbations, par exemple celles introduites par larithmtique inexacte des nombres virgule ottante. Considrons un algorithme F , qui, partir de donnes d, calcule x = F (d). Cet algorithme ne sera utilisable que sil namplie pas exagrment les erreurs sur d : une perturbation de d correspond une solution perturbe x = F (d + ). Il faut que lerreur introduite x x dpende raisonnablement de (de manire continue, ne croissant pas trop vite,...) : les algorithmes doivent avoir des proprits de stabilit pour pouvoir tre utilisables. Au chapitre 13, on explorera des problmes de stabilit pour les algorithmes utiliss en algbre linaire. Notons aussi que certains calculs sont dnitivement irralisables en prcision nie, comme par exemple le calcul de la suite donne dans lexercice 41 : toute perturbation, aussi faible soit-elle, entranera la convergence de la suite vers une valeur fausse ; cest un phnomne typique dinstabilit de la solution du problme que lon cherche rsoudre : ltude exprimentale dune suite laide de nombres virgule ottante doit tre mene avec une grande prudence. Le lecteur pourra peut-tre trouver dsesprante la pratique du calcul avec des nombres virgule ottante, mais ce jugement doit tre modr : la trs large majorit des ressources de calcul disponibles est utilise eectuer des oprations dans ces ensembles de nombres : rsolution approche dquations aux drives partielles, optimisation ou traitement du signal, etc. Les nombres virgule ottante doivent tre regards avec mance, mais ils nont pas empch le dveloppement du calcul et de ses applications : ce ne sont pas les erreurs darrondi qui limitent la validit de la prvision mtorologique, pour ne citer que cet exemple.

254

CHAP. 11. NOMBRES VIRGULE FLOTTANTE

quations non linaires


Ce chapitre explique comment rsoudre une quation non linaire avec Sage. Dans un premier temps on tudie les quations polynomiales et on montre les limitations de la recherche de solutions exactes. Ensuite on dcrit le fonctionnement de quelques mthodes classiques de rsolution numrique. Au passage on indique quels sont les algorithmes de rsolution numrique implments dans Sage.

12

12.1

quations algbriques

Par quation algbrique on entend une quation de la forme p(x) = 0 o p dsigne un polynme une indtermine dont les coecients appartiennent un anneau intgre A. On dit quun lment A est une racine du polynme p si p() = 0. Soit un lment de A. La division euclidienne de p par x assure lexistence dun polynme constant r tel que : p = (x )q + r. En valuant cette quation en , on obtient r = p(). Donc le polynme x divise p si, et seulement si, est une racine de p. Cette remarque permet dintroduire la notion de multiplicit dune racine du polynme p : il sagit du plus grand entier m tel que (x )m divise p. On observe que la somme des multiplicits des racines de p est infrieure ou gale au degr de p.

12.1.1

Mthode Polynomial.roots()

Rsoudre lquation algbrique p(x) = 0 consiste identier les racines du polynme p avec leur multiplicit. La mthode Polynomial.roots() donne les

256

CHAP. 12. QUATIONS NON LINAIRES

racines dun polynme. Elle prend jusqu trois paramtres, tous optionnels. Le paramtre ring permet de prciser lanneau o chercher les racines. Si on ne prcise pas de valeur pour ce paramtre, il sagira de lanneau des coecients du polynme. Le boolen multiplicities indique la nature des informations renvoyes par Polynomial.roots() : chaque racine peut tre accompagne de sa multiplicit. Le paramtre algorithm sert prciser quel algorithme utiliser ; les direntes valeurs possibles sont explicites plus loin (cf. 12.2.2). sage: R.<x> = PolynomialRing(RealField(prec=10)) sage: p = 2*x^7 - 21*x^6 + 64*x^5 - 67*x^4 + 90*x^3 \ ....: + 265*x^2 - 900*x + 375 sage: p.roots() [(-1.7, 1), (0.50, 1), (1.7, 1), (5.0, 2)] sage: p.roots(ring=ComplexField(10), multiplicities=False) [-1.7, 0.50, 1.7, 5.0, -2.2*I, 2.2*I] sage: p.roots(ring=RationalField()) [(1/2, 1), (5, 2)]

12.1.2

Reprsentation des nombres

Rappelons comment dsigner les anneaux usuels avec Sage (cf. 5.2). Les entiers relatifs sont reprsents par des objets de la classe Integer et, pour eectuer des conversions, on utilise le parent ZZ ou la fonction IntegerRing() qui renvoie lobjet ZZ. De la mme faon, les nombres rationnels sont reprsents par des objets de la classe Rational ; le parent commun ces objets est lobjet QQ que renvoie la fonction RationalField(). Dans les deux cas Sage utilise la bibliothque de calcul en prcision arbitraire GMP. Sans rentrer dans le dtail de la ralisation de cette bibliothque, les entiers manipuls avec Sage sont de taille arbitraire, la seule limitation provenant de la quantit de mmoire disponible sur la machine sur laquelle est excut le logiciel. Plusieurs reprsentations approches des nombres rels sont disponibles (cf. chapitre 11). Il y a RealField() pour la reprsentation utilisant les nombres virgule ottante avec une prcision donne et, en particulier, RR pour une prcision de 53 bits. Mais il y a aussi RDF et la fonction RealDoubleField() pour les nombres machine double prcision ; et encore les classes RIF et RealIntervalField() pour lesquelles un nombre rel est reprsent par un intervalle le contenant, les extrmits de cet intervalle tant des nombres virgule ottante. Les reprsentations analogues pour les nombres complexes se nomment : CC, CDF et CIF. L aussi, chaque objet est associ une fonction ; ce sont ComplexField(), ComplexDoubleField() et ComplexIntervalField(). Les calculs eectus par Polynomial.roots() sont exacts ou approchs selon le type de reprsentation des coecients du polynme et une ventuelle valeur du paramtre ring : par exemple avec ZZ ou QQ, les calculs sont exacts ; avec RR les calculs sont approchs. Dans la seconde partie de ce chapitre on prcise lalgorithme utilis pour le calcul des racines et le rle des paramtres ring et algorithm (cf. 12.2).

12.1. QUATIONS ALGBRIQUES

257

La rsolution des quations algbriques est intimement lie la notion de nombre. Le corps de dcomposition du polynme p (suppos non constant) est la plus petite extension du corps des coecients de p dans laquelle p est un produit de polynmes de degr 1 ; on montre quune telle extension existe toujours. Avec Sage, on peut construire le corps de dcomposition dun polynme irrductible avec la mthode Polynomial.root_field(). On peut alors calculer avec les racines implicites contenues dans le corps de dcomposition. sage: R.<x> = PolynomialRing(QQ, x ) sage: p = x^4 + x^3 + x^2 + x + 1 sage: K.<alpha> = p.root_field() sage: p.roots(ring=K, multiplicities=None) [alpha, alpha^2, alpha^3, -alpha^3 - alpha^2 - alpha - 1] sage: alpha^5 1

12.1.3

Thorme de dAlembert

Le corps de dcomposition du polynme coecients rels x2 + 1 nest autre que le corps des nombres complexes. Il est remarquable que tout polynme non constant coecients complexes possde au moins une racine complexe : cest ce quarme le thorme de dAlembert. En consquence tout polynme complexe non constant est un produit de polynmes de degr 1. On a observ un peu plus haut que la somme des multiplicits des racines dun polynme p est infrieure ou gale au degr de p. Dans le corps des complexes, on sait maintenant que cette somme est gale au degr de p. Autrement dit toute quation polynomiale de degr n coecients complexes possde n racines complexes, comptes avec leur multiplicit. Voyons comment la mthode Polynomial.roots() permet dillustrer ce rsultat. Dans lexemple qui suit, on construit lanneau des polynmes coecients rels (on se contente dune reprsentation utilisant les nombres virgule ottante avec une prcision de 53 bits). Puis un polynme de degr infrieur 15 est choisi alatoirement dans cet anneau. Enn on additionne les multiplicits des racines complexes calcules avec la mthode Polynomial.roots() et on compare cette somme au degr du polynme. sage: sage: sage: sage: True R.<x> = PolynomialRing(RR, x ) d = ZZ.random_element(1, 15) p = R.random_element(d) p.degree() == sum(r[1] for r in p.roots(CC))

12.1.4

Distribution des racines

On poursuit avec une curieuse illustration de la puissance de la mthode Polynomial.roots() : on trace tous les points du plan complexe dont laxe est une racine dun polynme de degr 12 et coecients gaux 1 ou -1. Le choix du degr est un compromis plus ou moins arbitraire ; il permet dobtenir un

258

CHAP. 12. QUATIONS NON LINAIRES

Figure 12.1 Distribution des racines de tous les polynmes de degr 12 coecients 1 ou 1.

trac prcis en peu de temps. Lutilisation de valeurs approches pour les nombres complexes sest galement impose pour des raisons de performance (cf. 13). sage: def build_complex_roots(degree): ....: R.<x> = PolynomialRing(CDF, x ) ....: v = [] ....: for c in CartesianProduct(*[[-1, 1]] * (degree + 1)): ....: v.extend(R(c).roots(multiplicities=False)) ....: return v sage: data = build_complex_roots(12) sage: g = plot(points(data, pointsize=1), aspect_ratio=1)

12.1.5

Rsolution par radicaux

Il est possible dans certains cas de calculer les valeurs exactes des racines dun polynme. Cest par exemple le cas ds que lon sait exprimer les racines en fonction des coecients du polynme et au moyen de radicaux (racines carrs, racines cubiques, etc.). Dans ce cas on parle de rsolution par radicaux. Pour eectuer ce type de rsolution avec Sage, il faut travailler avec les objets de la classe Expression qui reprsentent les expressions symboliques. On a vu que les entiers reprsents par des objets de la classe Integer ont un mme parent, lobjet ZZ. De la mme faon, les objets de la classe Expression ont un mme parent : il sagit de lobjet SR (acronyme de Symbolic Ring ) ; il ore notamment des possibilits de conversion vers la classe Expression. quations quadratiques. sage: sage: sage: <type a, b, c, x = var( a, b, c, x ) p = a * x^2 + b * x + c type(p) sage.symbolic.expression.Expression >

12.1. QUATIONS ALGBRIQUES sage: p.parent() Symbolic Ring sage: p.roots(x) [(-1/2*(b + sqrt(-4*a*c + b^2))/a, 1), (-1/2*(b - sqrt(-4*a*c + b^2))/a, 1)]

259

Degr strictement suprieur 2. Il est possible de rsoudre par radicaux les quations algbriques complexes de degr 3 et 4. En revanche il est impossible de rsoudre par radicaux toutes les quations polynomiales de degr suprieur ou gal 5 (cf. 7.3.4). Cette impossibilit conduit envisager des mthodes de rsolution numrique (cf. 12.2). sage: a, b, c, d, e, f, x = var( a, b, c, d, e, f, x ) sage: p = a*x^5+b*x^4+c*x^3+d*x^2+e*x+f sage: p.roots(x) Traceback (most recent call last): ... RuntimeError: no explicit roots found Illustrons avec Sage une mthode de rsolution des quations de degr 3 sur le corps des nombres complexes. Pour commencer on montre que lquation gnrale du troisime degr se ramne la forme x3 + px + q = 0. sage: x, a, b, c, d = var( x, a, b, c, d ) sage: P = a * x^3 + b * x^2 + c * x + d sage: alpha = var( alpha ) sage: P.subs(x = x + alpha).expand().coeff(x, 2) 3*a*alpha + b sage: P.subs(x = x - b / (3 * a)).expand().collect(x) a*x^3 - 1/3*(b^2/a - 3*c)*x - 1/3*b*c/a + 2/27*b^3/a^2 + d Pour obtenir les racines dune quation de la forme x3 + px + q = 0 on pose x = u + v. sage: sage: sage: u^3 + p, q, u, v = var( p, q, u, v ) P = x^3 + p * x + q P.subs(x = u + v).expand() 3*u^2*v + 3*u*v^2 + v^3 + p*u + p*v + q

Supposons la dernire expression nulle. On remarque alors que u3 + v 3 + q = 0 quivaut 3uv +p = 0 ; de plus, si ces galits sont vries, u3 et v 3 sont les racines dune quation du second degr : (X u3 )(X v 3 ) = X 2 (u3 + v 3 )X + (uv )3 = X 2 + qX p3 /27. sage: P.subs({x: (u + v)*(3*u*v + sage: P.subs({x: 0 sage: X = var( X sage: solve([X^2 u + v, q: -u^3 - v^3}).factor() p) u+v, q: -u^3 - v^3, p: -3 * u * v}).expand() ) + q*X - p^3 / 27 == 0], X, solution_dict=True)

260

CHAP. 12. QUATIONS NON LINAIRES

[{X: -1/2*q - 1/18*sqrt(12*p^3 + 81*q^2)}, {X: -1/2*q + 1/18*sqrt(12*p^3 + 81*q^2)}] Les solutions de lquation x3 + px + q = 0 sont donc les sommes u + v o u et v sont des racines cubiques de 4p3 + 27q 2 3 q 18 2 et 4p3 + 27q 2 3 q 18 2

vriant 3uv + p = 0.

12.1.6

Mthode Expression.roots()

Les exemples prcdents utilisent la mthode Expression.roots(). Cette mthode renvoie une liste de racines exactes, sans garantie de les trouver toutes. Parmi les paramtres optionnels de cette mthode, on retrouve les paramtres ring et multiplicities dj rencontrs avec la mthode Polynomial.roots(). Il est important de se rappeler que la mthode Expression.roots() ne sapplique pas uniquement des expressions polynomiales. sage: e = sin(x) * (x^3 + 1) * (x^5 + x^4 + 1) sage: roots = e.roots(); len(roots) 9 sage: roots [(0, 1), (-1/2*(I*sqrt(3) + 1)*(1/18*sqrt(3)*sqrt(23) - 1/2)^(1/3) - 1/6*(-I*sqrt(3) + 1)/(1/18*sqrt(3)*sqrt(23) - 1/2)^(1/3), 1), (-1/2*(-I*sqrt(3) + 1)*(1/18*sqrt(3)*sqrt(23) - 1/2)^(1/3) - 1/6*(I*sqrt(3) + 1)/(1/18*sqrt(3)*sqrt(23) - 1/2)^(1/3), 1), ((1/18*sqrt(3)*sqrt(23) - 1/2)^(1/3) + 1/3/(1/18*sqrt(3)*sqrt(23) - 1/2)^(1/3), 1), (-1/2*I*sqrt(3) - 1/2, 1), (1/2*I*sqrt(3) - 1/2, 1), (1/2*I*(-1)^(1/3)*sqrt(3) - 1/2*(-1)^(1/3), 1), (-1/2*I*(-1)^(1/3)*sqrt(3) - 1/2*(-1)^(1/3), 1), ((-1)^(1/3), 1)] Lorsque le paramtre ring nest pas dni, la mthode roots() de la classe Expression dlgue le calcul des racines au programme Maxima qui tente de factoriser lexpression puis eectue une rsolution par radicaux sur chaque facteur de degr strictement infrieur 5. Lorsque le paramtre ring est dni, lexpression est convertie en objet de la classe Polynomial dont les coecients ont pour parent lobjet identi par le paramtre ring ; ensuite le rsultat de la mthode Polynomial.roots() est renvoy. On dcrit plus loin lalgorithme utilis dans ce cas (cf. 12.2.2). On expose galement des exemples de calculs avec des racines implicites, auxquelles on accde par les objets QQbar et AA qui reprsentent les corps de nombres algbriques (cf. 7.3.2).

12.2. RSOLUTION NUMRIQUE

261

limination des racines multiples. tant donn un polynme p ayant des racines multiples, il est possible de construire un polynme racines simples (cest-dire de multiplicit 1), identiques celles de p. Donc, lorsquon calcule les racines dun polynme, on peut toujours supposer que ces racines sont simples. Justions lexistence du polynme racines simples et voyons comment le construire. Ceci permet de donner une nouvelle illustration de la mthode Expression.roots(). Soit une racine du polynme p dont la multiplicit est un entier m strictement suprieur 1. Cest une racine du polynme driv p avec multiplicit m 1. En eet, si p = (x )m q alors on a p = (x )m1 (mq + (x )q ). sage: alpha, m, x = var( alpha, m, x ); q = function( q , x) sage: p = (x - alpha)^m * q sage: p.derivative(x) m*(-alpha + x)^(m - 1)*q(x) + (-alpha + x)^m*D[0](q)(x) sage: simplify(p.derivative(x)(x=alpha)) 0 En consquence le pgcd de p et p est le produit (x )m 1 avec lensemble des racines de p de multiplicit strictement suprieure 1, et m la multiplicit de la racine . Si d dsigne ce pgcd, alors le quotient de p par d a bien les proprits attendues. Notons que le degr du quotient de p par d est strictement infrieur au degr de p. En particulier, si ce degr est strictement infrieur 5, il est possible dexprimer les racines au moyen de radicaux. Lexemple qui suit en donne une illustration pour un polynme coecients rationnels de degr 13. sage: R.<x> = PolynomialRing(QQ, x ) sage: p = 128 * x^13 - 1344 * x^12 + 6048 * x^11 - 15632 * x^10 \ ....: + 28056 * x^9 - 44604 * x^8 + 71198 * x^7 - 98283 * x^6 \ ....: + 105840 * x^5 - 101304 * x^4 + 99468 * x^3 - 81648 * x^2 \ ....: + 40824 * x - 8748 sage: d = gcd(p, p.derivative()) sage: (p // d).degree() 4 sage: roots = SR(p // d).roots(multiplicities=False) sage: roots [1/2*I*2^(1/3)*sqrt(3) - 1/2*2^(1/3), -1/2*I*2^(1/3)*sqrt(3) - 1/2*2^(1/3), 2^(1/3), 3/2] sage: [QQbar(p(alpha)).is_zero() for alpha in roots] [True, True, True, True]

12.2

Rsolution numrique

En mathmatiques, on oppose traditionnellement le discret et le continu. Lanalyse numrique relativise en quelque sorte cette opposition : un des aspects majeurs de lanalyse numrique consiste en eet aborder des questions portant sur les nombres rels, par essence du domaine du continu, en adoptant un point

262

CHAP. 12. QUATIONS NON LINAIRES

de vue exprimental sappuyant notamment sur lordinateur qui, lui, relve du discret. Sagissant de la rsolution dquations non linaires, de nombreuses questions se posent naturellement en dehors du calcul des valeurs approches des solutions : combien de racines relles possde une quation donne ? Combien de racines imaginaires, positives, ngatives ? Dans cette partie on commence par donner des lments de rponse pour le cas particulier des quations algbriques. Ensuite on dcrit quelques-unes des mthodes dapproximation qui permettent de calculer des valeurs approches des solutions dune quation non linaire.

12.2.1

Localisation des solutions des quations algbriques

Rgle de Descartes. La rgle de Descartes snonce de la manire suivante : le nombre de racines positives dun polynme coecients rels est infrieur ou gal au nombre de changements de signe de la suite des coecients du polynme. sage: R.<x> = PolynomialRing(RR, x ) sage: p = x^7 - 131/3*x^6 + 1070/3*x^5 - 2927/3*x^4 \ ....: + 2435/3*x^3 - 806/3*x^2 + 3188/3*x - 680 sage: sign_changes = \ ....: [p[i] * p[i + 1] < 0 for i in range(p.degree())].count(True) sage: real_positive_roots = \ ....: sum([alpha[1] if alpha[0] > 0 else 0 for alpha in p.roots()]) sage: sign_changes, real_positive_roots (7, 5) En eet, soient p un polynme coecients rels de degr d et p le polynme driv. On note u et u les suites des signes des coecients des polynmes p et p : on a ui = 1 selon que le coecient de degr i de p est positif ou ngatif. La suite u se dduit de u par simple troncature : on a ui = ui+1 pour 0 i < d. Il en rsulte que le nombre de changements de signe de la suite u est au plus gal au nombre de changements de signe de la suite u plus 1. Par ailleurs, le nombre de racines positives de p est au plus gal au nombre de racines positives de p plus un : un intervalle dont les extrmits sont des racines de p contient toujours une racine de p . Comme la rgle de Descartes est vraie pour un polynme de degr 1, les deux observations prcdentes montrent quelle est encore vraie pour un polynme de degr 2, etc. Il est possible de prciser la relation entre le nombre de racines positives et le nombre de changements de signes de la suite des coecients : la dirence entre ces nombres est toujours paire. Isolation de racines relles de polynmes. On vient de voir quil est possible dtablir, pour les polynmes coecients rels, une majoration du nombre de racines contenues dans lintervalle [0, +[. Plus gnralement, il existe des moyens de prciser le nombre de racines dans un intervalle donn.

12.2. RSOLUTION NUMRIQUE

263

nonons par exemple le thorme de Sturm. Soient p un polynme coecients rels, d son degr et [a, b] un intervalle. On construit une suite de polynmes par rcurrence. Pour commencer p0 = p et p1 = p ; ensuite, pi+2 est loppos du reste de la division euclidienne de pi par pi+1 . En valuant cette suite de polynmes aux points a et b on obtient deux suites relles nies (p0 (a), . . . , pd (a)) et (p0 (b), . . . , pd (b)). Le thorme de Sturm snonce ainsi : le nombre de racines de p appartenant lintervalle [a, b] est gal au nombre de changements de signe de la suite (p0 (a), . . . , pd (a)) diminu du nombre de changements de signe de la suite (p0 (b), . . . , pd (b)) en supposant que les racines de p sont simples, p(a) = 0 et p(b) = 0. Montrons comment implmenter ce thorme avec Sage. sage: def count_sign_changes(l): ....: changes = [l[i]*l[i + 1] < 0 for i in range(len(l) - 1)] ....: return changes.count(True) sage: def sturm(p, a, b): ....: assert p.degree() > 2 ....: assert not (p(a) == 0) ....: assert not (p(b) == 0) ....: assert a <= b ....: remains = [p, p.derivative()] ....: for i in range(p.degree() - 1): ....: remains.append(-(remains[i] % remains[i + 1])) ....: evals = [[], []] ....: for q in remains: ....: evals[0].append(q(a)) ....: evals[1].append(q(b)) ....: return count_sign_changes(evals[0]) \ ....: - count_sign_changes(evals[1]) Voici maintenant une illustration de cette fonction sturm(). sage: R.<x> = PolynomialRing(QQ, x ) sage: p = (x - 34) * (x - 5) * (x - 3) * (x - 2) * (x - 2/3) sage: sturm(p, 1, 4) 2 sage: sturm(p, 1, 10) 3 sage: sturm(p, 1, 200) 4 sage: p.roots(multiplicities=False) [34, 5, 3, 2, 2/3] sage: sturm(p, 1/2, 35) 5

264

CHAP. 12. QUATIONS NON LINAIRES

12.2.2

Mthodes dapproximations successives

Approximation : Gn. au sing. Opration par laquelle on tend se rapprocher de plus en plus de la valeur relle dune quantit ou dune grandeur sans y parvenir rigoureusement. Trsor de la Langue Franaise Dans cette section, on illustre direntes mthodes dapproximation des solutions dune quation non linaire f (x) = 0. Il y a essentiellement deux dmarches pour calculer ces approximations. Lalgorithme le plus performant mle les deux dmarches. La premire dmarche consiste construire une suite dintervalles embots qui contiennent une solution de lquation. On contrle la prcision, la convergence est assure mais la vitesse de convergence nest pas toujours bonne. La seconde dmarche suppose connue une valeur approche dune solution de lquation. Si le comportement local de la fonction f est susamment rgulier, on pourra calculer une nouvelle valeur approche plus proche de la solution. Par rcurrence, on obtient donc une suite de valeurs approches. Cette dmarche suppose donc connue une premire approximation du nombre cherch. Par ailleurs, son ecacit repose sur le bon comportement local de la fonction f : a priori, on ne matrise pas la prcision des valeurs approches ; pire, la convergence de la suite de valeurs approches nest pas ncessairement garantie. Dans toute cette partie, on considre une quation non linaire f (x) = 0 o f dsigne une fonction numrique dnie sur un intervalle [a, b] et continue sur cet intervalle. On suppose que les valeurs de f aux extrmits de lintervalle [a, b] sont non nulles et de signes opposs : autrement dit, le produit f (a)f (b) est strictement ngatif. La continuit de f assure donc lexistence dans lintervalle [a, b] dau moins une solution lquation f (x) = 0. Pour chaque mthode, on exprimente avec la fonction suivante. sage: f(x) = 4 * sin(x) - exp(x) / 2 + 1 sage: a, b = RR(-pi), RR(pi) sage: bool(f(a) * f(b) < 0) True Il convient de noter quavec cet exemple la commande solve nest daucune utilit. sage: solve(f(x) == 0, x) [sin(x) == 1/8*e^x - 1/4] sage: f.roots() Traceback (most recent call last): ... RuntimeError: no explicit roots found Les algorithmes de recherche de solutions dquations non linaires peuvent tre coteux : il convient de prendre quelques prcautions avant den dmarrer lexcution. On sassure notamment de lexistence de solutions en tudiant la continuit et la drivabilit de la fonction annuler ainsi que dventuels changements de signe ; cet eet le trac de graphe peut tre utile (cf. chapitre 4).

12.2. RSOLUTION NUMRIQUE

265

-3

-2

-1 -2 -4 -6 -8 -10

Figure 12.2 Courbe reprsentative de la fonction f .

Mthode de dichotomie. Cette mthode repose sur la premire dmarche : construire une suite dintervalles embots qui contiennent tous une solution de lquation f (x) = 0. On divise lintervalle [a, b] en son milieu, not c. Supposons f (c) = 0. Soit f (a)f (c) est strictement infrieur zro et lintervalle [a, c] contient ncessairement une solution de lquation ; soit f (c)f (b) est strictement infrieur zro et lintervalle [c, b] contient une solution de lquation. Ainsi on sait construire un intervalle contenant une solution et dont la longueur est deux fois plus petite que celle de lintervalle [a, b]. En rptant cette construction on obtient bien une suite dintervalles aux proprits attendues. Pour mettre en uvre cette dmarche, on dnit la fonction Python intervalgen comme suit. sage: def phi(s, t): return (s + t) / 2 sage: def intervalgen(f, phi, s, t): ....: msg = Wrong arguments: f({0})*f({1})>=0) .format(s, t) ....: assert (f(s) * f(t) < 0), msg ....: yield s ....: yield t ....: while True: ....: u = phi(s, t) ....: yield u ....: if f(u) * f(s) < 0:

266 ....: ....: ....: t = u else: s = u

CHAP. 12. QUATIONS NON LINAIRES

La dnition de cette fonction mrite quelques explications. La prsence du mot cl yield dans la dnition de intervalgen en fait un gnrateur (voir 15.2.4). Lors dun appel la mthode next() dun gnrateur, si linterprteur rencontre le mot cl yield, toutes les donnes locales sont sauvegardes, lexcution est interrompue et lexpression immdiatement droite du mot cl rencontr est renvoye. Lappel suivant la mthode next() dmarre linstruction qui suit le mot cl yield avec les donnes locales sauvegardes avant linterruption. Utilis dans une boucle innie (while True:) le mot cl yield permet donc de programmer une suite rcurrente avec une syntaxe proche de sa description mathmatique. Il est possible de stopper dnitivement lexcution en utilisant lhabituel mot cl return. Le paramtre phi reprsente une fonction ; elle caractrise la mthode dapproximation. Pour la mthode de la dichotomie, cette fonction calcule le milieu dun intervalle. Pour tester une autre mthode dapproximations successives reposant galement sur la construction dintervalles embots, on donne une nouvelle dnition de la fonction phi et on utilise nouveau la fonction intervalgen pour construire le gnrateur correspondant. Les paramtres s et t de la fonction reprsentent les extrmits du premier intervalle. Un appel assert permet de vrier que la fonction f change de signe entre les extrmits de cet intervalle ; on a vu que cela garantit lexistence dune solution. Les deux premires valeurs du gnrateur correspondent aux paramtres s et t. La troisime valeur est le milieu de lintervalle correspondant. Les paramtres s et t reprsentent ensuite les extrmits du dernier intervalle calcul. Aprs valuation de f au milieu de cet intervalle, on change une des extrmits de lintervalle en sorte que le nouvel intervalle contienne encore une solution. On convient de prendre pour valeur approche de la solution cherche le milieu du dernier intervalle calcul. Exprimentons avec lexemple choisi : suivent les trois approximations obtenues par la mthode de dichotomie applique sur lintervalle [, ]. sage: a, b (-3.14159265358979, 3.14159265358979) sage: bisection = intervalgen(f, phi, a, b) sage: bisection.next() -3.14159265358979 sage: bisection.next() 3.14159265358979 sage: bisection.next() 0.000000000000000 Pour comparer les direntes mthodes dapproximation, il est commode de disposer dun mcanisme automatisant le calcul de la valeur approche dune solution de lquation f (x) = 0 partir des gnrateurs dnis avec Sage pour

12.2. RSOLUTION NUMRIQUE

267

chacune de ces mthodes. Ce mcanisme doit permettre de contrler la prcision du calcul et le nombre maximum ditrations. Cest le rle de la fonction iterate dont la dnition suit. sage: from types import GeneratorType, FunctionType sage: def checklength(u, v, w, prec): ....: return abs(v - u) < 2 * prec sage: def iterate(series, check=checklength, prec=10^-5, maxit=100): ....: assert isinstance(series, GeneratorType) ....: assert isinstance(check, FunctionType) ....: niter = 2 ....: v, w = series.next(), series.next() ....: while niter <= maxit: ....: niter += 1 ....: u, v, w = v, w, series.next() ....: if check(u, v, w, prec): ....: print After {0} iterations: {1} .format(niter, w) ....: return ....: print Failed after {0} iterations .format(maxit) Le paramtre series doit tre un gnrateur. On conserve les trois dernires valeurs de ce gnrateur pour pouvoir eectuer un test de convergence. Cest le rle du paramtre check : une fonction qui stoppe ou non les itrations. Par dfaut la fonction iterate utilise la fonction checklength qui stoppe les itrations si le dernier intervalle calcul est de longueur strictement infrieure au double du paramtre prec ; cela garantit que la valeur calcule par la mthode de dichotomie est une valeur approche avec une erreur strictement infrieure prec. Une exception est dclenche ds que le nombre ditrations dpasse le paramtre maxit. sage: bisection = intervalgen(f, phi, a, b) sage: iterate(bisection) After 22 iterations: 2.15847275559132
Exercice 42. Modier la fonction intervalgen pour que le gnrateur stoppe si une des extrmits de lintervalle est une solution. Exercice 43. Utiliser les fonctions intervalgen et iterate pour programmer le calcul dune valeur approche dune solution de lquation f (x) = 0 partir dune suite dintervalles embots, chaque intervalle tant obtenu en divisant alatoirement le prcdent.

Mthode de la fausse position. Cette mthode repose encore sur la premire dmarche : construire une suite dintervalles embots qui contiennent tous une solution de lquation f (x) = 0. Mais cette fois-ci on utilise une interpolation linaire de la fonction f pour diviser chaque intervalle. Prcisment, pour diviser lintervalle [a, b], on considre le segment joignant les deux points de la courbe reprsentative de f dabscisses a et b. Comme f (a) et f (b) sont de signes opposs, ce segment coupe laxe des abscisses : il divise donc lintervalle [a, b] en deux intervalles. Comme pour la mthode de dichotomie,

268

CHAP. 12. QUATIONS NON LINAIRES

-3

-2

-1 -2 -4 -6 -8 -10

Figure 12.3 Mthode de la fausse position sur [, ].

on identie un intervalle contenant une solution en calculant la valeur que prend la fonction f au point commun ces deux intervalles. La droite passant par les points de coordonnes (a, f (a)) et (b, f (b)) a pour quation : f (b) f (a) (x a) + f (a). (12.1) y= ba Puisque f (b) = f (a), cette droite coupe laxe des abscisses au point dabscisse : a f (a) ba . f (b) f (a)

On peut donc tester cette mthode de la manire suivante. sage: sage: sage: After phi(s, t) = s - f(s) * (t - s) / (f(t) - f(s)) falsepos = intervalgen(f, phi, a, b) iterate(falsepos) 8 iterations: -2.89603757331027

Il est important de remarquer que les suites construites avec les mthodes de dichotomie et de la fausse position ne convergent pas ncessairement vers les mmes solutions. En rduisant lintervalle dtude on retrouve la solution positive obtenue avec la mthode de dichotomie.

12.2. RSOLUTION NUMRIQUE

269

2 0 -2 -4 -6 -8 -10

1.6

1.8

2.2

2.4

2.6

2.8

Figure 12.4 Mthode de la fausse position sur [/2, ].

sage: sage: sage: sage: sage: sage: After sage: After

a, b = RR(pi/2), RR(pi) phi(s, t) = t - f(t) * (s - t) / (f(s) - f(t)) falsepos = intervalgen(f, phi, a, b) phi(s, t) = (s + t) / 2 bisection = intervalgen(f, phi, a, b) iterate(falsepos) 15 iterations: 2.15846441170219 iterate(bisection) 20 iterations: 2.15847275559132

Mthode de Newton. Comme la mthode de la fausse position, la mthode de Newton utilise une approximation linaire de la fonction f . Du point de vue graphique, il sagit de considrer une tangente la courbe reprsentative de f comme approximation de cette courbe. On suppose donc maintenant f drivable et la fonction drive f de signe constant dans lintervalle [a, b] ; ainsi f est monotone. On suppose aussi que f change de signe dans lintervalle [a, b]. Lquation f (x) = 0 a donc une unique solution dans cet intervalle ; on note ce nombre. Soit u0 [a, b]. La tangente la courbe reprsentative de f au point dabscisse u0 a pour quation : y = f (u0 )(x u0 ) + f (u0 ). (12.2)

270

CHAP. 12. QUATIONS NON LINAIRES

Les coordonnes du point dintersection de cette droite avec laxe des abscisses sont : (u0 f (u0 )/f (u0 ), 0). On note la fonction x x f (x)/f (x). Elle est dnie condition que f ne sannule pas dans lintervalle [a, b]. On sintresse la suite rcurrente u dnie par un+1 = (un ). Si la suite u est convergente 1 , alors sa limite vrie = f ( )/f ( ) dont rsulte f ( ) = 0 : la limite est gale , la solution de lquation f (x) = 0. Pour que lexemple respecte les hypothses de monotonie, on est amen rduire lintervalle dtude. sage: f.derivative() x |--> -1/2*e^x + 4*cos(x) sage: a, b = RR(pi/2), RR(pi) On dnit un gnrateur Python newtongen reprsentant la suite rcurrente que lon vient de dnir. Ensuite on dnit un nouveau test de convergence checkconv qui stoppe les itrations si les deux derniers termes calculs sont susamment proches ; bien entendu ce test ne garantit pas la convergence de la suite des valeurs approches. sage: def newtongen(f, u): ....: while True: ....: yield u ....: u -= f(u) / f.derivative()(u) sage: def checkconv(u, v, w, prec): ....: return abs(w - v) / abs(w) <= prec On peut maintenant tester la mthode de Newton sur notre exemple. sage: iterate(newtongen(f, a), check=checkconv) After 6 iterations: 2.15846852566756 Mthode de la scante. Dans la mthode de Newton le calcul de drive peut tre coteux. Il est possible de substituer ce calcul de drive une interpolation linaire : si on dispose de deux approximations de la solution, donc de deux points de la courbe reprsentative de f , et si la droite passant par ces deux points rencontre laxe des abscisses, on considre labscisse du point dintersection comme une nouvelle approximation. Pour dmarrer la construction et lorsque les deux droites sont parallles on convient de calculer une nouvelle approximation de la mme faon que dans la mthode de Newton. Cela donne lieu la mme formule ditration que dans la mthode de la fausse position, mais applique en des points dirents. Contrairement la mthode de la fausse position, celle de la scante nidentie pas dintervalle contenant une racine. On dnit un gnrateur Python mettant en uvre cette mthode.
1. Un thorme de L. Kantorovich donne une condition susante pour que la mthode de Newton converge.

12.2. RSOLUTION NUMRIQUE

271

2 0 -2 -4 -6 -8 -10

1.6

1.8

2.2

2.4

2.6

2.8

Figure 12.5 Mthode de Newton.

sage: def secantgen(f, a): ....: yield a ....: estimate = f.derivative()(a) ....: b = a - f(a) / estimate ....: yield b ....: while True: ....: fa, fb = f(a), f(b) ....: if fa == fb: ....: estimate = f.derivative()(a) ....: else: ....: estimate = (fb - fa) / (b - a) ....: a = b ....: b -= fb / estimate ....: yield b On peut maintenant tester la mthode de la scante sur notre exemple. sage: iterate(secantgen(f, a), check=checkconv) After 8 iterations: 2.15846852557553

Mthode de Muller. Il est possible dtendre la mthode de la scante en substituant f des approximations polynomiales de degr quelconque. Par exemple

272

CHAP. 12. QUATIONS NON LINAIRES

2 0 -2 -4 -6 -8 -10

1.6

1.8

2.2

2.4

2.6

2.8

Figure 12.6 Mthode de la scante.

la mthode de Muller 2 utilise des approximations quadratiques. Supposons construites trois approximations r, s et t de la solution de lquation f (x) = 0. On considre le polynme dinterpolation de Lagrange dni par les trois points de la courbe reprsentative de f dabscisses r, s et t. Cest un polynme du second degr. On convient de prendre pour nouvelle approximation la racine de ce polynme qui est la plus proche de t. Par ailleurs, les trois premiers termes de la suite sont xs de manire arbitraire : a, b puis (a + b)/2. Il convient de remarquer que les racines des polynmes et donc les approximations calcules peuvent tre des nombres complexes. La programmation de cette mthode en Sage nest pas dicile ; elle peut se faire sur le mme modle que la mthode de la scante. Notre ralisation utilise toutefois une structure de donne mieux adapte lnumration des termes dune suite rcurrente. sage: from collections import deque sage: basering = PolynomialRing(CC, x ) sage: def quadraticgen(f, r, s): ....: t = (r + s) / 2 ....: yield t ....: points = deque([(r,f(r)), (s,f(s)), (t,f(t))], maxlen=3)
2. Il sagit ici de David E. Muller, bien connu aussi pour avoir invent le code de Reed-Muller, et non de Jean-Michel Muller cit au chapitre 11.

12.2. RSOLUTION NUMRIQUE ....: ....: ....: ....: ....: ....: while True: pol = basering.lagrange_polynomial(points) roots = pol.roots(ring=CC, multiplicities=False) u = min(roots, key=lambda x: abs(x - points[2][0])) points.append((u, f(u))) yield points[2][0]

273

Le module collections de la bibliothque de rfrence Python implmente plusieurs structures de donnes. Dans quadraticgen, la classe deque est utilise pour stocker les dernires approximations calcules. Un objet deque stocke des donnes dans la limite du nombre maxlen x lors de sa cration ; ici le nombre maximal de donnes stockes est gal lordre de rcurrence de la suite des approximations. Lorsquun objet deque a atteint sa capacit maximale de stockage, la mthode deque.append() ajoute les nouvelles donnes sur le principe premier entr, premier sorti . Notons que les itrations de cette mthode ne ncessitent pas le calcul de valeurs drives. De plus chaque itration ne ncessite quune valuation de la fonction f . sage: generator = quadraticgen(f, a, b) sage: iterate(generator, check=checkconv) After 5 iterations: 2.15846852554764 Retour aux polynmes. Revenons la situation tudie au dbut de ce chapitre. Il sagissait de calculer les racines dun polynme coecients rels ; on notera P ce polynme. Supposons P unitaire : P = a0 + a1 x + . . . + ad1 xd1 + xd . Il est facile de vrier que P est le polynme caractristique de la matrice compagnon (cf. 8.2.3) : 0 0 0 ... 0 a0 1 0 0 . . . 0 a1 0 1 0 . . . 0 a2 A= . . . . . . . . . . . . . . . . . . . . . . . . . . 0 0 0 . . . 1 ad1 En consquence les racines du polynme P sont les valeurs propres de la matrice A. Les mthodes du chapitre 13 sappliquent donc. On a vu que la mthode Polynomial.roots() prend jusqu trois paramtres, tous optionnels : ring, multiplicities et algorithm. Supposons quun objet Sage de la classe Polynomial est associ au nom p (donc isinstance(p, Polynomial) renvoie True). Lalgorithme utilis par la commande p.roots() dpend alors des paramtres ring et algorithm ainsi que de lanneau des coecients du polynme, cest--dire p.base_ring(). Lalgorithme teste si les oprations arithmtiques eectues dans ring et p.base_ring() sont exactes. Si cela nest pas le cas, des valeurs approches des

274

CHAP. 12. QUATIONS NON LINAIRES

racines sont calcules avec la bibliothque NumPy si p.base_ring() est RDF ou CDF, ou avec la bibliothque PARI autrement (le paramtre algorithm permet lutilisateur dimposer son choix de bibliothque pour ce calcul). En consultant le code source de NumPy on voit que la mthode dapproximation des racines utilise par cette bibliothque consiste calculer les valeurs propres de la matrice compagnon. La commande qui suit permet didentier les objets pour lesquels les oprations arithmtiques sont exactes (la valeur renvoye par la mthode Ring.is_exact() est True dans ce cas). sage: for ring in [ZZ, QQ, QQbar, RDF, RIF, RR, AA, CDF, CIF, CC]: ....: print("{0:50} {1}".format(ring, ring.is_exact())) Integer Ring True Rational Field True Algebraic Field True Real Double Field False Real Interval Field with 53 bits of precision False Real Field with 53 bits of precision False Algebraic Real Field True Complex Double Field False Complex Interval Field with 53 bits of precision False Complex Field with 53 bits of precision False Lorsque le paramtre ring vaut AA ou RIF, tandis que p.base_ring() vaut ZZ, QQ ou AA, lalgorithme appelle la fonction real_roots() du module sage.rings. polynomial.real_roots. Cette fonction convertit le polynme dans la base de Bernstein, puis utilise lalgorithme de Casteljau (pour valuer le polynme exprim dans la base de Bernstein) et la rgle de Descartes (cf. 12.2.1) pour localiser les racines. Lorsque le paramtre ring vaut QQbar ou CIF, et p.base_ring() vaut ZZ, QQ, AA ou reprsente des rationnels Gaussiens, lalgorithme dlgue les calculs NumPy et PARI dont les rsultats sont convertis dans les anneaux attendus. On peut prendre connaissance de toutes les situations couvertes par la mthode Polynomial.roots() en consultant la documentation de cette mthode. Vitesse de convergence. Considrons une suite numrique convergente u et notons sa limite. On dit que la vitesse de convergence de la suite u est linaire sil existe K ]0, 1[ tel que :
n

lim

|un+1 | = K. |un |

La vitesse de convergence de la suite u est dite quadratique sil existe K > 0 tel que : |un+1 | lim = K. n |u |2 n Revenons la mthode de Newton. On a construit une suite rcurrente u dnie par un+1 = (un ) avec la fonction x x f (x)/f (x). Sous lhypothse

12.2. RSOLUTION NUMRIQUE

275

que f est deux fois drivable, la formule de Taylor pour la fonction et x au voisinage de la racine scrit : (x) = () + (x ) () + (x )2 () + O ((x )3 ). 2

Or () = , () = 0 et () = f ()/f (). En substituant dans la formule prcdente et en revenant la dnition de la suite u, on obtient : un+1 = (un )2 f () + O ((un )3 ). 2 f ()

Lorsque la mthode de Newton converge, la vitesse de convergence de la suite construite est donc quadratique. Acclration de la convergence. partir dune suite convergente dont la vitesse de convergence est linaire, il est possible de construire une suite dont la vitesse de convergence est quadratique. La mme technique, applique la mthode de Newton, est connue sous le nom de mthode de Steensen. sage: def steffensen(sequence): ....: assert isinstance(sequence, GeneratorType) ....: values = deque(maxlen=3) ....: for i in range(3): ....: values.append(sequence.next()) ....: yield values[i] ....: while True: ....: values.append(sequence.next()) ....: u, v, w = values ....: yield u - (v - u)^2 / (w - 2 * v + u) sage: sage: sage: sage: After sage: After g(x) = sin(x^2 - 2) * (x^2 - 2) sequence = newtongen(g, RR(0.7)) accelseq = steffensen(newtongen(g, RR(0.7))) iterate(sequence, check=checkconv) 17 iterations: 1.41422192763287 iterate(accelseq, check=checkconv) 10 iterations: 1.41421041980166

On notera que la vitesse de convergence est une notion asymptotique : elle ne dit rien de lerreur |un | pour n donn. sage: sage: sage: After sage: After sequence = newtongen(f, RR(a)) accelseq = steffensen(newtongen(f, RR(a))) iterate(sequence, check=checkconv) 6 iterations: 2.15846852566756 iterate(accelseq, check=checkconv) 7 iterations: 2.15846852554764

276

CHAP. 12. QUATIONS NON LINAIRES

Rsolution des quations non linaires Racines approches dun polynme Racines exactes sans garantie de les avoir toutes Racines approches dans le corps des rels Racines approches par la mthode de Brent Polynomial.roots() Expression.roots() real_roots() Expression.find_root()

Tableau 12.1 Rcapitulatif des commandes dcrites dans ce chapitre.

Mthode Expression.find_root(). On sintresse maintenant la situation la plus gnrale : le calcul dune valeur approche dune solution dune quation f (x) = 0. Avec Sage, ce calcul se fait avec la mthode Expression.find_root(). Les paramtres de la mthode Expression.find_root() permettent de dnir un intervalle o chercher une racine, la prcision du calcul ou le nombre ditrations. Le paramtre full_output permet dobtenir des informations sur le calcul, notamment le nombre ditrations et le nombre dvaluations de la fonction. sage: result = (f == 0).find_root(a, b, full_output=True) sage: result[0], result[1].iterations (2.1584685255476415, 9) En fait, la mthode Expression.find_root() nimplmente pas rellement dalgorithme de recherche de solutions dquations : les calculs sont dlgus au module SciPy. La fonctionnalit de SciPy utilise par Sage pour rsoudre une quation implmente la mthode de Brent qui combine trois des mthodes vues prcdemment : la mthode de dichotomie, la mthode de la scante et linterpolation quadratique. Les deux premires valeurs approches sont les extrmits de lintervalle o est cherche la solution de lquation. La valeur approche suivante est obtenue par interpolation linaire comme on la fait dans la mthode de la scante. Avec les itrations suivantes la fonction est approche par une interpolation quadratique et labscisse du point dintersection de la courbe dinterpolation avec laxe des abscisses est la nouvelle valeur approche, moins que cette abscisse ne soit pas comprise entre les deux prcdentes valeurs approches calcules auquel cas on poursuit avec la mthode de dichotomie. La bibliothque SciPy ne permet pas de calculer en prcision arbitraire ( moins de se contenter de calculer avec des entiers) ; dailleurs le code source de la mthode Expression.find_root() commence par convertir les bornes en nombres machine double prcision. loppos, toutes les illustrations de mthodes de rsolution dquation construites dans ce chapitre fonctionnent en prcision arbitraire et mme symbolique. sage: a, b = pi/2, pi sage: generator = newtongen(f, a) sage: generator.next(); generator.next() 1/2*pi 1/2*pi - (e^(1/2*pi) - 10)*e^(-1/2*pi)
Exercice 44. crire un gnrateur pour la mthode de Brent qui fonctionne en prcision arbitraire.

Algbre linaire numrique

13

On traite ici les aspects numriques de lalgbre linaire, lalgbre linaire symbolique tant prsente au chapitre 8. Pour des textes en franais sur les mthodes et lanalyse numrique de lalgbre linaire, on pourra consulter les livres de M. Schatzman [Sch91], de P. Ciarlet [Cia82] ou ceux plus spcialiss de Lascaux-Thodor [LT93, LT94]. Le livre de Golub et Van Loan [GVL96], en anglais, est une rfrence incontournable. Lalgbre linaire numrique joue un rle prpondrant dans ce quil est convenu dappeler le calcul scientique, appellation impropre pour dsigner des problmes dont ltude mathmatique relve de lanalyse numrique : rsolution approche de systmes dquations direntielles, rsolution approche dquations aux drives partielles, optimisation, traitement du signal, etc. La rsolution numrique de la plupart de ces problmes, mme linaires, est fonde sur des algorithmes forms de boucles imbriques ; au plus profond de ces boucles, il y a trs souvent la rsolution dun systme linaire. On utilise souvent la mthode de Newton pour rsoudre des systmes algbriques non linaires : l encore il faut rsoudre des systmes linaires. La performance et la robustesse des mthodes dalgbre linaire numrique sont donc cruciales. Ce chapitre comporte trois sections : dans la premire, on seorce de sensibiliser le lecteur linuence de linexactitude des calculs en algbre linaire ; la deuxime section (13.2) traite, sans tre exhaustive, des problmes les plus classiques (rsolution de systmes, calcul de valeurs propres, moindres carrs) ; dans la troisime section (13.3) on montre comment rsoudre certains problmes si on fait lhypothse que les matrices sont creuses. Cette dernire partie se veut autant une initiation des mthodes qui font partie dun domaine de recherche actif quun guide dutilisation.

278

CHAP. 13. ALGBRE LINAIRE NUMRIQUE

13.1

Calculs inexacts en algbre linaire

On sintresse aux problmes classiques de lalgbre linaire (rsolution de systmes, calcul de valeurs et de vecteurs propres, etc.) rsolus au moyen de calculs inexacts. La premire source dinexactitude vient de ce quon va utiliser une approximation ottante des nombres (rels ou complexes), et donc non seulement travailler sur des objets connus approximativement, mais aussi entacher tous les calculs derreurs. Les dirents types de nombres ottants utilisables dans Sage sont dcrits au chapitre 12. Soit par exemple rsoudre le systme Ax = b o A est une matrice coecients rels. Quelle erreur x commet-on si on perturbe A de A ou b de b ? On apporte quelques lments de rponse dans ce chapitre.

13.1.1

Normes de matrices et conditionnement

Soit A Rnn (ou Cnn ). On quipe Rn (ou Cn ) dune norme x , par n exemple la norme x = max |xi | ou x 1 = i=1 |xi |, ou encore la norme n 2 1/ 2 euclidienne x 2 = ( i=1 xi ) ; alors la quantit A = max A x
x =1

dnit une norme sur lensemble des matrices n n. On dit quil sagit dune norme subordonne la norme dnie sur Rn (ou Cn ). Le conditionnement de A est dni par (A) = A1 A . Le rsultat fondamental est que, si on fait subir A une (petite) perturbation A et b une perturbation b, alors la solution x du systme linaire Ax = b est perturbe de x qui vrie : x x Les normes et et A 1 = max1 j n (
1

(A) 1 (A) A / A
n i=1

A b + A b

.
n

sont faciles calculer : A = max1 i n ( j =1 |Aij |) |Aij |). En revanche la norme 2 ne sobtient pas

simplement car A 2 = (t A A), le rayon spectral dune matrice A tant le maximum des modules de ses valeurs propres. La norme de Frobenius est dnie par
n n 1/ 2

=
i=1 j =1

|aij |2

la dirence des normes prcdentes, ce nest pas une norme subordonne. On t vrie aisment que A 2 F = trace( A A). Le calcul des normes de matrice dans Sage. Les matrices possdent une mthode norm(p). Selon la valeur de largument p on obtiendra : p=1: p = Infinity : A 1, A
,

p=2: p = frob :

A 2, A
F.

13.1. CALCULS INEXACTS EN ALGBRE LINAIRE

279

Cette mthode nest applicable que si les coecients de la matrice peuvent tre convertis en nombres complexes CDF. Noter quon crit A.norm(Infinity) mais A.norm( frob ). Avec A.norm() on obtiendra la norme A 2 (valeur par dfaut). Erreurs et conditionnement : une illustration, avec des calculs exacts, puis approchs. Utilisons la possibilit de Sage de faire des calculs exacts quand les coecients sont rationnels. On considre la matrice de Hilbert Aij = 1/(i + j 1), i, j = 1, . . . , n. Le programme suivant calcule exactement le conditionnement des matrices de Hilbert, en norme : sage: def cond_hilbert(n): ....: A = matrix(QQ, [[1/(i+j-1) for j in [1..n]] for i in [1..n]]) ....: return A.norm(Infinity) * (A^-1).norm(Infinity) Voici les rsultats, en fonction de n : n 2 4 8 16 32 conditionnement 27 28375 33872791095 5.06277478751e+22 1.35710782493e+47

On remarque laccroissement extrmement rapide du conditionnement en fonction de n. On peut montrer que (A) e7n/2 , ce qui videmment, est une quantit qui crot trs vite. Toujours en calculant exactement dans lensemble des rationnels, on peut perturber la matrice A, et comparer la solution dun systme linaire original celle du mme systme perturb : sage: sage: sage: sage: sage: sage: sage: n = 8 x = vector(QQ,[1 for i in range(0,n)]) A = matrix(QQ, [[1/(i+j-1) for j in [1..n]] for i in [1..n]]) y = A*x A[n-1,n-1] = (1/(2*n-1))*(1+1/(10^5)) # perturbe la matrice sol = A\y diff = max(float(sol[i]-x[i]) for i in range(0,n)) erreur (diff) 1.9999200e-05 0.00597609561 3.47053530779 63.2816091951 20034.3477421

On obtient : n 2 4 8 16 32

280

CHAP. 13. ALGBRE LINAIRE NUMRIQUE

et donc les calculs sont rapidement entachs dune erreur inacceptable. Calculons maintenant avec des matrices et des vecteurs coecients ottants. Cette fois, on ne perturbe pas explicitement la matrice A, mais larithmtique ottante va introduire de petites perturbations. On refait le calcul prcdent : le second membre tant calcul par y = Ax, on cherche retrouver x en rsolvant le systme linaire As = y : sage: sage: sage: sage: sage: sage: n = 8 A = matrix(RR, [[1/(i+j-1) for j in [1..n]] for i in [1..n]]) x = vector(RR, [1 for i in range(0,n)]) y = A*x s = A.solve_right(y) diff = [float(s[i]-x[i]) for i in range(0,n)] erreur (diff) 2.22044604925e-16 3.05977465587e-13 6.82028985288e-07 8.34139063331 257.663242705

En fonction de n on obtient : n 2 4 8 16 32

On voit que pour n = 16 par exemple, lerreur sur la solution (en norme innie) est telle quon ne calcule plus rien du tout de pertinent (avec le choix particulier de x que nous avons fait (xi = 1), les erreurs absolues et relatives en norme innie concident). Remarques. Pourquoi alors calculer avec des nombres ottants ? La question des performances nest pas forcment pertinente depuis quil existe des bibliothques implantant ecacement des algorithmes dalgbre linaire en arithmtique rationnelle (Linbox, utilise par Sage), algorithmes qui, sans tre aussi performants que leur quivalent ottant, pourraient avantageusement tre utiliss, pour certains problmes comme la rsolution de systmes linaires de taille modre. Mais cest ici quintervient une deuxime source dincertitude : dans les applications relles, les coecients ne peuvent tre connus quapproximativement. Par exemple la rsolution dun systme dquations non linaires par la mthode de Newton fait naturellement apparatre des termes calculs de manire inexacte. Les systmes linaires mal conditionns (sans tre aussi caricaturaux que la matrice de Hilbert) sont plutt la rgle que lexception : il est frquent (en physique, en chimie, en biologie, etc.) de rencontrer des systmes dquations direntielles ordinaires de la forme du/dt = F (u) o la matrice jacobienne DF (u), matrice des drives partielles Fi (u)/uj , dnit un systme linaire mal conditionn : les valeurs propres sont rparties dans un ensemble trs vaste, ce qui entrane le mauvais conditionnement de DF (u) ; cette proprit traduit le fait que le systme modlise des phnomnes mlangeant plusieurs chelles de temps. Malheureusement, en pratique, il faut rsoudre des systmes linaires dont la matrice est DF (u).

13.2. MATRICES PLEINES

281

Tous les calculs (dcomposition de matrices, calcul dlments propres, convergence de mthodes itratives) sont aects par le conditionnement. Il convient donc davoir cette notion prsente lesprit ds que lon calcule en utilisant une reprsentation ottante des nombres rels.

13.2
13.2.1

Matrices pleines
Rsolution de systmes linaires

Mthodes viter. Ce quil ne faut (presque) jamais faire, cest utiliser les formules de Cramer. Un raisonnement par rcurrence montre que le cot du calcul du dterminant dune matrice n n en utilisant les formules de Cramer est de lordre n! multiplications (et autant dadditions). Pour rsoudre un systme de taille n, ce sont n + 1 dterminants quil faut calculer. Prenons n = 20 : sage: n = 20; cout = (n+1)*factorial(n); cout 51090942171709440000 nous obtenons la valeur respectable de 51 090 942 171 709 440 000 multiplications. Supposons que notre calculateur eectue 3 109 multiplications par seconde (ce qui est raliste), et calculons la dure approximative du calcul : sage: v = 3*10^9 sage: print "%3.3f"%float(cout/v/3600/24/365) 540.028 Il faudra donc 540 ans (environ) pour eectuer le calcul ! Bien sr vous pouvez utiliser les formules de Cramer pour rsoudre un systme 2 2, mais pas bien au del ! Toutes les mthodes utilises en pratique ont en commun un cot polynomial, cest--dire de lordre de np , avec p petit (p = 3, en gnral). Mthodes pratiques. La rsolution de systmes linaires Ax = b est le plus souvent base sur une factorisation de la matrice A en un produit de deux matrices A = M1 M2 , M1 et M2 dnissant des systmes linaires faciles rsoudre. Pour rsoudre Ax = b, on rsout alors successivement M1 y = b, puis M2 x = y. Par exemple M1 et M2 peuvent tre deux matrices triangulaires ; dans ce cas, une fois la factorisation eectue, il faut rsoudre deux systmes linaires matrice triangulaire. Le cot de la factorisation est bien plus lev que celui de la rsolution des deux systmes triangulaires (par exemple O(n3 ) pour la factorisation LU contre O(n2 ) pour la rsolution des systmes triangulaires). Il convient donc, dans le cas de la rsolution de plusieurs systmes avec la mme matrice, de ne calculer quune seule fois la dcomposition. Bien entendu, on ninverse jamais une matrice pour rsoudre un systme linaire, linversion demandant la factorisation de la matrice, puis la rsolution de n systmes au lieu dun seul.

282

CHAP. 13. ALGBRE LINAIRE NUMRIQUE

13.2.2

Rsolution directe

Voici la manire la plus simple de procder : sage: A = matrix(RDF, [[-1,2],[3,4]]) sage: b = vector(RDF, [2,3]) sage: x = A\b; x (-0.2, 0.9) Dans Sage, les matrices possdent une mthode solve_right pour la rsolution de systmes linaires (base sur la dcomposition LU ) ; cest cette commande qui est appele ci-dessus. On aurait aussi pu crire : sage: x = A.solve_right(b) La syntaxe x = A\b est pratiquement identique ce quon utilise dans les systmes de calcul Matlab, Octave ou Scilab.

13.2.3

La dcomposition LU

sage: A = matrix(RDF, [[-1,2],[3,4]]) sage: P, L, U = A.LU() Cette mthode fournit les facteurs L et U ainsi que la matrice de permutation P , tels que A = P LU (ou de manire quivalente P A = LU , comme le lecteur averti aura remarqu). Ce sont les choix de pivots qui imposent la cration de la matrice P . La matrice L est triangulaire infrieure, diagonale unit, et U est une matrice triangulaire suprieure. Cette dcomposition est directement drive de la mthode de Gauss (dcrite en 8.2.1). En eet, en ngligeant pour la simplicit de lexpos les problmes de choix de pivots, la mthode de Gauss consiste transformer la matrice A (dordre n) pour faire apparatre des coecients nuls sous la diagonale de la premire colonne, puis de la deuxime colonne et ainsi de suite. Cette limination peut scrire Ln1 . . . L2 L1 A = U. En posant L = (Ln1 . . . L2 L1 )1 , on obtient bien A = LU et on vrie sans dicult que L est triangulaire infrieure diagonale unit. Notons que Sage garde en mmoire la factorisation de A : la commande A.LU_valid() va rpondre True si et seulement si la factorisation LU a dj t calcule. Mieux, la commande A.solve_right(b) ne calculera la factorisation que si cest ncessaire, cest--dire si elle na pas t calcule auparavant, ou si la matrice A a chang. Exemple. Crons une matrice de taille 1000, alatoire et un vecteur de taille 1000 : sage: A = random_matrix(RDF, 1000) sage: b = vector(RDF, range(1000)) factorisons A :

13.2. MATRICES PLEINES sage: %time A.LU() CPU times: user 0.23 s, sys: 0.01 s, total: 0.24 s Wall time: 0.29 s et prsent rsolvons le systme Ax = b : sage: %time x = A.solve_right(b) CPU times: user 0.10 s, sys: 0.00 s, total: 0.10 s Wall time: 0.12 s

283

La rsolution est plus rapide, parce quelle a tenu compte de la factorisation prcdemment calcule.

13.2.4

La dcomposition de Cholesky des matrices relles symtriques dnies positives

Une matrice symtrique A est dite dnie positive si pour tout vecteur x non nul, t x Ax > 0. Pour toute matrice symtrique dnie positive, il existe une matrice triangulaire infrieure C telle que A = C t C . Cette factorisation est appele dcomposition de Cholesky. Dans Sage, elle se calcule en appelant la mthode cholesky(). Dans lexemple suivant on construit une matrice A presque srement dnie positive : sage: m = random_matrix(RDF, 10) sage: A = transpose(m)*m sage: C = A.cholesky() Il faut noter quon ne peut pas tester en un cot raisonnable si une matrice symtrique est dnie positive ; si on applique la mthode de Cholesky avec une matrice qui ne lest pas, la dcomposition ne pourra pas tre calcule et une exception ValueError sera lance par cholesky() au cours du calcul. Pour rsoudre un systme Ax = b laide de la dcomposition de Cholesky, on procde comme avec la dcomposition LU . Une fois la dcomposition calcule, on excute A.solve_right(b). L aussi, la dcomposition nest pas recalcule. Pourquoi utiliser la dcomposition de Cholesky plutt que la dcomposition LU pour rsoudre des systmes matrice symtrique dnie positive ? Bien sr, la taille mmoire ncessaire pour stocker les facteurs est deux fois plus petite, mais cest surtout du point de vue du nombre doprations que la mthode de Cholesky savre avantageuse : en eet, pour une matrice de taille n, la factorisation de Cholesky cote n extractions de racines carres, n(n 1)/2 divisions, (n3 n)/6 additions et autant de multiplications. En comparaison la factorisation LU cote aussi n(n 1)/2 divisions, mais (n3 n)/3 additions et multiplications.

13.2.5

La dcomposition QR

Soit A Rnm , avec n m. Il sagit ici de trouver deux matrices Q et R telles que A = QR o Q Rnn est orthogonale (t Q Q = I ) et R Rnm est triangulaire suprieure. Bien sr, une fois la dcomposition calcule, on peut sen servir pour rsoudre des systmes linaires si la matrice A est carre et inversible,

284

CHAP. 13. ALGBRE LINAIRE NUMRIQUE

mais cest surtout, comme on le verra, une dcomposition intressante pour la rsolution de systmes aux moindres carrs et pour le calcul de valeurs propres. Bien noter que A nest pas forcment carre. La dcomposition existe si A est de rang maximum, soit m. Exemple : sage: A = random_matrix(RDF,6,5) sage: Q, R = A.QR()
Exercice 45 (Perturbation dun systme linaire). Soit A une matrice carre inversible dont on a calcul une dcomposition (LU , QR, Cholesky, etc). Soient deux vecteurs u et v . On considre la matrice B = A + u t v , et on suppose que 1 + t v A1 u = 0. Comment rsoudre conomiquement le systme Bx = f (cest--dire sans factoriser B ) ? On utilisera la formule de Sherman et Morrison (quon pourra prouver ou admettre) : (A + u t v )1 = A1 A1 u t v A1 . 1 + t v A1 u

13.2.6

La dcomposition en valeurs singulires

Il sagit dune dcomposition peu enseigne, et pourtant riche en applications ! Soit A une matrice n m coecients rels. Alors il existe deux matrices orthogonales U Rnn et V Rmm , telles que
t

U A V = = diag(1 , 2 , . . . , p ),

o 1 2 . . . p 0 (avec p = min(m, n)). Les nombres 1 , . . . , p sont les valeur singulires de A. Les matrices U et V sont orthogonales (U t U = I et V t V = I ) et par consquent : A = U tV . Exemple (les calculs ne sont videmment jamais exacts) : sage: A = matrix(RDF, [[1,3,2],[1,2,3],[0,5,2],[1,1,1]]) sage: U, Sig, V = A.SVD() sage: A1 = A - U*Sig*transpose(V); A1 [ 4.4408920985e-16 4.4408920985e-16 -8.881784197e-16] [ 6.66133814775e-16 -8.881784197e-16 -4.4408920985e-16] [-1.29063426613e-15 1.7763568394e-15 2.22044604925e-16] [ 6.66133814775e-16 -6.66133814775e-16 -1.11022302463e-15] On peut montrer que les valeurs singulires dune matrice A sont les racines carres des valeurs propres de t A A. Il est facile de vrier que, pour une matrice carre de taille n, la norme euclidienne A 2 est gale 1 et que, si la matrice est de plus non singulire, le conditionnement de A en norme euclidienne est gal 1 /n . Le rang de A est lentier r dni par : 1 2 r > r+1 = = p = 0.

13.2. MATRICES PLEINES

285

13.2.7

Application aux moindres carrs

On voudrait rsoudre le systme surdtermin Ax = b o A est une matrice coecients rels, rectangulaire, n lignes et m colonnes avec n > m. videmment ce systme na pas, en gnral, de solution. On considre alors le problme de minimisation du carr de la norme euclidienne 2 du rsidu : min Ax b 2 2.
x

La matrice A peut mme tre de rang infrieur m. En rsolvant les quations normales. En annulant la direntielle par rapport x du problme de minimisation, on vriera sans trop de peine que la solution vrie : t A Ax = t A b. Supposant A de rang maximum m, on peut donc penser former la matrice t A A et rsoudre le systme t A Ax = t A b, par exemple en calculant la dcomposition de Cholesky de t A A. Cest mme l lorigine du procd du commandant Cholesky 1 . Quel est le conditionnement de t A A ? Cest ce qui va conditionner la prcision des calculs. Les valeurs singulires de t A A, qui est de dimension m m, sont les carrs des valeurs singulires de A ; le conditionnement en norme euclidienne est 2 2 donc 1 /m , qui est facilement grand. On prfre donc des mthodes bases soit sur la dcomposition QR de A, soit sur sa dcomposition en valeurs singulires 2 . Malgr tout, cette mthode est utilisable pour de petits systmes, pas trop mal conditionns. Voici le code correspondant : sage: A = matrix(RDF, [[1,3,2],[1,4,2],[0,5,2],[1,3,2]]) sage: b = vector(RDF, [1,2,3,4]) sage: Z = transpose(A)*A sage: C = Z.cholesky() sage: R = transpose(A)*b sage: Z.solve_right(R) (-1.5, -0.5, 2.75) Bien noter ici que la dcomposition de Cholesky est cache et que la rsolution Z.solve_right(R) utilise cette dcomposition, sans la recalculer. Avec la dcomposition QR. Supposons A de rang maximum 3 , et soit A = QR. Alors t 2 2 Ax b 2 2 = QRx b 2 = Rx Q b 2 .
1. Polytechnicien et ocier dartillerie (1875-1918) ; la mthode a t invente pour rsoudre des problmes de godsie. 2. Mais le commandant Cholesky navait pas dordinateur, et nenvisageait probablement que la rsolution de petits systmes, pour lesquels le mauvais conditionnement nest pas vraiment un problme. 3. On peut sen aranchir en utilisant une mthode QR avec pivots.

286 On a : R =
t

CHAP. 13. ALGBRE LINAIRE NUMRIQUE R1 0 o R1 est un bloc triangulaire suprieur de taille m et

c 2 2 avec c de taille m. Donc Ax b 2 2 = R1 x c 2 + d 2 , et le d minimum est obtenu pour x solution du systme triangulaire R1 x = c : Qb = sage: A = matrix(RDF, [[1,3,2],[1,4,2],[0,5,2],[1,3,2]]) sage: b = vector(RDF, [1,2,3,4]) sage: Q, R = A.QR() sage: R1 = R[0:3,0:3] sage: b1 = transpose(Q)*b sage: c = b1[0:3] sage: R1.solve_right(c) (-1.5, -0.5, 2.75) Calculons le conditionnement de t A A en norme innie : sage: Z = A.transpose()*A sage: Z.norm(Infinity)*(Z^-1).norm(Infinity) 1992.375 Le systme tant de petite taille, il nest pas trop mal conditionn : la mthode QR et la mthode des quations normales (page 285) donnent donc le mme rsultat. Avec la dcomposition en valeurs singulires. La dcomposition en valeurs singulires A = U t V permet aussi de calculer la solution ; mieux, elle est utilisable mme si A nest pas de rang maximum. Si A nest pas identiquement nulle, possde r m coecients strictement positifs i (rangs par ordre dcroissant). On note ui les colonnes de U . On a alors : Ax b En posant = t V x, on a :
p m 2 2

U AV t V x t U b 2 2.

Ax b

2 2

=
i=1

(i i t ui b)2 +
i=p+1

(t ui b)2 .

Le minimum est donc atteint en prenant i = (t ui b)/i pour 1 i p. On choisit alors i = 0 pour i > p, et on obtient nalement la solution x = V . Voici le programme Sage (on na pas besoin de transposer U.column(i)) : sage: sage: sage: sage: sage: sage: A = matrix(RDF, [[1,3,2],[1,3,2],[0,5,2],[1,3,2]]) b = vector(RDF, [1,2,3,4]) U, Sig, V = A.SVD() m = A.ncols() x = vector(RDF, [0]*m) lamb = vector(RDF, [0]*m)

13.2. MATRICES PLEINES sage: for i in range(0,m): ....: s = Sig[i,i] ....: if s < 1e-12: ....: break ....: lamb[i] = U.column(i)*b / s sage: x = V*lamb; x (0.237037037037, 0.451851851852, 0.37037037037)

287

Notons que ci-dessus, la matrice A est de rang 2 (ce quon peut vrier laide de la commande A.rank()) et quelle nest donc pas de rang maximum (3) ; il y a donc plusieurs solutions au problme de moindres carrs et la dmonstration donne ci-dessus montre que x est la solution de norme euclidienne minimale. Regardons les valeurs singulires : sage: m = 3 sage: [ Sig[i,i] for i in range(0,m) ] [8.30931683326, 1.39830388849, 2.40449761305e-16] La matrice A tant de rang 2, la troisime valeur singulire est forcment 0. On a donc ici une erreur darrondi, due lapproximation ottante. Pour viter une division par 0, il convient de ne pas en tenir compte dans le calcul de valeurs singulires approches trop proches de 0 (cest la raison du test if s < 1e-12 dans le programme). Exemple. Parmi les merveilleuses applications de la dcomposition en valeurs singulires (SVD pour Singular Value Decomposition en anglais), voici un problme quon aura bien du mal rsoudre avec une autre mthode : soient A et B Rnm les rsultats dune exprience rpte deux fois. On se demande si B peut tre tourne sur A, cest--dire sil existe une matrice orthogonale Q telle que A = BQ. videmment, un bruit sest ajout aux mesures et le problme na pas, en gnral, de solution. Il convient donc de le poser aux moindres carrs ; pour cela, il faut donc calculer la matrice orthogonale Q qui minimise le carr de la norme de Frobenius : A BQ 2 F. On se souvient que A A BQ
2 F 2 F

= trace(t A A). Alors 0,

= trace(t A A) + trace(t B B ) 2 trace(t Q t B A)

et il faut donc maximiser trace(t Q t B A). On calcule alors la SVD de t B A : on a t U (t B A)V = . Soient i les valeurs singulires, et O = t V t Q U. Cette matrice est orthogonale et donc tous ses coecients sont infrieurs ou gaux 1. Alors :
m m

trace(t Q t B A) = trace(t Q U t V ) = trace(O) =


i=1

Oii i
i=1

i .

et le maximum est atteint pour Q = U t V . sage: A = matrix(RDF, [[1,2],[3,4],[5,6],[7,8]])

288

CHAP. 13. ALGBRE LINAIRE NUMRIQUE

B est obtenue en ajoutant un bruit alatoire A et en lui appliquant une rotation R dangle thta : sage: th = 0.7 sage: R = matrix(RDF, [[cos(th),sin(th)],[-sin(th),cos(th)]]) sage: B = (A + 0.1*random_matrix(RDF,4,2)) * transpose(R) sage: C = transpose(B)*A sage: U, Sigma, V = C.SVD() sage: Q = U*transpose(V) La perturbation alatoire est faible, et Q est proche de R comme attendu : sage: Q [ 0.76737943398 0.641193265954] [-0.641193265954 0.76737943398] sage: R [ 0.764842187284 0.644217687238] [-0.644217687238 0.764842187284]
Exercice 46 (Racine carre dune matrice symtrique semi-dnie positive). Soit A une matrice symtrique semi-dnie positive (cest--dire qui vrie t x Ax 0 pour tout vecteur x). Montrer quon peut calculer une matrice X , elle aussi symtrique semi-dnie positive, telle que X 2 = A.

13.2.8

Valeurs propres, vecteurs propres

Jusqu prsent, nous navons utilis que des mthodes directes (dcomposition LU , QR, de Cholesky), qui fournissent une solution en un nombre ni doprations (les quatre oprations lmentaires, plus la racine carre pour la dcomposition de Cholesky). Ce ne peut pas tre le cas pour le calcul des valeurs propres : en eet (cf. page 292), on peut associer tout polynme une matrice dont les valeurs propres sont les racines du polynme ; mais on sait quil nexiste pas de formule explicite pour le calcul des racines dun polynme de degr suprieur ou gal 5, formule que donnerait prcisment une mthode directe. Dautre part, former le polynme caractristique pour en calculer les racines serait extrmement coteux (cf. page 281) ; notons toutefois que lalgorithme de Faddeev-Le Verrier permet de calculer le polynme caractristique dune matrice de taille n en O(n4 ) oprations, ce qui est malgr tout considr comme bien trop coteux. Les mthodes numriques utilises pour le calcul de valeurs et de vecteurs propres sont toutes itratives. On va donc construire des suites convergeant vers les valeurs propres (et les vecteurs propres) et arrter les itrations quand on sera assez proche de la solution 4 .
4. Dans les exemples donns ci-aprs, le problme du choix des tests darrt des itrations est volontairement pass sous silence, pour des raisons de simplicit.

13.2. MATRICES PLEINES

289

La mthode de la puissance itre. Soit A une matrice appartenant Cnn . On choisit une norme quelconque . sur Cn . En partant de x0 , on considre la suite des xk dnie par : Axk xk+1 = . Axk Si les valeurs propres vrient |1 | > |2 | > . . . > |n |, alors la suite des vecteurs xk converge vers un vecteur propre associ la valeur propre dominante |1 |. De plus la suite k = t xk+1 xk converge vers |1 |. Cette hypothse de sparation des valeurs propres peut tre relche. sage: sage: sage: sage: sage: ....: ....: ....: ....: ....: ....: ....: 0 1 2 3 4 5 6 7 8 9 10 ... n = A = # A x = for 10 random_matrix(RDF, n); A = A*transpose(A) vrifie (presque srement) les hypothses vector(RDF, [1 for i in range(0,n)]) i in range(0,1000): y = A*x z = y/y.norm() lam = z*y s = (x-z).norm() print i, "\ts=", s, "\tlambda=", lam if s < 1e-10: break x = z s= 16.1640760201 lambda= 75.9549361783 s= 0.411503846291 lambda= 8.21816164112 s= 0.283595513527 lambda= 10.7020239604 s= 0.143945984315 lambda= 11.7626944491 s= 0.0671326308606 lambda= 12.0292765606 s= 0.0313379335883 lambda= 12.0876762358 s= 0.0149590182273 lambda= 12.1006031137 s= 0.00733280989323 lambda= 12.1036013532 s= 0.00368707185825 lambda= 12.1043343433 s= 0.00189514202573 lambda= 12.104522518 s= 0.000991461650756 lambda= 12.1045728607

Maintenant, utilisons : sage: A.eigenvalues() [12.1045923186, 6.62564474772, 5.45163183814, 4.81356332812, 2.46643846586, 1.37770690836, 0.966017076179, 0.653324011458, 0.0859636271843, 0.0541281947143] On a bien calcul la valeur propre dominante. Lintrt de cette mthode peut sembler limit, mais il apparatra pleinement lors de ltude des matrices creuses. Elle inspire aussi ce qui suit, qui est trs utile. La mthode de la puissance inverse avec translation. On suppose connue une approximation dune valeur propre j ( et j C). Comment calculer un vecteur propre associ j ?

290

CHAP. 13. ALGBRE LINAIRE NUMRIQUE

On fait lhypothse que k = j, 0 < | j | < | k |, et donc, j est une valeur propre simple. On considre alors (A I )1 , dont la plus grande valeur propre est (j )1 , et on applique la mthode de la puissance itre cette matrice. Prenons par exemple : sage: A = matrix(RDF, [[1,3,2],[1,2,3],[0,5,2]]) En appelant la mthode A.eigenvalues(), on trouve les valeurs propres 6.39294791649, 0.560519476112, -1.9534673926. On va chercher le vecteur propre associ la deuxime valeur propre, en partant dune valeur approche : sage: mu = 0.50519 sage: AT = A - mu*identity_matrix(RDF, 3) sage: x = vector(RDF, [1 for i in range(0,A.nrows())]) sage: P, L, U = AT.LU() sage: for i in range(1,10): ....: y = AT.solve_right(x) ....: x = y/y.norm() ....: lamb = x*A*x ....: print x, lamb (0.960798555257, 0.18570664547, -0.205862036435) 1.08914936279 (0.927972943625, 0.10448610518, -0.357699412529) 0.563839629189 (0.927691613383, 0.103298273577, -0.358772542336) 0.560558807639 (0.927684531828, 0.10329496332, -0.35879180587) 0.560519659839 (0.927684564843, 0.103294755297, -0.358791780397) 0.560519482021 (0.927684562912, 0.103294757323, -0.358791784805) 0.560519476073 (0.927684562945, 0.103294757253, -0.358791784742) 0.560519476114 (0.927684562944, 0.103294757254, -0.358791784744) 0.560519476112 (0.927684562944, 0.103294757254, -0.358791784744) 0.560519476112 On peut faire plusieurs remarques : on ne calcule pas linverse de la matrice AI , mais on utilise sa factorisation LU , qui est calcule une fois pour toutes (par solve_right) ; on prote des itrations pour amliorer lestimation de la valeur propre ; la convergence est trs rapide ; on peut eectivement montrer que (moyennant les hypothses ci-dessus, plus le choix dun vecteur de dpart non orthogonal au vecteur propre qj associ j ), on a, pour les itrs x(i) et (i) : i j x(i) qj = O K et 2i j (i) j = O , K o K est la seconde valeur propre par ordre de proximit ; le conditionnement de (A I ) (reli au rapport entre la plus grande et la plus petite valeur propre de (A I )) est mauvais ; mais on peut montrer (cf. [Sch91], qui cite Parlett) que les erreurs sont malgr tout sans importance !

13.2. MATRICES PLEINES

291

La mthode QR. Soit A une matrice carre non singulire. On considre la suite A0 = A, A1 , A2 , . . ., Ak , Ak+1 , . . . Dans la forme la plus brute de la mthode QR, le passage de Ak Ak+1 seectue ainsi : 1. on calcule la dcomposition QR de Ak : Ak = Qk Rk , 2. on calcule Ak+1 = Rk Qk . Programmons cette mthode avec pour A une matrice symtrique relle : sage: m = matrix(RDF, [[1,2,3,4],[1,0,2,6],[1,8,4,-2],[1,5,-10,-20]]) sage: Aref = transpose(m)*m sage: A = copy(Aref) sage: for i in range(0,20): ....: Q, R = A.QR() ....: A = R*Q ....: print A.str(lambda x: RealField(30)(x).str()) [ 347.58031 -222.89331 -108.24117 -0.067928252] [ -222.89331 243.51949 140.96827 0.081743964] [ -108.24117 140.96827 90.867499 -0.0017822044] [ -0.067928252 0.081743964 -0.0017822044 0.032699348] ... [ 585.03056 -4.2118495e-13 3.2967689e-14 -6.6742634e-14] [-3.0404094e-13 92.914265 6.1583133e-14 4.0818546e-16] [-1.5340786e-39 7.0477800e-25 4.0229095 2.0797973e-14] [ 1.1581440e-82 -4.1761905e-68 6.1677425e-42 0.032266909] On constate que la convergence est rapide, vers une matrice quasi-diagonale. Les coecients diagonaux sont les valeurs propres de A. Vrions : sage: Aref.eigenvalues() [585.03055862, 92.9142649915, 0.0322669089941, 4.02290947948] On peut prouver la convergence si la matrice est hermitienne dnie positive. Si on calcule avec une matrice non symtrique, il convient de travailler dans C, les valeurs propres tant a priori complexes, et, si la mthode converge, les parties triangulaires infrieures des Ak tendent vers zro, tandis que la diagonale tend vers les valeurs propres de A. La mthode QR ncessite beaucoup damliorations pour tre ecace, ne serait-ce que parce que les dcompositions QR successives sont coteuses ; parmi les ranements utiliss, on commence en gnral par rduire la matrice A une forme plus simple (forme de Hessenberg : triangulaire suprieure plus une sous-diagonale), ce qui rend les dcompositions QR bien moins coteuses ; ensuite, pour acclrer la convergence il faut pratiquer des translations A := A + I , astucieusement choisies (voir par exemple [GVL96]). Notons que cest la mthode utilise par Sage quand on travaille avec des matrices pleines CDF ou RDF. En pratique. Les programmes donns ci-dessus sont l titre dexemples pdagogiques ; on utilisera donc les mthodes fournies par Sage qui, dans la mesure du possible, fait appel aux routines optimises de la bibliothque Lapack.

292

CHAP. 13. ALGBRE LINAIRE NUMRIQUE

Les interfaces permettent dobtenir soit uniquement les valeurs propres, soit les valeurs et les vecteurs propres : sage: A = matrix(RDF, [[1,3,2],[1,2,3],[0,5,2]]) sage: A.eigenmatrix_right() ( [ 6.39294791649 0 0] [ 0 0.560519476112 0] [ 0 0 -1.9534673926], [ 0.542484060111 0.927684562944 0.0983425466742] [ 0.554469286109 0.103294757254 -0.617227053099] [ 0.631090211687 -0.358791784744 0.780614827195] ) Cet exemple calcule la matrice diagonale des valeurs propres et la matrice des vecteurs propres (les colonnes sont les vecteurs propres). Exemple (Calcul des racines dun polynme). tant donn un polynme ( coecients rels ou complexes) p(x) = xn + an1 xn1 + . . . + a1 x + a0 , il est facile de vrier que les valeurs propres de la matrice compagnon M , dnie par Mi+1,i = 1 et Mi,n1 = ai , sont les racines de p (voir 8.2.3), ce qui fournit donc une mthode pour obtenir les racines de p : sage: def pol2companion(p): ....: n = len(p) ....: m = matrix(RDF,n) ....: for i in range(1,n): ....: m[i,i-1]=1 ....: for i in range(0,n): ....: m[i,n-1]=-p[i] ....: return m sage: q = [1,-1,2,3,5,-1,10,11] sage: comp = pol2companion(q); comp [ 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0] [ 1.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0] [ 0.0 1.0 0.0 0.0 0.0 0.0 0.0 -2.0] [ 0.0 0.0 1.0 0.0 0.0 0.0 0.0 -3.0] [ 0.0 0.0 0.0 1.0 0.0 0.0 0.0 -5.0] [ 0.0 0.0 0.0 0.0 1.0 0.0 0.0 1.0] [ 0.0 0.0 0.0 0.0 0.0 1.0 0.0 -10.0] [ 0.0 0.0 0.0 0.0 0.0 0.0 1.0 -11.0] sage: racines = comp.eigenvalues(); racines [0.347521510119 + 0.566550553398*I, 0.347521510119 - 0.566550553398*I, 0.345023776962 + 0.439908702386*I, 0.345023776962 - 0.439908702386*I, -0.517257614325 + 0.512958206789*I, -0.517257614325 0.512958206789*I, -1.36699716455, -9.98357818097] Dans cet exemple le polynme est reprsent par la liste q de ses coecients, de 0 n 1. Le polynme x2 3x + 2 serait ainsi reprsent par q=[2,-3].

13.2. MATRICES PLEINES

293

13.2.9

Ajustement polynomial : le retour du diable

Version continue. On voudrait approcher la fonction f (x) par un polynme P (x) de degr n, sur lintervalle [, ]. On pose le problme aux moindres carrs.
n a0 ,...,an R

min

J (a0 , . . . , an ) =

(f (x)
i=0

ai xi )2 dx.

En drivant J (a0 , . . . , an ) par rapport aux coecients ai , on trouve que a0 , . . . , an sont solutions dun systme linaire M a = F o Mi,j = xi xj dx et Fj = xj f (x) dx. On voit immdiatement en regardant le cas = 0 et = 1 que Mi,j est la matrice de Hilbert ! Mais il y a un remde : il sut dutiliser une base de polynmes orthogonaux (par exemple, si = 1 et = 1 la base des polynmes de Legendre) : alors la matrice M devient lidentit. Version discrte. On considre m observations y1 , . . . , ym dun phnomne n aux points xi , . . . , xm . On veut ajuster un polynme i=0 ai xi de degr n au plus gal m 1 parmi ces points. On minimise donc la fonctionnelle :
m n

J (a0 , . . . , an ) =

(
j =1 i=0

2 ai xi j yj ) .

Ainsi crit, le problme va donner une matrice trs proche de la matrice de Hilbert et le systme sera dicile rsoudre. Mais on remarque alors que P, Q = m m1. j =1 P (xj )Q(xj ) dnit un produit scalaire sur les polynmes de degr n On peut donc dabord fabriquer n polynmes chelonns en degr, orthonorms pour ce produit scalaire, et donc diagonaliser le systme linaire. En se souvenant 5 que le procd de Gram-Schmidt se simplie en une rcurrence trois termes pour le calcul de polynmes orthogonaux, on cherche le polynme Pn+1 (x) sous la forme Pn+1 (x) = xPn (x) n Pn1 (x) n Pn2 (x) : cest ce que fait la procdure orthopoly ci-dessous (on reprsente ici les polynmes par la liste de leurs coecients : par exemple [1,-2,3] reprsente le polynme 1 2x + 3x2 ). Lvaluation dun polynme par le schma de Horner se programme ainsi : sage: def eval(P,x): ....: if len(P) == 0: ....: return 0 ....: else: ....: return P[0]+x*eval(P[1:],x) On peut ensuite programmer le produit scalaire de deux polynmes : sage: def pscal(P,Q,lx): ....: return float(sum(eval(P,s)*eval(Q,s) for s in lx)) et lopration P P + aQ pour deux polynmes P et Q :
5. Le prouver nest pas trs dicile !

294

CHAP. 13. ALGBRE LINAIRE NUMRIQUE

sage: def padd(P,a,Q): ....: for i in range(0,len(Q)): ....: P[i] += a*Q[i] Un programme un peu srieux doit lancer une exception quand il est mal utilis ; dans notre cas, on lance lexception dnie ci-dessous quand n m : sage: class BadParamsforOrthop(Exception): ....: def __init__(self, degreplusun, npoints): ....: self.deg = degreplusun ....: self.np = npoints ....: def __str__(self): ....: return "degre: " + str(self.deg) + \ ....: " nb. points: " + repr(self.np) La procdure suivante calcule les n polynmes orthogonaux : sage: def orthopoly(n,x): ....: if n > len(x): ....: raise BadParamsforOrthop(n-1, len(x)) ....: orth = [[1./sqrt(float(len(x)))]] ....: for p in range(1,n): ....: nextp = copy(orth[p-1]) ....: nextp.insert(0,0) ....: s = [] ....: for i in range(p-1,max(p-3,-1),-1): ....: s.append(pscal(nextp, orth[i], x)) ....: j = 0 ....: for i in range(p-1,max(p-3,-1),-1): ....: padd(nextp, -s[j], orth[i]) ....: j += 1 ....: norm = sqrt(pscal(nextp, nextp, x)) ....: nextpn = [nextp[i]/norm for i in range(len(nextp))] ....: orth.append(nextpn) ....: return orth Une fois les polynmes orthogonaux P0 (x), . . . , Pn (x) calculs, la solution est n donne par P (x) = i=0 i Pi (x), avec :
m

i =
j =1

Pi (xj )yj ,

ce quon peut videmment rapatrier sur la base des monmes 1, x, . . . , xn . Exemple (n = 15) : sage: sage: sage: sage: L X Y n = = = = 40 [100*float(i)/L for i in range(40)] [float(1/(1+25*X[i]^2)+0.25*random()) for i in range(40)] 15; orth = orthopoly(n, X)

13.2. MATRICES PLEINES

295

0.8

0.6

0.4

0.2

20

40

60

80

Figure 13.1 Ajustement polynomial.

Calculons les coecients de la solution sur la base des polynmes orthogonaux : sage: coeff = [sum(Y[j]*eval(orth[i],X[j]) for j in ....: range(0,len(X))) for i in range(0,n)] On peut ensuite transformer ce rsultat dans la base des monmes 1, x, . . . , xn an, par exemple, de pouvoir en dessiner le graphe : sage: sage: ....: sage: sage: polmin = [0 for i in range(0,n)] for i in range(0,n): padd(polmin, coeff[i], orth[i]) p = lambda x: eval(polmin, x) plot(p(x), x, 0, X[len(X)-1])

On ne dtaille pas ici le calcul de lajustement naf sur la base des monmes xi , ni sa reprsentation graphique. On obtient la gure 13.1. Les deux courbes, lune correspondant lajustement base de polynmes orthogonaux, lautre la mthode nave, sont trs proches, mais, en calculant leur rsidu (la valeur de la fonctionnelle J ) on trouve 0.1202 pour lajustement par les polynmes orthogonaux, et 0.1363 pour lajustement naf.

13.2.10

Implantation et performances

Les calculs avec des matrices coecients dans RDF sont eectus avec larithmtique ottante du processeur, ceux avec les matrices RR avec la bibliothque GNU MPFR. De plus dans le premier cas, Sage se sert de NumPy/SciPy, qui passe la main la bibliothque Lapack (code en Fortran) et cette dernire bibliothque

296

CHAP. 13. ALGBRE LINAIRE NUMRIQUE

utilise les BLAS 6 dATLAS optimises pour chaque machine. Ainsi, on obtient, pour le calcul du produit de deux matrices de taille 1000 : sage: a = random_matrix(RR, 1000) sage: b = random_matrix(RR, 1000) sage: %time a*b CPU times: user 421.44 s, sys: 0.34 s, total: 421.78 s Wall time: 421.79 s sage: c = random_matrix(RDF, 1000) sage: d = random_matrix(RDF, 1000) sage: %time c*d CPU times: user 0.18 s, sys: 0.01 s, total: 0.19 s Wall time: 0.19 s soit un rapport de plus de 2000 entre les deux temps de calcul ! On peut aussi remarquer la rapidit des calculs avec des matrices coecients RDF : on vrie immdiatement que le produit de deux matrices carres de taille n cote n3 multiplications (et autant dadditions) ; ici, on eectue donc 109 additions et multiplications en 0.18 seconde ; ce sont donc environ 1010 oprations quon eectue par seconde soit encore une vitesse de 10 gigaops. Lunit centrale de la machine de test battant 3.1 Ghz, on eectue donc plus dune opration par tour dhorloge : ceci est rendu possible par lappel presque direct de la routine correspondante de la bibliothque ATLAS 7 . Notons quil existe aussi un algorithme de cot infrieur n3 pour eectuer le produit de deux matrices : la mthode de Strassen. Elle nest pas implante en pratique (pour des calculs en ottant) pour des raisons de stabilit numrique. Le lecteur pourra vrier, avec les programmes ci-dessus, que le temps de calcul avec Sage est bien proportionnel n3 .

13.3

Matrices creuses

Les matrices creuses sont trs frquentes en calcul scientique : le caractre creux (sparsity en anglais) est une proprit recherche qui permet de rsoudre des problmes de grande taille, inaccessibles avec des matrices pleines. Une dnition approximative : on dira quun ensemble de matrices {Mn }n (de taille n) est une famille de matrices creuses si le nombre de coecients non nuls de Mn est de lordre de O(n). Bien videmment, ces matrices sont reprsentes en machine en utilisant des structures de donnes o ne sont stocks que les termes non nuls. En tenant compte du caractre creux des matrices, on veut, bien sr, gagner de la place mmoire et donc pouvoir manipuler de grandes matrices, mais aussi rduire fortement le cot des calculs.
6. Basic Linear Algebra Subroutines (produits matrice-vecteur, matrice-matrice, etc.). 7. Cette bibliothque procde par blocs de taille automatiquement adapte (dtermine par essais successifs) lors de la compilation : elle est en partie responsable du temps considrable qui est ncessaire la compilation de Sage partir du code source.

13.3. MATRICES CREUSES

297

13.3.1

Origine des systmes creux

Problmes aux limites. Lorigine la plus frquente est la discrtisation dquations aux drives partielles. Considrons par exemple lquation de Poisson (quation de la chaleur stationnaire) : u = f o u = u(x, y ), f = f (x, y ), u := 2u 2u + 2. x2 y

Lquation est pose dans le carr [0, 1]2 , et munie de conditions aux limites u = 0 sur le bord du carr. Lanalogue en dimension un est le problme 2u = f, x2 (13.1)

avec u(0) = u(1) = 0. Une des mthodes les plus simples pour approcher la solution de cette quation consiste utiliser la mthode des dirences nies : on dcoupe lintervalle [0, 1] en un nombre ni N dintervalles de pas h constant. On note ui la valeur approche de u au point xi = ih. On approche la drive de u par (ui+1 ui )/h et sa drive seconde par ui+1 2ui + ui1 (ui+1 ui )/h (ui ui1 )/h = . h h2 On voit immdiatement que les u0 , . . . , uN , qui approchent u aux points ih, satisfont un systme linaire nayant que 3 termes non nuls par ligne (et dont on peut vrier que la matrice est symtrique dnie positive). En dimension 2, on peut plaquer une grille de pas h sur le carr unit et on obtient un systme pentadiagonal (avec 4/h2 sur la diagonale, deux sur-diagonales et deux sous-diagonales dont les coecients sont 1/h2 ). En dimension 3, en procdant de la mme manire dans un cube, on obtient un systme o chaque ligne possde 7 coecients non nuls. On a donc bien des matrices trs creuses. Marche alatoire sur un grand graphe creux. On considre un graphe dans lequel chaque sommet est reli un petit nombre de sommets (petit par rapport au nombre total de sommets). Par exemple, on pourra se gurer un graphe dont les sommets sont les pages de linternet : chaque page ne cite quun petit nombre dautres pages (ce qui dnit les artes du graphe), mais cest assurment un trs grand graphe. Une marche alatoire sur le graphe est dcrite par une matrice stochastique, cest--dire une matrice dont chaque coecient est un rel compris entre 0 et 1 et dont la somme des coecients de chaque ligne vaut 1. On montre quune telle matrice A a une valeur propre dominante gale un. La distribution stationnaire de la marche alatoire est le vecteur propre x gauche associ la valeur propre dominante, cest--dire le vecteur qui vrie xA = x. Une des applications les plus spectaculaires est lalgorithme Pagerank de Google, dans lequel le vecteur x sert pondrer les rsultats des recherches.

298

CHAP. 13. ALGBRE LINAIRE NUMRIQUE

13.3.2

Sage et les matrices creuses

Sage permet de travailler avec des matrices creuses, en spciant sparse = True lors de la cration de la matrice. Il sagit dun stockage sous forme de dictionnaire. Dun autre ct, les calculs avec de grandes matrices creuses, coecients ottants (RDF ou CDF) sont eectus par Sage avec la bibliothque SciPy, qui ore ses propres classes de matrices creuses. Dans ltat actuel des choses, il nexiste pas dinterface entre les matrices sparse de Sage et les matrices creuses de SciPy. Il convient donc dutiliser directement les objets de SciPy. Les classes fournies par SciPy pour reprsenter des matrices creuses sont : une structure sous forme de liste de listes (mais pas identique celle utilise par Sage) pratique pour crer et modier des matrices, les lil_matrix ; des structures immuables, ne stockant que les coecients non nuls, et qui sont un standard de fait en algbre linaire creuse (formats csr et csv).

13.3.3

Rsolution de systmes linaires

Pour des systmes de taille modre tels que ceux dtaills ci-dessus (en dimension 1 et 2), on peut utiliser une mthode directe, base sur la dcomposition LU . On peut se convaincre sans grande dicult que, dans la dcomposition LU dune matrice A creuse, les facteurs L et U contiennent en gnral plus de termes non nuls eux deux que A. Il faut utiliser des algorithmes de renumrotation des inconnues pour limiter la taille mmoire ncessaire, comme dans la bibliothque SuperLU utilise par Sage de manire transparente : sage: sage: sage: sage: sage: sage: sage: sage: ....: ....: ....: ....: ....: sage: sage: sage: sage: from scipy.sparse.linalg.dsolve import * from scipy.sparse import lil_matrix from numpy import array n = 200 n2 = n*n A = lil_matrix((n2, n2)) h2 = 1./float((n+1)^2) for i in range(0,n2): A[i,i]=4*h2+1. if i+1<n2: A[i,int(i+1)]=-h2 if i>0: A[i,int(i-1)]=-h2 if i+n<n2: A[i,int(i+n)]=-h2 if i-n>=0: A[i,int(i-n)]=-h2 Acsc = A.tocsc() b = array([1 for i in range(0,n2)]) solve = factorized(Acsc) # factorisation LU S = solve(b) # rsolution

Aprs avoir cr la matrice sous forme de lil_matrix (attention ce format ncessite des indices de type int de Python) il faut la convertir au format csc. Ce programme nest pas particulirement performant : la construction de la lil_matrix est lente, les structures lil_matrix ntant pas trs ecaces. En

13.3. MATRICES CREUSES

299

Commandes les plus utiles Rsoudre un systme linaire Dcomposition LU Dcomposition de Cholesky Dcomposition QR Dcomposition en valeurs singulires Valeurs et vecteurs propres x = A\b P, L, U = A.LU() C = A.cholesky() Q, R = A.QR() U, Sig, V = A.SVD() Val, Vect = A.eigenmatrix_right()

Tableau 13.1 Rcapitulatif.

revanche, la conversion en une matrice csc et la factorisation sont rapides, et la rsolution qui suit lest plus encore. Mthodes itratives. Le principe de ces mthodes est de construire une suite qui converge vers la solution du systme Ax = b. Les mthodes itratives modernes utilisent lespace de Krylov Kn , espace vectoriel engendr par b, Ab, . . . , An b. Parmi les mthodes les plus populaires, citons : la mthode du gradient conjugu : elle ne peut tre utilise que pour des systmes dont la matrice A est symtrique dnie positive. Dans ce cas x A = t x Ax est une norme, et litr xn est calcul de sorte minimiser lerreur x xn A entre la solution x et xn pour xn Kn (il existe des formules explicites, faciles programmer, cf. par exemple [LT94],[GVL96]) ; la mthode du rsidu minimal gnralis (GMRES ou generalized minimal residual ) : elle a lavantage de pouvoir tre utilise pour des systmes linaires non symtriques. litration n cest la norme euclidienne du rsidu Axn b 2 qui est minimise pour xn Kn . On notera quil sagit l dun problme aux moindres carrs. En pratique, ces mthodes ne sont ecaces que prconditionnes : au lieu de rsoudre Ax = b, on rsout M Ax = M b o M est une matrice telle que M A est mieux conditionne que A. Ltude et la dcouverte de prconditionneurs ecaces est une branche actuelle et riche de dveloppements de lanalyse numrique. titre dexemple, voici la rsolution du systme tudi ci-dessus par la mthode du gradient conjugu, o le prconditionneur M , diagonal, est linverse de la diagonale de A. Cest un prconditionneur simple, mais peu ecace : sage: sage: sage: ....: sage: sage: sage: b = array([1 for i in range(0,n2)]) m = lil_matrix((n2, n2)) for i in range(0,n2): m[i,i] = 1./A[i,i] msc = m.tocsc() from scipy.sparse.linalg import cg x = cg(A, b, M = msc, tol=1.e-8)

300

CHAP. 13. ALGBRE LINAIRE NUMRIQUE

13.3.4

Valeurs propres, vecteurs propres

La mthode de la puissance itre. La mthode de la puissance itre est particulirement adapte au cas de trs grandes matrices creuses ; en eet il sut de savoir eectuer des produits matrice-vecteur (et des produits scalaires) pour savoir implanter lalgorithme. titre dexemple, revenons aux marches alatoires sur un graphe creux, et calculons la distribution stationnaire, par la mthode de la puissance itre : sage: from scipy import sparse sage: from numpy.linalg import * sage: from numpy import array sage: from numpy.random import rand sage: def power(A,x): # Puissance itre ....: for i in range(0,1000): ....: y = A*x ....: z = y/norm(y) ....: lam = sum(x*y) ....: s = norm(x-z) ....: print i,"s= "+str(s)+" lambda= "+str(lam) ....: if s < 1e-3: ....: break ....: x = z ....: return x sage: n = 1000 sage: m = 5 sage: # fabriquer une matrice stochastique de taille n sage: # avec m coefficients non nuls par ligne sage: A1 = sparse.lil_matrix((n, n)) sage: for i in range(0,n): ....: for j in range(0,m): ....: l = int(n*rand()) ....: A1[l,i] = rand() sage: for i in range(0,n): ....: s = sum(A1[i,0:n]) ....: A1[i,0:n] /= s sage: At = A1.transpose().tocsc() sage: x = array([rand() for i in range(0,n)]) sage: # calculer la valeur propre dominante et sage: # le vecteur propre associ sage: y = power(At, x) 0 s= 17.637122289 lambda= 255.537958336 1 s= 0.374734872232 lambda= 0.91243996321 2 s= 0.215216267956 lambda= 0.968970901784 3 s= 0.120794893336 lambda= 0.98672095617 4 s= 0.071729229056 lambda= 0.990593746559 ...

13.3. MATRICES CREUSES

301

En excutant cet exemple, on pourra samuser chronomtrer ses direntes parties, et on constatera que la quasi totalit du temps de calcul est passe dans la fabrication de la matrice ; la transposition nest pas trs coteuse ; les itrations du calcul proprement dit occupent un temps ngligeable sur les 7.5 secondes du calcul (sur la machine de test). Les stockages sous forme de listes de matrices de grande taille ne sont pas trs ecaces et ce genre de problme doit plutt tre trait avec des langages compils et des structures de donnes adaptes.

13.3.5

Thme de rexion : rsolution de trs grands systmes non linaires

La mthode la puissance itre et les mthodes bases sur lespace de Krylov partagent une proprit prcieuse : il sut de savoir calculer des produits matricevecteur pour pouvoir les implanter. On nest mme pas oblig de connatre la matrice, il sut de connatre laction de la matrice sur un vecteur. On peut donc faire des calculs dans des cas o on ne connat pas exactement la matrice ou des cas o on est incapable de la calculer. Les mthodes de SciPy acceptent en fait des oprateurs linaires comme arguments. Voici une application laquelle on pourra rchir (et quon pourra implanter). Soit F : Rn Rn . On veut rsoudre F (x) = 0. La mthode de choix est la mthode de Newton, o on calcule les itrs xn+1 = xn J (xn )1 F (xn ) en partant de x0 . La matrice J (xn ) est la jacobienne de F en xn , matrice des drives partielles de F en xn . En pratique, on rsoudra successivement J (xn )yn = F (xn ), puis xn+1 = xn yn . Il faut donc rsoudre un systme linaire. Si F est un objet un peu compliqu calculer, alors ses drives sont en gnral encore beaucoup plus diciles calculer et coder et ce calcul peut mme savrer pratiquement impossible. On a donc recours la drivation numrique : si ej est le vecteur de Rn partout gal 0 sauf sa j -ime composante gale 1, alors (F (x + hej ) F (x))/h fournit une (bonne) approximation de la j -ime colonne de la matrice jacobienne. Il faudra donc faire n + 1 valuations de F pour obtenir J de manire approche, ce qui est trs coteux si n est grand. Et si on applique une mthode itrative de type Krylov pour rsoudre le systme J (xn )yn = F (xn ) ? On remarque alors que J (x n )V (F (xn + hV ) F (xn ))/h pour h assez petit, ce qui vite de calculer toute la matrice. Dans SciPy, il sura donc de dnir un oprateur linaire comme tant lapplication V (F (xn + hV ) F (xn ))/h. Ce genre de mthode est couramment utilise pour la rsolution de grands systmes non linaires. La matrice ntant pas symtrique, on utilisera par exemple la mthode GMRES.

302

CHAP. 13. ALGBRE LINAIRE NUMRIQUE

Intgration numrique et quations direntielles


Ce chapitre traite le calcul numrique dintgrales (14.1) ainsi que la rsolution numrique dquations direntielles ordinaires (14.2) avec Sage. Nous rappelons des bases thoriques des mthodes dintgration, puis nous dtaillons les fonctions disponibles et leur usage (14.1.1). Le calcul symbolique dintgrales avec Sage a t trait prcdemment (2.3.8), et ne sera que mentionn rapidement ici comme une possibilit de calculer la valeur numrique dune intgrale. Cette approche symbolique puis numrique , lorsquelle est possible, constitue une des forces de Sage et est privilgier car le nombre de calculs eectus, et donc derreurs darrondi, est en gnral moindre que pour les mthodes dintgration numrique. Nous donnons une rapide introduction aux mthodes classiques de rsolution dquations direntielles, puis le traitement dun exemple (14.2.1) dbutera linventaire des fonctions disponibles en Sage (14.2.2).

14

14.1

Intgration numrique

On sintresse au calcul numrique dintgrales de fonctions relles ; pour une fonction f : I R, o I est un intervalle de R, on veut calculer : f (x) dx.
I

Par exemple, calculons


3

exp(x2 ) log(x) dx.


1

304

CHAP. 14. INTGRATION NUMRIQUE


0.8

0.04 0.03 0.02 0.01 0 1 1.5 2 2.5 3

0.6 0.4 0.2 0 -0.2


sin(x2 ) . x2

10

Figure 14.1 Les fonctions x exp(x2 ) log(x) et x

sage: x = var( x ); f(x) = exp(-x^2) * log(x) sage: N(integrate(f, x, 1, 3)) 0.035860294991267694 sage: plot(f, 1, 3, fill= axis ) La fonction integrate calcule lintgrale symbolique de lexpression, il faut demander explicitement une valeur numrique pour lobtenir. Il est aussi, en principe, possible de calculer des intgrales sur un intervalle dont les bornes sont innies : sage: N(integrate(sin(x^2)/(x^2), x, 1, infinity)) 0.285736646322858 sage: plot(sin(x^2)/(x^2), x, 1, 10, fill= axis ) Il existe plusieurs mthodes dans Sage pour calculer numriquement une intgrale, et si leurs implmentations dirent techniquement, elles reposent toutes sur lun des deux principes suivants : une interpolation polynomiale (mthode de Gauss-Kronrod en particulier) ; une transformation de fonction (mthode doublement exponentielle). Mthodes interpolatoires. Dans ces mthodes, on value la fonction f intgrer en un certain nombre n de points bien choisis x1 , x2 , . . . , xn , et on calcule une valeur approche de lintgrale de f sur [a, b] par
b n

f (x) dx
a i=1

wi f (xi ).

Les coecients wi sont appels les poids de la mthode, et ils sont dtermins par la condition que la mthode doit tre exacte pour tout polynme f de degr infrieur ou gal n 1. Pour des points (xi ) xs, les poids (wi ) sont dtermins de manire unique par cette condition. On dnit lordre de la mthode comme le degr maximal des polynmes quelle intgre exactement ; cet ordre est donc au moins n 1 par construction mais il peut tre plus grand.

14.1. INTGRATION NUMRIQUE

305

Ainsi la famille des mthodes dintgration de Newton-Cotes (dont font partie les mthodes des rectangles, des trapzes, la rgle de Simpson) choisissent pour points dintgration des points quirpartis sur lintervalle [a, b] : sage: sage: sage: ....: sage: sage: sage: fp = plot(f, 1, 3, color= red ) n = 4 interp_points = [(1+2*u/(n-1), N(f(1+2*u/(n-1)))) for u in xrange(n)] A = PolynomialRing(RR, x ) pp = plot(A.lagrange_polynomial(interp_points), 1, 3, fill= axis ) show(fp+pp)

0.04 0.03 0.02 0.01 0 1 1.5 2 2.5 3

Pour les mthodes de type interpolatoire, on peut donc considrer que lon calcule le polynme dinterpolation de Lagrange de la fonction donne et que lintgrale de ce polynme est choisie comme valeur approche de lintgrale de la fonction. Ces deux tapes sont en ralit condenses en une formule appele rgle de quadrature, le polynme dinterpolation de Lagrange nest jamais calcul explicitement. Le choix des points dinterpolation inue grandement sur la qualit de lapproximation polynomiale obtenue, et le choix de points quirpartis nassure pas la convergence quand le nombre de points augmente (phnomne de Runge). La mthode dintgration correspondante peut ainsi sourir de ce problme illustr en gure 14.2. Lorsquon demande Sage de calculer numriquement une intgrale sur un intervalle quelconque, la mthode dintgration nest pas applique directement sur le domaine entier : on subdivise le domaine dintgration en intervalles susamment petits pour que la mthode lmentaire donne un rsultat assez prcis (on parle de composition de mthodes). Comme stratgie de subdivision, on peut par exemple sadapter dynamiquement la fonction intgrer : si on b b appelle Ia (f ) la valeur de a f (x) dx calcule par la mthode dintgration, on compare b I0 = Ia (f )

306

CHAP. 14. INTGRATION NUMRIQUE

4 3 2 1 -10 -5 5 10

Figure 14.2 Interpolation par un polynme de degr 10 (trait n) de la fonction x 1/(1 + x2 ) (trait gras) sur 11 points quirpartis sur [10, 10]. Le phnomne de Runge est apparent aux bornes.

avec

(a+b)/2 b I1 = Ia (f ) + I( a+b)/2 (f )

et on arrte de subdiviser si |I0 I1 | nest pas signicatif par rapport la prcision de calcul utilise. Cest ici que la notion dordre dune mthode est importante : pour une mthode dordre n, diviser lintervalle dintgration en 2 divise lerreur thorique par 2n , sans tenir compte des erreurs darrondi. Une mthode de type interpolatoire particulire disponible dans Sage est la mthode de Gauss-Legendre. Dans cette mthode les n points dintgration sont choisis comme les racines du polynme de Legendre de degr n (avec un intervalle de dnition correctement translat lintervalle dintgration considr [a, b]). Les proprits des polynmes de Legendre, orthogonaux pour le produit scalaire
b

f, g =
a

f (x)g (x) dx,

font que la mthode dintgration obtenue calcule exactement les intgrales des polynmes de degr 2n 1 inclus, au lieu de simplement jusquau degr n 1 comme on pouvait sy attendre. De plus les poids dintgration correspondants sont toujours positifs, ce qui rend la mthode moins vulnrable des problmes numriques du type cancellation 1 Pour terminer sur les mthodes de type interpolatoire, la mthode de GaussKronrod 2n+1 points est une augmentation de la mthode de Gauss-Legendre n points :
1. Ce phnomne se produit lorsquune somme est signicativement plus petite (en valeur absolue) que les termes de la somme : chaque erreur darrondi peut alors tre plus grande que le rsultat nal, do une perte totale de prcision. Voir aussi 11.3.3.

14.1. INTGRATION NUMRIQUE

307

parmi les 2n + 1 points, n sont les points de la mthode de Gauss-Legendre ; la mthode est exacte pour tout polynme de degr infrieur ou gal 3n + 1. On peut observer navement que les 3n + 2 inconnues (les 2n + 1 poids et les n + 1 points ajouts) sont a priori dtermins en exigeant que la mthode soit au moins dordre 3n + 1 (ce qui donne bien 3n + 2 conditions). Attention, les poids associs dans la mthode de Gauss-Kronrod aux n points de Gauss-Legendre nont aucune raison de concider avec ceux qui leur sont associs dans la mthode de Gauss-Legendre. Lintrt dune telle mthode augmente se manifeste lorsque lon considre que le cot principal dun algorithme dintgration est le nombre dvaluations de la fonction f intgrer (en particulier si les points et poids sont tabuls). La mthode de Gauss-Kronrod tant en principe plus prcise que celle de GaussLegendre, on peut utiliser son rsultat I1 pour valider le rsultat I0 de cette dernire et obtenir une estimation de lerreur commise par |I1 I0 |, tout en minimisant le nombre dappels f . On peut comparer cette stratgie, particulire la mthode de Gauss-Legendre, avec la stratgie plus gnrale de subdivision vue en page 306. Mthodes doublement exponentielles. Les mthodes doublement exponentielles (DE) reposent sur le choix dun changement de variable qui transforme un intervalle dintgration born R, et sur la trs bonne prcision obtenue par la mthode des trapzes sur R pour les fonctions analytiques. Pour une fonction f intgrable sur R et un pas dintgration h la mthode des trapzes consiste calculer
+

Ih = h
i= +

f (hi)

comme valeur approche de f (x) dx. Dcouverte en 1973 par Takahasi et Mori, la transformation doublement exponentielle est couramment utilise par les logiciels dintgration numrique. Une introduction la transformation et sa dcouverte est donne dans [Mor05] ; lessentiel en est restitu ici. On y trouve en particulier une explication de la surprenante prcision obtenue par la mthode des trapzes (elle est optimale dans un certain sens) pour les fonctions analytiques sur R. Pour calculer
1

I=
1

f (x) dx,

il est possible dutiliser une transformation x = (t) o est analytique sur R et vrie lim (t) = 1, lim (t) = 1,
t t

et alors I=

f ((t)) (t) dt.

308
1 0.5 -3 -2 -1 -0.5 -1 1 2

CHAP. 14. INTGRATION NUMRIQUE


1.6 1.4 1.2 1 3 0.8 0.6 0.4 0.2 -3 -2 -1 1 2 3

Figure 14.3 La transformation (t) = tanh( sinh t) utilise dans la mthode doublement 2 exponentielle ( gauche) et la dcroissance de (t) ( droite).

En appliquant la formule des trapzes cette dernire expression on calcule


N N Ih =h k=N

f ((kh)) (kh)

pour un certain pas de discrtisation h et en tronquant la somme aux termes de N N . Le choix de transformation propos est (t) = tanh qui donne la formule
N N Ih =h k=N

sinh t 2

f tanh

sinh kh 2

2 cosh kh . cosh2 ( 2 sinh kh)

La formule doit son nom la dcroissance doublement exponentielle de (t) =


2 cosh t cosh2 ( 2 sinh t)

quand |t| (voir gure 14.3). Le principe de la transformation est de concentrer lessentiel de la contribution de la fonction intgrer autour de 0, do la forte dcroissance quand |t| crot. Il y a un compromis trouver dans le choix des paramtres et de la transformation utilise : une dcroissance plus rapide que doublement exponentielle diminue lerreur de troncature mais augmente lerreur de discrtisation. Depuis la dcouverte de la transformation DE, cette mthode est applique seule ou avec dautres transformations, en fonction de la nature de lintgrande, de ses singularits et du domaine dintgration. Un tel exemple est la dcomposition sinus cardinal sinc :
N

f (x)
k=N

f (kh)Sk,h (x)

14.1. INTGRATION NUMRIQUE

309

1 0.8 0.6 0.4 0.2 -4 -3 -2 -1 -0.2


Figure 14.4 La fonction sinus cardinal.

o Sk,h (x) =

sin( (x kh)/h) , (x kh)/h

utilise conjointement la mthode doublement exponentielle dans [TSM05] pour amliorer les formules prcdentes qui utilisaient une transformation simplement exponentielle (t) = tanh(t/2). La fonction sinc est dnie par 1 si x = 0, sinc = sin(x) sinon, x et son graphe est donn en gure 14.4. Le choix de la transformation utiliser dtermine en grande partie la qualit du rsultat en prsence de singularits aux bornes (il ny a cependant pas de bonne solution en cas de singularits lintrieur de lintervalle). Nous verrons plus loin que dans la version de Sage considre, seules les fonctions dintgration de PARI utilisent des transformations doublement exponentielles avec la possibilit de prciser le comportement aux bornes.

14.1.1

Fonctions dintgration disponibles

Nous allons maintenant voir plus en dtail les direntes faons de calculer une intgrale numrique avec Sage, travers quelques exemples de calculs dintgrales :
42 1

I1

=
17

exp(x2 ) log(x) dx,

I2 =
0

x log(1 + x) dx =

1 , 4

310
1

CHAP. 14. INTGRATION NUMRIQUE =


0 1

I3 I4

1 x2 dx =

, 4
4

=
0

max(sin(x), cos(x)) dx =
0

cos(x) dx +

= I5 I7 I9 =

sin
1

+ cos cos 1 = 2 cos 1, 4 4

sin(x) dx

sin(sin(x)) dx,
0 1

I6 =
0

1 sin(x) exp(cos(x)) dx = e , e
1,1

=
0

1 dx = 105 arctan(105 ), 1 + 1010 x2 1 x sin(x ) dx = (1 cos(1000)), 3


2 3

I8 =
0 1

exp(x100 ) dx, x dx = 2 . 3

10

=
0

I10 =
0

Nous ne donnons pas une description exhaustive de lusage des fonctions dintgration traites cela se trouve dans laide en ligne mais uniquement leur usage le plus courant. N(integrate(...)). La premire mthode que lon peut utiliser avec Sage pour calculer numriquement est N(integrate(...)) : sage: N(integrate(exp(-x^2)*log(x), x, 17, 42)) 2.5657285006962035e-127 Il faut remarquer quil nest pas garanti que lintgrale sera calcule numriquement par ce biais, en eet la fonction integrate demande une intgration symbolique. Si celle-ci est possible, alors Sage ne fera quvaluer numriquement lexpression symbolique obtenue : sage: integrate(log(1+x)*x, x, 0, 1) 1/4 sage: N(integrate(log(1+x)*x, x, 0, 1)) 0.250000000000000 numerical_integral. La fonction numerical_integral, linverse, demande explicitement une intgration numrique de la fonction donne en paramtre. Elle utilise pour ceci la bibliothque numrique GSL qui implmente la mthode de Gauss-Kronrod pour un nombre n x de points dintgration. Les points et poids sont prcalculs, et la prcision est limite la prcision des nombres ottants machine (53 bits de mantisse). Le rsultat est un couple compos du rsultat calcul et dune estimation de lerreur : sage: numerical_integral(exp(-x^2)*log(x), 17, 42) (2.5657285006962035e-127, 3.3540254049238093e-128) Lestimation de lerreur nest pas une borne garantie de lerreur commise, mais une simple valeur indicative de la dicult calculer lintgrale donne. On constate que dans lexemple ci-dessus lestimation donne de lerreur est telle que lon peut douter de presque tous les chires du rsultat (sauf le premier). Les arguments de numerical_integral permettent notamment :

14.1. INTGRATION NUMRIQUE

311

de choisir le nombre de points utiliss (six choix allant de rule=1 pour 15 points rule=6 pour 61 points, valeur par dfaut) ; de demander une subdivision adaptative (choix par dfaut), ou dimposer une application directe sans composition de la mthode sur lintervalle dintgration (par lajout de algorithm= qng ) ; de borner le nombre dappels lintgrande. Empcher GSL de procder une intgration adaptative peut entraner une perte de prcision : sage: numerical_integral(exp(-x^100), 0, 1.1) (0.99432585119150..., 4.0775730...e-09) sage: numerical_integral(exp(-x^100), 0, 1.1, algorithm= qng ) (0.994327538576531..., 0.016840666914688864) Lorsque la fonction integrate ne trouve pas dexpression analytique correspondant lintgrale demande, elle renvoie une expression symbolique inchange : sage: integrate(exp(-x^2)*log(x), x, 17, 42) integrate(e^(-x^2)*log(x), x, 17, 42) et le calcul numrique eectu via N utilise numerical_integral. Ceci explique en particulier pourquoi le paramtre de la prcision sera ignor dans ce cas : sage: N(integrate(exp(-x^2)*log(x), x, 17, 42), 200) 2.5657285006962035e-127 mais on aura : sage: N(integrate(sin(x)*exp(cos(x)), x, 0, pi), 200) 2.3504023872876029137647637011912016303114359626681917404591 car lintgration symbolique est possible dans ce cas. sage.calculus.calculus.nintegral. Pour les fonctions dnies symboliquement, il est possible de demander Maxima de calculer numriquement une intgrale : sage: sage.calculus.calculus.nintegral(sin(sin(x)), x, 0, 1) (0.430606103120690..., 4.780688102287053...e-15, 21, 0) mais il est aussi possible dappeler la mthode nintegral directement sur un objet de type Expression : sage: g(x) = sin(sin(x)) sage: g.nintegral(x, 0, 1) (0.430606103120690..., 4.780688102287053...e-15, 21, 0) Maxima utilise la bibliothque dintgration numrique QUADPACK, qui comme GSL est limite aux nombres ottants machine. La fonction nintegral utilise une stratgie de subdivision adaptative de lintervalle dintgration, et il est possible de prciser : la prcision relative dsire pour la sortie ;

312

CHAP. 14. INTGRATION NUMRIQUE le nombre maximal de sous-intervalles considrs pour le calcul.

La sortie est un tuple : 1. la valeur approche de lintgrale ; 2. une estimation de lerreur absolue ; 3. le nombre dappels lintgrande ; 4. un code derreur (0 si aucun problme na t rencontr, pour plus de dtails sur les autres valeurs possibles vous pouvez consulter la documentation avec sage.calculus.calculus.nintegral?). gp(intnum(...)). Le calculateur PARI est disponible depuis Sage et implmente aussi une commande pour lintgration numrique de fonctions nomme intnum : sage: gp( intnum(x=17, 42, exp(-x^2)*log(x)) ) 2.5657285005610514829173563961304785900 E-127 La fonction intnum utilise la mthode doublement exponentielle. Il est possible de choisir la prcision du rsultat en modiant la prcision globale de linterprte PARI : sage: gp( intnum(x=0, 1, sin(sin(x))) ) 0.43060610312069060491237735524846578643 sage: old_prec = gp.set_precision(50) sage: gp( intnum(x=0, 1, sin(sin(x))) ) 0.43060610312069060491237735524846578643360804182200 Un inconvnient majeur de cette mthode est que la fonction intgrer est donner sous la forme dune chane en respectant la syntaxe de PARI, il nest pas possible dintgrer des fonctions arbitraires par ce biais. La fonction intnum permet dindiquer le comportement de lintgrande aux bornes de lintervalle dintgration. Lexemple suivant illustre limpact que cela peut avoir sur la prcision du rsultat. Intgrons x x1/2 sans indication : sage: p = gp.set_precision(old_prec) # on remet la prcision par dfaut sage: gp( intnum(x=0, 1, x^(-1/2)) ) 1.999999999999999999999999999998... En indiquant la nature de la singularit, savoir que la fonction se comporte comme x x1/2 en 0 : sage: gp( intnum(x=[0, -1/2], 1, x^(-1/2)) ) 2.00000000000000000000000000000... Lutilisateur est responsable de lexactitude du comportement annonc ; si par exemple nous indiquons (de faon errone) que la fonction se comporte comme x x1/42 en 0, lerreur commise restera importante : sage: gp( intnum(x=[0, -1/42], 1, x^(-1/2)) ) 1.9999999999999999999999999999996...

14.1. INTGRATION NUMRIQUE

313

mpmath.quad*. La bibliothque mpmath est une bibliothque de calcul numrique en prcision arbitraire crite en Python. Elle est capable de calculer avec des nombres ottants rels et complexes, des matrices, et des intervalles de nombres ottants rels. Elle dispose de fonctions dintgration numrique (la principale tant quad) et est disponible en Sage, il sut de limporter : sage: import mpmath sage: mpmath.mp.prec = 53 sage: mpmath.quad(lambda x: mpmath.sin(mpmath.sin(x)), [0, 1]) mpf( 0.43060610312069059 ) La valeur de sortie nest pas garantie tre exacte avec toute la prcision demande, comme on le constate sur lexemple suivant : sage: mpmath.mp.prec = 113 sage: mpmath.quad(lambda x: mpmath.sin(mpmath.sin(x)), [0, 1]) mpf( 0.430606103120690604912377355248465809 ) sage: mpmath.mp.prec = 114 sage: mpmath.quad(lambda x: mpmath.sin(mpmath.sin(x)), [0, 1]) mpf( 0.430606103120690604912377355248465785 ) Il est possible de spcier la prcision demande en nombre de chires dcimaux (mpmath.mp.dps) ou en nombre de bits (mpmath.mp.prec). Dans un souci de cohrence avec la fonction N de Sage nous nous restreignons une prcision en bits. La fonction mpmath.quad peut faire appel soit la mthode de Gauss-Legendre, soit la transformation doublement exponentielle (cest cette dernire qui est utilise par dfaut). Il est possible de spcier directement la mthode utiliser avec les fonctions mpmath.quadgl et mpmath.quadts. 2 Une limitation importante pour lutilisation des fonctions dintgration de mpmath dans Sage est quelles ne savent pas manipuler directement des fonctions arbitraires dnies en Sage : sage: mpmath.quad(sin(sin(x)), [0, 1]) Traceback (most recent call last): ... TypeError: no canonical coercion from <type sage.libs.mpmath.ext_main.mpf > to Symbolic Ring La situation est cependant moins problmatique que pour lutilisation de PARI qui est elle limite une interaction en mode texte. Il est en eet possible dajouter les fonctions dvaluation et de conversion ncessaires pour pouvoir intgrer via mpmath.quad des fonctions quelconques 3 : sage: g(x) = max_symbolic(sin(x), cos(x)) sage: mpmath.mp.prec = 100
2. Du nom de la transformation utilise : t tanh( sinh(t)) et vue prcdemment. 2 3. Le lecteur curieux de savoir pourquoi on a utilis max_symbolic essayera avec max, et regardera ensuite la documentation de max_symbolic.

314

CHAP. 14. INTGRATION NUMRIQUE

1 0.95 0.9 0.85 0.8 0.75 0.7 0 0.2 0.4 0.6 0.8 1

Figure 14.5 La fonction x max(sin(x), cos(x)). Lirrgularit en /4 rend lintgration numrique trs problmatique.

sage: mpmath.quadts(lambda x: g(N(x, 100)), [0, 1]) mpf( 0.873912416263035435957979086252 ) On constate que lintgration de fonctions non rgulires (comme lexemple de I4 ci-dessus) peut entraner des pertes de prcision consquentes, mme en demandant le rsultat avec une grande prcision : sage: mpmath.mp.prec = 170 sage: mpmath.quadts(lambda x: g(N(x, 190)), [0, 1]) mpf( 0.87391090757400975205393005981962476344054148354188794 ) sage: N(sqrt(2) - cos(1), 100) 0.87391125650495533140075211677 Seuls 5 chires sont corrects ici. On peut nanmoins aider mpmath en suggrant une subdivision de lintervalle dintgration (ici, au point irrgulier, cf. gure 14.5) : sage: mpmath.quadts(lambda x: g(N(x, 170)), [0, mpmath.pi / 4, 1]) mpf( 0.87391125650495533140075211676672147483736145475902551 ) Les fonctions discontinues reprsentent un pige classique pour les mthodes dintgration ; nanmoins une stratgie dadaptation automatique par subdivision, telle quvoque plus haut, peut limiter les dgts.
Exercice 47 (Calcul des coecients de Newton-Cotes). On cherche calculer les coecients de la mthode de Newton-Cotes n points, celle-ci ntant pas disponible dans Sage. On considre pour simplier que lintervalle dintgration est I = [0, n 1], les points dintgration tant alors x1 = 0, x2 = 1, . . . , xn = n 1. Les coecients (wi ) de la mthode sont tels que lquation
n1 n1

f (x) dx =
0 i=0

wi f (i)

(14.1)

14.2. RSOLUTION DQUATIONS DIFFRENTIELLES


est exacte pour tout polynme f de degr infrieur ou gal n 1. 1. On considre pour i {0, . . . , n 1} le polynme Pi (X ) =
n1
j =0

315

(X xj ). En

j =i

appliquant lquation (14.1) Pi , exprimer wi en fonction de Pi . 2. En dduire une fonction NCRule qui n associe les coecients de la mthode de Newton-Cotes n points sur lintervalle [0, n 1]. 3. Montrer comment appliquer ces poids sur un segment dintgration [a, b] quelconque. 4. crire une fonction QuadNC qui calcule lintgrale dune fonction sur un segment de R donn en paramtre. Comparer les rsultats avec les fonctions dintgration disponibles en Sage sur les intgrales I1 I10 .

14.2

Rsolution numrique des quations direntielles ordinaires

On sintresse dans cette section la rsolution numrique dquations direntielles ordinaires. Les fonctions de rsolution disponibles dans Sage sont capables de traiter des systmes dquations de la forme : dy1 dt (t) = f1 (t, y1 (t), y2 (t), . . . , yn (t)) dy2 (t) = f2 (t, y1 (t), y2 (t), . . . , yn (t)) dt . . . dyn ( t ) = fn (t, y1 (t), y2 (t), . . . , yn (t)) dt avec des conditions initiales (y1 (0), y2 (0), . . . , yn (0)) connues. Cette formalisation permet aussi de sintresser des problmes dordre suprieur 1, en introduisant des variables supplmentaires (voir lexemple dvelopp en 14.2.1). Elle ne permet cependant pas dexprimer le systme dquations vri par la fonction de Dickman : u (u) + (u 1) = 0 pour u (u) = 1 pour 0 1, u 1.

Les outils de rsolution dquations direntielles ordinaires ne sont en eet pas adapts une telle quation (dite retard ). Les mthodes de rsolution numrique dites un pas utilisent toutes un mme principe gnral : pour un pas h et des valeurs de y (t0 ) et y (t0 ) connues, on calcule une valeur approche de y (t0 + h) partir dune estimation de y (t) prise sur lintervalle [t0 , t0 + h]. Par exemple la mthode la plus simple consiste faire lapproximation : t [t0 , t0 + h],
t0 +h t0

y (t) y (t0 ), y (t) dt hy (t0 ),

y (t0 + h) y (t0 ) + hy (t0 ).

316

CHAP. 14. INTGRATION NUMRIQUE

Le fait dapprocher y par une fonction constante sur [t0 , t0 + h] rappelle la mthode dintgration numrique des rectangles. La mthode obtenue est dordre 1, cest--dire que lerreur obtenue aprs un pas de calcul est en O(h2 ) sous lhypothse que f est susamment rgulire. De manire gnrale une mthode est dordre p si lerreur quelle commet sur un pas de longueur h est en O(hp+1 ). La valeur obtenue en t1 = t0 + h sert alors de point de dpart pour progresser dun pas de plus, aussi loin que dsir. Cette mthode dordre 1, appele mthode dEuler, nest pas rpute pour sa prcision (tout comme la mthode des rectangles pour lintgration) et il existe des mthodes dordre plus lev, par exemple la mthode Runge-Kutta dordre 2 pour rsoudre lquation y = f (t, y ) : k1 k2 y (tn+1 ) = hf (tn , y (tn )) 1 1 = hf (tn + h, y (tn ) + k1 ) 2 2 y (tn ) + k2 + O(h3 ).

Dans cette mthode, on essaie dvaluer y (tn + h/2) pour obtenir une meilleure estimation de y (tn + h). On trouve aussi des mthodes multi-pas (cest le cas par exemple des mthodes de Gear) qui consistent calculer y (tn ) partir des valeurs dj obtenues (y (tn1 ), y (tn2 ), . . . , y (tn )) pour un certain nombre de pas . Ces mthodes dmarrent ncessairement par une phase dinitialisation avant quun nombre susant de pas soient calculs. Tout comme la mthode de Gauss-Kronrod pour lintgration numrique, il existe des mthodes hybrides pour la rsolution dquations direntielles. Ainsi la mthode de Dormand et Prince calcule avec les mmes points dapproximation une valeur aux ordres 4 et 5, la deuxime servant pour lestimation derreur de la premire. On parle dans ce cas de mthode adaptative. On distingue encore les mthodes dites explicites des mthodes implicites : dans une mthode explicite, la valeur de y (tn+1 ) est donne par une formule nutilisant que des valeurs connues ; pour une mthode implicite il faut rsoudre une quation. Prenons lexemple de la mthode dEuler implicite : y (tn+1 ) = y (tn ) + hf (tn+1 , y (tn+1 )). On constate que la valeur recherche y (tn+1 ) apparat des deux cts de lquation ; si la fonction f est susamment complexe il faudra rsoudre un systme algbrique non linaire, typiquement avec la mthode de Newton (voir 12.2.2). A priori, on sattend obtenir des rsultats plus prcis mesure que lon diminue le pas dintgration h ; outre le cot en calculs supplmentaires que cela reprsente, ce gain espr en prcision est toutefois tempr par un plus grand nombre derreurs darrondi qui risquent, la longue, de polluer le rsultat.

14.2. RSOLUTION DQUATIONS DIFFRENTIELLES

317

14.2.1

Exemple de rsolution

Considrons loscillateur de Van der Pol de paramtre vriant lquation direntielle suivante : d2 x dx (t) (1 x2 ) (t) + x(t) = 0. dt2 dt Posons y0 (t) = x(t) et y1 (t) =
dy0 dt dy1 dt dx dt ,

on obtient ce systme dordre 1 :

= y1 , 2 = (1 y0 )y1 y0 .

Pour le rsoudre, nous allons utiliser un objet solveur que lon obtient avec la commande ode_solver : sage: T = ode_solver() Un objet solveur sert enregistrer les paramtres et la dnition du systme que lon cherche rsoudre ; il donne accs aux fonctions de rsolution numrique dquations direntielles disponibles dans la bibliothque GSL, dj mentionne au sujet de lintgration numrique. Les quations du systme sont renseignes sous la forme dune fonction : sage: def f_1(t,y,params): return [y[1],params[0]*(1-y[0]^2)*y[1]-y[0]] sage: T.function = f_1 Le paramtre y reprsente le vecteur des fonctions inconnues, et on doit renvoyer en fonction de t et dun paramtre optionnel (ici params[0] reprsentant ) le vecteur des membres droits du systme dquations. Certains des algorithmes de GSL ncessitent de plus de connatre la jacobienne fi du systme (la matrice dont le terme (i, j ) est y , et dont la dernire ligne j contient
fj t )

sage: def j_1(t,y,params): ....: return [[0, 1], ....: [-2*params[0]*y[0]*y[1]-1, params[0]*(1-y[0]^2)], ....: [0,0]] sage: T.jacobian = j_1 Il est maintenant possible de demander une rsolution numrique. On choisit lalgorithme, lintervalle sur lequel calculer la solution et le nombre de pas voulus (ce qui dtermine h) : sage: T.algorithm = "rk8pd" sage: T.ode_solve(y_0=[1,0], t_span=[0,100], params=[10], ....: num_points=1000) sage: f = T.interpolate_solution() Ici on a pris lalgorithme de Runge-Kutta Dormand-Prince pour calculer la solution sur [0, 100] ; les conditions initiales ainsi que la valeur des paramtres (ici

318

CHAP. 14. INTGRATION NUMRIQUE

un seul) sont prcises : ici y_0=[1,0] signie y0 (0) = 1, y1 (0) = 0, cest--dire x(0) = 1, x (0) = 0. Pour acher la solution (avec plot(f, 0, 2) on verra bien la drive nulle en t = 0) : sage: plot(f, 0, 100)

2 1.5 1 0.5 -0.5 -1 -1.5 -2 20 40 60 80 100

14.2.2

Fonctions de rsolution disponibles

Nous avons dj voqu pour les objets solveur de GSL la mthode rk8pd. Dautres mthodes sont disponibles : rkf45 : Runga-Kutta-Fehlberg, une mthode adaptative dordres 5 et 4 ; rk2 : Runge-Kutta adaptative dordres 3 et 2 ; rk4 : la mthode Runge-Kutta classique dordre 4 ; rk2imp : une mthode de Runge-Kutta implicite dordre 2 avec valuation au milieu de lintervalle ; rk4imp : une mthode de Runge-Kutta implicite dordre 4 avec valuation aux points Gaussiens 4 ; bsimp : la mthode implicite de Burlisch-Stoer ; gear1 : la mthode implicite de Gear un pas ; gear2 : la mthode implicite de Gear deux pas. Nous renvoyons le lecteur intress par les dtails de toutes ces mthodes [AP98] ou [CM84]. Il faut noter que la limitation de GSL aux ottants machine donc de prcision xe voque pour lintgration numrique reste valide pour les mthodes de rsolution dquations direntielles. Maxima dispose aussi de routines de rsolution numrique, avec sa syntaxe propre :
4. Il sagit des racines du polynme de Legendre de degr 2 dcals sur lintervalle [t, t + h], nommes en rfrence la mthode dintgration de Gauss-Legendre.

14.2. RSOLUTION DQUATIONS DIFFRENTIELLES

319

sage: t, y = var( t, y ) sage: desolve_rk4(t*y*(2-y), y, ics=[0,1], end_points=[0, 1], step=0.5) [[0, 1], [0.5, 1.12419127425], [1.0, 1.46159016229]] La fonction desolve_rk4 utilise la mthode de Runge-Kutta dordre 4 (la mme que rk4 pour GSL) et prend comme paramtres : le membre droit de lquation y (t) = f (t, y (t)), ici y = ty (2 y ) ; le nom de la variable fonction inconnue, ici y ; les conditions initiales ics, ici t = 0 et y = 1 ; lintervalle de rsolution end_points, ici [0, 1] ; le pas step, ici 0.5. Nous ne dveloppons pas la commande similaire desolve_system_rk4, dj voque au chapitre 4 et qui sapplique un systme dquations direntielles. Maxima se limite aussi la prcision machine. Si lon recherche des solutions calcules en prcision arbitrairement grande, il est possible de se tourner vers odefun du module mpmath : sage: import mpmath sage: mpmath.mp.prec = 53 sage: sol = mpmath.odefun(lambda t, y: y, 0, 1) sage: sol(1) mpf( 2.7182818284590451 ) sage: mpmath.mp.prec = 100 sage: sol(1) mpf( 2.7182818284590452353602874802307 ) sage: N(exp(1), 100) 2.7182818284590452353602874714 Les arguments de la fonction mpmath.odefun sont : les membres droits du systme dquations, sous la forme dune fonction (t, y ) f (t, y (t)), ici y = y , comme pour la fonction ode_solver. La dimension du systme est dduite automatiquement de la dimension de la valeur de retour de la fonction ; les conditions initiales t0 et y (t0 ), ici y (0) = 1. Par exemple pour ce systme de dimension 2 y1 y2 = = y2 y1

dont les solutions sont (cos(t), sin(t)), avec comme conditions initiales y1 (0) = 1 et y2 (0) = 0 : sage: sage: sage: [mpf( sage: mpmath.mp.prec = 53 f = mpmath.odefun(lambda t, y: [-y[1], y[0]], 0, [1, 0]) f(3) -0.98999249660044542 ), mpf( 0.14112000805986721 )] (cos(3.), sin(3.))

320

CHAP. 14. INTGRATION NUMRIQUE

(-0.989992496600445, 0.141120008059867) La fonction mpmath.odefun utilise la mthode de Taylor. Pour un degr p on utilise : y (tn+1 ) = y (tn ) + h dy hp dp y h2 d2 y (tn ) + . . . + (tn ) + O(hp+1 ). (tn ) + 2 dt 2! dt p! dtp

La principale question est celle du calcul des drives de y . Pour ce faire, odefun calcule des valeurs approches [y (tn + h), . . . , y (tn + ph)] [y (tn + h), . . . , y (tn + ph)] par p pas de la mthode peu prcise dEuler. On calcule ensuite dy y (tn + h) y (tn ) (tn ) , dt h puis
y dy (tn + h) d d2 y dt (tn ) (tn ) dt , 2 dt h et ainsi de suite jusqu obtenir des estimations des drives de y en tn jusqu lordre p. Il faut tre vigilant lorsque lon change la prcision de calcul ottant de mpmath. Pour illustrer ce problme, reprenons la rsolution de lquation direntielle y = y vrie par la fonction exp donne plus haut :

dy y (tn + 2h) y (tn + h) (tn + h) dt h

sage: mpmath.mp.prec = 10 sage: sol = mpmath.odefun(lambda t, y: y, 0, 1) sage: sol(1) mpf( 2.7148 ) sage: mpmath.mp.prec = 100 sage: sol(1) mpf( 2.7135204235459511323824699502438 ) Lapproximation de exp(1) est trs mauvaise, et pourtant elle est calcule avec 100 bits de prcision ! La fonction solution sol (un interpolant dans le jargon mpmath) a t calcule avec seulement 10 bits de prcision et ses coecients ne sont pas recalculs en cas de changement de prcision, ce qui explique le rsultat.

Quatrime partie

Combinatoire

Dnombrement et combinatoire

15

Ce chapitre aborde principalement le traitement avec Sage des problmes combinatoires suivants : le dnombrement (combien y a-t-il dlments dans un ensemble S ?), lnumration (calculer tous les lments de S , ou itrer parmi eux), le tirage alatoire (choisir au hasard un lment de S selon une loi, par exemple uniforme). Ces questions interviennent naturellement dans les calculs de probabilits (quelle est la probabilit au poker dobtenir une suite, ou un carr das ?), en physique statistique, mais aussi en calcul formel (nombre dlments dans un corps ni), ou en analyse dalgorithmes. La combinatoire couvre un domaine beaucoup plus vaste (ordres partiels, mots, thorie des reprsentations, etc.) pour lesquels nous nous contentons de donner quelques pointeurs vers les possibilits oertes par Sage ; la thorie des graphes et la programmation linaire font lobjet de chapitres spars, respectivement 16 et 17. Une caractristique de la combinatoire eective est la profusion de types dobjets et densembles que lon veut manipuler. Il serait impossible de les dcrire tous, et a fortiori de les implanter. Ce chapitre illustre donc la mthodologie sous-jacente : fournir des briques de base pour dcrire les ensembles combinatoires usuels (15.2), des outils pour les combiner et construire de nouveaux ensembles (15.3), et des algorithmes gnriques pour traiter uniformment de grandes classes de problmes (15.4). En premire lecture, ce chapitre peut tre parcouru en diagonale, en sarrtant sur les synthses de 15.1.2 et 15.3. Cest un domaine o Sage a des fonctionnalits bien plus tendues que la plupart des systmes de calcul formel et est en pleine expansion ; en revanche il reste encore trs jeune avec de multiples incohrences et limitations arbitraires. Ce chapitre a t traduit en anglais et intgr dans le manuel de rfrence de Sage. On peut y accder avec : sage: sage.combinat.tutorial?

324

CHAP. 15. DNOMBREMENT ET COMBINATOIRE

15.1
15.1.1

Premiers exemples
Jeu de poker et probabilits

Nous commenons par rsoudre un problme classique : dnombrer certaines combinaisons de cartes dans un jeu de poker, pour en dduire leur probabilit. Une carte de poker est caractrise par une couleur (cur, carreau, pique ou tre) et une valeur (2, 3, . . ., 9, 10, valet, dame, roi, ou as). Le jeu de poker est constitu de toutes les cartes possibles ; il sagit donc du produit cartsien de lensemble des couleurs et de lensemble des valeurs : Cartes = Symboles Valeurs = {(s, v ) | s Symboles et v Valeurs} . Construisons ces ensembles dans Sage : sage: Symboles = Set(["Coeur", "Carreau", "Pique", "Trefle"]) sage: Valeurs = Set([2..10] + ["Valet", "Dame", "Roi", "As"]) sage: Cartes = CartesianProduct(Valeurs, Symboles) Il y a 4 couleurs et 13 valeurs possibles donc 4 13 = 52 cartes dans le jeu de poker : sage: Symboles.cardinality() 4 sage: Valeurs.cardinality() 13 sage: Cartes.cardinality() 52 Tirons une carte au hasard : sage: Cartes.random_element() [6, Trefle ] Une petite digression technique est ici ncessaire. Les lments du produit cartsien sont renvoys sous forme de listes : sage: type(Cartes.random_element()) <type list > Une liste Python ntant pas immuable, on ne peut pas la mettre dans un ensemble (voir 3.3.7), ce qui nous poserait problme par la suite. Nous rednissons donc notre produit cartsien pour que les lments soient reprsents par des tuples : sage: Cartes = CartesianProduct(Valeurs, Symboles).map(tuple) sage: Cartes.first() ( Roi , Pique ) On peut maintenant construire un ensemble de cartes 1 : sage: Set([Cartes.random_element(), Cartes.random_element()])
1. Ce problme devrait disparatre terme : il est prvu de changer limplantation des produits cartsiens pour que leurs lments soient immuables par dfaut.

15.1. PREMIERS EXEMPLES {(2, Coeur ), (4, Pique )}

325

Revenons notre propos. On considre ici une version simplie du jeu de poker, o chaque joueur pioche directement cinq cartes, qui forment une main. Toutes les cartes sont distinctes et lordre na pas dimportance ; une main est donc un sous-ensemble de taille 5 de lensemble des cartes. Pour tirer une main au hasard, on commence par construire lensemble de toutes les mains possibles puis on en demande un lment alatoire : sage: Mains = Subsets(Cartes, 5) sage: Mains.random_element() {(2, Coeur ), (7, Trefle ), (7, Coeur ), (2, Pique ), (9, Coeur )} Le nombre total de mains est donn par le nombre de sous-ensembles de taille 5 dun ensemble de taille 52, cest--dire le coecient binomial 52 5 : sage: binomial(52, 5) 2598960 On peut aussi ne pas se proccuper de la mthode de calcul, et simplement demander sa taille lensemble des mains : sage: Mains.cardinality() 2598960 La force dune main de poker dpend de la combinaison de ses cartes. Une de ces combinaisons est la couleur ; il sagit dune main dont toutes les cartes ont le mme symbole (en principe il faut exclure les quintes ush ; ce sera lobjet dun exercice ci-dessous). Une telle main est donc caractrise par le choix dun symbole parmi les quatre possibles et le choix de cinq valeurs parmi les treize possibles. Construisons lensemble de toutes les couleurs, pour en calculer le nombre : sage: Couleurs = CartesianProduct(Subsets(Valeurs, 5), Symboles) sage: Couleurs.cardinality() 5148 La probabilit dobtenir une couleur en tirant une main au hasard est donc de : sage: Couleurs.cardinality() / Mains.cardinality() 33/16660 soit denviron deux sur mille : sage: 1000.0 * Couleurs.cardinality() / Mains.cardinality() 1.98079231692677 Faisons une petite simulation numrique. La fonction suivante teste si une main donne est une couleur : sage: def est_couleur(main): ....: return len(set(symb for (val, symb) in main)) == 1 Nous tirons maintenant 10000 mains au hasard, et comptons le nombre de couleurs obtenues (cela prend environ 10 secondes) :

326

CHAP. 15. DNOMBREMENT ET COMBINATOIRE

F F F F F F

F F F F F F

F F F F

F F F F

Figure 15.1 Les cinq arbres binaires complets quatre feuilles.

sage: sage: ....: ....: ....: sage: 10000

n = 10000; ncouleurs = 0 for i in range(n): main = Mains.random_element() if est_couleur(main): ncouleurs += 1 print n, ncouleurs 18

Exercice 48. Une main contenant quatre cartes de la mme valeur est appele un carr. Construire lensemble des carrs (indication : utiliser Arrangements pour tirer au hasard un couple de valeurs distinctes puis choisir un symbole pour la premire valeur). Calculer le nombre de carrs, en donner la liste, puis dterminer la probabilit dobtenir un carr en tirant une main au hasard. Exercice 49. Une main dont les cartes ont toutes le mme symbole et dont les valeurs se suivent est appele une quinte ush et non une couleur. Compter le nombre de quintes ush, puis en dduire la probabilit correcte dobtenir une couleur en tirant une main au hasard. Exercice 50. Calculer la probabilit de chacune des combinaisons de cartes au poker (voir http://fr.wikipedia.org/wiki/Main_au_poker) et comparer avec le rsultat de simulations.

15.1.2

Dnombrement darbres par sries gnratrices

Dans cette section, nous traitons lexemple des arbres binaires complets, et illustrons sur cet exemple plusieurs techniques de dnombrement o le calcul formel intervient naturellement. Ces techniques sont en fait gnrales, sappliquant chaque fois que les objets combinatoires considrs admettent une dnition rcursive (grammaire) (voir 15.4.3 pour un traitement automatis). Lobjectif nest pas de prsenter ces mthodes formellement ; aussi les calculs seront rigoureux mais la plupart des justications seront passes sous silence. Les prrequis augmentent progressivement et le lecteur ne doit pas hsiter lire certains passages en diagonale pour parvenir jusqu la synthse. Un arbre binaire complet est soit une feuille F, soit un nud sur lequel on a gre deux arbres binaires complets (voir gure 15.1).
Exercice 51. Chercher la main tous les arbres binaires complets n = 1, 2, 3, 4, 5 feuilles (voir lexercice 59 pour les chercher avec Sage).

Notre objectif est de compter le nombre cn darbres binaires complets n feuilles (dans cette section, tous les arbres sont binaires complets). Cest une situation typique o lon ne sintresse pas seulement un ensemble isol, mais une famille densembles, typiquement paramtre par n N.

15.1. PREMIERS EXEMPLES Daprs lexercice 51, les premiers termes sont donns par c1 , . . . , c5 = 1, 1, 2, 5, 14.

327

Le simple fait davoir ces quelques nombres est dj prcieux. En eet, ils permettent une recherche dans une mine dor : lencyclopdie en ligne des suites de nombres entiers http://oeis.org/ appele communment le Sloane , du nom de son auteur principal, et qui contient plus de 190000 suites dentiers 2 : sage: sloane_find([1,1,2,5,14]) Searching Sloane s online database... [[108, Catalan numbers: C(n) = binomial(2n,n)/(n+1) ... Le rsultat suggre que les arbres sont compts par lune des plus fameuses suites, les nombres de Catalan. En fouillant dans les rfrences fournies par lencyclopdie, on trouverait que cest eectivement le cas : les quelques nombres ci-dessus forment une empreinte digitale de nos objets, qui permet de retrouver en quelques secondes un rsultat prcis dans une abondante littrature. Dnombrement par sries gnratrices. Notre objectif est de retrouver ce rsultat avec laide de Sage. Soit Cn lensemble des arbres n feuilles, de sorte que cn = |Cn | ; par convention, on dnira C0 = , soit c0 = 0. Lensemble de tous les arbres est alors lunion disjointe des Cn : C=
n N

Cn .

Du fait davoir nomm lensemble C de tous les arbres, on peut traduire la dnition rcursive des arbres en une quation ensembliste : C {F} C C.

En eet, un arbre t (donc dans C ) est soit une feuille (donc dans {F}) soit un nud sur lequel on a gre deux arbres t1 et t2 et que lon peut donc identier avec le couple (t1 , t2 ) (donc dans le produit cartsien C C ). Lide fondatrice de la combinatoire algbrique, introduite par Euler dans une lettre Goldbach en 1751 pour traiter un problme similaire [Vie07], est de manipuler simultanment tous les nombres cn en les encodant sous la forme dune srie formelle, dite srie gnratrice des cn : C (z ) =
n N

cn z n ,

o z est une indtermine formelle (on na donc pas besoin de se proccuper de questions de convergence). La beaut de cette ide est que les oprations ensemblistes (A B , A B ) se traduisent naturellement en oprations algbriques
2. La commande sloane_find est en panne dans Sage 5.9 (voir http://trac.sagemath.org/ sage_trac/ticket/10358) ; mais on peut toujours consulter le site web directement.

328

CHAP. 15. DNOMBREMENT ET COMBINATOIRE

sur les sries (A(z )+ B (z ), A(z ) B (z )), de sorte que lquation ensembliste vrie par C se traduit en une quation algbrique sur C (z ) : C (z ) = z + C (z ) C (z ) . Rsolvons cette quation avec Sage. Pour cela, on introduit deux variables C et z , et on pose le systme : sage: C, z = var( C, z ); sys = [ C == z + C*C ] On a alors deux solutions, qui par chance sont sous forme close : sage: sol = solve(sys, C, solution_dict=True); sol [{C: -1/2*sqrt(-4*z + 1) + 1/2}, {C: 1/2*sqrt(-4*z + 1) + 1/2}] sage: s0 = sol[0][C]; s1 = sol[1][C] et dont les dveloppements de Taylor commencent par : sage: s0.series(z, 6) 1*z + 1*z^2 + 2*z^3 + 5*z^4 + 14*z^5 + Order(z^6) sage: s1.series(z, 6) 1 + (-1)*z + (-1)*z^2 + (-2)*z^3 + (-5)*z^4 + (-14)*z^5 + Order(z^6) La deuxime solution est clairement aberrante ; par contre, on retrouve les coecients prvus sur la premire. Posons donc : sage: C = s0 On peut maintenant calculer les termes suivants : sage: C.series(z, 11) 1*z + 1*z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + 429*z^8 + 1430*z^9 + 4862*z^10 + Order(z^11) ou calculer quasi instantanment le 100-ime coecient : sage: C.series(z, 101).coeff(z,100) 227508830794229349661819540395688853956041682601541047340 Il est cependant dommage de devoir tout recalculer si jamais on voulait le 101-ime coecient. Les sries formelles paresseuses (voir 7.5.3) prennent alors tout leur sens, dautant que lon peut les dnir directement partir du systme dquations, sans le rsoudre, et donc en particulier sans avoir besoin de forme close pour le rsultat. On commence par dnir lanneau des sries formelles paresseuses : sage: L.<z> = LazyPowerSeriesRing(QQ) Puis on cre une srie formelle libre , laquelle on donne un nom, et que lon dnit ensuite par une quation rcursive : sage: C = L() sage: C._name = C sage: C.define( z + C * C )

15.1. PREMIERS EXEMPLES sage: [C.coefficient(i) for i in range(11)] [0, 1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862]

329

On peut dsormais qurir un coecient quelconque sans avoir rednir C : sage: C.coefficient(100) 227508830794229349661819540395688853956041682601541047340 sage: C.coefficient(200) 1290131580644291140012229076696766751343495305527288824998 10851598901419013348319045534580850847735528275750122188940 Relation de rcurrence et forme close. Nous revenons maintenant la forme close pour C (z ) : sage: z = var( z ); C = s0; C -1/2*sqrt(-4*z + 1) + 1/2 Le n-ime coecient du dveloppement de Taylor de C (z ) tant donn par 1 (n) (0), regardons les drives successives C (n) (z ) : n! C sage: derivative(C, z, 1) 1/sqrt(-4*z + 1) sage: derivative(C, z, 2) 2/(-4*z + 1)^(3/2) sage: derivative(C, z, 3) 12/(-4*z + 1)^(5/2) Cela suggre lexistence dune formule explicite simple que lon recherche maintenant. La petite fonction suivante renvoie dn = n! cn : sage: def d(n): return derivative(C, n).subs(z=0) En prenant les quotients successifs : sage: [ (d(n+1) / d(n)) for n in range(1,17) ] [2, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62] on constate que dn satisfait la relation de rcurrence dn+1 = (4n 2)dn , do lon n2 dduit que cn satisfait la relation de rcurrence cn+1 = 4n +1 cn . En simpliant, on obtient alors que cn est le (n 1)-ime nombre de Catalan : cn = Catalan(n 1) = Vrions cela : sage: def c(n): return 1/n*binomial(2*(n-1),n-1) sage: [c(k) for k in range(1, 11)] [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862] sage: [catalan_number(k-1) for k in range(1, 11)] [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862] 1 2(n 1) . n n1

330

CHAP. 15. DNOMBREMENT ET COMBINATOIRE

On peut maintenant calculer les coecients beaucoup plus loin ; ici on calcule c100000 qui a plus de 60000 chires : sage: %time cc = c(100000) CPU times: user 2.34 s, sys: 0.00 s, total: 2.34 s Wall time: 2.34 s sage: ZZ(cc).ndigits() 60198 Traitement systmatique par quations algbrico-direntielles. Les mthodes que nous avons utilises se gnralisent tous les objets dnis rcursivement : le systme dquations ensembliste se traduit en un systme dquations sur la srie gnratrice ; celui-ci permet de calculer rcursivement ses coecients. Lorsque les quations ensemblistes sont susamment simples (par exemple ne font intervenir que des produits cartsiens et unions disjointes), on obtient une quation algbrique en C (z ). Celle-ci nadmet gnralement pas une solution en forme close ; cependant, on peut en dduire par connement une quation direntielle linaire sur C (z ), qui elle-mme se traduit en une quation de rcurrence de longueur xe sur les coecients cn (la srie est alors dite D-nie ). Au nal, aprs le prcalcul de cette quation de rcurrence, le calcul des coecients devient trs rapide. Toutes ces tapes sont purement algorithmiques, et il est prvu de porter vers Sage les implantations existantes dans Maple (paquets gfun et combstruct) ou MuPAD-Combinat (bibliothque decomposableObjects). Pour linstant, nous nous contentons dillustrer cette procdure gnrale dans le cas des arbres binaires complets. La srie gnratrice C (z ) est solution dune quation algbrique P (z, C (z )) = 0, o P (x, y ) = y 2 y + x est un polynme coecients dans Q. Drivons formellement cette quation algbrique par rapport z: sage: x, y, z = var( x, y, z ) sage: P = function( P , x, y); C = function( C , z) sage: equation = P(x=z, y=C) == 0 sage: diff(equation, z) D[0](C)(z)*D[1](P)(z, C(z)) + D[0](P)(z, C(z)) == 0 ou, de manire plus lisible, dC (z ) P P (z, C (z )) + (z, C (z )) = 0 dz y x Do lon tire :
P dC (z ) x = P (z, C (z )) . dz y

Dans le cas des arbres binaires complets, cela donne : sage: P = y^2 - y + x; Px = diff(P, x); Py = diff(P, y) sage: - Px / Py -1/(2*y - 1)

15.1. PREMIERS EXEMPLES

331

Or, P (x, y ) = 0. On peut donc calculer cette fraction modulo P , et ainsi exprimer la drive de C (z ) comme un polynme en C (z ) coecients dans Q(z ). Pour cela, on construit lanneau quotient R = Q(x)[y ]/(P ) : sage: Qx = QQ[ x ].fraction_field(); Qxy = Qx[ y ] sage: R = Qxy.quo(P); R Univariate Quotient Polynomial Ring in ybar over Fraction Field of Univariate Polynomial Ring in x over Rational Field with modulus y^2 - y + x Note : ybar est le nom de la variable y dans le quotient ; pour plus dinformations sur les anneaux quotients, voir 7.2.2. Reprenons maintenant le calcul de cette fraction dans R : sage: fraction = - R(Px) / R(Py); fraction (1/2/(x - 1/4))*ybar - 1/4/(x - 1/4) Remontons le rsultat dans Q(x)[y ], puis substituons z et C (z ) pour obtenir d lexpression de dz C (z ) : sage: fraction = fraction.lift(); fraction (1/2/(x - 1/4))*y - 1/4/(x - 1/4) sage: fraction(x=z, y=C) 2*C(z)/(4*z - 1) - 1/(4*z - 1) o, plus lisiblement, C (z ) 1 2 = C (z ) . z 1 4z 1 4z Dans ce cas simple, on peut en tirer directement une quation direntielle linaire coecients dans Q[z ] : sage: equadiff = diff(C,z) == fraction(x=z, y=C); equadiff D[0](C)(z) == 2*C(z)/(4*z - 1) - 1/(4*z - 1) sage: equadiff = equadiff.simplify_rational() sage: equadiff = equadiff * equadiff.rhs().denominator() sage: equadiff = equadiff - equadiff.rhs() sage: equadiff (4*z - 1)*D[0](C)(z) - 2*C(z) + 1 == 0 ou, plus lisiblement, (1 4z ) C (z ) + 2 C (z ) 1 = 0 . z

On peut la vrier trivialement ici sur la forme close : sage: Cf = sage.symbolic.function_factory.function( C ) sage: bool(equadiff.substitute_function(Cf, s0)) True

332

CHAP. 15. DNOMBREMENT ET COMBINATOIRE

Dans le cas gnral, on doit poursuivre le calcul des drives successives de C (z ). Mais celles-ci sont connes dans lanneau quotient Q(z )[C ]/(P ) qui est de dimension nie degy P sur Q(z ). On nit donc ncessairement par trouver une relation linaire entre les degy P premires drives de C (z ). En rduisant au mme dnominateur, on obtient une quation direntielle linaire coecients dans Q[z ] dordre degy P . En extrayant le coecient de z n dans lquation direntielle, on obtient lquation de rcurrence dsire sur les coecients ; on retrouve ici celle que nous avions obtenue partir de la forme close : cn+1 = 4n 2 cn . n+1

En insrant les bonnes conditions initiales, on peut alors calculer les coecients de C (z ) rcursivement : sage: def C(n): return n if n <= 1 else (4*n-6)/n * C(n-1) sage: [ C(i) for i in range(10) ] [0, 1, 1, 2, 5, 14, 42, 132, 429, 1430] Lorsque n devient trop grand pour calculer cn explicitement, on peut rechercher un quivalent asymptotique de la suite des coecients cn . L encore, les techniques sont gnriques. Loutil central est lanalyse complexe, avec ltude du comportement de la srie gnratrice aux alentours de ses singularits. Ici la n1 singularit est z0 = 1/4 et on obtiendrait cn n4 3/2 . Synthse. On retrouve ici un phnomne gnral du calcul formel : la meilleure structure de donne pour dcrire un objet mathmatique compliqu (un nombre rel, une suite, une srie formelle, une fonction, un ensemble) est souvent une quation (ou un systme dquations, typiquement avec des conditions initiales) qui le dnit. Chercher rsoudre cette quation par une forme close na pas forcment dintrt : dune part une telle forme existe rarement (cf. problme de rsolution par radicaux), et dautre part lquation en elle-mme contient toute linformation ncessaire pour calculer algorithmiquement les proprits de lobjet considr (une approximation numrique, les premiers termes ou lments, un quivalent asymptotique), ou calculer avec lobjet lui-mme (cf. arithmtique sur les sries). Au lieu de cela, on recherche la meilleure quation dcrivant lobjet pour rsoudre le problme pos ; voir aussi 2.2.2. Ainsi que nous lavons vu dans cet exemple, le connement (par exemple dans un espace de dimension nie) est un outil fondamental pour rechercher de telles quations. Ce connement sappuie gnralement sur des techniques dlimination (algbre linaire, bases de Grbner et gnralisations algbrico-direntielles). Le mme outil est central dans les algorithmes de sommation symbolique ou de vrication automatique didentits (algorithmes de Gosper, de Zeilberger et leurs gnralisations [PWZ96] ; voir aussi les exemples en 2.3.1 et exercice 54). Toutes ces techniques et leurs multiples gnralisations sont au cur de thmes trs actifs de recherche : la combinatoire automatique et la combinatoire analytique, avec des applications majeures pour lanalyse dalgorithmes [FS09]. Il est probable et souhaitable quelles soient progressivement implantes dans Sage.

15.2. ENSEMBLES NUMRS USUELS

333

15.2
15.2.1

Ensembles numrs usuels


Exemple : les sous-ensembles dun ensemble

Fixons un ensemble E de taille n et considrons les sous-ensembles de E de taille k . On sait que ces sous-ensembles sont compts par les coecients binomiaux n k . On peut donc calculer le nombre de sous-ensembles de taille k = 2 de E = {1, 2, 3, 4} avec la fonction binomial : sage: binomial(4, 2) 6 Alternativement, on peut construire lensemble P2 (E ) des sous-ensembles de taille 2 de E , puis lui demander sa cardinalit : sage: S = Subsets([1,2,3,4], 2); S.cardinality() 6 Une fois S construit, on peut aussi obtenir la liste de ses lments, tirer un lment au hasard, ou demander un lment typique : sage: S.list() [{1, 2}, {1, 3}, {1, 4}, {2, 3}, {2, 4}, {3, 4}] sage: S.random_element() {1, 4} sage: S.an_element() {2, 3} Plus prcisment, lobjet S modlise lensemble P2 (E ), muni dune numration xe (donne ici par lordre lexicographique). On peut donc demander son 5-ime lment, en prenant garde au fait que, comme pour les listes Python, le premier lment est de rang 0 ( titre de raccourci, on peut utiliser ici la notation S[.]) : sage: S.unrank(4) {2, 4} sage: S[4] {2, 4} mais cela est utiliser avec prudence car certains ensembles sont munis dune indexation naturelle dirente. Rciproquement, on peut calculer le rang dun objet dans cette numration : sage: s = S([2,4]); S.rank(s) 4 noter que S nest pas la liste de ses lments. On peut par exemple modliser 24 lensemble P (P (P (E ))) et calculer sa cardinalit (22 ) : sage: E = Set([1,2,3,4]) sage: S = Subsets(Subsets(Subsets(E))); S.cardinality() 2003529930406846464979072351560255750447825475569751419265016...736 soit environ 2 1019728 :

334

CHAP. 15. DNOMBREMENT ET COMBINATOIRE

sage: S.cardinality().ndigits() 19729 ou demander son 237 102 124-ime lment : sage: S.unrank(237102123) {{{2}, {3}, {1, 2, 3, 4}, {1, 2}, {1, 4}, {}, {2, 3, 4}, {1, 2, 4}, {3, 4}, {4}, {2, 3}, {1, 2, 3}}, {{2}, {3}, {1, 2, 3, 4}, {1, 2}, {1, 4}, {2, 3, 4}, {3, 4}, {1, 3, 4}, {1}, {1, 3}, {1, 2, 3}}} Il serait physiquement impossible de construire explicitement tous les lments de S car il y en a bien plus que de particules dans lunivers (estimes 1082 ). Remarque : il serait naturel avec Python dutiliser len(S) pour demander la cardinalit de S. Cela nest pas possible car Python impose que le rsultat de len soit un entier de type int ; cela pourrait causer des dbordements et ne permettrait pas de renvoyer Infinity pour les ensembles innis. sage: len(S) Traceback (most recent call last): ... AttributeError: __len__ has been removed; use .cardinality() instead

15.2.2

Partitions dentiers

Nous considrons maintenant un autre problme classique : tant donn un entier positif n, de combien de faons peut-on lcrire sous la forme dune somme n = i1 + i2 + + i , o i1 , . . . , i sont des entiers strictement positifs ? Il y a deux cas distinguer : lordre des lments dans la somme na pas dimportance, auquel cas (i1 , . . . , i ) est une partition de n ; lordre des lments dans la somme revt une importance, auquel cas (i1 , . . . , i ) est une composition de n. Regardons pour commencer les partitions de n = 5 ; comme prcdemment, on commence par construire lensemble de ces partitions : sage: P5 = Partitions(5); P5 Partitions of the integer 5 puis on demande sa cardinalit : sage: P5.cardinality() 7 Regardons ces 7 partitions ; lordre nayant pas dimportance, les entres sont tries, par convention, par ordre dcroissant : sage: P5.list() [[5], [4, 1], [3, 2], [3, 1, 1], [2, 2, 1], [2, 1, 1, 1], [1, 1, 1, 1, 1]]

15.2. ENSEMBLES NUMRS USUELS

335

Le calcul du nombre de partitions utilise la formule de Rademacher 3 , implante en C et fortement optimise, ce qui lui confre une grande rapidit : sage: Partitions(100000).cardinality() 2749351056977569651267751632098635268817342931598005475820312598430214 7328114964173055050741660736621590157844774296248940493063070200461792 7644930335101160793424571901557189435097253124661084520063695589344642 4871682878983218234500926285383140459702130713067451062441922731123899 9702284408609370935531629697851569569892196108480158600569421098519 Les partitions dentiers sont des objets combinatoires naturellement munis de multiples oprations. Elles sont donc renvoyes sous la forme dobjets plus riches que de simples listes : sage: P7 = Partitions(7); p = P7.unrank(5); p [4, 2, 1] sage: type(p) <class sage.combinat.partition.Partitions_n_with_category.element_class > On peut les reprsenter graphiquement par un diagramme de Ferrers : sage: print p.ferrers_diagram() **** ** * Nous laissons lutilisateur explorer par introspection les oprations oertes. On peut aussi construire une partition directement comme suit : sage: Partition([4,2,1]) [4, 2, 1] sage: P7([4,2,1]) [4, 2, 1] Si lon souhaite restreindre les valeurs possibles pour les parts i1 , . . . , i de la partition, comme par exemple dans les problmes de rendu de monnaie, on peut utiliser WeightedIntegerVectors. Par exemple, le calcul suivant : sage: WeightedIntegerVectors(8, [2,3,5]).list() [[0, 1, 1], [1, 2, 0], [4, 0, 0]] indique que pour former 8 dollars partir de billets de 2$, 3$ et 5$, on peut utiliser un billet de 3$ et un de 5$, ou un billet de 2$ et deux de 3$, ou quatre billets de 2$. Les compositions dentiers se manipulent de la mme faon : sage: C5 = Compositions(5); C5 Compositions of 5
3. Voir http://fr.wikipedia.org/wiki/Partition_d%27un_entier

336

CHAP. 15. DNOMBREMENT ET COMBINATOIRE

sage: C5.cardinality() 16 sage: C5.list() [[1, 1, 1, 1, 1], [1, 1, 1, 2], [1, 1, 2, 1], [1, 1, 3], [1, 2, 1, 1], [1, 2, 2], [1, 3, 1], [1, 4], [2, 1, 1, 1], [2, 1, 2], [2, 2, 1], [2, 3], [3, 1, 1], [3, 2], [4, 1], [5]] Le 16 ci-dessus ne parat pas anodin et suggre lexistence dune ventuelle formule. Regardons donc le nombre de compositions pour n variant de 0 9 : sage: [ Compositions(n).cardinality() for n in range(10) ] [1, 1, 2, 4, 8, 16, 32, 64, 128, 256] De mme, si lon compte le nombre de compositions de 5 par longueur, on retrouve une ligne du triangle de Pascal : sage: x = var( x ); sum( x^len(c) for c in C5 ) x^5 + 4*x^4 + 6*x^3 + 4*x^2 + x Lexemple ci-dessus utilise une fonctionnalit que lon navait pas encore croise : C5 tant itrable, on peut lutiliser comme une liste dans une boucle for ou une comprhension (15.2.4).
Exercice 52. Dmontrer les formules suggres par les exemples ci-dessus pour le nombre de compositions de n et le nombre de compositions de n de longueur k et chercher par introspection si Sage utilise ces formules pour le calcul de cardinalit.

15.2.3

Quelques autres ensembles nis numrs

Au nal, le principe est le mme pour tous les ensembles nis sur lesquels on veut faire de la combinatoire avec Sage ; on commence par construire un objet qui modlise cet ensemble puis on utilise les mthodes idoines qui suivent une interface uniforme 4 . Nous donnons maintenant quelques autres exemples typiques. Les intervalles dentiers : sage: C = IntegerRange(3, 21, 2); C {3, 5, .., 19} sage: C.cardinality() 9 sage: C.list() [3, 5, 7, 9, 11, 13, 15, 17, 19] Les permutations : sage: C = Permutations(4); C Standard permutations of 4 sage: C.cardinality() 24 sage: C.list()
4. Ou en tout cas cela devrait tre le cas ; il reste de nombreux coins nettoyer.

15.2. ENSEMBLES NUMRS USUELS [[1, [1, [2, [3, [3, [4, 2, 4, 3, 1, 4, 2, 3, 2, 1, 2, 1, 1, 4], 3], 4], 4], 2], 3], [1, [1, [2, [3, [3, [4, 2, 4, 3, 1, 4, 2, 4, 3, 4, 4, 2, 3, 3], 2], 1], 2], 1], 1], [1, [2, [2, [3, [4, [4, 3, 1, 4, 2, 1, 3, 2, 3, 1, 1, 2, 1, 4], 4], 3], 4], 3], 2], [1, [2, [2, [3, [4, [4, 3, 1, 4, 2, 1, 3, 4, 4, 3, 4, 3, 2, 2], 3], 1], 1], 2], 1]]

337

0
Figure 15.2 Un ordre partiel sur 8 sommets.

Les partitions ensemblistes : sage: C = SetPartitions([1,2,3]); C Set partitions of {1, 2, 3} sage: C.cardinality() 5 sage: C.list() [{{1, 2, 3}}, {{1}, {2, 3}}, {{1, 3}, {2}}, {{1, 2}, {3}}, {{1}, {2}, {3}}] Les ordres partiels sur 8 sommets, un isomorphisme prs : sage: C = Posets(8); C Posets containing 8 vertices sage: C.cardinality() 16999 Reprsentons graphiquement lun de ces ordres (voir gure 15.2) : sage: C.unrank(20).plot()

338

CHAP. 15. DNOMBREMENT ET COMBINATOIRE

Figure 15.3 Les graphes simples 5 sommets avec 4 artes ou moins.

Il est aussi possible ditrer parmi tous les graphes un isomorphisme prs. Il y a par exemple 34 graphes simples 5 sommets : sage: len(list(graphs(5))) 34 Voici comment obtenir ceux ayant au plus 4 artes (gure 15.3) : sage: show(graphs(5, lambda G: G.size() <= 4)) Cependant lensemble C de ces graphes nest pas encore modlis dans Sage ; de ce fait, les commandes suivantes ne sont pas encore implantes : sage: C = Graphs(5); C.cardinality() 34 sage: Graphs(19).cardinality() 24637809253125004524383007491432768 sage: Graphs(19).random_element() Graph on 19 vertices Ce que lon a vu sapplique aussi, en principe, aux structures algbriques nies comme le groupe dihdral : sage: G = DihedralGroup(4); G

15.2. ENSEMBLES NUMRS USUELS Dihedral group of order 8 as a permutation group sage: G.cardinality() 8 sage: G.list() [(), (2,4), (1,2)(3,4), (1,2,3,4), (1,3), (1,3)(2,4), (1,4,3,2), (1,4)(2,3)] ou lalgbre des matrices 2 2 sur le corps ni Z/2Z : sage: C = MatrixSpace(GF(2), 2); C.list() [ [0 0] [1 0] [0 1] [0 0] [0 0] [1 1] [1 0] [1 0] [0 1] [0 0], [0 0], [0 0], [1 0], [0 1], [0 0], [1 0], [0 1], [1 0], [0 1] [0 0] [1 1] [1 1] [1 0] [0 1] [1 1] [0 1], [1 1], [1 0], [0 1], [1 1], [1 1], [1 1] ] Cependant ceci devrait renvoyer 16, mais nest pas encore implant : sage: C.cardinality() Traceback (most recent call last): ... AttributeError: MatrixSpace object has no attribute cardinality

339

Exercice 53. numrer tous les monmes de degr 5 dans les polynmes en trois variables (voir IntegerVectors). Manipuler les partitions ensemblistes ordonnes (OrderedSetPartitions) et les tableaux standard (StandardTableaux). Exercice 54. numrer les matrices signe alternant (AlternatingSignMatrices) de taille 3, 4 et 5, et essayer de deviner leur dnition. La dcouverte et la dmonstration de la formule de dnombrement de ces matrices (voir la mthode cardinality), motive par des calculs de dterminants en physique, a t lobjet de toute une pope. En particulier la premire dmonstration, donne par Zeilberger en 1992, a t produite automatiquement par un programme, occupe 84 pages, et a ncessit lintervention de presque cent vricateurs [Zei96]. Exercice 55. Calculer la main le nombre de vecteurs dans (Z/2Z)5 puis le nombre de matrices dans GL3 (Z/2Z) (cest--dire le nombre de matrices 3 3 coecients dans Z/2Z et inversibles). Vrier votre rponse avec Sage. Gnraliser GLn (Z/q Z).

15.2.4

Comprhensions et itrateurs

Nous allons maintenant montrer quelques possibilits oertes par Python pour construire (et itrer sur) des ensembles avec une notation exible et proche des mathmatiques, et le prot que lon peut en tirer en combinatoire. Commenons par construire lensemble ni {i2 | i {1, 3, 7}} : sage: [ i^2 for i in [1, 3, 7] ] [1, 9, 49] puis le mme ensemble avec i variant cette fois entre 1 et 9 :

340

CHAP. 15. DNOMBREMENT ET COMBINATOIRE

sage: [ i^2 for i in range(1,10) ] [1, 4, 9, 16, 25, 36, 49, 64, 81] On appelle comprhension une telle construction Python. On peut ajouter un prdicat pour ne garder que les lments avec i premier : sage: [ i^2 for i in range(1,10) if is_prime(i) ] [4, 9, 25, 49] En combinant plusieurs comprhensions, on peut construire lensemble des couples (i, j ) avec 1 j < i < 5 : sage: [ (i,j) for i in range(1,6) for j in range(1,i) ] [(2, 1), (3, 1), (3, 2), (4, 1), (4, 2), (4, 3), (5, 1), (5, 2), (5, 3), (5, 4)] ou bien acher le triangle de Pascal : sage: [[binomial(n, i) for i in range(n+1)] for n in range(10)] [[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1], [1, 6, 15, 20, 15, 6, 1], [1, 7, 21, 35, 35, 21, 7, 1], [1, 8, 28, 56, 70, 56, 28, 8, 1], [1, 9, 36, 84, 126, 126, 84, 36, 9, 1]] Lexcution dune comprhension se fait en deux tapes ; tout dabord un itrateur est construit, puis une liste est remplie avec les lments renvoys successivement par litrateur. Techniquement, un itrateur est un objet avec une mthode next qui renvoie chaque appel une nouvelle valeur, jusqu puisement. Par exemple, litrateur it suivant : sage: it = (binomial(3, i) for i in range(4)) renvoie successivement les coecients binomiaux sage: 1 sage: 3 sage: 3 sage: 1 it.next() it.next() it.next() it.next()
3 i

avec i = 0, 1, 2, 3 :

Lorsque litrateur est nalement puis, une exception est leve : sage: it.next()

15.2. ENSEMBLES NUMRS USUELS Traceback (most recent call last): ... StopIteration

341

Plus gnralement, un itrable est un object Python L (une liste, un ensemble...) sur les lments duquel on peut itrer ; techniquement, on construit litrateur avec iter(L). Dans la pratique, on nutilise que trs rarement iter ou next, les boucles for et les comprhensions fournissant une syntaxe bien plus agrable : sage: for s in Subsets(3): s {} {1} {2} {3} {1, 2} {1, 3} {2, 3} {1, 2, 3} sage: [ s.cardinality() for s in Subsets(3) ] [0, 1, 1, 1, 2, 2, 2, 3] Quel est lintrt dun itrateur ? Considrons lexemple suivant : sage: sum( [ binomial(8, i) for i in range(9) ] ) 256 lexcution, une liste avec 9 lments est construite, puis elle est passe en argument sum pour les ajouter. Si au contraire on passe directement litrateur sum (noter labsence de crochets) : sage: sum( binomial(8, i) for i in xrange(9) ) 256 la fonction sum reoit directement litrateur, et peut ainsi court-circuiter la construction de la liste intermdiaire. Lorsquil y a un grand nombre dlments, cela vite donc dallouer une grosse quantit de mmoire pour stocker une liste qui sera immdiatement dtruite 5 . La plupart des fonctions prenant une liste dlments en entre acceptent un itrateur (ou un itrable) la place. Et pour commencer, on peut obtenir la liste (ou le tuple) des lments dun itrateur avec : sage: list(binomial(8, i) for i in xrange(9)) [1, 8, 28, 56, 70, 56, 28, 8, 1] sage: tuple(binomial(8, i) for i in xrange(9)) (1, 8, 28, 56, 70, 56, 28, 8, 1)
5. Dtail technique : xrange renvoie un itrateur sur {0,...,8} alors que range en renvoie la liste. partir de Python 3.0, range se comportera comme xrange, et on pourra oublier ce dernier.

342

CHAP. 15. DNOMBREMENT ET COMBINATOIRE

Considrons maintenant les fonctions all et any (qui dnotent respectivement le et et le ou n-aire) : sage: True sage: False sage: False sage: True all([True, True, True, True]) all([True, False, True, True]) any([False, False, False, False]) any([False, False, True, False])

Lexemple suivant vrie que tous les entiers premiers entre 3 et 99 sont impairs : sage: all( is_odd(p) for p in xrange(3,100) if is_prime(p) ) True Les nombres de Mersenne Mp sont les nombres de la forme 2p 1. Ici nous vrions, pour p < 1000, que si Mp est premier alors p est premier aussi : sage: def mersenne(p): return 2^p - 1 sage: [ is_prime(p) for p in range(1000) if is_prime(mersenne(p)) ] [True, True, True, True, True, True, True, True, True, True, True, True, True, True] La rciproque est-elle vraie ?
Exercice 56. Essayer les deux commandes suivantes et expliquer la dirence considrable de temps de calcul : sage: all( [ is_prime(mersenne(p)) for p in range(1000) if is_prime(p)] ) False sage: all( is_prime(mersenne(p)) for p in range(1000) if is_prime(p) ) False

On cherche maintenant trouver le plus petit contre-exemple. Pour cela on utilise la fonction Sage exists : sage: exists( (p for p in range(1000) if is_prime(p)), ....: lambda p: not is_prime(mersenne(p)) ) (True, 11) Alternativement, on peut construire un itrateur sur tous les contre-exemples : sage: contre_exemples = (p for p in range(1000) \ ....: if is_prime(p) and not is_prime(mersenne(p))) sage: contre_exemples.next() 11 sage: contre_exemples.next() 23
Exercice 57. Que font les commandes suivantes ? sage: cubes = [t**3 for t in range(-999,1000)]

15.2. ENSEMBLES NUMRS USUELS


sage: exists([(x,y) for x in cubes for y in cubes], lambda (x,y): x+y == 218) sage: exists(((x,y) for x in cubes for y in cubes), lambda (x,y): x+y == 218)

343

Laquelle des deux dernires est-elle la plus conome en temps ? En mmoire ? De combien ? Exercice 58. Essayer tour tour les commandes suivantes, et expliquer leurs rsultats. Attention : il sera ncessaire dinterrompre lexcution de certaines de ces commandes en cours de route. sage: x = var( x ); sum( x^len(s) for s in Subsets(8) ) sage: sum( x^p.length() for p in Permutations(3) ) sage: factor(sum( x^p.length() for p in Permutations(3) )) sage: P = Permutations(5) sage: all( p in P for p in P ) sage: for p in GL(2, 2): print p; print sage: for p in Partitions(3): print p sage: for p in Partitions(): print p sage: for p in Primes(): print p sage: exists( Primes(), lambda p: not is_prime(mersenne(p)) ) sage: contre_exemples = (p for p in Primes() if not is_prime(mersenne(p))) sage: for p in contre_exemples: print p

Oprations sur les itrateurs. Python fournit de nombreux utilitaires pour manipuler des itrateurs ; la plupart dentre eux font partie de la bibliothque itertools que lon peut importer avec : sage: import itertools Nous en montrons quelques applications, en prenant comme point de dpart lensemble des permutations de 3 : sage: list(Permutations(3)) [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]] Nous pouvons numrer les lments dun ensemble en les numrotant, sage: list(enumerate(Permutations(3))) [(0, [1, 2, 3]), (1, [1, 3, 2]), (2, [2, 1, 3]), (3, [2, 3, 1]), (4, [3, 1, 2]), (5, [3, 2, 1])] slectionner les lments en position 2, 3 et 4 (analogue de l[1:4]), sage: list(itertools.islice(Permutations(3), 1, 4)) [[1, 3, 2], [2, 1, 3], [2, 3, 1]]

344

CHAP. 15. DNOMBREMENT ET COMBINATOIRE

appliquer une fonction sur tous les lments, sage: list(itertools.imap(lambda z: z.cycle_type(), Permutations(3))) [[1, 1, 1], [2, 1], [2, 1], [3], [3], [2, 1]] ou slectionner les lments vriant un certain prdicat : sage: list(itertools.ifilter(lambda z: z.has_pattern([1,2]), ....: Permutations(3))) [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2]] Dans toutes ces situations, attrcall peut tre une alternative avantageuse la cration dune fonction anonyme : sage: list(itertools.imap(attrcall("cycle_type"), Permutations(3))) [[1, 1, 1], [2, 1], [2, 1], [3], [3], [2, 1]] Implantation de nouveaux itrateurs. Il est possible de construire trs facilement de nouveaux itrateurs, en utilisant le mot clef yield dj vu en 12.2.2 plutt que return dans une fonction : sage: def f(n): ....: for i in range(n): ....: yield i la suite du yield, lexcution nest pas arrte, mais seulement suspendue, et prte reprendre au mme point. Le rsultat de la fonction est alors un itrateur sur les valeurs successives renvoyes par yield : sage: sage: 0 sage: 1 sage: 2 sage: 3 g = f(4) g.next() g.next() g.next() g.next()

sage: g.next() Traceback (most recent call last): ... StopIteration En utilisation courante, cela donnera : sage: [ x for x in f(5) ] [0, 1, 2, 3, 4] Ce paradigme de programmation, appel continuation, est trs utile en combinatoire, surtout quand on le combine avec la rcursivit. Voici comment engendrer tous les mots de longueur sur un alphabet donn :

15.2. ENSEMBLES NUMRS USUELS sage: def words(alphabet,l): ....: if l == 0: yield [] ....: else: ....: for word in words(alphabet, l-1): ....: for l in alphabet: yield word + [l] sage: [ w for w in words([ a , b ], 3) ] [[ a , a , a ], [ a , a , b ], [ a , b , a ], [ a , b , b ], [ b , a , a ], [ b , a , b ], [ b , b , a ], [ b , b , b ]] On peut les compter avec : sage: sum(1 for w in words([ a , b , c , d ], 10)) 1048576

345

Compter les mots un par un nest videmment pas une mthode ecace dans ce cas, puisque lon pourrait utiliser la formule n ; au moins cela ne consomme quasiment aucune mmoire. On considre maintenant les mots de Dyck, cest--dire les mots bien parenthss en les lettres ( et ) . La fonction ci-dessous engendre tous les mots de Dyck dune longueur donne (o la longueur est le nombre de paires de parenthses), en utilisant la dnition rcursive disant quun mot de Dyck est soit vide, soit de la forme (w1 )w2 avec w1 et w2 des mots de Dyck : sage: def dyck_words(l): ....: if l == 0: yield ....: else: ....: for k in range(l): ....: for w1 in dyck_words(k): ....: for w2 in dyck_words(l-k-1): ....: yield ( + w1 + ) + w2 Voici tous les mots de Dyck de longueur 4 : sage: list(dyck_words(4)) [ ()()()() , ()()(()) , ()(())() , ()(()()) , ()((())) , (())()() , (())(()) , (()())() , ((()))() , (()()()) , (()(())) , ((())()) , ((()())) , (((()))) ] On retrouve, en les comptant, une suite bien connue : sage: [ sum(1 for w in dyck_words(l)) for l in range(10) ] [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862]
Exercice 59. Construire un itrateur sur lensemble Cn des arbres binaires complets n feuilles (voir 15.1.2). Indication : Sage 5.9 na pas encore de structure de donne native pour reprsenter des arbres binaires complets. Une manire simple de reprsenter des arbres est de dnir une variable formelle Leaf pour les feuilles et une fonction formelle Node darit 2 : sage: Leaf = var( Leaf ); Node = function( Node , nargs=2) Le deuxime arbre de la gure 15.1 peut alors tre reprsent par lexpression : sage: tree = Node(Node(Leaf, Node(Leaf, Leaf)), Leaf)

346

CHAP. 15. DNOMBREMENT ET COMBINATOIRE

15.3

Constructions

Nous allons voir maintenant comment construire de nouveaux ensembles partir de briques de base. En fait, nous avons dj commenc le faire lors de la construction de P (P (P ({1, 2, 3, 4}))) dans la section prcdente, ou pour construire des ensembles de cartes en 15.1. Considrons un produit cartsien un peu consquent : sage: C = CartesianProduct(Compositions(8), Permutations(20)); C Cartesian product of Compositions of 8, Standard permutations of 20 sage: C.cardinality() 311411457046609920000 Il ne serait videmment pas envisageable de construire la liste de tous les lments de ce produit cartsien. Pour linstant, la construction CartesianProduct ignore les proprits algbriques de ses arguments. Cela est partiellement corrig en Sage 5.9, avec la construction cartesian_product. terme, les deux constructions seront fusionnes et, dans lexemple suivant, H sera la fois muni des oprations combinatoires usuelles, mais aussi de sa structure de groupe produit : sage: G = DihedralGroup(4) sage: H = cartesian_product([G,G]) Nous construisons maintenant lunion disjointe de deux ensembles : sage: C = DisjointUnionEnumeratedSets([Compositions(4),Permutations(3)]) sage: C Disjoint union of Family (Compositions of 4, Standard permutations of 3) sage: C.cardinality() 14 sage: C.list() [[1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1], [4], [1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]] On peut faire une union disjointe de plus de deux ensembles, voire mme dune innit dentre eux. Nous allons construire lensemble de toutes les permutations, vu comme lunion de tous les ensembles Pn des permutations de taille n. On commence par construire la famille innie F = (Pn )nN : sage: F = Family(NonNegativeIntegers(), Permutations); F Lazy family (Permutations(i))_{i in Non negative integers} sage: F.keys() Non negative integers sage: F[1000] Standard permutations of 1000 On peut maintenant construire lunion disjointe
n N

Pn :

sage: U = DisjointUnionEnumeratedSets(F); U Disjoint union of Lazy family (Permutations(i))_{i in Non negative integers}

15.4. ALGORITHMES GNRIQUES Cest un ensemble inni : sage: U.cardinality() +Infinity

347

ce qui nempche pas ditrer travers ses lments, quoiquil faille bien entendu interrompre le calcul un moment donn : sage: for p in U: p [] [1] [1, 2] [2, 1] [1, 2, 3] [1, 3, 2] [2, 1, 3] [2, 3, 1] [3, 1, 2] ... Note : on aurait pu construire lensemble ci-dessus directement avec : sage: U = Permutations(); U Standard permutations Synthse. En rsum, Sage fournit une bibliothque densembles numrs usuels, qui peuvent tre combins entre eux par les constructions usuelles, ce qui donne une bote outils exible, quoique encore loin dtre aboutie. Il est de plus possible dajouter en quelques lignes de nouvelles briques dans Sage (voir le code de FiniteEnumeratedSets().example). Cela est rendu possible par luniformit des interfaces et le fait que Sage soit bas sur un langage orient objet. Dautre part, on peut manipuler des ensembles trs grands, voire innis, grce aux stratgies dvaluation paresseuse (itrateurs, etc.). Il ny a rien de magique : en arrire-boutique, Sage se contente dappliquer les rgles usuelles de calcul (par exemple, la cardinalit de E E vaut |E |2 ) ; la valeur ajoute provient de la possibilit de manipuler des constructions compliques. La situation est rapprocher de lanalyse o, pour driver une formule, Sage se contente dappliquer les rgles usuelles de drivation des fonctions usuelles et de leur composition, et o la valeur ajoute vient de la possibilit de manipuler des formules compliques. En ce sens, Sage implante un calculus sur les ensembles dnombrables.

15.4
15.4.1

Algorithmes gnriques
Gnration lexicographique de listes dentiers

Parmi les ensembles numrs classiques, en particulier en combinatoire algbrique, un certain nombre sont composs de listes dentiers de somme xe comme par exemple les partitions, les compositions ou les vecteurs dentiers. Ces

348

CHAP. 15. DNOMBREMENT ET COMBINATOIRE

ensembles peuvent de plus avoir des contraintes supplmentaires. Voici quelques exemples. Tout dabord, les vecteurs dentiers de somme 10 et de longueur 3, dont les parts sont entre 2 et 5, et respectivement bornes infrieurement par 2, 4 et 2 : sage: IntegerVectors(10, 3, min_part = 2, max_part = 5, ....: inner = [2, 4, 2]).list() [[4, 4, 2], [3, 5, 2], [3, 4, 3], [2, 5, 3], [2, 4, 4]] Les compositions de 5 dont chaque part est au plus 3, et dont la longueur est entre 2 et 3 inclus : sage: Compositions(5, max_part = 3, ....: min_length = 2, max_length = 3).list() [[3, 2], [3, 1, 1], [2, 3], [2, 2, 1], [2, 1, 2], [1, 3, 1], [1, 2, 2], [1, 1, 3]] Les partitions de 5 strictement dcroissantes : sage: Partitions(5, max_slope = -1).list() [[5], [4, 1], [3, 2]] Ces ensembles partagent la mme algorithmique sous-jacente, implante dans la classe plus gnrale et un peu plus lourde dutilisation IntegerListsLex. Cette dernire permet de modliser des ensembles de vecteurs ( 0 , . . . , k ) dentiers non ngatifs, avec des contraintes de somme, de longueur et de bornes sur les parts et sur les dirences entre parts conscutives. Voici quelques exemples : sage: IntegerListsLex(10, length=3, min_part = 2, max_part = 5, ....: floor = [2, 4, 2]).list() [[4, 4, 2], [3, 5, 2], [3, 4, 3], [2, 5, 3], [2, 4, 4]] sage: IntegerListsLex(5, min_part = 1, max_part = 3, ....: min_length = 2, max_length = 3).list() [[3, 2], [3, 1, 1], [2, 3], [2, 2, 1], [2, 1, 2], [1, 3, 1], [1, 2, 2], [1, 1, 3]] sage: IntegerListsLex(5, min_part = 1, max_slope = -1).list() [[5], [4, 1], [3, 2]] sage: list(Compositions(5, max_length=2)) [[5], [4, 1], [3, 2], [2, 3], [1, 4]] sage: list(IntegerListsLex(5, max_length=2, min_part=1)) [[5], [4, 1], [3, 2], [2, 3], [1, 4]] Lintrt du modle de IntegerListsLex provient du bon compromis entre gnralit et ecacit de litration. Lalgorithme principal permet en eet ditrer travers les lments dun ensemble S dans lordre lexicographique inverse, et en complexit constante amortie (CAT), sauf cas dgnr ; en gros, le temps ncessaire pour parcourir tous les lments est proportionnel au nombre de ces

15.4. ALGORITHMES GNRIQUES


()

349

(5)

(4)

(3)

(2)

(1)

(4, 1)

(3, 1)

(3, 2)

(2, 2)

(2, 1)

(1, 1)

(3, 1, 1)

(2, 2, 1)

(2, 1, 1)

(1, 1, 1)

(2, 1, 1, 1)

(1, 1, 1, 1)

(1, 1, 1, 1, 1)

Figure 15.4 Larbre prxe des partitions de 5.

lments, ce qui est optimal. De plus, la mmoire utilise est proportionnelle au plus gros lment rencontr, cest--dire ngligeable en pratique. Cet algorithme repose sur un principe trs gnral de parcours darbre de dcision (ou branch and bound ) : au plus haut niveau, on parcourt tous les choix possibles pour la premire part 0 du vecteur ; pour chaque choix pour 0 , on parcourt rcursivement tous les choix pour 1 , et ainsi de suite. Mathmatiquement parlant, on a mis une structure darbre prxe sur les lments de S : un nud de larbre la profondeur k correspond un prxe 0 , . . . , k dun (ou plusieurs) lments de S (voir gure 15.4). Le problme usuel dans ce type dapproche est dviter les mauvaises dcisions amenant sortir de larbre prxe et lexploration de branches mortes, ce dautant que la croissance du nombre dlments avec la profondeur est exponentielle. Il se trouve que les contraintes voques ci-dessus sont susamment simples pour garantir la proprit suivante : tant donn un prxe 0 , . . . , k de S , lensemble des k+1 tels que 0 , . . . , k+1 est un prxe de S est soit vide, soit un intervalle de la forme [a, b], et les bornes a et b peuvent tre calcules en temps linaire en la longueur du plus long lment de S ayant 0 , . . . , k comme prxe. noter : cet algorithme a t originellement dvelopp et implant dans MuPAD-Combinat et port lidentique sous Sage ; cette implantation nest pas robuste en cas dentres subtilement incohrentes, ce qui peut donner des rsultats surprenants. Par exemple, lexemple suivant devrait donner lensemble des partitions de 9 croissantes et strictement dcroissantes, ce que [5, 5] ne vrie clairement pas : sage: Partitions(9, max_slope=-1, min_slope=0).list() [[9], [5, 5]]

15.4.2

Points entiers dans les polytopes

Si lalgorithme ditration de IntegerListsLex est ecace, son algorithme de comptage est naf : il se contente ditrer travers tous les lments. Il y a une approche alternative pour traiter ce problme : modliser les listes dentiers dsires comme lensemble des points entiers dun polytope, cest-dire lensemble des solutions coordonnes entires dun systme dinquations

350

CHAP. 15. DNOMBREMENT ET COMBINATOIRE

linaires. Cest un cadre trs gnral pour lequel il existe des algorithmes de comptage avancs (par exemple celui de Barvinok), qui sont implants dans des bibliothques comme LattE. Litration ne pose en principe pas de grosse dicult. Il y a cependant deux limitations qui justient lexistence de IntegerListsLex. La premire est dordre thorique : les points dentiers dun polytope ne permettent de modliser que des problmes en dimension (longueur) xe ; la deuxime dordre pratique : lheure actuelle seule la bibliothque PALP a une interface avec Sage ; si elle ore de multiples fonctionnalits sur ltude des polytopes, pour ce qui nous intresse ici elle ne permet que de construire la liste des points entiers, sans fournir ditrateur ni de comptage non naf : sage: A = random_matrix(ZZ,3,6,x=7) sage: L = LatticePolytope(A) sage: L.points() [1 6 6 2 5 5 6 5 4 5 4 5 4 2 5 3 4 5 3 4 5 3 3] [4 4 2 6 4 1 3 2 3 3 4 4 3 4 3 4 4 4 4 4 4 5 5] [3 1 1 6 5 1 1 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 5] sage: L.npoints() 23 Ce polytope peut tre visualis en 3D avec L.plot3d() (voir gure 15.5).

Figure 15.5 Le polytope L et ses points entiers, en vision strographique yeux croiss.

15.4.3

Espces, classes combinatoires dcomposables

En 15.1.2, nous avons montr comment utiliser la dnition rcursive des arbres binaires complets pour les dnombrer ecacement au moyen de sries gnratrices. Les techniques exposes sont trs gnrales, et sappliquent ds quun ensemble peut tre dni rcursivement (selon les communauts, un tel ensemble est appel classe combinatoire dcomposable ou espce combinatoire). Cela inclut

15.4. ALGORITHMES GNRIQUES

351

toutes les varits darbres, mais aussi les permutations, les compositions, les graphes fonctionnels, etc. Nous nous contentons ici dillustrer quelques exemples dutilisation de la bibliothque de Sage sur les espces combinatoires : sage: from sage.combinat.species.library import * sage: o = var( o ) Nous commenons par rednir les arbres binaires complets ; pour cela, on stipule lquation de rcurrence directement sur les ensembles : sage: BT = CombinatorialSpecies() sage: Leaf = SingletonSpecies() sage: BT.define( Leaf + (BT*BT) ) On peut maintenant construire lensemble des arbres cinq nuds, les numrer, les compter, etc : sage: BT5 = BT.isotypes([o]*5); BT5.cardinality() 14 sage: BT5.list() [o*(o*(o*(o*o))), o*(o*((o*o)*o)), o*((o*o)*(o*o)), o*((o*(o*o))*o), o*(((o*o)*o)*o), (o*o)*(o*(o*o)), (o*o)*((o*o)*o), (o*(o*o))*(o*o), ((o*o)*o)*(o*o), (o*(o*(o*o)))*o, (o*((o*o)*o))*o, ((o*o)*(o*o))*o, ((o*(o*o))*o)*o, (((o*o)*o)*o)*o] Les arbres sont construits en utilisant une structure de donne rcursive gnrique ; lachage ne peut donc tre fameux ; pour faire mieux, il faudrait fournir Sage une structure de donne plus spcialise, avec lachage dsir. On retrouve la srie gnratrice des nombres de Catalan : sage: g = BT.isotype_generating_series(); g x + x^2 + 2*x^3 + 5*x^4 + 14*x^5 + O(x^6) qui est renvoye sous forme dune srie paresseuse : sage: g[100] 227508830794229349661819540395688853956041682601541047340 Nous nissons avec les mots de Fibonacci, qui sont les mots binaires sans deux 1 conscutifs (voir 3.2.3). Ils admettent une dnition rcursive naturelle : sage: sage: sage: sage: Eps = EmptySetSpecies(); Z0 = SingletonSpecies() Z1 = Eps*SingletonSpecies() FW = CombinatorialSpecies() FW.define(Eps + Z0*FW + Z1*Eps + Z1*Z0*FW)

On reconnat la fameuse suite de Fibonacci, do le nom : sage: L = FW.isotype_generating_series().coefficients(15); L [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987] sage: sloane_find(L)

352

CHAP. 15. DNOMBREMENT ET COMBINATOIRE

Searching Sloane s online database... [[45, Fibonacci numbers: F(n) = F(n-1) + F(n-2), F(0) = 0, F(1) = 1, F(2) = 1, ... , [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, ... ce qui est une consquence directe de lquation de rcurrence. L encore, on peut aussi gnrer immdiatement tous les mots de Fibonacci dune longueur donne, avec les mmes limitations de lachage gnrique : sage: FW3 = FW.isotypes([o]*3) sage: FW3.list() [o*(o*(o*{})), o*(o*(({}*o)*{})), o*((({}*o)*o)*{}), (({}*o)*o)*(o*{}), (({}*o)*o)*(({}*o)*{})] En remplaant o par 0, {}*o par 1, en oubliant les parenthses et le dernier {}, on lit respectivement 000, 001, 010, 100 et 101.

15.4.4

Graphes un isomorphisme prs

Nous avons vu en 15.2.3 que Sage pouvait engendrer les graphes et les ordres partiels un isomorphisme prs. Nous allons maintenant dcrire lalgorithme sous-jacent, qui est le mme dans les deux cas, et couvre une gamme nettement plus large de problmes. Commenons par quelques rappels : un graphe G = (V, E ) est la donne dun ensemble V de sommets et dun ensemble E dartes reliant ces sommets, une arte tant dcrite par une paire {u, v } de deux sommets distincts de V . Un tel graphe est dit tiquet ; ses sommets sont typiquement numrots par V = {1, 2, 3, 4, 5}. Dans beaucoup de problmes, les tiquettes sur les sommets ne jouent aucun rle. Typiquement un chimiste voudra rechercher toutes les molcules possibles ayant une composition donne, mettons un alcane avec n = 8 atomes de carbone et 2n + 2 = 18 atomes dhydrogne ; il recherche alors tous les graphes avec 8 sommets ayant chacun 4 voisins, et 18 sommets ayant un unique voisin. En dehors de cela, tous les atomes de carbone sont identiques, et de mme pour les atomes dhydrogne. Le problme de notre chimiste nest pas anecdotique ; ce type dapplication est en fait lorigine dune part importante des recherches en thorie des graphes sur les problmes disomorphisme. Lorsque lon travaille la main sur un petit graphe on peut, comme dans lexemple de 15.2.3, en faire un dessin, eacer les tiquettes et oublier linformation gomtrique sur la disposition des sommets dans le plan. En revanche, pour reprsenter un graphe dans un programme, on ne peut faire lconomie dintroduire des tiquettes sur les sommets pour pouvoir dcrire comment sont connectes les artes. Pour compenser cela, on dit que deux graphes tiquets sont isomorphes sil existe une bijection des sommets du premier vers les sommets du second qui envoie les artes du premier sur les artes du second ; un graphe non tiquet est alors une classe dquivalence de graphes tiquets. En gnral, tester si deux graphes tiquets sont isomorphes est trs coteux. Cependant, le nombre de graphes, mme non tiquets, crot trs rapidement ; du

15.4. ALGORITHMES GNRIQUES

353

coup il reste possible dnumrer les graphes non tiquets trs ecacement en regard de leur nombre. Ainsi, le programme Nauty est capable dnumrer les 12 005 168 graphes simples 10 sommets en 20 secondes. Comme en 15.4.1, le principe gnral de lalgorithme est dorganiser les objets numrer selon un arbre que lon parcourt. Pour cela, dans chaque classe dquivalence de graphes tiquets (cest--dire pour chaque graphe non tiquet) on choisit convenablement un reprsentant canonique. Les oprations fondamentales sont alors les suivantes : 1. vrier si un graphe tiquet est canonique ; 2. calculer le reprsentant canonique dun graphe tiquet. Ces oprations, invitables, restent coteuses ; on cherche donc en minimiser le nombre dappels. Les reprsentants canoniques sont de plus choisis de telle manire que, pour chaque graphe tiquet canonique G, il existe un choix canonique dune arte dont la suppression redonne un graphe canonique, nomm le pre de G. Cette proprit permet dorganiser les reprsentants canoniques des graphes sur un ensemble V de sommets le long dun arbre : la racine, le graphe avec zro arte ; en dessous son unique ls, le graphe avec une arte ; puis les graphes avec deux artes, et ainsi de suite (voir gure 15.6). Lensemble des ls dun graphe G peut tre construit par augmentation en ajoutant une arte de toutes les faons possibles G, et en slectionnant parmi les graphes obtenus ceux qui sont encore canoniques 6 . Rcursivement, on obtient alors tous les graphes canoniques. En quoi cet algorithme est-il gnrique ? Considrons par exemple les graphes planaires (graphes que lon peut dessiner dans le plan sans croisement dartes) : en supprimant une arte dun graphe planaire, on obtient de nouveau un graphe planaire ; ainsi les graphes planaires forment un sous-arbre de larbre prcdent. Pour les engendrer, on peut rutiliser exactement le mme algorithme ; il sut de ne garder, au fur et mesure, que les ls qui sont planaires : sage: [len(list(graphs(n, property = lambda G: G.is_planar()))) ....: for n in range(7)] [1, 1, 2, 4, 11, 33, 142] De manire similaire, on peut engendrer toute famille de graphes close par suppression darte, et en particulier celles dnies par sous-graphes interdits. Cela inclus par exemple les arbres et forts (graphes sans cycle) ; les graphes bipartis (graphes sans cycle impair). Comme application indirecte, on peut citer la gnration : des ordres partiels, via la bijection avec leurs diagrammes de Hasse, ces derniers tant les graphes orients sans cycles et sans artes de transitivit (arte a z entre deux sommets relis par un chemin a b z de longueur deux ou plus)
6. Dans la pratique, une implantation ecace se doit dexploiter les symtries de G, cest-dire son groupe dautomorphismes, pour rduire le nombre de ls potentiels, et pour rduire le cot de chaque test de canonicit.

354

CHAP. 15. DNOMBREMENT ET COMBINATOIRE


1 2 3 0

1 2 3 0

1 2 3 0 2

1 0 3

1 2 3 0 2

1 0 3 2

1 0 3

1 2 3 0 2

1 0 3

1 2 3 0

1 2 3 0

Figure 15.6 Larbre de gnration des graphes simples 4 sommets.

des treillis (non implant dans Sage), via la bijection avec les demi-treillis infrieurs obtenus par suppression du sommet maximal ; il faut de plus utiliser une augmentation par sommets plutt que par artes.

Thorie des graphes


Ce chapitre prsente ltude de la thorie des graphes avec Sage, en dcrivant tout dabord la classe Graph (16.1) ainsi que ses mthodes (16.2), puis en les utilisant pour rsoudre des problmes pratiques (16.4) ou vrier exprimentalement des rsultats thoriques (16.3).

16

16.1
16.1.1

Construire un graphe
partir de zro

Ici les graphes sont dnis comme une paire (V, E ), o V reprsente un ensemble de sommets (vertices en anglais) et E un ensemble dartes (edges), cest-dire de paires non ordonnes de sommets. Le graphe reprsent en gure 16.1 est dni sur lensemble de sommets {0, 1, 2, 5, 9, Madrid, Edimbourg} et a pour artes (1, 2), (1, 5), (1, 9), (2, 5), (2, 9) ainsi que (Madrid, Edimbourg). Les graphes sont sans aucune surprise reprsents dans Sage par la classe Graph : sage: g = Graph() Par dfaut, g est un graphe vide. Lexemple suivant illustre comment lui ajouter sommets et artes : lorsquune arte est cre, les sommets correspondants sils ne sont pas dj prsents dans le graphe sont silencieusement ajouts. Nous contrlons le droulement de la procdure avec des mthodes dont les rles sont faciles deviner : sage: g.order(), g.size() (0, 0) sage: g.add_vertex(0)

356

CHAP. 16. THORIE DES GRAPHES

sage: g.order(), g.size() (1, 0) sage: g.add_vertices([1, 2, 5, 9]) sage: g.order(), g.size() (5, 0) sage: g.add_edges([(1,5), (9,2), (2,5), (1,9)]) sage: g.order(), g.size() (5, 4) sage: g.add_edge("Madrid", "Edimbourg") sage: g.order(), g.size() (7, 5) Ajouter larte (1,2) est quivalent ajouter larte (2,1). On notera de plus que les mthodes add_vertex et add_edge ont toutes les deux un pluriel (add_vertices et add_edges) qui prend une liste en argument et permet une criture plus compacte (voir par exemple 16.4.1, o lon construit un graphe aprs avoir gnr lensemble de ses artes). En gnral, Sage nest pas regardant quant au type des objets quil est possible dutiliser comme sommets dun graphe. Il acceptera en fait tout objet Python immuable (et donc pas, au moment de la version 5.9 de Sage, des objets de la classe Graph eux-mmes), cest--dire tout ce quun dictionnaire pourrait accepter comme nom de clef (cf. 3.3.9). Il est bien entendu possible de supprimer ensuite les lments ajouts laide des mthodes delete_* et dnumrer les sommets ou les artes, sur lesquels nous itrerons souvent. sage: g.delete_vertex(0) sage: g.delete_edges([(1,5), (2,5)]) sage: g.order(), g.size() (6, 3) sage: g.vertices() [1, 2, 5, 9, Edimbourg , Madrid ] sage: g.edges() [(1, 9, None), (2, 9, None), ( Edimbourg , Madrid , None)] Les artes dun graphe sont en ralit pour Sage des triplets, dont la dernire entre est une tiquette (ou label). Elle sert la plupart du temps stocker des valeurs numriques interprtes par exemple par les algorithmes de ot ou de connectivit comme des capacits, ou comme un poids pour le problme de couplage (matching ) et peut aussi contenir tout objet immuable. Par dfaut, ltiquette vaut None. Lorsque lon connat lavance les sommets et artes dun graphe, on peut le construire de manire compacte avec un dictionnaire associant chaque sommet la liste de ses voisins : sage: g = Graph({ ....: 0 : [], ....: 1 : [5, 9], ....: 2 : [1, 5, 9], ....: Edimbourg : [ Madrid ]})

16.1. CONSTRUIRE UN GRAPHE

357

Figure 16.1 Un graphe dont les sommets sont des entiers ou des chanes de caractres.

L encore, on peut se permettre doublier les lignes correspondant aux sommets 5, 9, ou Madrid, qui sont mentionns comme voisins dautres sommets. On peut galement se permettre de dire que 1 est un voisin de 2 alors que 2 napparat pas dans la liste des voisins de 1 : larte (1,2) sera bel et bien cre.
Exercice 60 (Graphes circulants). Le graphe circulant de paramtres n, d est un graphe n sommets numrots de 0 n 1 (que lon peut se reprsenter disposs le long dun cercle), tel que deux sommets u et v sont relis par une arte si u v + c mod n, avec d c d. crire une mthode prenant en paramtres n et d, et renvoyant le graphe associ.

16.1.2

Les constructeurs disponibles

En dpit des illustrations prcdentes, il est assez rare de saisir une table dadjacence sous Sage, ou mme dnumrer manuellement une par une ses artes pour crer un graphe. La plupart du temps, il est plus ecace de les dnir partir des lments de base dj disponibles : les mthodes de graphs.* permettent de construire plus de soixante-dix graphes ou familles de graphes, que nous prsentons maintenant. Les graphes de Chvtal et de Petersen, par exemple, sont obtenus sous Sage par les lignes suivantes : sage: P = graphs.PetersenGraph() sage: C = graphs.ChvatalGraph() Commenons cette description par les petits graphes par opposition aux familles de graphes que nous rencontrerons par la suite. Petits graphes. Ces graphes portent le plus souvent le nom de leur dcouvreur, ou dun objet auquel ils ressemblent (une maison, une sucette, un taureau). Ils apparaissent souvent comme contre-exemples certaines conjectures, ou comme plus petits graphes satisfaisant telle ou telle proprit. Le graphe de

358

CHAP. 16. THORIE DES GRAPHES


Petits graphes BullGraph DesarguesGraph FlowerSnark HexahedralGraph HouseGraph KrackhardtKiteGraph OctahedralGraph TetrahedralGraph ChvatalGraph DiamondGraph FruchtGraph HigmanSimsGraph HouseXGraph LollipopGraph PappusGraph ThomsenGraph ClawGraph DodecahedralGraph HeawoodGraph HoffmanSingletonGraph IcosahedralGraph MoebiusKantorGraph PetersenGraph

Petersen, par exemple, est non-planaire : il possde simultanment les deux mineurs interdits par le thorme de Kuratowski (K5 et K3,3 ). Cest de plus un graphe sans triangle (sa maille girth est gale 5), 3-rgulier et de nombre chromatique 3. Cest aussi un graphe sommet-transitif. Chacun de ces paramtres peut tre retrouv par Sage laide des mthodes correspondantes : sage: P = graphs.PetersenGraph() sage: P.is_planar() False sage: P.minor(graphs.CompleteBipartiteGraph(3,3)) {0: [0], 1: [2], 2: [8], 3: [1, 6], 4: [3, 4], 5: [5, 7]} sage: P.minor(graphs.CompleteGraph(5)) {0: [0, 5], 1: [1, 6], 2: [2, 7], 3: [3, 8], 4: [4, 9]} sage: P.girth() 5 sage: P.is_regular(3) True sage: P.chromatic_number() 3 sage: P.is_vertex_transitive() True sage: P.show()

16.1. CONSTRUIRE UN GRAPHE

359

Familles de graphes. Les constructeurs prsents ici dcrivent des familles de graphes, et prennent donc en argument un ou plusieurs paramtres ( une exception prs, nauty_geng, qui ne dcrit pas une famille spcique de graphes mais lensemble de tous les graphes isomorphisme prs ; voir section 15.4.4).
Familles de graphes BarbellGraph CircularLadderGraph DegreeSequenceBipartite DegreeSequenceTree FibonacciTree GeneralizedPetersenGraph GridGraph HyperStarGraph LCFGraph NKStarGraph OddGraph nauty_geng BubbleSortGraph DegreeSequence DegreeSequenceConfigurationModel DorogovtsevGoltsevMendesGraph FuzzyBallGraph Grid2dGraph HanoiTowerGraph KneserGraph LadderGraph NStarGraph ToroidalGrid2dGraph

Dans cette liste se trouve une gnralisation (en fait, deux) du graphe de Petersen : le graphe de Kneser. Ce graphe se construit partir de deux paramtres, n et k , et ses sommets sont les n k sous-ensembles de taille k de {1, . . . , n}. Deux de ces ensembles sont adjacents si et seulement si ils sont disjoints. Les sommets du graphe de Petersen correspondent aux sous-ensembles de taille k = 2 dun ensemble de taille n = 5 : sage: K = graphs.KneserGraph(5, 2); P = graphs.PetersenGraph() sage: K.is_isomorphic(P) True Par construction, les graphes de Kneser sont eux aussi sommets-transitifs. Leur nombre chromatique est exactement n 2k + 2, un rsultat surprenant de Lovsz prouv par lintermdiaire du thorme de Borsuk-Ulam et donc par des considrations de topologie [Mat03]. Vrions cela immdiatement, sur quelques exemples : sage: all( graphs.KneserGraph(n,k).chromatic_number() == n - 2*k + 2 ....: for n in range(5,9) for k in range(2,floor(n/2)) ) True
Exercice 61 (Graphes de Kneser). crire une fonction de deux paramtres n, k renvoyant le graphe de Kneser associ, si possible sans utiliser de if .

Graphes lmentaires. Les graphes suivants sont les pices fondamentales les plus courantes en thorie des graphes (graphes complets, bipartis complets, circulants, chemins, cycles, toiles, etc.). L encore, une exception noter : trees ; cette mthode permet ditrer sur lensemble des arbres n sommets. Graphes alatoires. Cette dernire classe de graphes est trs riche en proprits. On y trouve entre autres les Gn,p et Gn,m , qui sont les deux modles les plus simples de graphes alatoires.

360

CHAP. 16. THORIE DES GRAPHES


Graphes lmentaires BalancedTree CompleteGraph EmptyGraph WheelGraph&&trees CirculantGraph CubeGraph PathGraph CompleteBipartiteGraph CycleGraph StarGraph

Les graphes Gn,p sont dnis par un entier n et un rel 0 p 1. On obtient un graphe alatoire Gn,p sur n sommets {0, . . . , n 1} en lanant pour chacune des n 2 paires de sommets i, j une pice de monnaie dont la probabilit de tomber sur pile est p et en ajoutant au graphe larte correspondante lorsque pile sort. On observe que pour tout graphe H x, la probabilit que Gn,p contienne H comme sous-graphe induit 1 tend vers 1 lorsque 0 < p < 1 est x et n tend vers linni (voir 16.3.4) : sage: H = graphs.ClawGraph() sage: def test(): ....: g = graphs.RandomGNP(20,2/5) ....: return not g.subgraph_search(H, induced=True) is None sage: sum( test() for i in range(100) ) >= 80 True

16.1.3

Unions disjointes

En plus de ces briques fondamentales, Sage permet deectuer des unions disjointes de graphes laide de deux oprations simples mais ecaces. Laddition de deux graphes correspond leur union disjointe : sage: sage: sage: sage: True P = graphs.PetersenGraph() H = graphs.HoffmanSingletonGraph() U = P + H; U2 = P.disjoint_union(H) U.is_isomorphic(U2)

Le produit dun graphe G par un entier k renvoie lunion disjointe de k copies de G : sage: C = graphs.ChvatalGraph() sage: U = 3 * C; U2 = C.disjoint_union(C.disjoint_union(C)) sage: U2.is_isomorphic(U) True La ligne suivante cre lunion disjointe de trois copies du graphe de Petersen et de deux copies du graphe de Chvtal : sage: U = 3*P + 2*C
1. H est un sous-graphe induit de G sil existe un ensemble S V (G) de sommets tel que la restriction S de G (cest--dire le graphe dont les sommets sont S et les artes sont les artes de G ne touchant que des sommets de S ) est isomorphe H . On note dailleurs ce sous-graphe induit G[S ].

16.1. CONSTRUIRE UN GRAPHE


Graphes alatoires DegreeSequenceExpected RandomGNM RandomInterval RandomRegular RandomBarabasiAlbert RandomGNP RandomLobster RandomShell RandomBipartite RandomHolmeKim RandomNewmanWattsStrogatz RandomTreePowerlaw

361

Il existe quantit de faons de sassurer de ce rsultat, qui sont autant dexcuses pour crire quelques lignes de code. Par exemple, en sassurant que chaque composante connexe est isomorphe lun des deux graphes : sage: all( (CC.is_isomorphic(P) or CC.is_isomorphic(C)) ....: for CC in U.connected_components_subgraphs() ) True ou en comptant le nombre exact de sous-graphes : sage: sum( CC.is_isomorphic(P) ....: for CC in U.connected_components_subgraphs() ) 3 sage: sum( CC.is_isomorphic(C) ....: for CC in U.connected_components_subgraphs() ) 2 Dtails techniques. Il est noter que les oprations daddition et de multiplication sont en termes de cot en mmoire et en temps, des copies. Cela peut parfois tre source de lenteurs. En revanche, modier P ou C la suite de lexemple prcdent ne modiera pas U. De plus, ces oprations font perdre deux informations : les sommets du graphe nal sont renumrots en entiers {0, 1, 2, . . .} ; les positions (dans le plan) des sommets ne sont pas conserves dans U. La mthode disjoint_union a un comportement dirent : si le graphe g contient un sommet a et le graphe h un sommet b, le graphe renvoy par g.disjoint_union(h) contient les sommets (0,a) et (1,b). Dans le cas o a ou b ne sont pas des entiers mais tout autre objet (chane de caractres, tuples...) lutilisation de cette mthode simplie grandement le travail sur le graphe rsultant de lunion.

16.1.4

Achage des graphes

Un aspect trs apprciable de ltude des graphes sous Sage est la possibilit de les visualiser. Sans variantes ni oritures, il sut dune seule commande : sage: C = graphs.ChvatalGraph(); C.show()

362

CHAP. 16. THORIE DES GRAPHES

Il sagit l dun outil prcieux pour visualiser le rsultat de certaines fonctions. Ici, nous mettons en valeur un ensemble indpendant : sage: C.show(partition = [C.independent_set()])

Largument partition de la mthode show reoit, comme son nom lindique, une partition de lensemble des sommets. Une couleur est alors attribue chaque ensemble de la partition, an de les sparer visuellement. Une dernire couleur est attribue aux sommets napparaissant pas dans la partition. Dans notre exemple on a donc en tout deux couleurs. Il est bien entendu possible de spcier soi-mme les couleurs que lon souhaite attribuer aux sommets, laide dun dictionnaire et dune syntaxe plutt naturelle : sage: C.show(vertex_colors = { ....: "red" : [0, 1, 2], "blue" : [3, 4, 5], ....: "yellow" : [6, 7, 8], "purple" : [9, 10, 11]})

16.1. CONSTRUIRE UN GRAPHE

363

Les couleurs souhaites ntant pas toujours primaires ou secondaires, il est possible de les spcier par leur code hexadcimal, comme on le ferait en HTML. Des mthodes comme coloring sont justement faites pour ces situations : sage: C.coloring(hex_colors = True) { #00ffff : [3, 8, 5], #7f00ff : [11], #ff0000 : [0, 2, 7, 10], #7fff00 : [1, 4, 6, 9]} sage: C.show(vertex_colors = C.coloring(hex_colors = True))

Le comportement de largument edge_colors est identique : sage: from sage.graphs.graph_coloring import edge_coloring sage: edge_coloring(C, hex_colors = True) { #00ffff : [(0,6), (1,2), (3,9), (4,8), (5,10), (7,11)], #7f00ff : [(0,9), (1,7), (2,6), (3,4), (5,11), (8,10)], #ff0000 : [(0,1), (2,3), (4,5), (6,11), (7,8), (9,10)], #7fff00 : [(0,4), (1,5), (2,8), (3,7), (6,10), (9,11)]} sage: C.show(edge_colors = edge_coloring(C, hex_colors = True))

364

CHAP. 16. THORIE DES GRAPHES

Exporter des images. Il est aussi possible dexporter individuellement les images construites par Sage. Lexemple ci-dessous trace les graphes complets 3, 4, ..., 12 sommets, dans les chiers graph0.png, ..., graph9.png. sage: L = [graphs.CompleteGraph(i) for i in range(3,3+10)] sage: for number, G in enumerate(L): ....: G.plot().save( /tmp/ + graph + str(number) + .png ) Les options des commandes show et plot sont sans n, et fort documentes. Tout au plus mentionnera-t-on loption figsize = 15, qui prcise la rsolution de limage et se rvlera utile pour les graphes de grande taille.

16.2

Mthodes de la classe Graph

La classe Graph dispose de plus de 250 mthodes, en mettant de ct celles dnies exclusivement dans la classe DiGraph, ou celles napparaissant que dans des modules annexes. Cela fait de Sage une bibliothque expressive et complte pour la thorie des graphes, permettant de se concentrer sur lessentiel, cest--dire vitant davoir programmer longueur de temps dautres fonctions que celles qui nous intressent. Comme lors de lapprentissage de tout langage de programmation (ou bibliothque), il est utile de parcourir au moins une fois la liste de ses fonctions an de reprer ce dont il (ou elle) est capable. Cette section (non-exhaustive) tente de les prsenter succinctement. Il est conseill au lecteur de sacrier les quelques minutes ncessaires la lecture du contenu de chaque catgorie et mme de la liste complte des mthodes disponibles : le temps pass le faire se rvlera inniment rentable une fois en face dun problme de graphes ! Il est aussi conseill davoir prs de soi une session Sage ouverte an de pouvoir consulter la documentation des fonctions prsentes (par exemple g.degree_constrained_subgraph?), certaines dentre elles ayant plusieurs options, ou lorsque leur intitul nest pas assez explicite.

16.2. MTHODES DE LA CLASSE GRAPH

365

16.2.1

Modication de la structure dun graphe

Bien entendu, une grande partie de la classe Graph contient les mthodes naturelles lies la dnition et la modication des graphes, ncessaires bien que napportant pas de fonctionnalit remarquable.
Mthodes daccs et de modication de la classe Graph add_cycle add_path adjacency_matrix allows_loops delete_edge delete_vertex edge_label edges_incident has_edge has_vertex loop_edges merge_vertices neighbor_iterator num_edges order remove_multiple_edges save set_vertex subdivide_edge vertices add_edge add_vertex allow_loops allows_multiple_edges delete_edges delete_vertices edge_labels get_vertex has_loops incidence_matrix loop_vertices multiple_edges neighbors num_verts relabel rename set_edge_label set_vertices subdivide_edges weighted add_edges add_vertices allow_multiple_edges clear delete_multiedge edge_iterator edges get_vertices has_multiple_edges latex_options loops name networkx_graph number_of_loops remove_loops reset_name set_latex_options size vertex_iterator weighted_adjacency_matrix

16.2.2

Oprateurs

Dans la mme ligne de mthodes apparaissent les oprateurs, qui renvoient un objet de type Graph (ou DiGraph). Par exemple, la mthode complement applique G renvoie un graphe dni sur le mme ensemble de sommets, dans lequel larte uv existe si et seulement si uv G. La mthode subgraph permet de son ct dobtenir partir dun graphe G le sous-graphe induit par un ensemble donn de sommets (voir dnition page 360), opration souvent note G[{v1 , . . . , vk }]. 5 ) Vrions quelques relations lmentaires. Le complmentaire de P5 (not P est une maison, et les graphes P4 et C5 sont auto-complmentaires : sage: sage: True sage: True sage: True P5 = graphs.PathGraph(5); House = graphs.HouseGraph() P5.complement().is_isomorphic(House) P4 = graphs.PathGraph(4); P4.complement().is_isomorphic(P4) C5 = graphs.CycleGraph(5); C5.complement().is_isomorphic(C5)

Sage dnit aussi (par la mthode ponyme) le line graph de G souvent not L(G) dont les sommets correspondent aux artes de G, et dans lequel deux sommets sont adjacents si les artes correspondantes sont incidentes dans G. On trouve aussi la dnition de dirents produits de graphes. Dans chacun des exemples suivants, on suppose que G est le produit de G1 par G2 , dni sur

366

CHAP. 16. THORIE DES GRAPHES

lensemble de sommets V (G1 ) V (G2 ). Deux sommets (u, v ), (u , v ) G sont adjacents si et seulement si : Produit cartsien cartesian_product ou u = u et vv E (G2 ) uu E (G1 ) et v = v Produit lexicographique lexicographic_product ou uu E (G1 ) u = u et vv E (G2 )

Produit disjonctif disjunctive_product ou uu E (G1 ) vv E (G2 )

Produit tensoriel tensor_product et uu E (G1 ) vv E (G2 )

Produit fort strong_product u = u et vv E (G2 ) uu E (G1 ) et v = v ou uu E (G1 ) et vv E (G2 ) On peut construire la grille carre GridGraph comme le produit cartsien de deux chemins : sage: n = 5; Path = graphs.PathGraph(n) sage: Grid = Path.cartesian_product(Path) sage: Grid.is_isomorphic(graphs.GridGraph([n,n])) True

Produits, oprateurs, . . . cartesian_product copy kirchhoff_matrix lexicographic_product to_directed tensor_product union categorical_product disjoint_union laplacian_matrix strong_product to_simple transitive_closure complement disjunctive_product line_graph subgraph to_undirected transitive_reduction

16.2.3

Parcours de graphes et distances

Sage ore les mthodes habituelles de parcours de graphe, comme les parcours en profondeur (depth_first_search) et en largeur (breadth_first_search) qui sont les routines fondamentales des calculs de distances, de ot ou de connectivit. Il contient aussi une implmentation du moins classique lex_BFS (lexicographic breadth-rst search), utilis par exemple pour la reconnaissance des graphes cordaux (cf. is_chordal). Ces mthodes renvoient un ordonnancement des sommets

16.2. MTHODES DE LA CLASSE GRAPH correspondant leur ordre de dcouverte 2 : sage: g = graphs.RandomGNP(10, .6) sage: list(g.depth_first_search(0)) [0, 8, 5, 4, 9, 2, 3, 7, 6, 1] sage: list(g.breadth_first_search(0)) [0, 8, 5, 4, 1, 3, 6, 7, 9, 2] sage: g.lex_BFS(0) [0, 8, 5, 4, 1, 6, 7, 3, 9, 2]

367

On dnit laide de ces parcours la mthode shortest_path, qui est probablement la plus utilise de toutes 3 . Sage permet galement de calculer divers invariants lis aux distances : eccentricity : associe un sommet v du graphe la distance maximale entre v et tout autre sommet du graphe ; center : renvoie un sommet v central du graphe cest--dire dexcentricit minimale ; radius : renvoie lexcentricit dun centre ; diameter : renvoie la distance maximale entre deux sommets ; periphery : renvoie la liste des sommets dont lexcentricit est gale au diamtre.
Distances, parcours average_distance depth_first_search distance_all_pairs lex_BFS shortest_path shortest_path_lengths breadth_first_search diameter distance_graph periphery shortest_path_all_pairs shortest_paths center distance eccentricity radius shortest_path_length

16.2.4

Flots, connectivit, couplage (matching)

Sage sait rsoudre les problmes de ot maximum (cf. 17.4.3) laide de la mthode flow 4 . Grce aux parcours mentionns prcdemment, il contient aussi plusieurs mthodes lies la connectivit (is_connected, edge_connectivity, vertex_connectivity, connected_components, . . .) ainsi que les consquences du thorme de Menger : Soient G un graphe et u, v deux de ses sommets. Les assertions suivantes sont quivalentes :
2. Si lex_BFS renvoie bien une liste de sommets, les mthodes depth_first_search et breadth_first_search sont elles des itrateurs sur les sommets, do lutilisation de la mthode list. 3. Il est noter que shortest_path ne fait pas ncessairement appel breadth_first_search : lorsque les artes du graphe sont munies dune distance, des implmentations de lalgorithme de Dijkstra (standard ou bidirectionnel) prennent le relais. 4. Deux implmentations sont dailleurs disponibles : la premire suit lalgorithme de FordFulkerson, la seconde est un programme linaire.

368

CHAP. 16. THORIE DES GRAPHES la valeur du ot maximal entre u et v est k (voir flow) ; il existe k (mais pas k + 1) chemins arte-disjoints entre u et v (voir edge_disjoint_paths) ; il existe un ensemble de k artes dans G qui, une fois retires du graphe, dconnectent u de v (voir edge_cut).

Les contreparties ces mthodes portant sur la connectivit en terme de sommets sont flow (grce son option vertex_bound=True), vertex_cut et vertex_disjoint_paths. Vrions par exemple quavec (trs) forte probabilit, la connectivit dun graphe alatoire Gn,p est gale son degr minimal : sage: n = 30; p = 0.3; trials = 50 sage: def equality(G): ....: return G.edge_connectivity() == min(G.degree()) sage: sum(equality(graphs.RandomGNP(n,p)) for i in range(trials))/trials 1 On peut aussi obtenir la dcomposition dun graphe en composantes 2-connexes ou bien son arbre de Gomory-Hu, respectivement par blocks_and_cut_vertices et gomory_hu_tree. Puisque cest lune des fonctions fondamentales de la thorie des graphes, mentionnons ici la mthode matching, qui construit un couplage maximal par lalgorithme dEdmonds. Les couplages sont galement abords en 16.4.2 et 17.4.2.
Flots, connectivit, . . . blocks_and_cut_vertices connected_components connected_components_subgraphs edge_boundary edge_cut edge_disjoint_spanning_trees gomory_hu_tree matching vertex_boundary vertex_cut connected_component_containing_vertex connected_components_number degree_constrained_subgraph edge_connectivity edge_disjoint_paths flow is_connected multicommodity_flow vertex_connectivity vertex_disjoint_paths

16.2.5

Problmes NP-complets

Sage contient pour certains problmes NP-complets des algorithmes de rsolution exacte. Bien entendu, ces problmes peuvent demander selon les cas de grands temps de calcul, mais les instances relles ont souvent le bon got dtre plus faciles rsoudre que les contre-exemples thoriques. Il est par exemple possible de rsoudre les problmes doptimisation suivants.

16.2. MTHODES DE LA CLASSE GRAPH

369

Figure 16.2 Le graphe de Chvtal et un cycle hamiltonien de celui-ci.

Cliques et ensemble indpendant maximum. Une clique maximum dun graphe est un ensemble de sommets deux deux adjacents de cardinal maximum (non-adjacents dans le cas de lensemble indpendant). Une application de ce type de problme est prsente en 16.4.1. Lalgorithme utilis est celui du programme Cliquer [NO]. Mthodes : clique_maximum, independent_set Coloration de sommets, dartes. Une coloration propre des sommets dun graphe est une aectation de couleurs aux sommets telle que deux sommets adjacents possdent des couleurs direntes. Sage possde plusieurs fonctions de calcul exact pour certaines colorations, utilisant la plupart du temps la programmation linaire ou lalgorithme Dancing Links. Le lecteur trouvera en 16.3.1 lexplication dun algorithme simple, mais non optimal, de coloration. Mthodes : chromatic_number, coloring, edge_coloring 1 , grundy_coloring1 . Ensemble dominant. Un ensemble S de sommets dun graphe est dit dominant si tout sommet v de G est voisin dun lment de S on dit alors quil est domin ou sil est lui-mme membre de S . Lensemble de tous les sommets tant trivialement dominant, le problme associ consiste minimiser la taille de lensemble S . Ce problme est rsolu dans Sage laide de la programmation linaire. Mthode : dominating_set Cycle hamiltonien, voyageur de commerce. Un graphe G est dit hamiltonien sil possde un cycle passant une fois et une seule par chacun des sommets de G. Contrairement au problme de cycle eulrien le cycle doit alors passer une fois et une seule par chaque arte de G ce problme est NP-complet, et se rsout dans Sage par la programmation linaire comme un cas particulier du problme du voyageur de commerce. Nous illustrons la fonction hamiltonian_cycle, qui renvoie un cycle hamiltonien lorsquun tel cycle existe (gure 16.2) :
1. Ces mthodes ne sont pas directement accessibles par la classe Graph. Pour y accder, ainsi qu dautres fonctions de coloration, consulter le module graph_coloring.

370

CHAP. 16. THORIE DES GRAPHES

sage: g = graphs.ChvatalGraph(); cycle = g.hamiltonian_cycle() sage: g.show(vertex_labels = False); cycle.show(vertex_labels = False) Mthodes : is_hamiltonian, hamiltonian_cycle, traveling_salesman_problem Problmes divers. Sage sait aussi calculer le genre dun graphe (genus), des coupes maximales (max_cut), des arbres de Steiner (steiner_tree), etc. Il permet aussi de rsoudre des problmes existentiels comme les multiots entiers (multicommodity_flow), le test dexistence de mineurs (minor recherche dun mineur isomorphe un graphe donn) ou la recherche de sous-graphes (subgraph_search). Bien que la complexit thorique de ces problmes ne soit pas encore connue, des algorithmes sont disponibles pour rsoudre le problme disomorphisme de graphes (is_isomorphic) ainsi que pour calculer les groupes dautomorphisme dun graphe (automorphism_group).
Problmes NP-complets (ou assimils) automorphism_group chromatic_number coloring edge_coloring genus independent_set_of_representatives is_isomorphic minor multiway_cut traveling_salesman_problem vertex_cover characteristic_polynomial chromatic_polynomial disjoint_routed_paths dominating_set hamiltonian_cycle is_hamiltonian max_cut multicommodity_flow subgraph_search steiner_tree

16.2.6

Reconnaissance et test de proprits

Quantit de problmes NP-complets possdent un algorithme de rsolution ecace (linaire, quadratique...) lorsque les graphes appartiennent une classe particulire. Il est par exemple trivial de rsoudre un problme de clique maximum sur un graphe cordal, et il est polynomial (bien que compliqu) de calculer une coloration optimale des sommets dun graphe parfait. Sage possde des algorithmes de reconnaissance pour certaines classes lmentaires de graphes : forts (is_forest), arbres (is_tree), graphes bipartis (is_bipartite), graphes eulriens (is_eulerian), graphes rguliers (is_regular), etc. Il est galement possible didentier les classes suivantes. Graphes cordaux. Un graphe est dit cordal sil nadmet aucun cycle de taille suprieure quatre comme sous-graphe induit. De faon quivalente, tout graphe cordal peut tre dcompos en retirant squentiellement des sommets dont le voisinage est un graphe complet (cet ordre de dcomposition est appel ordonnancement dlimination parfaite). Ces graphes sont reconnus laide dun parcours lexicographique en largeur (lex_BFS). Mthode : is_chordal

16.2. MTHODES DE LA CLASSE GRAPH

371

Graphes dintervalle. Soit I = {I1 , . . . , In } un ensemble ni dintervalles de lensemble des rels. On dnit partir de I un graphe G sur n sommets {1, . . . , n}, les sommets i et j tant adjacents si et seulement si les intervalles Ii et Ij ont une intersection non vide. Les graphes dintervalles sont ceux que lon peut obtenir de cette faon. Ils constituent une sous-classe des graphes cordaux, reconnaissable en temps linaire grce la structure de PQ-trees. Mthode : is_interval Graphes parfaits. Un graphe G est dit parfait si pour tout sous-graphe induit G G le nombre chromatique de G est gal la taille maximum dune clique (i.e., lgalit (G ) = (G ) est vrie). Bien que la reconnaissance de ces graphes soit un problme polynomial, les algorithmes connus sont complexes et limplmentation de Sage utilise un algorithme exponentiel. Mthode : is_perfect Graphes sommets-transitifs. Un graphe G est dit sommet-transitif sil existe pour toute paire de sommets u et v un isomorphisme h : V (G) V (G) tel que h(u) = v . Bien que la complexit thorique de ce problme ne soit pas tablie, limplmentation disponible dans Sage est trs ecace. Mthode : is_vertex_transitive Produit cartsien de graphes. Seuls certains graphes sexpriment comme le produit cartsien dune suite G1 , ..., Gk de graphes. Il est dailleurs possible, tant donn un graphe G connexe, de trouver lunique faon de lcrire ainsi laide dun lgant rsultat de caractrisation, facilement traduit en un algorithme polynomial. Mthode : is_cartesian_transitive De nombreuses classes de graphes trouvent, en plus de leur caractrisation par une construction (les graphes cordaux) ou une proprit particulire (les graphes parfaits), une formulation quivalente en termes de sous-graphes exclus. Cela revient dire quun graphe G appartient une classe C si et seulement sil ne contient aucune occurrence dun graphe parmi {G1 , . . . , Gk }. On peut dans ce cas crire un algorithme de reconnaissance qui se contente de tester lexistence de chacun de ces sous-graphes, ce que permet de faire la commande subgraph_search.
Reconnaissance et tests de proprits is_bipartite is_equitable is_forest is_overfull is_subgraph is_triangle_free is_chordal is_eulerian is_interval is_regular is_transitively_reduced is_vertex_transitive is_directed is_even_hole_free is_odd_hole_free is_split is_tree

372

CHAP. 16. THORIE DES GRAPHES

16.3

Graphes en action

Il est temps de tirer parti des fonctionnalits que nous avons dcouvertes. Les exemples suivants ont pour motivation un prtexte pratique ou thorique, et ne sont en gnral pas la meilleure faon dutiliser Sage pour rsoudre les problmes quils dcrivent. Ils sont souvent brutaux et numratifs, et cest ce qui leur donne tout leur charme : leur but est bien videmment de constituer une liste agrable et facile aborder dexemples dutilisation de la bibliothque de graphes de Sage tout est ici dans la forme, pas dans le fond.

16.3.1

Coloration gloutonne des sommets dun graphe

Colorer les sommets dun graphe consiste aecter chacun dentre eux une couleur (nous considrerons ici quun nombre entier est une couleur respectable), de telle faon que chaque sommet possde une couleur dirente de celles de ses voisins. Ceci est bien entendu possible : il sut de choisir autant de couleurs quil existe de sommets dans notre graphe ; cest pour cette raison que le problme de coloration est un problme de minimisation : trouver, tant donn un graphe G, le plus petit nombre (G) de couleurs permettant de colorer ses sommets sous la contrainte annonce. Si le calcul du nombre (G) est un problme dicile adoss une impressionnante littrature, le lecteur aux vues plus pratiques sera ravi dapprendre quil existe des faons expditives dtre plus proche de loptimal quen utilisant |V | couleurs. ceux-ci nous proposons lalgorithme suivant : Coloration gloutonne des sommets dun graphe . Prenons un sommet au hasard, et donnons-lui comme couleur lentier 0. Itrativement, prenons un sommet non color et donnons-lui comme couleur le plus petit entier disponible non utilis par ses voisins. Cet algorithme ne demande que quelques lignes dexplications, et il en va de mme pour le faire comprendre Sage. Nous lappliquons ici sur un graphe alatoire : sage: n = 100; p = 5/n; g = graphs.RandomGNP(n, p) sage: # Ensemble de couleurs disponibles. sage: # Dans le pire des cas, n couleurs suffisent sage: couleurs_disponibles = Set(range(n)) sage: sage: sage: sage: ....: ....: ....: # Ce dictionnaire contient la couleur associe # chaque sommet du graphe couleur = {} for u in g: interdits = Set([couleur[v] for v in g.neighbors(u) if v in couleur]) couleur[u] = min(couleurs_disponibles - interdits)

sage: # Nombre de couleurs utilises

16.3. GRAPHES EN ACTION sage: max(couleur.values()) + 1 6

373

Cela est sensiblement plus ecace que dutiliser 100 couleurs. Il est cependant facile damliorer cet algorithme, lorsque lon remarque que la coloration dun graphe dpend dune inconnue : lordre dans lequel les sommets sont slectionns. Il est vrai que nous ne gardons avec cet algorithme aucun contrle de cet ordre, puisque nous nous contentons de les numrer par for u in g ce qui minimise surtout le temps dcriture du programme. Le chapitre 15, riche en enseignements, a abord le sujet des ensembles numrs par Sage, dont Permutations fait partie. Bien mieux que a, cette classe possde une mthode random_element dont nous pouvons nous servir : sage: P = Permutations([0,1,2,3]); P.random_element() [2, 0, 1, 3] Nous allons donc tenter dobtenir de meilleurs rsultats en colorant 30 fois les sommets de notre graphe dans lordre donn par des permutations alatoires. Le rsultat est le code suivant, que nous appliquons au graphe g dj dni : sage: couleurs_disponibles = Set(range(n)) sage: sage: sage: sage: sage: nombre_tests = 30 vertices = g.vertices() P = Permutations(range(n)) meilleure_coloration = {} meilleur_nombre_chromatique = +oo

sage: for t in range(nombre_tests): ....: # Ordre alatoire sur les sommets ....: p = P.random_element() ....: couleur = {} ....: for i in range(g.order()): ....: u = vertices[p[i]] ....: interdits = Set([couleur[v] for v in g.neighbors(u) ....: if v in couleur]) ....: couleur[u] = min(couleurs_disponibles - interdits) ....: # Mise jour de la meilleure coloration ....: if max(couleur.values()) + 1 < meilleur_nombre_chromatique: ....: meilleure_coloration = couleur ....: meilleur_nombre_chromatique = 1 + max(couleur.values()) sage: # Nombre de couleurs utilises sage: meilleur_nombre_chromatique 4 Soit un gain, tout de mme ! Toute cette artillerie de mise jour de minimum, cependant, ntait pas ncessaire. Inutile de reprogrammer ce qui lest dj. En Python, la trs grande majorit des objets et dans le cas prsent les paires

374

CHAP. 16. THORIE DES GRAPHES

entier, dictionnaire sont comparables, et ce dans lordre lexicographique (on compare dabord les premiers termes un entier puis le second un dictionnaire ce qui na pas beaucoup de signication ici). En rcrivant nos premires lignes de code pour en faire une fonction, il est possible dobtenir le rsultat suivant : sage: def coloration_gloutonne(G, permutation): ....: n = g.order() ....: couleurs_disponibles = Set(xrange(n)) ....: vertices = g.vertices() ....: couleur = {} ....: for i in range(g.order()): ....: u = vertices[permutation[i]] ....: interdits = Set([couleur[v] for v in g.neighbors(u) ....: if v in couleur]) ....: couleur[u] = min(couleurs_disponibles - interdits) ....: return max(couleur.values()) + 1, couleur Une fois cette fonction dnie, faire 50 essais et rcuprer le minimum est une trivialit : sage: P = Permutations(range(g.order())) sage: nombre_couleurs, coloration = min( ....: coloration_gloutonne(g, P.random_element()) for i in range(50)) sage: nombre_couleurs 4 Pour colorer un graphe en utilisant le nombre minimal de couleurs, il est prfrable dutiliser la mthode coloring. Ce problme tant NP-complet, il faut sattendre des temps de calcul plus longs que lors dune coloration gloutonne.
Exercice 62 (Ordre optimal pour la coloration gloutonne). Lalgorithme de coloration gloutonne est capable de colorer un graphe avec le nombre minimum de couleurs possible (i.e. (G)) sil parcourt les sommets dans le bon ordre. laide de la mthode coloring, qui calcule une coloration optimale, crire une fonction renvoyant un ordre sur les sommets partir duquel lalgorithme de coloration gloutonne construit une coloration optimale.

16.3.2

Gnrer des graphes sous contraintes

Les graphes alatoires Gn,p ont des proprits de connexit trs intressantes. En particulier, leurs coupes minimales sont presque srement le voisinage dun sommet : on y trouve donc des coupes dont lune des deux composantes connexes est un sommet unique. Ceci peut aussi paratre dplaisant : tout ensemble consquent de sommets dnit une coupe dont la cardinalit est trs grande devant la coupe minimale. Il est cependant possible, avec beaucoup de patience (pour obtenir de gros graphes) et quelques lignes de Sage, de produire des graphes alatoires un peu dirents. Voici la mthode que nous allons implmenter. Fixons deux entiers n et k , le premier reprsentant un nombre de sommets et le second une connectivit. Lalgorithme dbute avec un arbre sur n sommets,

16.3. GRAPHES EN ACTION

375

calcule une coupe minimale et ses deux ensembles correspondants. Tant que cette coupe minimale est de cardinal infrieur k < k , on ajoute au hasard k k artes entre les deux ensembles. Comme prcdemment, nous aurons besoin, tant donns deux ensembles S , de gnrer une paire dlments (s, s . Nous utiliserons pour cela la et S ) S S classe CartesianProduct et sa mthode random_element. sage: n = 20; k = 4; g = graphs.RandomGNP(n, 0.5) sage: g = g.subgraph(edges = g.min_spanning_tree()) sage: while True: ....: _, edges, [S,Sb] = g.edge_connectivity(vertices = True) ....: cardinality = len(edges) ....: if cardinality < k: ....: CP = CartesianProduct(S, Sb) ....: g.add_edges([CP.random_element() ....: for i in range(k - len(edges))]) ....: else: ....: break Tout est dit.

16.3.3

Appliquer un algorithme probabiliste pour trouver un grand ensemble indpendant

Bien que Sage possde une mthode Graph.independent_set permettant de trouver dans un graphe un ensemble indpendant (ensemble de sommets deux deux non adjacents) de taille maximale, rien ne nous interdit dutiliser des rsultats amusants de thorie des graphes pour dnicher nous-mmes un ensemble indpendant. On lit par exemple dans le livre The Probabilistic Method [AS00] quil existe dans tout graphe G un ensemble indpendant S tel que |S |
v G

1 d(v ) + 1

o d(v ) reprsente le degr de v . La preuve de ce rsultat tient dans lalgorithme suivant. Prenons au hasard une bijection n : V {1, . . . , |V |}, associant chaque sommet de G un entier unique. Associons maintenant cette fonction un ensemble indpendant Sn , dni comme tant lensemble des sommets de G ayant une image infrieure celle de tous leurs voisins (sommets minimaux). Formellement, cela scrit : Sn = {v G : u tel que uv E (G), n(v ) < n(u)}. Cet ensemble est par dnition un ensemble indpendant, mais comment sassurer de sa taille ? Il sut en fait de se demander, pour chaque sommet,

376

CHAP. 16. THORIE DES GRAPHES

avec quelle frquence celui-ci apparat dans lensemble Sn . Si nous considrons lensemble P des bijections de V vers {1, . . . , |V |}, nous remarquons que |Sn | =
n P n P v G

1 si v est minimum pour n, 0 sinon 1 si v est minimum pour n, 0 sinon


v G nP

= =
v G

|P | = |P | d(v ) + 1

v G

1 . d(v ) + 1

Par consquent, une telle fonction correspond en moyenne un ensemble indpendant de taille vG d(v1 )+1 . Pour esprer obtenir un ensemble de cette taille sous Sage, nous utiliserons donc des bijections alatoires obtenues par la classe Permutations, jusqu obtenir lensemble promis par le thorme : sage: g = graphs.RandomGNP(40, 0.4) sage: P = Permutations(range(g.order())) sage: moyenne = sum( 1/(g.degree(v)+1) for v in g ) sage: while True: ....: n = P.random_element() ....: S = [v for v in g if all( n[v] < n[u] for u in g.neighbors(v))] ....: if len(S) >= moyenne: ....: break

16.3.4

Trouver un sous-graphe induit dans un graphe alatoire

Nous allons ici nous intresser aux graphes alatoires Gn,p , rapidement dcrits dans la section 16.1.2 portant sur les constructeurs de graphes. Comme nous lavions alors mentionn, ces graphes possdent la proprit suivante. Soit H un graphe, et 0 < p < 1. Alors :
n+

lim P [H est un sous-graphe induit de Gn,p ] = 1

ce qui signie qu H et p xs, un grand graphe alatoire Gn,p ne manquera pas de contenir H comme sous-graphe induit (voir dnition page 360). Rendons cela plus clair : tant donn un graphe H et un grand graphe alatoire, il est possible de trouver une copie de H dans Gn,p , et ce en associant itrativement chaque sommet vi de V (H ) = {v1 , . . . , vk } un reprsentant h(vi ), o chaque vi est une extension correcte des sommets dj slectionns. Nous suivrons donc lalgorithme : associer v1 un sommet alatoire h(v1 ) Gn,p ; associer v2 un sommet alatoire h(v2 ) Gn,p tel que h(v1 ) est adjacent h(v2 ) dans G si et seulement si v1 est adjacent v2 dans H ;

16.3. GRAPHES EN ACTION

377

... aprs j < k tapes, nous avons associ un reprsentant h(vi ) Gn,p tous les vi (i j ), de telle faon que pour tous i, i j, h(vi )h(vi ) E (G) si et seulement vi vi E (H ). Nous associons maintenant vj +1 un sommet alatoire h(vj +1 ) tel que pour tout i j , h(vj +1 ) vrie que h(vi )h(vj +1 ) E (G) si et seulement vi vj +1 E (H ) ; ... aprs k tapes, le sous-graphe de Gn,p induit par les reprsentants des sommets v1 , . . . , vk est une copie de H . Proposition. Quand n devient grand, cette stratgie fonctionne avec haute probabilit. Dmonstration. Notons Hj = H [{v1 , . . . , vj }], et notons P [H ind Gn,p ] la probabilit que H soit un sous-graphe induit de Gn,p . Nous pouvons borner grossirement la probabilit que Hj , mais pas Hj +1 , soit un sous-graphe induit de Gn,p de la faon suivante : tant donne une copie de Hj dans un Gn,p , calculons la probabilit quaucun autre sommet ne puisse complter la copie courante en une copie de Hj +1 . La probabilit quun sommet soit acceptable tant de pdHj+1 (vj+1 ) (1 p)j dHj+1 (vj+1 ) min(p, 1 p)j ,

la probabilit quaucun des n j sommets restants ne soit acceptable est dau plus nj 1 min(p, 1 p)j . Il existe dans notre graphe au maximum j ! n j copies direntes de Hj (en n fait j faons de choisir un ensemble de j sommets, et j ! bijections entre ces sommets et ceux de Hj ). Puisque 0 < p < 1, nous crivons 0 < = min(p, 1 p) ; par consquent la probabilit que Hj , mais pas Hj +1 , soit un sous-graphe induit de Gn,p est au plus, pour tout j k x, j! n (1 j )nj j j !nj (1 j )nj = o(1/n)

qui est asymptotiquement nulle lorsque n grandit. Finalement : P [H ind Gn,p ] 1 P [H2 ind Gn,p , H3 ind Gn,p ] P [H3 ind Gn,p , H4 ind Gn,p ] ... P [Hk1 ind Gn,p , Hk ind Gn,p ] P [H ind Gn,p ] 1
j k

j !nj (1 j )nj 1 . n

1k o

378

CHAP. 16. THORIE DES GRAPHES

De plus, cette dmonstration nous donne un algorithme probabiliste permettant de trouver une copie dun graphe H dans un graphe alatoire Gn,p . Bien que cet algorithme ne trouve pas toujours une copie de H si celle-ci existe, la probabilit quil russisse tend vers 1 lorsque n tend vers linni. sage: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: def trouver_induit(H, G): # la fonction de V(H) vers V(G) que nous cherchons dfinir f = {} # ensemble de sommets de G non encore utiliss par f G_restants = G.vertices() # L ensemble des sommets pour lesquels nous n avons # pas encore trouv de reprsentant H_restants = H.vertices() # Tant que la fonction n est pas complte while H_restants: v = H_restants.pop(0) # cherchons le sommet suivant de H # et ses images potentielles candidats = [u for u in G_restants if all([H.has_edge(h,v) == G.has_edge(f_h,u) for h, f_h in f.iteritems()])] # Si nous n en trouvons pas, nous abandonnons immdiatement ! if not candidats: raise ValueError("No copy of H has been found in G") # Sinon, nous prenons le premier d entre eux f[v] = candidats[0] G_restants.remove(f[v]) return f

En une ligne. Pour trouver une copie dun graphe H dans un graphe G, il est plus ecace de faire appel la mthode Graph.subgraph_search.

16.4
16.4.1

Quelques problmes modliss par des graphes


Une nigme du journal Le Monde 2

On pouvait lire dans lexemplaire 609 du Monde 2 lnigme suivante. Quelle est la taille du plus grand ensemble S [0, ..., 100] qui ne contient pas deux entiers i, j S tels que |i j | est un carr ? Ce problme est facilement modlisable dans le formalisme de la thorie des graphes. La relation |i j | est un carr ? tant binaire et symtrique, nous commencerons par crer le graphe sur lensemble de sommets [0, . . . , 100] dans lequel deux sommets sont adjacents (incompatibles) si leur dirence est un carr. Nous utiliserons pour cela la classe Subsets qui nous permet dans le cas prsent ditrer sur les sous-ensembles de taille 2.

16.4. QUELQUES PROBLMES MODLISS PAR DES GRAPHES sage: n = 100; V = range(n+1) sage: G = Graph() sage: G.add_edges([ ....: (i,j) for i,j in Subsets(V,2) if is_square(abs(i-j)) ])

379

Puisque nous sommes la recherche dun ensemble maximum dlments compatibles , nous pouvons faire appel la mthode independent_set, qui renvoie un sous-ensemble maximum dlments deux deux non-adjacents. sage: G.independent_set() [4, 6, 9, 11, 16, 21, 23, 26, 28, 33, 38, 43, 50, 56, 61, 71, 76, 78, 83, 88, 93, 95, 98, 100] La rponse est donc 24, et pas 42 . Par consquent, lnigme du Monde 2 ntait pas La grande question sur la vie, lunivers et le reste , quil faudra rechercher ailleurs.

16.4.2

Aectation de tches

Nous sommes maintenant dans la situation suivante : en face dun important chantier, dix personnes doivent eectuer un total de dix tches. On peut associer chaque personne une sous-liste de tches qui rentrent dans ses comptences. Comment distribuer les tches an que tout soit fait dans les rgles de lart ? L encore, nous commencerons par modliser le problme par un graphe : il sera biparti, dni sur lunion {w0 , . . . , w9 } {t0 , . . . , t9 } des personnes et des tches, et nous dnirons ti comme adjacent wj si wj est capable deectuer ti . sage: tasks = {0: [2, 5, 3, 7], 1: ....: 2: [5, 0, 4], 3: ....: 4: [8], 5: ....: 6: [8, 9, 7], 7: ....: 8: [2, 5, 3, 6, 4], 9: sage: G = Graph() sage: for i in tasks: ....: G.add_edges(("w" + str(i), [0, 1, 4], [0, 1], [2], [5, 8, 7], [2, 5, 8, 6, 1]}

"t" + str(j)) for j in tasks[i])

Il ne nous reste plus maintenant qu utiliser la mthode matching, qui nous renverra un ensemble maximum de tches qui peuvent tre eectues simultanment par des personnes comptentes : sage: for task, worker,_ in sorted(G.matching()): ....: print task, "peut tre effectue par", worker t0 peut tre effectue par w2 t1 peut tre effectue par w3 t2 peut tre effectue par w5 t3 peut tre effectue par w8 t4 peut tre effectue par w1 t5 peut tre effectue par w7 t6 peut tre effectue par w9 t7 peut tre effectue par w0

380 t8 peut tre effectue par w4 t9 peut tre effectue par w6

CHAP. 16. THORIE DES GRAPHES

16.4.3

Planier un tournoi

tant donn un nombre n dquipes participant un tournoi, lors duquel toutes les paires dquipes doivent se rencontrer, comment peut-on planier les matches de la faon la plus rapide possible, sachant que plusieurs matches peuvent avoir lieu simultanment ? Ce problme est un cas typique dapplication de la coloration propre dartes en thorie des graphes. Ce problme consiste, tant donn un graphe G, assigner une couleur chaque arte an quaucun sommet ne touche deux artes de mme couleur. De manire quivalente, ce problme revient trouver une partition des artes en couplages (union dartes disjointes) de cardinal minimum. Dans le cas prsent, nous chercherons colorer les artes du graphe complet chacune dentre elles reprsentant le match devant avoir lieu entre les quipes correspondant ses deux extrmits : sage: n = 10 sage: G = graphs.CompleteGraph(n) sage: from sage.graphs.graph_coloring import edge_coloring sage: for jour,matches in enumerate(edge_coloring(G)): ....: print "Matches du jour", jour, ":", matches Matches du jour 0 : [(0, 9), (1, 8), (2, 7), (3, 6), (4, 5)] Matches du jour 1 : [(0, 2), (1, 9), (3, 8), (4, 7), (5, 6)] Matches du jour 2 : [(0, 4), (1, 3), (2, 9), (5, 8), (6, 7)] Matches du jour 3 : [(0, 6), (1, 5), (2, 4), (3, 9), (7, 8)] Matches du jour 4 : [(0, 8), (1, 7), (2, 6), (3, 5), (4, 9)] Matches du jour 5 : [(0, 1), (2, 8), (3, 7), (4, 6), (5, 9)] Matches du jour 6 : [(0, 3), (1, 2), (4, 8), (5, 7), (6, 9)] Matches du jour 7 : [(0, 5), (1, 4), (2, 3), (6, 8), (7, 9)] Matches du jour 8 : [(0, 7), (1, 6), (2, 5), (3, 4), (8, 9)] Il serait ais dadapter cette solution au cas o tous les participants nauraient pas se rencontrer les uns les autres. Pour le plaisir, limage suivante, qui reprsente une coloration propre des artes du graphe complet. Une couleur commune indique que les matches correspondants ont lieu le mme jour. sage: g = graphs.CompleteGraph(10) sage: g.show(edge_colors=edge_coloring(g, hex_colors=True))

16.4. QUELQUES PROBLMES MODLISS PAR DES GRAPHES

381

382

CHAP. 16. THORIE DES GRAPHES

Programmation linaire
Le chapitre prsent aborde la programmation linaire (LP), et la programmation linaire en nombres entiers (MILP), avec force illustrations des problmes quelles permettent de rsoudre. Les exemples donns seront en grande partie issus de la thorie des graphes, les plus simples pouvant tre compris sans connaissance spcique. En tant quoutil pour la combinatoire, utiliser la programmation linaire se rduit comprendre comment rcrire un problme dexistence ou doptimisation sous la forme de contraintes linaires.

17

17.1

Dnition

Un programme linaire est un systme dquations linaires dont on cherche une solution optimale. Formellement, on le dnit par une matrice A : Rm Rn et deux vecteurs b Rn et c Rm . Rsoudre un programme linaire revient alors trouver un vecteur x Rm maximisant une fonction objectif, tout en satisfaisant un systme de contraintes, i.e., ct x =
y tel que Ay b

max

ct y

o la relation u u entre deux vecteurs indique que les valeurs de u sont infrieures ou gales aux valeurs de u , composante par composante. Nous crirons aussi : maximiser : ct x tel que : Ax b.

384

CHAP. 17. PROGRAMMATION LINAIRE Le programme linaire suivant admet pour solution x = 4, y = 0, z = 1.6 : max : x + y + 3z tel que : x + 2y 5z y 4 8.

De faon quivalente, nous pourrions dire que rsoudre un programme linaire revient trouver un point maximisant une fonction linaire dnie sur un polytope (en loccurrence la primage A1 ( b)). Ces dnitions ne nous expliquent cependant pas encore lintrt de la programmation linaire en combinatoire, ce qui est lobjet principal du prsent chapitre. Nous verrons donc comment utiliser ce formalisme pour rsoudre, entre autres, les problmes de sac dos (17.4.1), de couplage (17.4.2), ou de ot (17.4.3). Dans 17.5, nous utiliserons les gnrations de contraintes pour rsoudre le problme dexistence de cycle hamiltonien.

17.2

Programmation entire

La dnition donne linstant saccompagne dune mauvaise nouvelle : la rsolution dun programme linaire peut tre faite en temps polynomial. Cest une mauvaise nouvelle, parce que cela signie qu moins de dnir des programmes linaires de taille exponentielle, il ne serait pas possible dutiliser cette mthode pour rsoudre des problmes NP-complets. Heureusement, tout se complique lorsque lon ajoute comme contrainte que toutes ou certaines des composantes de x doivent tre entires, et non relles. On obtient alors, selon les cas, un programme linaire en nombres entiers (ILP), ou bien si seulement certaines composantes doivent tre entires, un programme linaire mixte (en anglais Mixed Integer Linear Program ou MILP). La rsolution de ILP ou de MILP est elle un problme NP-complet. Nous pouvons donc en attendre beaucoup.

17.3
17.3.1

En pratique
La classe MixedIntegerLinearProgram

La classe MixedIntegerLinearProgram reprsente dans Sage un ... MILP ! On lutilise cependant aussi pour rsoudre des problmes continus si ncessaire. Elle possde un nombre trs rduit de mthodes, qui servent dnir le MILP, le rsoudre, puis lire la solution obtenue. Il est aussi possible de visualiser son contenu, ou de lexporter aux formats LP ou MPS tous deux standards. Pour lillustrer, rsolvons le programme linaire prsent en 17.1. Il faut pour cela construire un objet de la classe MixedIntegerLinearProgram, sage: p = MixedIntegerLinearProgram() les 3 variables dont nous avons besoin, sage: x, y, z = p[ x ], p[ y ], p[ z ]

17.3. EN PRATIQUE la fonction objectif, sage: p.set_objective( x + y + 3*z ) puis les contraintes : sage: p.add_constraint( x + 2*y <= 4 ) sage: p.add_constraint( 5*z - y <= 8 )

385

La mthode solve de MixedIntegerLinearProgram renvoie la valeur optimale de la fonction objectif : sage: p.solve() 8.8 On obtient une aectation optimale pour x, y , et z en appelant la mthode get_values : sage: p.get_values(x), p.get_values(y), p.get_values(z) (4.0, 0.0, 1.6)

17.3.2

Variables

Les variables associes une instance de MixedIntegerLinearProgram sont des objets de type MIPVariable, mais cela ne nous concerne pas vraiment. Dans lexemple prcdent, nous avons obtenu ces variables par le raccourci p[x], ce qui est susant lorsque le nombre de variables est rduit. Les programmes linaires que nous dnirons par la suite demandent rgulirement dassocier des variables une liste dobjets comme des entiers, les sommets dun graphe, ou quantit dautres choses. Il est donc ncessaire de pouvoir parler de vecteur de variables, voire de dictionnaire de variables. Par exemple, si notre programme linaire ncessite de dnir des variables x1 , . . . , x15 , il sera bien plus ais de faire appel la mthode new_variable : sage: x = p.new_variable() Il est maintenant possible de dnir des contraintes en utilisant nos 15 variables : sage: p.add_constraint( x[1] + x[12] - x[14] >= 8 ) On remarquera quil nest pas ncessaire pour cela de dnir la taille du vecteur x. En fait, x acceptera sans discuter toute clef de type immuable (cf. 3.3.7), exactement comme un dictionnaire. On peut donc se permettre dcrire : sage: p.add_constraint( x["je_suis_un_indice_valide"] + x["a",pi] <= 3 ) On notera au passage que ce formalisme permet lutilisation de variables indices multiples. Pour dnir la contrainte 0 i,j<4 xi,j 1 on crira : sage: p.add_constraint( p.sum( ....: x[i,j] for i in range(4) for j in range(4)) <= 1 ) La notation x[i,j] est quivalente la notation x[(i,j)].

386

CHAP. 17. PROGRAMMATION LINAIRE

Types de variables. Par dfaut, les variables renvoyes par new_variable sont de type rel positif ou nul. Il est possible de les dnir comme binaires en utilisant largument binary = True ou entires avec integer = True. On pourra par la suite dnir ou rednir des bornes minimales et maximales pour les variables (par exemple pour obtenir des valeurs ngatives) laide des mthodes set_min et set_max. Il est aussi possible de changer le type dune variable aprs sa cration, laide des mthodes set_binary, set_integer ou set_real.

17.3.3

Problmes infaisables ou non borns

Certains programmes linaires nont, formellement, pas de solution. Il est en eet ambitieux de chercher optimiser une fonction mme linaire sur un ensemble vide, ou linverse sur un domaine si peu contraint que la fonction objectif ny est pas borne. Dans les deux cas, Sage renverra une exception lors de lappel de la mthode solve : sage: p = MixedIntegerLinearProgram() sage: p.set_objective( p[3] + p[2] ) sage: p.add_constraint( p[3] <= 5 ) sage: p.solve() Traceback (most recent call last): ... MIPSolverException: GLPK : Solution is undefined sage: p.add_constraint( p[2] <= 8 ) sage: p.solve() 13.0 sage: p.add_constraint( p[3] >= 6 ); p.solve() Traceback (most recent call last): ... MIPSolverException: GLPK : Solution is undefined De mme, la contrainte dintgrit dune variable peut rendre le domaine vide : sage: p = MixedIntegerLinearProgram() sage: p.set_objective( p[3] ) sage: p.add_constraint( p[3] <= 4.75 ); p.add_constraint( p[3] >= 4.25 ) sage: p.solve() 4.75 sage: p.set_integer(p[3]); p.solve() Traceback (most recent call last): ... MIPSolverException: GLPK : Solution is undefined Quel que soit le cas de gure, il serait draisonnable de stopper net un code sous prtexte quun programme linaire na pas pu tre rsolu ; certains programmes linaires ont dailleurs pour unique but de tester lexistence dune solution, et sont

17.4. PREMIRES APPLICATIONS LA COMBINATOIRE

387

donc souvent infaisables. Pour grer ces cas de gure, on utilisera le mcanisme classique try-except de Python pour linterception des exceptions : sage: try: ....: p.solve() ....: print "Le problme a une solution !" ....: except: ....: print "Le problme est infaisable !" Le problme est infaisable !

17.4

Premires applications la combinatoire

Maintenant que les bases sont tablies, passons un aspect plus intressant, la modlisation. Dans cette section se trouvent plusieurs problmes doptimisation ou dexistence : on commence par donner leur dnition abstraite, puis une modlisation en tant que MILP, permettant dobtenir en quelques lignes de code un algorithme pour un problme NP-complet.

17.4.1

Sac dos

Le problme dit du sac dos est le suivant. Nous avons en face de nous une srie dobjets ayant tous un poids propre, ainsi quune utilit mesure par un rel. Nous souhaitons maintenant choisir certains de ces objets en nous assurant que la charge totale ne dpasse pas une constante C , la meilleure faon de le faire tant pour nous doptimiser la somme des utilits des objets contenus dans le sac. Pour cela, nous associerons chaque objet o dune liste L une variable binaire prendre[o], valant 1 si lobjet doit tre mis dans le sac, et 0 sinon. Nous cherchons donc rsoudre le MILP suivant : max :
oL

utilito prendreo poidso prendreo


oL

tel que :

C.

Sous Sage, nous associerons aux objets un cot et une utilit : sage: sage: sage: sage: sage: ....: C = 1 L = ["Casserole", "Livre", "Couteau", "Gourde", "Lampe de poche"] p = [0.57,0.35,0.98,0.39,0.08]; u = [0.57,0.26,0.29,0.85,0.23] poids = {}; utilite = {} for o in L: poids[o] = p[L.index(o)]; utilite[o] = u[L.index(o)]

Nous pouvons maintenant crire le MILP lui-mme. sage: p = MixedIntegerLinearProgram() sage: prendre = p.new_variable( binary = True )

388

CHAP. 17. PROGRAMMATION LINAIRE

sage: p.add_constraint( ....: p.sum( poids[o] * prendre[o] for o in L ) <= C ) sage: p.set_objective( ....: p.sum( utilite[o] * prendre[o] for o in L ) ) sage: p.solve() 1.4199999999999999 sage: prendre = p.get_values(prendre) La solution trouve vrie bien la contrainte de poids : sage: sum( poids[o] * prendre[o] for o in L ) 0.960000000000000 Faut-il prendre une gourde ? sage: prendre["Gourde"] 1.0
Exercice 63 (Subset Sum ). Le problme calculatoire dnomm Subset Sum consiste trouver, dans un ensemble dentiers relatifs, un sous-ensemble non vide dlments dont la somme est nulle. Rsoudre ce problme avec un programme linaire en nombres entiers sur lensemble {28, 10, 89, 69, 42, 37, 76, 78, 40, 92, 93, 45}.

17.4.2

Couplages

Trouver un couplage dans un graphe, cest trouver un ensemble dartes deux deux disjointes. Lensemble vide tant un couplage, lattention se porte plutt sur les couplages maximum : on cherche maximiser le nombre dartes dun couplage. Le problme de couplage maximum est un problme polynomial, en vertu dun rsultat de Jack Edmonds [Edm65]. Son algorithme se base sur des amliorations locales et la preuve que lalgorithme ne sarrte quen prsence dun couplage maximum. Il ne sagit pas l dun des algorithmes les plus diciles implmenter en thorie des graphes, mais il demeure que sa formulation en MILP ne prend que deux lignes. Il nous faudra pour cela, comme prcdemment, associer chacun de nos objets les artes dun graphe une valeur binaire indiquant si oui ou non cette arte appartient notre couplage. Il faut ensuite nous assurer que deux artes adjacentes ne peuvent pas se trouver simultanment dans le couplage. Cela ressemble, mme de trs loin, une contrainte linaire : si x et y sont deux artes dun mme graphe, et si mx et my sont les deux variables qui leur sont associes, il sut dexiger que mx + my 1. Ces deux artes ne pourront pas se trouver simultanment dans notre solution, et nous sommes donc capables dcrire un programme linaire calculant un couplage maximum. Il est cependant possible dtre plus expditif, en remarquant que si deux artes ne peuvent pas tre dans un couplage simultanment, cest parce quelles passent toutes les deux par un sommet v du graphe. Il est donc plus rapide de dire que chaque sommet v est touch par au plus une arte dun couplage.

17.4. PREMIRES APPLICATIONS LA COMBINATOIRE Cette contrainte, elle aussi, est linaire. max :
eE (G)

389

me me
eE (G) e=uv

tel que : v V (G),

1.

Sous Sage, un tel MILP se retranscrit facilement : sage: g = graphs.PetersenGraph() sage: p = MixedIntegerLinearProgram() sage: couplage = p.new_variable(binary = True) sage: p.set_objective(p.sum(couplage[e] ....: for e in g.edges(labels = False))) sage: for v in g: ....: p.add_constraint(p.sum(couplage[e] ....: for e in g.edges_incident(v, labels = False)) <= 1) sage: p.solve() 5.0 sage: couplage = p.get_values(couplage) sage: [e for e, b in couplage.iteritems() if b == 1] [(0, 1), (6, 9), (2, 7), (3, 4), (5, 8)]
Exercice 64 (Ensemble dominant). Un ensemble dominant dun graphe est un ensemble S de sommets tel que tout sommet qui nest pas dans S a au moins un voisin dans S . crire un programme linaire en nombres entiers pour trouver un ensemble dominant de cardinal minimum dans le graphe de Petersen.

17.4.3

Flot

Cette section prsente un autre algorithme fondamental de la thorie des graphes : le ot ! Celui-ci consiste, tant donns deux sommets s et t dun graphe dirig G (cest--dire dont les artes ont une direction, voir gure 17.1), faire passer de s t un ux (ot) maximum, en utilisant pour cela les artes de G. Chacune de ces artes possde une capacit maximale i.e., le ux maximal pouvant les traverser. La dnition de ce problme nous ore directement sa formulation en programme linaire : nous sommes la recherche dune valeur relle associe chaque arte, reprsentant lintensit du ot la traversant, et rpondant deux contraintes : la quantit de ot arrivant sur un sommet (dirent de s ou de t) doit tre gale la quantit de ot quittant ce sommet ; une arte ne peut pas tre traverse par un ot suprieur sa capacit.

390

CHAP. 17. PROGRAMMATION LINAIRE

Figure 17.1 Un problme de ot sur le graphe de Chvtal.

Ceci tant dit, il ne reste plus qu chercher maximiser la valeur du ot quittant s : celui-ci ne pourra terminer sa course quau point t, puisque les autres sommets ne font que retransmettre ce quils reoivent. On formule donc le problme de ot par le programme linaire suivant (en supposant les capacits des artes gales 1) : max :
sv E (G)

fsv fvu =
vuE (G) uv E (G)

tel que : v V (G)\{s, t}, uv E (G), fuv 1.

fuv

Nous rsolvons ici le problme de ot sur une orientation du graphe de Chvtal (cf. gure 17.1), dans lequel les capacits des artes sont toutes gales 1 : sage: g = graphs.ChvatalGraph() sage: g = g.minimum_outdegree_orientation() sage: p = MixedIntegerLinearProgram() sage: f = p.new_variable() sage: s, t = 0, 2 sage: for v in g: ....: if v == s or v == t: continue ....: p.add_constraint( ....: p.sum(f[v,u] for u in g.neighbors_out(v)) == ....: p.sum(f[u,v] for u in g.neighbors_in(v))) sage: for e in g.edges(labels = False): p.add_constraint( f[e] <= 1 )

17.5. GNRATION DE CONTRAINTES ET APPLICATION sage: p.set_objective(p.sum( f[s,u] for u in g.neighbors_out(s))) sage: p.solve() 2.0

391

17.5

Gnration de contraintes application au problme du voyageur de commerce

Bien que les exemples prcdents puissent donner limpression dune grande expressivit, linterprtation dun problme doptimisation (ou dexistence) donne par sa formulation en programme linaire est un choix arbitraire. Un mme problme peut tre rsolu par direntes formulations dont les performances sont elles aussi trs variables. Ceci nous mne utiliser de faon plus intelligente les capacits des solveurs de MILP en leur demandant maintenant de rsoudre des programmes linaires dont ils ne connaissent pas toutes les contraintes, et en najoutant que celles qui leur sont ncessaires au fur et mesure de la rsolution : cette technique devient indispensable ds que le nombre de contraintes est trop grand pour pouvoir tre explicit lors de la cration du programme linaire. Nous nous apprtons rsoudre le problme de cycle hamiltonien (cas particulier du voyageur de commerce traveling salesman problem).

Figure 17.2 La grille de taille 4 6 sur laquelle nous testerons nos formulations.

On dit quun cycle C E (G) contenu dans un graphe G est hamiltonien sil passe par tous les sommets de G. Tester lexistence dun cycle hamiltonien dans un graphe donn est un problme NP-complet : il ne faut donc pas sattendre trouver de faon rapide de le rsoudre, ce qui ne doit pas nous empcher de tenter de le formuler en tant que programme linaire. Une premire formulation pourrait commencer de la faon suivante : associer chaque arte une variable binaire be indiquant si larte est incluse dans le circuit C ; imposer chaque sommet davoir exactement deux de ses artes incidentes dans C .

392

CHAP. 17. PROGRAMMATION LINAIRE

Cette formulation nest malheureusement pas exacte. Il est en eet tout fait possible que la solution obtenue par cette formulation soit lunion disjointe de plusieurs cycles chaque sommet aurait donc bien deux voisins dans C , mais il ne serait pas ncessairement possible daller dun sommet v un sommet u en nutilisant que les artes de C .

Figure 17.3 Une solution possible aux quations de degrs.

Il est cependant possible de trouver une formulation plus complexe et exacte (dite formulation de Miller-Tucker-Zemlin) : on associe chaque sommet v du graphe un entier iv reprsentant ltape laquelle le cycle C le traverse, avec iv0 = 0 pour un sommet v0 x ; on associe chaque arte uv de G deux variables binaires buv et bvu indiquant si larte fait partie du cycle C (et nous indiquant aussi dans quelle direction cette arte est utilise) ; on impose chaque sommet davoir une arte sortante et une arte entrante dans C ; une arte uv ne peut appartenir C que si iu < iv (les artes vont dans le sens croissant des ordres de visite). Cette formulation peut tre transcrite en quations linaires de la faon suivante : max : pas de fonction optimiser tel que : u V (G),
uv E (G)

buv = 1 bvu = 1
uv E (G)

u V (G), uv E (G\v0 ), v V (G), iv

iu iv + |V (G)|buv iv iu + |V (G)|bvu |V (G)| 1

|V (G)| 1 |V (G)| 1

buv est une variable binaire iv est une variable entire.

17.5. GNRATION DE CONTRAINTES ET APPLICATION

393

On notera la prsence dun coecient |V (G)| dans cette formulation, ce qui est assez frquemment le signe que le solveur ne parviendra pas rapidement rsoudre le problme linaire. Aussi, nous utiliserons une autre modlisation du problme de cycle hamiltonien. Son principe est en fait bien plus simple, et repose sur lobservation suivante : sil existe un cycle hamiltonien C dans notre graphe, il existe pour tout ensemble propre S de sommets au moins deux artes de C lensemble des artes ayant entrant ou sortant de S . Si lon choisit de noter S exactement une seule extrmit dans S , nous obtenons la formulation suivante (en identiant les variables buv et bvu ) : max : pas de fonction optimiser tel que : u V (G),
uv E (G)

buv = 2 ve
e S

S V (G), = S = V (G), buv est une variable binaire.

Il serait cependant risqu dutiliser aussi directement que prcdemment cette formulation pour rsoudre un problme de cycle hamiltonien, mme sur un graphe aussi petit que notre grille 4 6 = 24 lments : les contraintes portant sur les ensembles S seraient au nombre de 224 2 = 16 777 214. En revanche, la mthode branch-and-bound (ou branch-and-cut) utilise par les solveurs dinquations linaires se prte bien la gnration de contraintes durant la rsolution dun programme linaire 1 . Gnrer des contraintes pour le problme de cycle hamiltonien consiste donc suivre les tapes suivantes : crer un programme linaire sans fonction dobjectif ayant une variable binaire par arte ; ajouter pour chaque sommet la contrainte imposant un degr de 2 ; rsoudre le programme linaire ; tant que la solution courante nest pas un cycle hamiltonien (cest donc un sous-graphe ayant plusieurs composantes connexes), appeler S lune de ses composantes connexes et ajouter la contrainte imposant quau moins deux artes sortent de S . Heureusement pour nous, il est algorithmiquement rapide de vrier que la solution courante est invalide et de gnrer la contrainte correspondante. En utilisant la gnration de contraintes par Sage, voici comment rsoudre le problme du cycle hamiltonien sur notre grille : sage: g = graphs.Grid2dGraph(4, 6) sage: p = MixedIntegerLinearProgram() sage: b = p.new_variable(binary = True)
1. Cest--dire quil est possible, une fois un programme linaire rsolu, dajouter une contrainte additionnelle et de rsoudre le nouveau programme en utilisant une partie des calculs eectus durant la rsolution qui vient davoir lieu.

394

CHAP. 17. PROGRAMMATION LINAIRE

Figure 17.4 Un cycle hamiltonien calcul par gnration de contraintes.

Pour viter la dirence entre les variables b[u,v] et b[v,u], il est pratique de crer une lambda-fonction remplaant le couple x, y par lensemble {x, y } : sage: B = lambda x,y : b[frozenset([x,y])] Ajoutons maintenant les contraintes de degr : sage: for u in g: ....: p.add_constraint( p.sum( B(u,v) for v in g.neighbors(u) ) == 2 ) Il est temps de calculer la premire solution de notre problme et de crer le graphe la reprsentant, sage: p.solve() 0.0 sage: h = Graph() sage: h.add_edges( [(u,v) for u, v in g.edges(labels = False) ....: if p.get_values(B(u,v)) == 1.0 ] ) puis de commencer nos itrations : sage: while not h.is_connected(): ....: S = h.connected_components()[0] ....: p.add_constraint( ....: p.sum( B(u,v) for u,v ....: in g.edge_boundary(S, labels = False)) ....: >= 2) ....: zero = p.solve() ....: h = Graph() ....: h.add_edges( [(u,v) for u,v in ....: g.edges(labels = False) ....: if p.get_values(B(u,v)) == 1.0 ] ) En moins dune dizaine ditrations (et donc en ralisant une conomie de calculs agrable par rapport 224 2) nous obtenons une solution admissible pour notre grille (cf. gure 17.4). Les performances de cette mthode de rsolution sont

17.5. GNRATION DE CONTRAINTES ET APPLICATION

395

incomparables celles de la formulation de Miller-Tucker-Zemlin. Lorsque lon implmente les deux programmes linaires sous Sage, on obtient sur un graphe alatoire G35,0.3 les temps de calcul suivants : sage: g = graphs.RandomGNP(35, 0.3) sage: %time MTZ(g) CPU times: user 51.52 s, sys: 0.24 s, total: 51.76 s Wall time: 52.84 s sage: %time constraint_generation(g) CPU times: user 0.23 s, sys: 0.00 s, total: 0.23 s Wall time: 0.26 s

396

CHAP. 17. PROGRAMMATION LINAIRE

Annexes

Solutions des exercices


A.1 Premiers pas

Exercice 1 page 16. La commande SR.var( u ) cre la variable symbolique u et laecte la variable informatique u. La variable informatique u reoit ensuite deux reprises sa valeur courante plus un, soit u + 1 puis u + 2 (o u est toujours la variable symbolique).

A.2

Analyse et algbre avec Sage

Exercice 2 page 28. (Un calcul de somme par rcurrence ) sage: n = var( n ); pmax = 4; s = [n + 1] sage: for p in [1..pmax]: ....: s += [factor(((n+1)^(p+1) - sum(binomial(p+1, j) * s[j] ....: for j in [0..p-1])) / (p+1))] sage: s On obtient ainsi :
n

k=0 n

1 k = (n + 1)n, 2

k2 =
k=0 n

1 (n + 1)(2 n + 1)n, 6 1 (n + 1)(2 n + 1) 3 n2 + 3 n 1 n. 30

k=0

1 2 k 3 = (n + 1) n2 , 4

k4 =
k=0

Exercice 3 page 31. (Un calcul symbolique de limite ) Pour rpondre la question, on va utiliser une fonction symbolique, dont on va calculer le polynme de Taylor en 0 lordre 3.

400

ANNEXE A. SOLUTIONS DES EXERCICES

sage: x, h, a = var( x, h, a ); f = function( f ) sage: g(x) = taylor(f(x), x, a, 3) sage: phi(h) = (g(a+3*h) - 3*g(a+2*h) + 3*g(a+h) - g(a)) / h^3; phi(h) D[0, 0, 0](f)(a) La fonction g dire de f dun reste qui est ngligeable devant h3 , donc la fonction phi dire du quotient tudi dun reste qui est o(1) ; donc phi a pour limite en zro la limite cherche. En conclusion,
h0

lim

1 f (a + 3h) 3f (a + 2h) + 3f (a + h) f (a) = f (a). h3

Cette formule permet notamment deectuer un calcul approch de la drive tierce de f en a sans eectuer aucune drivation. On peut supposer que la formule se gnralise sous la forme suivante : lim 1 hn
n

h0

(1)nk
k=0

n f (a + kh) k

= f (n) (a).

Pour tester cette formule pour de plus grandes valeurs de n, on peut alors facilement adapter ce qui prcde : sage: n = 7; x, h, a = var( x h a ); f = function( f ) sage: g(x) = taylor(f(x), x, a, n) sage: sum((-1)^(n-k) * binomial(n,k) * g(a+k*h) for k in (0..n)) / h^n D[0, 0, 0, 0, 0, 0, 0](f)(a) Exercice 4 page 32. (Une formule due Gauss ) 1. On utilise successivement trig_expand et trig_simplify : sage: theta = 12*arctan(1/38) + 20*arctan(1/57) \ ....: + 7*arctan(1/239) + 24*arctan(1/268) sage: tan(theta).trig_expand().trig_simplify() 1 2. La fonction tangente est convexe sur I = 0, 4 , donc sa courbe reprsenta4 tive est en-dessous de sa corde ; autrement dit x I, tan x x. sage: 12*(1/38) + 20*(1/57) + 7*(1/239) + 24*(1/268) 37735/48039 On en dduit : = 12 arctan 1 38 37735 = 48039 12 1 1 1 1 + 20 arctan + 7 arctan + 24 arctan 38 57 239 268 1 1 1 + 20 +7 + 24 57 239 268 4 .

Donc I ; or (cf. question 1) tan = 1 = tan 4 et tan est injective sur I . On en conclut = . 4

A.2. ANALYSE ET ALGBRE AVEC SAGE 3. On substitue le polynme de Taylor dans la formule de Gauss : sage: x = var( x ); f(x) = taylor(arctan(x), x, 0, 21) sage: approx = 4 * (12 * f(1/38) + 20 * f(1/57) ....: + 7 * f(1/239) + 24 * f(1/268)) sage: approx.n(digits = 50); pi.n(digits = 50) 3.1415926535897932384626433832795028851616168852864 3.1415926535897932384626433832795028841971693993751 sage: approx.n(digits = 50) - pi.n(digits = 50) 9.6444748591132486785420917537404705292978817080880e-37

401

Exercice 5 page 33. (Dveloppement asymptotique dune suite ) Lencadrement de xn permet darmer xn n , soit xn = n + o(n). On injecte alors cette galit dans lquation suivante, obtenue partir de arctan x + arctan(1/x) = /2 : xn = n + arctan 2 1 xn .

On rinjecte ensuite les dveloppements asymptotiques de xn ainsi obtenus dans cette quation, bis repetita... (mthode des ranements successifs). Sachant qu chaque tape, un dveloppement dordre p permet dobtenir un dveloppement lordre p + 2, on peut obtenir en quatre tapes un dveloppement dordre 6. En anticipant sur le chapitre 3, on peut eectuer ces quatre tapes lintrieur dune boucle. sage: n = var( n ); phi = lambda x: n*pi + pi/2 - arctan(1/x) sage: x = n*pi sage: for i in range(4): ....: x = taylor(phi(x), n, infinity, 2*i); x Au nal, on obtient : xn = 1 1 1 1 1 3 2 + 8 1 2 + 8 + n + + 2 n 2 n2 12 3 n3 8 3 n4 4 2 1 15 + 240 + 208 1 3 4 + 80 2 + 208 + +O 5 5 240 n 96 5 n6

1 n7

Exercice 6 page 34. (Un contre-exemple d Peano au thorme de Schwarz ) Les applications partielles f (x, 0) et f (0, x) sont identiquement nulles en (0, 0) ; on en dduit, sans calculs, 1 f (0, 0) = 2 f (0, 0) = 0. On calcule alors les valeurs des drives partielles secondes en (0, 0) : sage: sage: -1 sage: 1 sage: h = var( h ); f(x, y) = x * y * (x^2 - y^2) / (x^2 + y^2) D1f(x, y) = diff(f(x,y), x); limit((D1f(0,h) - 0) / h, h=0) D2f(x, y) = diff(f(x,y), y); limit((D2f(h,0) - 0) / h, h=0) g = plot3d(f(x, y), (x, -3, 3), (y, -3, 3))

402

ANNEXE A. SOLUTIONS DES EXERCICES

Figure A.1 La surface de Peano.

On en dduit 1 2 f (0, 0) = 1 et 2 1 f (0, 0) = 1. Donc cette fonction fournit un contre-exemple au thorme de Schwarz (gure A.1). Exercice 7 page 35. (La formule BBP ) 1. On commence par comparer
1/ 2

un =
0

f (t) t8n dt et vn =

4 8n+1

2 8n+4

1 8n+5

1 8n+6

1 n . 16

sage: sage: sage: sage: sage: sage: 0

n, t = var( n, t ) v(n) = (4/(8*n+1)-2/(8*n+4)-1/(8*n+5)-1/(8*n+6))*1/16^n assume(8*n+1>0) f(t) = 4*sqrt(2)-8*t^3-4*sqrt(2)*t^4-8*t^5 u(n) = integrate(f(t) * t^(8*n), t, 0, 1/sqrt(2)) (u(n)-v(n)).simplify_full()

On en dduit un = vn . Par linarit de lintgrale, on obtient :


1/ 2 N N N

IN =
0

f (t)
n=0

t 8n

dt =
n=0

un =
n=0

vn = SN .

2. La srie entire sur le segment

n 0 1 0, 2

t8n a pour rayon de convergence 1, donc elle converge . Sur ce segment, on peut donc intervertir lintgrale

A.2. ANALYSE ET ALGBRE AVEC SAGE et la limite :


1/ 2 N N

403

lim SN = lim =
0

N 1/ 2

f (t)
0 n=0

t 8n t8n dt

dt

f (t)
1/ 2 n=0

=
0

f (t)

1 dt = J. 1 t8

3. On procde ensuite au calcul de J : sage: t = var( t ); J = integrate(f(t) / (1-t^8), t, 0, 1/sqrt(2)) sage: J.simplify_full() pi + 2*log(sqrt(2) - 1) + 2*log(sqrt(2) + 1) Pour simplier cette expression, il faut indiquer Sage de combiner la somme de logarithmes : sage: J.simplify_log().simplify_full() pi En dnitive, on obtient la formule demande :
+

n=0

4 2 1 1 8n + 1 8n + 4 8n + 5 8n + 6

1 16

= .

laide de cette formule, donnons de nouveau une valeur approche de : sage: l = sum(v(n) for n in (0..40)); l.n(digits=60) 3.14159265358979323846264338327950288419716939937510581474759 sage: pi.n(digits=60) 3.14159265358979323846264338327950288419716939937510582097494 sage: print "%e" % (l-pi).n(digits=60) -6.227358e-54 Exercice 8 page 36. (Approximation polynomiale du sinus ) On munit lespace vectoriel C ([, ]) du produit scalaire f | g = f g . Le polynme cherch est la projection orthogonale de la fonction sinus sur le sous-espace vectoriel R5 [X ]. La dtermination de ce polynme se ramne la rsolution dun systme linaire : en eet, P est le projet du sinus si et seulement si la fonction (P sin) est orthogonale chacun des vecteurs de la base canonique de R5 [X ]. Voici le code Sage : sage: sage: sage: sage: sage: x = n = P = equ sol var( x ); ps = lambda f, g : integral(f * g, x, -pi, pi) 5; a = var( a0, a1, a2, a3, a4, a5 ) sum(a[k] * x^k for k in (0..n)) = [ps(P - sin(x), x^k) for k in (0..n)] = solve(equ, a)

404

ANNEXE A. SOLUTIONS DES EXERCICES

sage: P = sum(sol[0][k].rhs() * x^k for k in (0..n)); P 105/8*(pi^4 - 153*pi^2 + 1485)*x/pi^6 - 315/4*(pi^4 - 125*pi^2 + 1155)*x^3/pi^8 + 693/8*(pi^4 - 105*pi^2 + 945)*x^5/pi^10 sage: g = plot(P,x,-6,6,color= red ) + plot(sin(x),x,-6,6,color= blue ) sage: g.show(ymin = -1.5, ymax = 1.5) Le polynme cherch est donc : P = 105 4 153 2 + 1485 315 4 125 2 + 1155 3 x x 6 8 4 8 693 4 105 2 + 945 5 + x . 8 10

On peut ensuite tracer la fonction sinus et son projet orthogonal pour apprcier la qualit de cette approximation polynomiale (gure A.2).
1 0.5 -4 -3 -2 -1 -0.5 -1
Figure A.2 Approximation du sinus par la mthode des moindres carrs.

Exercice 9 page 36. (Le problme de Gauss ) On prouve tout dabord formellement les relations demandes. Sensuivra lapplication numrique. On commence par dnir les vecteurs ri : p, e = var( p, e ) theta1, theta2, theta3 = var( theta1, theta2, theta3 ) r(theta) = p / (1 - e * cos(theta)) r1 = r(theta1); r2 = r(theta2); r3 = r(theta3) R1 = vector([r1 * cos(theta1), r1 * sin(theta1), 0]) R2 = vector([r2 * cos(theta2), r2 * sin(theta2), 0]) R3 = vector([r3 * cos(theta3), r3 * sin(theta3), 0]) On vrie que S + e D est le vecteur nul, sage: sage: sage: sage: D = R1.cross_product(R2)+R2.cross_product(R3)+R3.cross_product(R1) S = (r1 - r3) * R2 + (r3 - r2) * R1 + (r2 - r1) * R3 i = vector([1, 0, 0]); V = S + e * i.cross_product(D) V.simplify_full() sage: sage: sage: sage: sage: sage: sage:

A.2. ANALYSE ET ALGBRE AVEC SAGE (0, 0, 0) do la relation demande. On en dduit : e = D normal au plan de lorbite, et donc . On vrie ensuite que est colinaire S D : sage: S.cross_product(D).simplify_full()[1:3] (0, 0)
S

405

S D

, puisque D est

Le rsultat renvoy montre que les deuxime et troisime composantes sont nulles. De mme, on vrie que p S + e N est le vecteur nul, sage: N = r3 * R1.cross_product(R2) + r1 * R2.cross_product(R3)\ ....: + r2 * R3.cross_product(R1) sage: W = p * S + e * i.cross_product(N) sage: W.simplify_full() (0, 0, 0) do la relation demande. On en dduit : N N p=e =e S S N , D

puisque N est normal au plan de lorbite, et donc . p Daprs le formulaire sur les coniques, on a a = 1e2 . On passe prsent lapplication numrique demande : sage: sage: sage: ....: sage: sage: ....: sage: sage: sage: sage: sage: 2.360 R1=vector([0,1,0]); R2=vector([2,2,0]); R3=vector([3.5,0,0]) r1 = R1.norm(); r2 = R2.norm(); r3 = R3.norm() D = R1.cross_product(R2) + R2.cross_product(R3) \ + R3.cross_product(R1) S = (r1 - r3) * R2 + (r3 - r2) * R1 + (r2 - r1) * R3 N = r3 * R1.cross_product(R2) + r1 * R2.cross_product(R3) \ + r2 * R3.cross_product(R1) e = S.norm() / D.norm(); p = N.norm() / D.norm() a = p/(1-e^2); c = a * e; b = sqrt(a^2 - c^2) X = S.cross_product(D); i = X / X.norm() phi = atan2(i[1], i[0]) * 180 / pi.n() print("%.3f %.3f %.3f %.3f %.3f %.3f" % (a, b, c, e, p, phi)) 1.326 1.952 0.827 0.746 17.917 b 1.326, c 1.952, e 0.827, p 0.746, 17.917.

En conclusion, on trouve : a 2.360, Linclinaison du grand axe par rapport laxe des abscisses vaut 17.92. Exercice 10 page 37. (Bases de sous-espaces vectoriels ) 1. Lensemble S des solutions du systme linaire homogne associ A est un sous-espace vectoriel de R5 , dont on obtient la dimension et une base grce la fonction right_kernel :

406

ANNEXE A. SOLUTIONS DES EXERCICES sage: A = matrix(QQ, [[ 2, -3, 2, -12, 33], ....: [ 6, 1, 26, -16, 69], ....: [10, -29, -18, -53, 32], ....: [ 2, 0, 8, -18, 84]]) sage: A.right_kernel() Vector space of degree 5 and dimension 2 over Rational Field Basis matrix: [ 1 0 -7/34 5/17 1/17] [ 0 1 -3/34 -10/17 -2/17] S est donc le plan vectoriel engendr par les deux vecteurs ci-dessus (quil faut lire en ligne, comme plus bas).

2. On extrait de la famille gnratrice donne une base du sous-espace recherch de la manire suivante. On rduit la matrice A (forme par les colonnes u1 , u2 , u3 , u4 , u5 ) par rapport aux lignes jusqu la forme dHermite : sage: H = A.echelon_form(); 1 0 0 0 H 0 4 0 1 2 0 0 0 1 0 0 0 3 7 5 0

Soit F = Vect(u1 , u2 , u3 , u4 , u5 ) la famille des vecteurs colonnes de A. Cest un sous-espace vectoriel de R4 . Sur H , on observe que les pivots sont dans les colonnes 1, 2 et 4. Plus prcisment, on a : (u1 , u2 , u4 ) est une famille libre, u3 = 4u1 + 2u2 , u5 = 3u1 + 7u2 5u4 . Donc F = Vect(u1 , u2 , u3 , u4 , u5 ) = Vect(u1 , u2 , u4 ) est engendr par la famille (u1 , u2 , u4 ) ; or cette famille est libre ; donc (u1 , u2 , u4 ) est une base de F . On aurait galement pu utiliser, plus directement, la fonction column_space : sage: A.column_space() Vector space of degree 4 and dimension 3 over Rational Field Basis matrix: [ 1 0 0 1139/350] [ 0 1 0 -9/50] [ 0 0 1 -12/35] 3. On cherche prsent des quations du sous-espace engendr. Pour cela, on rduit la matrice A augmente dun second membre, en indiquant Sage quon travaille dans un anneau de polynmes quatre indtermines : sage: S.<x, y, z, t> = QQ[] sage: C = matrix(S, 4, 1, [x, y, z, t]) sage: B = block_matrix([A, C], ncols=2)

A.2. ANALYSE ET ALGBRE AVEC SAGE sage: C = B.echelon_form() sage: C[3,5]*350 1139x + 63y + 120z + 350t

407

On en dduit que F est lhyperplan de R4 dquation 1139 x + 63 y + 120 z + 350 t = 0. On aurait galement pu obtenir cette quation en calculant le noyau gauche de A, qui donne les coordonnes des formes linaires dnissant F (ici il ny en a quune) : sage: K = A.left_kernel(); K Vector space of degree 4 and dimension 1 over Rational Field Basis matrix: [ 1 -63/1139 -120/1139 -350/1139] Lhyperplan dni par cette forme linaire a pour base les trois vecteurs suivants, dj obtenus avec A.column_space() : sage: matrix(K.0).right_kernel() Vector space of degree 4 and dimension 3 over Rational Field Basis matrix: [ 1 0 0 1139/350] [ 0 1 0 -9/50] [ 0 0 1 -12/35] Exercice 11 page 37. (Une quation matricielle ) On commence par dnir les matrices A et C : sage: A = matrix(QQ, [[-2, 1, 1], [8, 1, -5], [4, 3, -3]]) sage: C = matrix(QQ, [[1, 2, -1], [2, -1, -1], [-5, 0, 3]]) Lquation A = BC est une quation linaire, donc lensemble des solutions est un sous-espace ane de M3 (R). On cherche donc une solution particulire de notre quation. sage: B [ 0 -1 [ 2 3 [ 2 1 = C.solve_left(A); B 0] 0] 0]

Ensuite, on dtermine la forme gnrale des solutions de lquation homogne, autrement dit, le noyau gauche de C . sage: C.left_kernel() Vector space of degree 3 and dimension 1 over Rational Field Basis matrix: [1 2 1] Enn, on donne la forme gnrale des solutions de notre quation : sage: x, y, z = var( x, y, z ); v = matrix([[1, 2, 1]]) sage: B = B + (x*v).stack(y*v).stack(z*v); B

408

ANNEXE A. SOLUTIONS DES EXERCICES

1 3 0.5 2.5 0.5 -0.5 1 1.5 2 2 1.5 1 0.5 -1


(a) Conchodes de Pascal.

-1 -0.5

0.5

1.5

2.5

(b) tude dune suite rcurrente.

On peut eectuer une vrication rapide : sage: A == B*C True En conclusion, lensemble des solutions est un sous-espace ane de dimension 3 : x 2x 1 x y + 2 2y + 3 y (x, y, z ) R3 . z + 2 2z + 1 z

A.4

Graphiques

Exercice 12 page 81. (Conchodes de Pascal ) sage: t = var( t ); liste = [a + cos(t) for a in srange(0, 2, 0.1)] sage: g = polar_plot(liste, (t, 0, 2 * pi)); g.show(aspect_ratio = 1) Exercice 13 page 85. (Trac des termes dune suite rcurrente ) sage: sage: ....: ....: ....: ....: ....: sage: sage: sage: sage: sage: f = lambda x: abs(x**2 - 1/4) def liste_pts(u0, n): u = u0; liste = [[u0,0]] for k in range(n): v, u = u, f(u) liste.extend([[v,u], [u,u]]) return(liste) g = line(liste_pts(1.1, 8), rgbcolor = (.9,0,0)) g += line(liste_pts(-.4, 8), rgbcolor = (.01,0,0)) g += line(liste_pts(1.3, 3), rgbcolor = (.5,0,0)) g += plot(f, -1, 3, rgbcolor = blue ) g += plot(x, -1, 3, rgbcolor = green )

A.4. GRAPHIQUES

409

4 2 -3 -2 -1 -2 -4
Figure A.3 Courbes intgrales de x2 y y = 0.

sage: g.show(aspect_ratio = 1, ymin = -.2, ymax = 3) Exercice 14 page 88. (quation direntielle linaire, du premier ordre, rsolue ) sage: x = var( x ); y = function( y ) sage: DE = x^2 * diff(y(x), x) - y(x) == 0 sage: desolve(DE, y(x)) c*e^(-1/x) sage: g = plot([c*e^(-1/x) for c in srange(-8, 8, 0.4)], (x, -3, 3)) sage: y = var( y ) sage: g += plot_vector_field((x^2, y), (x,-3,3), (y,-5,5)) sage: g.show() Exercice 15 page 90. (Modle proie-prdateur ) sage: sage: sage: sage: sage: ....: sage: sage: sage: sage: sage: sage: from sage.calculus.desolvers import desolve_system_rk4 f = lambda x, y: [a*x-b*x*y,-c*y+d*b*x*y] x, y, t = var( x, y, t ) a, b, c, d = 1., 0.1, 1.5, 0.75 P = desolve_system_rk4(f(x,y), [x,y],\ ics=[0,10,5], ivar=t, end_points=15) Ql = [[i,j] for i,j,k in P]; p = line(Ql, color= red ) p += text("Lapins", (12,37), fontsize=10, color= red ) Qr = [[i,k] for i,j,k in P]; p += line(Qr, color= blue ) p += text("Renards", (12,7), fontsize=10, color= blue ) p.axes_labels(["temps", "population"]) p.show(gridlines = True)

On peut aussi refaire le graphe de droite de la gure 4.12 :

410

ANNEXE A. SOLUTIONS DES EXERCICES

2 1 -3 -2 -1 -1 -2 1 2 3

Figure A.4 Un systme direntiel autonome.

sage: sage: sage: sage: ....: ....: ....: ....: sage:

n = def q = for

10; L = srange(6, 18, 12 / n); R = srange(3, 9, 6 / n) g(x,y): v = vector(f(x, y)); return v / v.norm() plot_vector_field(g(x, y), (x, 0, 60), (y, 0, 36)) j in range(n): P = desolve_system_rk4(f(x,y), [x,y], ics=[0,L[j],R[j]], ivar=t, end_points=15) Q = [[j,k] for i,j,k in P] q += line(Q, color=hue(.8-j/(2*n))) q.axes_labels(["lapins", "renards"]); q.show()

Exercice 16 page 90. (Un systme direntiel autonome ) sage: sage: sage: sage: sage: sage: sage: sage: ....: ....: sage: sage: from scipy import integrate def dX_dt(X, t=0): return [X[1], 0.5*X[1] - X[0] - X[1]^3] t = srange(0, 40, 0.01); x0 = srange(-2, 2, 0.1); y0 = 2.5 CI = [[i, y0] for i in x0] + [[i, -y0] for i in x0] def g(x,y): v = vector(dX_dt([x, y])); return v / v.norm() x, y = var( x, y ); n = len(CI) q = plot_vector_field(g(x, y), (x, -3, 3), (y, -y0, y0)) for j in xrange(n): X = integrate.odeint(dX_dt, CI[j], t) q += line(X, color=(1.7*j/(4*n),1.5*j/(4*n),1-3*j/(8*n))) X = integrate.odeint(dX_dt, [0.01,0], t) q += line(X, color = red ); q.show()

A.5. DOMAINES

411

Exercice 17 page 90. (coulement autour dun cylindre avec eet Magnus ) Pour rsoudre cet exercice, on peut par exemple utiliser la fonction odeint de SciPy : sage: sage: sage: sage: ....: sage: ....: ....: ....: ....: ....: ....: ....: ....: from scipy import integrate t = srange(0, 40, 0.2) n = 35; CI_cart = [[4, .2 * i] for i in range(n)] CI = map(lambda x: [sqrt(x[0]^2+x[1]^2),\ pi - arctan(x[1]/x[0])], CI_cart) for alpha in [0.1, 0.5, 1, 1.25]: dX_dt = lambda X, t=0: [cos(X[1])*(1-1/X[0]^2), \ -sin(X[1]) * (1/X[0]+1/X[0]^3) + 2*alpha/X[0]^2] q = circle((0, 0), 1, fill=True, rgbcolor= purple ) for j in range(n): X = integrate.odeint(dX_dt, CI[j], t) Y = [[u[0]*cos(u[1]), u[0]*sin(u[1])] for u in X] q += line(Y, xmin = -4, xmax = 4, color= blue ) q.show(aspect_ratio = 1, axes = False)

(a) Cas = 0.1.

(b) Cas = 0.5. Figure A.5 Eet Magnus.

(c) Cas = 1.

Les solutions correspondantes = 0.1, 0.5, 1 sont reprsentes en gure A.5.

A.5

Domaines

Exercice 18 page 102. La classe de lanneau ZZ sappelle IntegerRing_class, comme on peut le voir par les commandes suivantes : sage: <type sage: <type print type(ZZ) sage.rings.integer_ring.IntegerRing_class > ZZ.__class__ sage.rings.integer_ring.IntegerRing_class >

Lanneau ZZ est en fait lunique instance de cette classe, que lon se gardera de confondre avec la catgorie de ZZ,

412

ANNEXE A. SOLUTIONS DES EXERCICES

sage: ZZ.category() Category of euclidean domains ou encore avec la classe de ses lments : sage: ZZ.an_element().__class__ <type sage.rings.integer.Integer >

A.6

Corps nis et thorie lmentaire des nombres

Exercice 19 page 126. On suppose n = pqr avec p < q < r. Ncessairement p3 n, donc la fonction principale scrit : sage: def enum_carmichael(N, verbose=True): ....: p = 3; s = 0 ....: while p^3 <= N: ....: s += enum_carmichael_p(N, p, verbose); p = next_prime(p) ....: return s o la fonction enum_carmichael_p compte les nombres de Carmichael multiples de p, qui sont de la forme a + m avec un entier positif ou nul, a = p et m = p(p 1), puisque n doit tre multiple de p, et n 1 multiple de p 1 : sage: def enum_carmichael_p (n, p, verbose): ....: a = p; m = p*(p-1); q = p; s = 0 ....: while p*q^2 <= n: ....: q = next_prime(q) ....: s += enum_carmichael_pq(n, a, m, p, q, verbose) ....: return s La fonction enum_carmichael_pq compte les nombres de Carmichael multiples de pq , qui sont de la forme a + m avec un entier positif ou nul, o a a mod m et a q mod q (q 1), et m est multiple la fois de m = p(p 1) et de q (q 1). On utilise la fonction crt pour rsoudre les congruences simultanes, en liminant les cas o il ne peut pas y avoir de solution, sinon Sage provoquerait une erreur. On impose aussi a > pq 2 pour avoir r > q : sage: def enum_carmichael_pq(n,a,m,p,q,verbose): ....: if (a-q) % gcd(m,q*(q-1)) <> 0: return 0 ....: s = 0 ....: a = crt (a, q, m, q*(q-1)); m = lcm(m,q*(q-1)) ....: while a <= p*q^2: a += m ....: for t in range(a, n+1, m): ....: r = t // (p*q) ....: if is_prime(r) and t % (r-1) == 1: ....: if verbose: ....: print p*q*r, factor(p*q*r) ....: s += 1 ....: return s

A.6. CORPS FINIS ET THORIE LMENTAIRE DES NOMBRES Avec ces fonctions, on obtient :

413

sage: enum_carmichael(10^4) 561 3 * 11 * 17 1105 5 * 13 * 17 2465 5 * 17 * 29 1729 7 * 13 * 19 2821 7 * 13 * 31 8911 7 * 19 * 67 6601 7 * 23 * 41 7 sage: enum_carmichael(10^5, False) 12 sage: enum_carmichael(10^6, False) 23 sage: enum_carmichael(10^7, False) 47

Exercice 20 page 128. On commence par crire une fonction aliq calculant la suite aliquote partant de n, et sarrtant ds quon atteint 1 ou un cycle :

sage: ....: ....: ....: ....: ....: ....: sage: sage: (748, sage:

def aliq(n): l = [n] while n <> 1: n = sigma(n) - n if n in l: break l.append(n) return l l = aliq(840) len(l), l[:5], l[-5:] [840, 2040, 4440, 9240, 25320], [2714, 1606, 1058, 601, 1]) points([(i, log(l[i])/log(10)) for i in range(len(l))])

414

ANNEXE A. SOLUTIONS DES EXERCICES

40

30

20

10

100

200

300

400

500

600

700

Exercice 21 page 129. (Constante de Masser-Gramain ) Pour la question 1, soit C le cercle frontire dun plus petit disque. Sans restriction de gnralit on peut supposer que lorigine O est sur le cercle en eet, il y a au moins un point de Z2 sur le cercle, sinon le disque nest pas optimal. On peut aussi supposer que le centre du cercle est dans le premier quadrant (par rotation du disque dun multiple de /2 autour de O). On admettra quon a galement deux points A et B du premier quadrant sur le cercle, et donc le cercle C est circonscrit au triangle OAB . La borne rk < k/ permet de dlimiter les points A et B , car leur distance O est au plus 2 k/ . On peut supposer quun des points A et B , par exemple A, est dans le second octant (sils sont tous deux dans le premier octant, par symtrie par rapport la droite x = y on les ramne dans le second octant). On peut aussi supposer que langle en A du triangle OAB est aigu (en changeant A et B au besoin, aprs une symtrie par rapport la droite x = y sils sont dans des octants dirents). Labscisse de A vrie donc xA < 2k/ , son ordonne vrie xA yA < 4k/ x2 A . Pour le point B , 2 on a 0 xB < 2 k/ , et 0 xA yB + yA xB x2 + y A A (angle aigu en A). Cela donne le code suivant, o la routine rk_aux calcule le nombre de points dans le disque de centre (xc /d, yc /d), et de rayon r2 /d, o xc , yc , d, r2 sont tous entiers.
sage: def rk_aux(xc, yc, d, r2): ....: s = 0 ....: xmin = ceil((xc - sqrt(r2))/d) ....: xmax = floor((xc + sqrt(r2))/d) ....: for x in range(xmin,xmax+1): ....: r3 = r2 - (d*x-xc)^2 # (d*y-yc)^2 <= r2 - (d*x-xc)^2 ....: ymin = ceil((yc - sqrt(r3))/d) ....: ymax = floor((yc + sqrt(r3))/d) ....: s += ymax + 1 - ymin ....: return s

A.6. CORPS FINIS ET THORIE LMENTAIRE DES NOMBRES


sage: def rk(k): # renvoie (r_k^2, xc, yc) ....: if k == 2: return 1/4, 1/2, 0 ....: dmax = (2*sqrt(k/pi)).n(); xamax = (sqrt(2*k/pi)).n() ....: sol = (dmax/2)^2, 0, 0, 0 ....: for xa in range(0, floor(xamax)+1): ....: # si xa=0, ya > 0 car A ne peut tre en O ....: yamin = max(xa, 1) ....: for ya in range(yamin, floor(sqrt(dmax^2-xa^2))+1): ....: xbmin = 0 # on veut xb*ya <= xa^2+ya^2 ....: if xa == 0: ....: xbmin = 1 # O, A, B ne doivent pas tre aligns ....: xbmax = min(floor(dmax), floor((xa*xa+ya*ya)/ya)) ....: for xb in range(xbmin, xbmax+1): ....: ybmax = floor(sqrt(dmax^2-xb^2)) ....: if xa > 0: # on veut xb*ya+yb*xa <= xa^2+ya^2 ....: tmp = floor((xa*xa+ya*ya-xb*ya)/xa) ....: ybmax = min(ybmax, tmp) ....: # si xb=0, yb > 0 car B doit tre distinct de O ....: ybmin = 0 ....: if xb == 0: ....: ybmin = 1 ....: for yb in range(ybmin,ybmax+1): ....: d = 2*abs(xb*ya - xa*yb) ....: if d <> 0: ....: ra2 = xa^2+ya^2; rb2 = xb^2+yb^2 ....: xc = abs(ra2*yb - rb2*ya) ....: yc = abs(rb2*xa - ra2*xb) ....: r2 = ra2*rb2*((xa-xb)^2+(ya-yb)^2) ....: m = rk_aux(xc,yc,d,r2) ....: if m >= k and r2/d^2 < sol[0]: ....: sol = r2/d^2, xc/d, yc/d ....: return sol sage: for k in range(2,10): print k, rk(k) 2 (1/4, 1/2, 0) 3 (1/2, 1/2, 1/2) 4 (1/2, 1/2, 1/2) 5 (1, 0, 1) 6 (5/4, 1/2, 1) 7 (25/16, 3/4, 1) 8 (2, 1, 1) 9 (2, 1, 1)

415

Pour la question 2, une solution est la suivante : sage: def plotrk(k): ....: r2, x0, y0 = rk(k); r = n(sqrt(r2)) ....: var( x, y ) ....: c = implicit_plot((x-x0)^2+(y-y0)^2-r2, ....: (x, x0-r-1/2, x0+r+1/2),(y, y0-r-1/2, y0+r+1/2)) ....: center = points([(x0,y0)], pointsize=50, color= black )

416 ....: ....: ....: ....: ....: ....: ....:

ANNEXE A. SOLUTIONS DES EXERCICES # on veut (i-x0)^2+(j-y0)^2 <= r2 # donc |i-x0| <= r et |j-y0| <= r2 - (i-x0)^2 l = [(i, j) for i in range(ceil(x0-r), floor(x0+r)+1) for j in range(ceil(y0-sqrt(r^2-(i-x0)^2)), floor(y0+sqrt(r2-(i-x0)^2))+1)] d = points(l, pointsize=100) return (c+center+d).show(aspect_ratio=1, axes=True)
j

2 La question 3 demande un peu de rexion. Notons Si,j = k=i 1/(rk ). 2 Partant de la borne suprieure (6.2) pour rk , on obtient rk < (k 1)/ , donc N +1 N 2 ) > 1/(k 1), et Sn,N > k=n 1/(k 1) > n dk/k = log((N + 1)/n). 1/(rk 2 La borne infrieure de (6.2) donne 1/(rk ) < 1/k + 2/k 3/2 pour k 407, qui N N conduit pour n 407 Sn,N < k=n (1/k + 2/k 3/2 ) < n1 (1/k + 2/k 3/2 )dk = log(N/(n 1)) + 4/ n 1 4/ N , do : S2,n1 + log(1/n) S2,n1 + log(1/(n 1)) + 4/ n 1.

sage: def bound(n): ....: s = sum(1/pi/rk(k)[0] for k in range(2,n+1)) ....: return float(s+log(1/n)), float(s+log(1/(n-1))+4/sqrt(n-1)) sage: bound(60) (1.7327473659779615, 2.2703101282176377) On en dduit 1.73 < < 2.28, soit lapproximation 2.00 avec une erreur borne par 0.28. Exercice 22 page 130. On reprend ici les mmes notations que dans larticle de Beauzamy. On pose si = 1 xi xk avec sk+1 = 1. On doit donc avoir x1 + + xi1 si , et en particulier x2 x1 s2 . Soit C1 =
s2 x1 =x2
1 xn 1 dx1 =

1 1 +1 (sn1 +1 xn ). 2 n1 + 1 2

sage: x1, x2, s2 = var( x1, x2, s2 ) sage: n1 = 9; C1 = integrate(x1^n1, x1, x2, s2); C1 1/10*s2^10 - 1/10*x2^10 Ensuite on a x3 x2 s3 = s2 + x2 , donc en remplaant s2 par s3 x2 dans C1 , et en intgrant pour x2 allant de x3 s3 /2 car x1 + x2 s3 et x2 x1 on obtient :
sage: x3, s3 = var( x3, s3 ) sage: n2 = 7; C2 = integrate(C1.subs(s2=s3-x2)*x2^n2, x2, x3, s3/2); C2 44923/229417943040*s3^18 - 1/80*s3^10*x3^8 + 1/9*s3^9*x3^9 - 9/20*s3^8*x3^10 + 12/11*s3^7*x3^11 - 7/4*s3^6*x3^12 + 126/65*s3^5*x3^13 - 3/2*s3^4*x3^14 + 4/5*s3^3*x3^15 - 9/32*s3^2*x3^16 + 1/17*s3*x3^17

A.7. POLYNMES

417

et ainsi de suite. chaque itration Ci est un polynme en xi+1 et si+1 coecients rationnels, homogne et de degr total n1 + . . . + ni + i. Pour la dernire variable, on intgre entre xk = 0 et xk = 1/k . En supposant connue une borne sur le numrateur et le dnominateur de I , on peut calculer I modulo p pour dirents nombres premiers ne divisant pas le dnominateur de I , puis en dduire par restes chinois la valeur de I modulo le produit de ces nombres premiers, et enn par reconstruction rationnelle la valeur exacte de I .

A.7

Polynmes

Exercice 23 page 133. 1. On peut par exemple (il y a beaucoup dautres solutions) prendre sage: x = polygen(QQ, y ); y = polygen(QQ, x ) Rappelons la dirence, en Sage, entre variables Python et variables mathmatiques. Les variables Python sont des noms qui servent la programmation et dsignent des emplacements en mmoire. Les variables mathmatiques, dont font partie les indtermines des polynmes, sont de nature compltement dirente : ce sont des objets Sage, qui peuvent tre stocks dans des variables Python. Quand on cre une indtermine appele x , rien noblige la stocker dans la variable Python x et rien nempche dy ranger plutt y . 2. On commence par aecter la variable Python x lindtermine x des polynmes coecients rationnels. Lexpression x+1 svalue alors en le polynme x + 1 Q[x], que lon aecte la variable p. Puis lon aecte lentier 2 la variable x. Cela na pas deet sur p, qui vaut toujours x + 1 : ce x-l (lindtermine) na plus rien voir avec la variable Python qui vaut maintenant 2. ce stade p+x svalue en x + 3, et donc la valeur nale de p est x + 3. Exercice 24 page 139. Une solution simple consiste eectuer des divisions euclidiennes successives par les polynmes de Tchebyche pris par degrs dcroissants : si le polynme p rcrire sur la base de Tchebyche est de degr n, on pose p = cn Tn + Rn1 avec cn Q et deg Rn1 n 1, puis Rn1 = cn1 Tn1 + Rn2 , et ainsi de suite. Dans le code Sage suivant, plutt que de renvoyer les coecients cn obtenus comme une simple liste, on a choisi de construire une expression symbolique o le polynme Tn est reprsent comme une fonction inerte (cest--dire garde sous forme non value) T(n,x). sage: T = sage: def ....: ....: ....: ....: ....: sage.symbolic.function_factory.function( T , nargs=2) to_chebyshev_basis(pol): (x,) = pol.variables() res = 0 for n in xrange(pol.degree(), -1, -1): quo, pol = pol.quo_rem(chebyshev_T(n, x)) res += quo * T(n, x)

418 ....: return res

ANNEXE A. SOLUTIONS DES EXERCICES

Testons cette fonction. Pour vrier les rsultats, il sut de substituer notre fonction inerte T la fonction qui calcule les polynmes de Tchebyche, et de dvelopper : sage: p = QQ[ x ].random_element(degree=6); p 4*x^6 + 4*x^5 + 1/9*x^4 - 2*x^3 + 2/19*x^2 + 1 sage: p_cheb = to_chebyshev_basis(p); p_cheb 1069/456*T(0, x) + T(1, x) + 2713/1368*T(2, x) + 3/4*T(3, x) + 55/72*T(4, x) + 1/4*T(5, x) + 1/8*T(6, x) sage: p_cheb.substitute_function(T, chebyshev_T).expand() 4*x^6 + 4*x^5 + 1/9*x^4 - 2*x^3 + 2/19*x^2 + 1 Exercice 25 page 139. Une traduction directe de lalgorithme en Sage donne quelque chose comme : sage: def mydiv(u, v, n): ....: v0 = v.constant_coefficient() ....: quo = 0; rem = u ....: for k in xrange(n+1): ....: c = rem[0]/v0 ....: rem = (rem - c*v) >> 1 # dcalage des coefficients ....: quo += c*x^k ....: return quo, rem (On pourra chronomtrer cette fonction sur des exemples un peu gros, et essayer de rendre le code plus ecace sans changer lalgorithme.) Mais le quotient dans la division par les puissances croissantes jusqu lordre n est simplement le dveloppement en srie de la fraction rationnelle u/v , tronqu lordre n + 1. En utilisant la division de sries formelles (voir 7.5), on peut donc calculer la division suivant les puissances croissantes comme suit. sage: def mydiv2(u, v, n): ....: x = u.parent().gen() ....: quo = (u / (v + O(x^(n+1)))).polynomial() ....: rem = (u - quo*v) >> (n+1) ....: return quo, rem La ligne quo = ... utilise, premirement, quajouter un O() un polynme le convertit automatiquement en srie tronque, et deuximement, que la division dun polynme par une srie se fait par dfaut la prcision du diviseur. Exercice 26 page 141. Tout dabord, on sattend ce que u1010000 ait de lordre de 1010000 chires. Il est donc compltement hors de question de chercher le calculer entirement. Puisquon ne sintresse quaux cinq derniers chires, ce nest pas vraiment un problme : on fera tout le calcul modulo 105 . La mthode par exponentiation rapide prsente en 3.2.4 demande alors quelques dizaines de milliers de multiplications de matrices 1000 1000 coecients dans Z/105 Z. Chacun de ces produits de matrices revient un milliard de multiplications modulo

A.7. POLYNMES

419

105 , ou un peu moins avec un algorithme rapide. Ce nest pas compltement inaccessible, mais un essai sur une seule multiplication laisse penser que le calcul avec Sage prendrait une bonne heure : sage: Mat = MatrixSpace (IntegerModRing(10^5), 1000) sage: m1, m2 = (Mat.random_element() for i in (1,2)) sage: %time m1*m2 CPU times: user 0.24 s, sys: 0.02 s, total: 0.26 s Wall time: 0.26 s Il est possible de faire beaucoup mieux du point de vue algorithmique. Notons S loprateur de dcalage (an )nN (an+1 )nN . Lquation satisfaite par u = (un )nN se rcrit P (S ) u = 0, o P (x) = x1000 23x729 + 5x2 12x 7 ; et pour tout N (notamment N = 10100 ), le terme uN est le premier de la suite S N u. Soit R le reste de la division euclidienne de xN par P . Comme P (S ) u = 0, on a S N u = R(S ) u. Il sut donc de calculer limage de xN dans (Z/105 Z) [x]/ P (x) . On aboutit au code suivant, qui, sur la mme machine, sexcute en une trentaine de secondes : sage: sage: sage: sage: sage: 63477 Poly.<x> = Integers(10^5)[] P = x^1000 - 23*x^729 + 5*x^2 - 12*x - 7 Quo.<s> = Poly.quo(P) op = s^(10^10000) add(op[n]*(n+7) for n in range(1000))

Les cinq chires cherchs sont donc 63477. Lcart entre les deux versions en termes de temps de calcul grandit rapidement avec lordre de la rcurrence. Exercice 27 page 151. 1. Supposons as un+s + as1 un+s1 + + a0 un = 0 pour tout n 0, et notons u(z ) = n=0 un z n . Soit Q(z ) = as + as1 z + + a0 z s . Alors

S (z ) = Q(z ) u(z ) =
n=0

(as un + as1 un1 + + a0 uns )z n ,

avec la convention que un = 0 pour n < 0. Le coecient de z n dans S (z ) est nul pour n s, donc S (z ) est un polynme, et u(z ) = S (z )/Q(z ). Le dnominateur Q(z ) est le polynme rciproque du polynme caractristique de la rcurrence, et le numrateur code les conditions initiales. 2. Les quelques premiers coecients susent pour deviner une rcurrence dordre 3 que satisfont manifestement les coecients donns. En faisant appel rational_reconstruct, on obtient une fraction rationnelle quil sut de dvelopper en srie pour retrouver tous les coecients donns, et des coecients suivants vraisemblables : sage: sage: sage: sage: p = previous_prime(2^30); ZpZx.<x> = Integers(p)[] s = ZpZx([1, 1, 2, 3, 8, 11, 34, 39, 148, 127, 662, 339]) num, den = s.rational_reconstruct(x^12, 6, 6) S = ZpZx.completion(x)

420

ANNEXE A. SOLUTIONS DES EXERCICES sage: map(lift_sym, S(num)/S(den)) [1, 1, 2, 3, 8, 11, 34, 39, 148, 127, 662, 339, 3056, 371, 14602, -4257, 72268, -50489, 369854, -396981] (La fonction lift_sym est celle dnie dans le texte du chapitre. Les 20 premiers coecients de la suite sont largement infrieurs 229 , de sorte quon peut se permettre de drouler la rcurrence modulo 230 puis de remonter le rsultat dans Z plutt que le contraire.) Avec berlekamp_massey, le rsultat est le polynme caractristique de la rcurrence, directement coecients dans Z : sage: berlekamp_massey([1, 1, 2, 3, 8, 11, 34, 39, 148, 127]) x^3 - 5*x + 2 On vrie que tous les coecients donns satisfont un+3 = 5un+1 2un , et lon devine partir de l les coecients manquants 72268 = 5 14602 2 371, 50489 = 5 (4257) 2 14602, et ainsi de suite.

Exercice 28 page 151. On commence par calculer un polynme de degr 3 qui satisfait la condition dinterpolation donne. Cela fournit une solution avec deg p = 3 : sage: R.<x> = GF(17)[] sage: pairs = [(0,-1), (1,0), (2,7), (3,5)] sage: s = R(QQ[ x ].lagrange_polynomial(pairs)); s 6*x^3 + 2*x^2 + 10*x + 16 sage: [s(i) for i in range(4)] [16, 0, 7, 5] On sest ainsi ramen au problme de reconstruction rationnelle p/q s mod x(x 1)(x 2)(x 3). Comme s nest pas inversible modulo x(x 1)(x 2)(x 3) (car s(1) = 0), il ny a pas de solution avec p constant. Avec deg p = 1, on trouve : sage: s.rational_reconstruct(mul(x-i for i in range(4)), 1, 2) (15*x + 2, x^2 + 11*x + 15) Exercice 29 page 155. Le raisonnement est le mme que dans lexemple du x texte : on rcrit lquation tan x = 0 (1 + tan2 t) dt, et lon cherche un point xe en partant de la condition initiale tan(0) = 0. sage: S.<x> = PowerSeriesRing(QQ) sage: t = S(0) sage: for i in range(7): # ici t est correct jusqu au degr 2i+1 ....: # le O(x^15) vite que l ordre de troncature ne grandisse ....: t = (1+t^2).integral() + O(x^15) sage: t x + 1/3*x^3 + 2/15*x^5 + 17/315*x^7 + 62/2835*x^9 + 1382/155925*x^11 + 21844/6081075*x^13 + O(x^15)

A.8. ALGBRE LINAIRE

421

A.8

Algbre linaire

Exercice 30 page 175. (Polynme minimal de vecteurs ) 1. A est un polynme annulateur de tous les vecteurs ei de la base. Il est donc un commun multiple des A,ei . Soit le ppcm des A,ei . Donc |A . Par ailleurs, (A) = (A)e1 . . . (A)en = 0 est annulateur de la matrice A. Do A | . Comme ces polynmes sont unitaires, ils sont gaux. 2. Dans ce cas, tous les A,ei sont sous la forme i , o est un polynme irrductible. Daprs la question prcdente, A concide donc avec celui des i ayant la puissance i maximale. 3. Soit un polynme annulateur de e = ei + ej et 1 = A,ei , 2 = A,ej . On a 2 (A)(A)ei = 2 (A)(A)e (A)2 (A)ej = 0. Donc 2 est annulateur de ei et est donc divisible par 1 . Or 1 et 2 tant premiers entre eux, on a 1 |. De la mme faon on montre que 2 |, donc est un multiple de 1 2 . Or 1 2 est annulateur de e, donc = 1 2 . 4. P1 et P2 tant premiers entre eux, il existe deux polynmes et tels que 1 = P1 + P2 . Ainsi pour tout x, on a x = (A)P1 (A)x + (A)P2 (A)x = x2 + x1 , o x1 = (A)P2 (A)x et x2 = (A)P1 (A)x. Comme A = P1 P2 , P1 est annulateur de x1 = (A)P2 (A)x (de mme P2 est annulateur de x2 ). Si pour tout x, x1 = 0, alors P2 est annulateur de A et est donc un multiple de P1 P2 , do 1 = P1 ( + P2 ), qui implique deg P1 = 0. Il existe donc un x1 non nul tel que P1 soit un polynme annulateur de x1 . 1 un polynme annulateur de Montrons que P1 est minimal pour x1 : soit P 1 P2 x1 . Alors P1 (A)P2 (A)x = P2 (A)P1 (A)x1 + P1 (A)P2 (A)x2 = 0, donc P est un multiple de A = P1 P2 . Ainsi P1 |P1 et P1 est donc le polynme minimal de x1 . Le raisonnement est identique pour x2 .
mi i 5. Pour chaque facteur m est le polynme i , il existe un vecteur xi dont i minimal et le vecteur x1 + + xk a A pour polynme minimal.

6. On calcule dabord le polynme minimal de la matrice A. sage: A = matrix(GF(7),[[0,0,3,0,0],[1,0,6,0,0],[0,1,5,0,0], ....: [0,0,0,0,5],[0,0,0,1,5]]) sage: P = A.minpoly(); P x^5 + 4*x^4 + 3*x^2 + 3*x + 1 sage: P.factor() (x^2 + 2*x + 2) * (x^3 + 2*x^2 + x + 4) Il est de degr maximal. sage: e1 = identity_matrix(GF(7),5)[0] sage: e4 = identity_matrix(GF(7),5)[3] sage: A.transpose().maxspin(e1) [(1, 0, 0, 0, 0), (0, 1, 0, 0, 0), (0, 0, 1, 0, 0)] sage: A.transpose().maxspin(e4) [(0, 0, 0, 1, 0), (0, 0, 0, 0, 1)] sage: A.transpose().maxspin(e1 + e4)

422

ANNEXE A. SOLUTIONS DES EXERCICES [(1, 0, 0, 1, 0), (0, 1, 0, 0, 1), (0, 0, 1, 5, 5), (3, 6, 5, 4, 2), (1, 5, 3, 3, 0)] La fonction maxspin itre un vecteur gauche. On lapplique donc sur la transpose de la matrice an dobtenir la liste des itrs de Krylov linairement indpendants partir des vecteurs e1 et e4 . Le polynme minimal de e1 a donc degr 3, celui de e4 a degr 2, et celui de e1 + e4 a degr 5. On note que la forme particulire de la matrice fait que les vecteurs e1 et e4 engendrent comme itrs dautres vecteurs de la base canonique. Cette forme est appele la forme normale de Frobenius (voir 8.2.3). Elle dcrit de quelle manire la matrice dcompose lespace en sous-espaces cycliques invariants qui sont engendrs par des vecteurs de la base canonique.

Exercice 31 page 182. (Test si deux matrices sont semblables ) sage: def Semblables(A, B): ....: F1, U1 = A.frobenius(2) ....: F2, U2 = B.frobenius(2) ....: if F1 == F2: ....: return True, ~U2*U1 ....: else: ....: return False, F1 - F2 sage: B = matrix(ZZ, [[0,1,4,0,4],[4,-2,0,-4,-2],[0,0,0,2,1], ....: [-4,2,2,0,-1],[-4,-2,1,2,0]]) sage: U = matrix(ZZ, [[3,3,-9,-14,40],[-1,-2,4,2,1],[2,4,-7,-1,-13], ....: [-1,0,1,4,-15],[-4,-13,26,8,30]]) sage: A = (U^-1 * B * U).change_ring(ZZ) sage: ok, V = Semblables(A, B); ok True sage: V [ 1 2824643/1601680 -6818729/1601680 -43439399/11211760 73108601/11211760] [ 0 342591/320336 -695773/320336 -2360063/11211760 -10291875/2242352] [ 0 -367393/640672 673091/640672 -888723/4484704 15889341/4484704] [ 0 661457/3203360 -565971/3203360 13485411/22423520 -69159661/22423520] [ 0 -4846439/3203360 7915157/3203360 -32420037/22423520 285914347/22423520] sage: ok, V = Semblables(2*A, B); ok False

A.9

Systmes polynomiaux

Exercice 32 page 184. tant donn un anneau de polynmes ring, la fonction test_poly renvoie la somme de tous les monmes de degr total born par la

A.9. SYSTMES POLYNOMIAUX

423

valeur du paramtre deg. Son code est relativement compact, mais procde avec quelques contorsions. La premire instruction construit et aecte la variable locale monomials un ensemble (reprsent par un objet spcique SubMultiset, voir 15.2) de listes chacune deg lments dont le produit constitue un terme du polynme : sage: ring = QQ[ x,y,z ]; deg = 2 sage: tmp1 = [(x,)*deg for x in (1,) [(1, 1), (x, x), (y, y), (z, z)] sage: tmp2 = flatten(tmp1); tmp2 [1, 1, x, x, y, y, z, z] sage: monomials = Subsets(tmp2, deg, SubMultiset of [1, 1, z, z, y, y, x, sage: monomials.list() [[1, 1], [1, z], [1, y], [1, x], [z, [y, x], [x, x]]

+ ring.gens()]; tmp1

submultiset=True); monomials x] of size 2 z], [z, y], [z, x], [y, y],

Pour cela, on commence par adjoindre 1 au tuple des indtermines, et remplacer chaque lment du rsultat par un tuple de deg copies de lui-mme, et regrouper ces tuples dans une liste. Remarquons lusage de la syntaxe (x,) qui dnote un tuple un seul lment, ainsi que des oprateurs de concatnation + et de rptition * des tuples. La liste de tuples obtenue est aplatie par flatten en une liste contenant exactement deg fois chacune des indtermines et la constante 1. La fonction Subsets avec loption submultiset=True calcule ensuite lensemble des parties de cardinal deg du multiensemble (collection sans ordre mais avec rptitions) des lments de cette liste. Lobjet monomials est itrable : ainsi, (mul(m) for m in monomials) est un gnrateur Python qui parcourt les monmes fabriqus en passant mul les listes reprsentant les parties. Ce gnrateur est nalement pass add. La dernire ligne pourrait tre remplace par add(map(mul, monomials)). On peut aussi crire ((1,) + ring.gens())*deg pour simplier lexpression [(x,)*deg for x in (1,) + ring.gens()]. Exercice 33 page 185. Un exemple de la page daide PolynomialRing? suggre une solution : pour obtenir une famille dindtermines complique ici, indexe par les nombres premiers on passe PolynomialRing une liste fabrique par comprhension (voir 3.3.2) : sage: [ x%d % n for n in [2,3,5,7]] [ x2 , x3 , x5 , x7 ] sage: R = PolynomialRing(QQ, [ x%d % n for n in primes(40)]) sage: R.inject_variables() Defining x2, x3, x5, x7, x11, x13, x17, x19, x23, x29, x31, x37 La mthode inject_variables initialise des variables Python x2, x3, ... contenant chacune le gnrateur correspondant de R. Exercice 34 page 190. On vrie que (3, 2, 1) est lunique solution relle, par exemple via

424

ANNEXE A. SOLUTIONS DES EXERCICES

sage: R.<x,y,z> = QQ[] sage: J = R.ideal(x^2*y*z-18, x*y^3*z-24, x*y*z^4-6) sage: J.variety(AA) [{x: 3, z: 1, y: 2}] ou encore par sage: V = J.variety(QQbar) sage: [u for u in V if all(a in AA for a in u.values())] [{z: 1, y: 2, x: 3}] Une substitution de la forme (x, y, z ) ( a x, b y, c z ) avec k = 1 laisse le systme invariant si et seulement si (a, b, c) est solution modulo k du systme linaire homogne de matrice sage: M = matrix([ [p.degree(v) for v in (x,y,z)] ....: for p in J.gens()]); M [2 1 1] [1 3 1] [1 1 4] En calculant son dterminant sage: M.det() 17 on voit que k = 17 convient. Il ny a plus qu trouver un lment non nul du noyau : sage: M.change_ring(GF(17)).right_kernel() Vector space of degree 3 and dimension 1 over Finite Field of size 17 Basis matrix: [1 9 6] Exercice 35 page 203. Cest presque immdiat : sage: L.<a> = QQ[sqrt(2-sqrt(3))]; L Number Field in a with defining polynomial x^4 - 4*x^2 + 1 sage: R.<x,y> = QQ[] sage: J1 = (x^2 + y^2 - 1, 16*x^2*y^2 - 1)*R sage: J1.variety(L) [{y: 1/2*a, x: 1/2*a^3 - 2*a}, {y: 1/2*a, x: -1/2*a^3 + 2*a}, {y: -1/2*a, x: 1/2*a^3 - 2*a}, {y: -1/2*a, x: -1/2*a^3 + 2*a}, {y: 1/2*a^3 - 2*a, x: 1/2*a}, {y: 1/2*a^3 - 2*a, x: -1/2*a}, {y: -1/2*a^3 + 2*a, x: 1/2*a}, {y: -1/2*a^3 + 2*a, x: -1/2*a}] Ainsi, par exemple pour la premire solution ci-dessus, on a : x= 1 (2 3)3/2 2 2 2 3, y= 1 2 2 3.

Exercice 36 page 207. Nous avons vu comment obtenir une base B du Q-espace vectoriel Q[x, y ]/J2 :

A.9. SYSTMES POLYNOMIAUX sage: R.<x,y> = QQ[]; J2 = (x^2+y^2-1, 4*x^2*y^2-1)*R sage: basis = J2.normal_basis(); basis [x*y^3, y^3, x*y^2, y^2, x*y, y, x, 1]

425

On calcule ensuite limage de B par mx , et on en dduit la matrice de mx dans la base B : sage: xbasis = [(x*p).reduce(J2) for p in basis]; xbasis [1/4*y, x*y^3, 1/4, x*y^2, -y^3 + y, x*y, -y^2 + 1, x] sage: mat = matrix([ [xp[q] for q in basis] ....: for xp in xbasis]) sage: mat [ 0 0 0 0 0 1/4 0 0] [ 1 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 1/4] [ 0 0 1 0 0 0 0 0] [ 0 -1 0 0 0 1 0 0] [ 0 0 0 0 1 0 0 0] [ 0 0 0 -1 0 0 0 1] [ 0 0 0 0 0 0 1 0] Le polynme x et ses racines sont alors donns par (voir chapitres 2 et 8) : sage: x^8 sage: [x == charpoly = mat.characteristic_polynomial(); charpoly 2*x^6 + 3/2*x^4 - 1/2*x^2 + 1/16 solve(SR(charpoly), SR(x)) -1/2*sqrt(2), x == 1/2*sqrt(2)]

On peut observer sur cet exemple que les racines de sont les abscisses des points de V (J2 ). Pour un idal J quelconque, supposons () = 0 avec C. Cest donc que est une valeur propre de mx . Soit p Q[x, y ] \ J un reprsentant dun vecteur propre associ : on a xp = p + q pour un certain q J . Comme p / J , on peut trouver (x0 , y0 ) V (J ) tel que p(x0 , y0 ) = 0, et lon a alors (x0 ) p(x0 , y0 ) = q (x0 , y0 ) = 0, do = x0 . Exercice 37 page 217. Les expressions sin, cos, sin(2) et cos(2) sont lies par les formules trigonomtriques classiques sin2 + cos2 = 1, sin(2) = 2(sin )(cos ), cos(2) = cos2 sin2 .

Posons pour allger les notations c = cos et s = sin . Lidal u (s + c), v (2sc + c2 s2 ), s2 + c2 1 de Q[s, c, u, v ] traduit les dnitions de u() et v () de lnonc ainsi que la relation entre sinus et cosinus. Pour un ordre monomial qui limine prioritairement s et c, la forme canonique de s6 modulo cet idal donne le rsultat recherch.

426

ANNEXE A. SOLUTIONS DES EXERCICES

sage: R.<s, c, u, v> = PolynomialRing(QQ, order= lex ) sage: Rel = ideal(u-(s+c), v-(2*s*c+c^2-s^2), s^2+c^2-1) sage: Rel.reduce(s^6) 1/16*u^2*v^2 - 3/8*u^2*v + 7/16*u^2 + 1/8*v^2 - 1/8*v - 1/8

A.10

quations direntielles et suites dnies par une relation de rcurrence

Exercice 38 page 227. (quations direntielles variables sparables ) 1. Utilisons la mme mthode que dans la section 10.1.2 : sage: x = var( x ) sage: y = function( y ,x) sage: ed = (desolve(y*diff(y,x)/sqrt(1+y^2) == sin(x),y)); ed sqrt(y(x)^2 + 1) == c - cos(x) Le mme problme apparat. On impose que c-cos(x) soit positif : sage: sage: sage: [y(x) y(x) c = ed.variables()[0] assume(c-cos(x) > 0) sol = solve(ed,y) ; sol == -sqrt(c^2 - 2*c*cos(x) + cos(x)^2 - 1), == sqrt(c^2 - 2*c*cos(x) + cos(x)^2 - 1)]

sage: P = Graphics() sage: for j in [0,1]: ....: for k in range(0,20,2): ....: P += plot(sol[j].subs_expr(c == 2+0.25*k).rhs(), ....: x,-3,3) sage: P
6 4 2 -3 -2 -1 -2 -4 -6 1 2 3

2. Mme mthode : sage: solu = desolve(diff(y,x) == sin(x)/cos(y),y,\ ....: show_method = True) sage: solu [sin(y(x)) == c - cos(x), separable ] sage: solve(solu[0],y)

A.11. NOMBRES VIRGULE FLOTTANTE [y(x) == -arcsin(-c + cos(x))]

427

Exercice 39 page 229. (quations homognes ) On vrie que lquation xyy = x2 + y 2 dnie sur ]0, +[ et sur ], 0[ est bien homogne, puis on essaie de la rsoudre par le changement de fonction inconnue indiqu dans lexemple trait la section 10.1.2. sage: x = var( x ) sage: y = function( y ,x) sage: id(x) = x sage: u = function( u ,x) sage: d = diff(u*id,x) sage: DE = (x*y*d == x**2+y**2).subs_expr(y == u*id) sage: equ = desolve(DE,u) sage: solu = solve(equ,u) sage: solu [u(x) == -sqrt(2*c + 2*log(x)), u(x) == sqrt(2*c + 2*log(x))] sage: Y = [x*solu[0].rhs() , x*solu[1].rhs()] sage: Y[0] -sqrt(2*c + 2*log(x))*x On peut ajouter des conditions sur x (avec assume) pour se rappeler que lquation nest pas dnie en 0.

A.11

Nombres virgule ottante

Exercice 40 page 246. On propose deux solutions. 1. Eectuons le calcul sans utiliser les mthodes de la classe RealField qui donnent la mantisse et lexposant dun nombre. On vrie dabord que 299 < 1030 < 2100 (on remarque que 1030 = (103 )10 (210 )10 ). sage: sage: sage: True sage: True sage: sage: sage: sage: sage: ....: ....: ....: ....: R100=RealField(100) x=R100(10^30) x>2^99 x<2^100

On calcule ensuite la mantisse de x : e=2^100 s1=10^30 mantisse=[] nbchiffres=0 # compteur du nombre de chiffres ncessaires while s1>0: e/=2 if e<=s1: mantisse.append(1) s1-=e

428

ANNEXE A. SOLUTIONS DES EXERCICES ....: else: ....: mantisse.append(0) ....: nbchiffres+=1 sage: print mantisse [1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1] sage: print "nombre de chiffres ncessaires ",nbchiffres nombre de chiffres ncessaires 70 Les chires binaires de la mantisse au-del du soixante-dixime sont nuls. Le nombre le plus proche de 1030 est donc obtenu en ajoutant 2100 la mantisse, do le rsultat, x.ulp() vaut : 2100 2100 = 1.

2. En utilisant la mthode sign_mantissa_exponent() de la classe RealField, on a directement : sage: R100=RealField(100) sage: x=R100(10^30) sage: s,m,e = x.sign_mantissa_exponent() sage: print s,m,e 1 1000000000000000000000000000000 0 La commande m.binary() permet de constater quon obtient bien la mme mantisse dans les deux cas. Exercice 41 page 249. 1. Cherchons dabord les valeurs de , et dans la formule : un = 100n+1 + 6n+1 + 5n+1 . 100n + 6n + 5n (A.1)

Pourquoi ne pas utiliser Sage pour cela ? On se sert des valeurs de u0 , u1 et u2 pour obtenir et rsoudre un systme dquations, dont les inconnues sont , et . Dnissons la rcurrence et la solution gnrale : sage: var("u0 u1 u2 alpha beta gamma n") (u0, u1, u2, alpha, beta, gamma, n) sage: recurrence = lambda a,b: 111-1130/a+3000/(a*b) sage: gener1 = lambda n :(alpha*100^n+beta*6^n+gamma*5^n) sage: solGen = lambda n: gener1(n+1)/gener1(n) Calculons u2 en fonction de u1 et u0 et posons le systme : sage: u2 = recurrence(u1,u0) sage: s = [u2==solGen(2),u1==solGen(1),u0==solGen(0)] sage: t = [s[i].substitute(u0=2,u1=-4) for i in range(0,3)] puis rsolvons-le : sage: solve(t,alpha,beta,gamma)

A.11. NOMBRES VIRGULE FLOTTANTE [[alpha == 0, beta == -3/4*r1, gamma == r1]]

429

Le calcul nous montre que reste indtermin. Nous devons vrier que nous obtenons bien une solution gnrale, cest-dire que lquation (A.1) est vrie pour tout n : sage: sage: sage: sage: 0 alpha=0 beta = -3/4*gamma final=solGen(n)-recurrence(solGen(n-1),solGen(n-2)) print final.simplify_full()

On peut prendre nimporte quelle valeur pour , par exemple = 4, et lon a alors = 3 et = 0. 2. On dnit une procdure qui implmente la rcurrence, avec des coecients exacts an de pouvoir la rutiliser direntes prcisions : sage: def recur(x1,x0): ....: return 111 - 1130/x1 + 3000/(x0*x1) Les conditions initiales en revanche sont prises dans RealField(), de sorte que le calcul a lieu dans ce domaine : sage: u0 = 2. sage: u1 = -4. sage: for i in range(1,25): ....: x = recur(u1,u0) ....: print i,x ....: u0 = u1 ....: u1 = x 1 18.5000000000000 2 9.37837837837838 3 7.80115273775217 4 7.15441448097533 5 6.80678473692481 6 6.59263276872179 .................. 23 99.9999986592167 24 99.9999999193218 La suite converge visiblement vers 100 ! 3. Lexplication du comportement du programme tient ce que les valeurs un ne sont pas calcules exactement : si lon considre la rcurrence dnie en prenant pour conditions initiales les termes un1 et un2 , calculs avec une erreur darrondi, la formule (A.1) ne donne plus la solution gnrale. Cherchons les valeurs stationnaires de la rcurrence : sage: var("x") x

430

ANNEXE A. SOLUTIONS DES EXERCICES sage: solve(x==recurrence(x,x),x) [x == 100, x == 5, x == 6] Il y a 3 valeurs stationnaires : 100, 5 et 6. La convergence vers 100 observe en prsence derreurs darrondi provient de considrations de stabilit de ces 3 valeurs (considrations qui sont hors des limites de cet exercice).

4. Augmenter la prcision ne sert rien, la suite converge toujours vers 100 : sage: RL = RealField(5000) sage: u0 = RL(2) sage: u1 = RL(-4) sage: for i in range(1,2500): ....: x = recur(u1,u0) ....: u0 = u1 ....: u1= x sage: x 100.00000000000000000000000000000000000000000000000000000... Il sut quun seul des ui ne soit pas calcul exactement, pour que la suite diverge ( nest plus nul). 5. Le programme ne subit que peu de modications. On fait en sorte que les variables u0 et u1 soient initialiss comme entires : sage: sage: sage: ....: ....: ....: sage: 6.0 u0 = 2 u1 = -4 for i in range(1,2500): x = recur(u1,u0) u0 = u1 u1 = x float(x)

On trouve bien la valeur 6.0, mais si on imprime x, on voit lnorme quantit dinformation utilise par le calcul (impression non reproduite ici !). En imprimant x-6, on vrie que la limite na pas t atteinte : la taille occupe par reprsentation machine de x na aucune raison de diminuer si on poursuit les itrations.

A.12

quations non linaires

Exercice 42 page 267. On a vu que le mot cl return termine lexcution de la fonction. Il sut donc de tester si f(u) est nul ou pas. Pour viter dvaluer la fonction f en u plusieurs reprises, on stocke sa valeur dans une variable. Aprs modication on obtient donc la fonction suivante. sage: def intervalgen(f, phi, s, t): ....: assert (f(s) * f(t) < 0), \ ....: Wrong arguments: f(%s) * f(%s) >= 0) %(s, t)

A.12. QUATIONS NON LINAIRES ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: yield s yield t while 1: u = phi(s, t) yield u fu = f(u) if fu == 0: return if fu * f(s) < 0: t = u else: s = u

431

Testons cette fonction avec une quation dont on connat une solution, par exemple construite partir dune fonction linaire. sage: f(x) = 4 * x - 1 sage: a, b = 0, 1 sage: phi(s, t) = (s + t) / 2 sage: list(intervalgen(f, phi, a, b)) [0, 1, 1/2, 1/4] Exercice 43 page 267. La fonction phi passe en paramtre de intervalgen dtermine le point o diviser un intervalle. Il sut donc de donner cette fonction la dnition adquate. sage: sage: sage: sage: sage: After f(x) = 4 * sin(x) - exp(x) / 2 + 1 a, b = RR(-pi), RR(pi) def phi(s, t): return RR.random_element(s, t) random = intervalgen(f, phi, a, b) iterate(random, maxit=10000) 19 iterations: 2.15848379485564

Exercice 44 page 276. Il est naturel de vouloir faire les calculs avec Polynomial Ring(SR, x ). Une dicult technique vient de ce que cet objet nimplante pas la mthode roots(). sage: basering.<x> = PolynomialRing(SR, x ) sage: p = x^2 + x sage: p.parent() Univariate Polynomial Ring in x over Symbolic Ring sage: p.roots(multiplicities=False) Traceback (most recent call last): ... NotImplementedError La fonction solve() nest pas non plus prvue pour fonctionner avec lobjet PolynomialRing(SR, x ). Une alternative serait dutiliser SR, qui implante ces mthodes, mais il nore pas dquivalent de la mthode lagrange_polynomial()

432 de PolynomialRing(SR, ces objets. sage: sage: sage: sage: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....: ....:

ANNEXE A. SOLUTIONS DES EXERCICES x ). On est donc amen faire des conversions entre

from collections import deque basering = PolynomialRing(SR, x ) q, method = None, None def quadraticgen(f, r, s): global q, method t = r - f(r) / f.derivative()(r) method = newton yield t pts = deque([(p, f(p)) for p in (r, s, t)], maxlen=3) while True: q = basering.lagrange_polynomial(pts) p = sum([c*x^d for d, c in enumerate(q.list())]) roots = [r for r in p.roots(x,multiplicities=False) \ if CC(r).is_real()] approx = None for root in roots: if (root - pts[2][0]) * (root - pts[1][0]) < 0: approx = root break elif (root - pts[0][0]) * (root - pts[1][0]) < 0: pts.pop() approx = root break if approx: method = quadratic else: method = dichotomy approx = (pts[1][0] + pts[2][0]) / 2 pts.append((approx, f(approx))) yield pts[2][0]

Il est maintenant possible dacher les premiers termes de la suite dnie par la mthode de Brent. Attention, les calculs sont relativement longs eectuer (et les rsultats impossibles acher sur une page de ce livre...). sage: basering = PolynomialRing(SR, x ) sage: a, b = pi/2, pi sage: f(x) = 4 * sin(x) - exp(x) / 2 + 1 sage: generator = quadraticgen(f, a, b) sage: print generator.next() 1/2*pi - (e^(1/2*pi) - 10)*e^(-1/2*pi) En excutant le code suivant, le lecteur patient pourra visualiser les arcs de paraboles utiliss dans les calculs des premiers termes de la suite. sage: generator = quadraticgen(f, a, b)

A.13. ALGBRE LINAIRE NUMRIQUE sage: g = plot(f, a, b, rgbcolor= blue ) sage: g += point((a, 0), rgbcolor= red , legend_label= 0 ) sage: g += point((b, 0), rgbcolor= red , legend_label= 1 ) sage: data = { 2 : blue , 3 : violet , 4 : green } sage: for l, color in data.iteritems(): ....: u = RR(generator.next()) ....: print u, method ....: g += point((u, 0), rgbcolor=color, legend_label=l) ....: if method == quadratic : ....: q = sum([c*x^d for d, c in enumerate(q.list())]) ....: g += plot(q, 0, 5, rgbcolor=color) 2.64959209030252 newton 2.17792417785919 quadratic 2.15915701248844 quadratic sage: g.show()

433

A.13

Algbre linaire numrique

Exercice 45 page 284. Daprs la formule de Sherman et Morrison, la rsolution de Bx = f quivaut celle de Ax = (I + u t v A1 )f avec = (1 + t v A1 u)1 . On procde alors de la manire suivante. 1. On calcule w solution de Aw = u, puis = (1 + t v w)1 . 2. On calcule z solution de Az = f puis g = t v z (qui est un scalaire). 3. On calcule alors h = (f gu) et on rsout Ax = h ; x est bien la solution de Bx = f . On remarque quon a rsolu 3 systmes linaires avec la matrice factorise A, soit la rsolution de 6 systmes linaires matrice triangulaire. Chacune de ces rsolutions cote de lordre de n2 oprations, bien moins que le cot dune factorisation (qui est de lordre de n3 ). Pour vrier la formule de Sherman et Morrison, il sut de multiplier ( droite) le second membre de la formule par A + u t v puis de vrier que cette expression est gale la matrice identit. Exercice 46 page 288. On considre la factorisation de Cholesky A = C t C , puis la dcomposition en valeurs singulires de C : C = U t V . Alors, X = U t U . En eet : A = C t C = (U t V )(V t U ) = U t U U t U = X 2 . Fabriquons une matrice alatoire symtrique dnie positive : sage: sage: sage: sage: sage: m = random_matrix(RDF,4) a = transpose(m)*m c = a.cholesky() U,S,V = c.SVD() X = U*S*transpose(U)

Vrions que X 2 a est nulle (modulo erreurs numriques) : sage: M = (X*X-a) sage: all(abs(M[i,j]) < 10^-14 ....: for i in range(4) for j in range(4) )

434 True

ANNEXE A. SOLUTIONS DES EXERCICES

A.14

Intgration numrique et quations direntielles

Exercice 47 page 314. (Calcul des coecients de Newton-Cotes ) 1. En remarquant que Pi est de degr n 1 (donc la formule (14.1) sapplique) et que Pi (j ) = 0 pour j {0, . . . , n 1} et j = i, on en dduit
n1

Pi (x) dx = wi Pi (i)
0

soit wi =

n1 0

Pi (x) dx . Pi (i)

2. Le calcul des poids sen dduit simplement : sage: x = sage: def ....: ....: ....: var( x ) NCRule(n): P = prod([x - j for j in xrange(n)]) return [integrate(P / (x-i), x, 0, n-1) \ / (P/(x-i)).subs(x=i) for i in xrange(n)]

3. Par un simple changement de variable :


b

f (x) dx =
a

ba n1

n1

f
0

a+

ba u du. n1

4. En appliquant la formule prcdente, on trouve le programme suivant : sage: def QuadNC(f, a, b, n): ....: W = NCRule(n) ....: ret = 0 ....: for i in xrange(n): ....: ret += f(a + (b-a)/(n-1)*i) * W[i] ....: return (b-a)/(n-1)*ret Avant de comparer la prcision de cette mthode avec dautres, nous pouvons dj vrier quelle ne renvoie pas de rsultats incohrents : sage: QuadNC(lambda u: 1, 0, 1, 12) 1 sage: N(QuadNC(sin, 0, pi, 10)) 1.99999989482634 Comparons succinctement la mthode obtenue avec les fonctions de GSL sur les intgrales I2 et I3 : sage: numerical_integral(x * log(1+x), 0, 1) (0.25, 2.7755575615628914e-15)

A.15. DNOMBREMENT ET COMBINATOIRE sage: N(QuadNC(lambda x: x * log(1+x), 0, 1, 19)) 0.250000000000000 sage: numerical_integral(sqrt(1-x^2), 0, 1) (0.785398167726482..., 9.042725224567119...e-07) sage: N(pi/4) 0.785398163397448 sage: N(QuadNC(lambda x: sqrt(1-x^2), 0, 1, 20)) 0.784586419900198

435

Remarquons que la qualit du rsultat dpend du nombre de points utiliss : sage: [N(QuadNC(lambda x: x * log(1+x), 0, 1, n) - 1/4) ....: for n in [2, 8, 16]] [0.0965735902799726, 1.17408932943930e-7, 2.13546194616221e-13] sage: [N(QuadNC(lambda x: sqrt(1-x^2), 0, 1, n) - pi/4) ....: for n in [2, 8, 16]] [-0.285398163397448, -0.00524656673640445, -0.00125482109302663] Une comparaison plus intressante entre les direntes fonctions dintgration de Sage et notre mthode QuadNC demanderait de la convertir en une mthode adaptative qui subdivise automatiquement lintervalle considr comme le fait numerical_integral.

A.15

Dnombrement et combinatoire

Exercice 48 page 326. (Probabilit de tirer un carr au Poker ) Construisons lensemble des carrs : sage: Symboles = FiniteEnumeratedSet( ....: ["Coeur","Carreau","Pique","Trefle"]) sage: Valeurs = FiniteEnumeratedSet([2, 3, 4, 5, 6, 7, 8, 9, 10, ....: "Valet", "Dame", "Roi", "As"]) sage: Carres = CartesianProduct((Arrangements(Valeurs,2)), Symboles) Nous avons utilis FiniteEnumeratedSet plutt que Set an de spcier lordre des symboles, des valeurs, et donc des carrs : sage: [[[2, [[2, ... [[ As Carres.list() 3], Coeur ], 3], Carreau ], , Roi ], Trefle ]]

La liste prcdente commence par un carr de deux complt par un 3 de cur, et termine par un carr das complt par un roi de tre. Au total, il y a 624 carrs : sage: Carres.cardinality() 624

436

ANNEXE A. SOLUTIONS DES EXERCICES

Rapport au nombre de mains, on obtient une probabilit dune chance sur 4165 dobtenir un carr lorsque lon tire une main au hasard : sage: Cartes = CartesianProduct(Valeurs, Symboles).map(tuple) sage: Mains = Subsets(Cartes, 5) sage: Carres.cardinality() / Mains.cardinality() 1/4165 Exercice 49 page 326. (Probabilit de tirer une quinte ush et une couleur au Poker ) Choisir une quinte ush revient choisir par exemple sa plus petite carte (entre 1 et 10) et son symbole. Il y en a donc 40. sage: QuinteFlush = CartesianProduct(srange(1, 11), Symboles) sage: QuinteFlush.cardinality() 40 Il y a donc 5108 couleurs : sage: ToutesCouleurs = CartesianProduct(Subsets(Valeurs,5),Symboles) sage: ToutesCouleurs.cardinality() - QuinteFlush.cardinality() 5108 Au nal la probabilit dobtenir une couleur en tirant une main au hasard est denviron deux sur mille : sage: _ / Mains.cardinality() 1277/649740 sage: float(_) 0.0019654015452334776 Il serait satisfaisant deectuer le calcul prcdent par opration ensembliste, en construisant explicitement lensemble des couleurs comme dirence de ToutesCouleurs et de QuinteFlush. Cependant il nexiste pas dalgorithme gnrique ecace pour calculer la dirence A \ B de deux ensembles : sans information supplmentaire, il ny a gure mieux que de parcourir tous les lments de A et de tester sils sont dans B . Dans le calcul ci-dessus, nous avons utilis le fait que B est inclus dans A, ce que Sage ne peut deviner priori. Un autre obstacle, quoique facile dpasser, est quil faudrait que les lments de B et de A soient reprsents de la mme faon. Exercice 50 page 326. Nous nous contenterons dillustrer le cas de la main pleine, forme dun brelan et dune paire. Commenons par implanter une fonction testant si une main est pleine. Pour une criture concise, nous utilisons la mthode suivante permettant de compter les rptitions des lettres dun mot : sage: Word([ a , b , b , a , a , b , a ]).evaluation_dict() { a : 4, b : 3} sage: def est_main_pleine(main): ....: symboles = Word([valeur for (valeur, symbole) in main]) ....: repetitions = sorted(symboles.evaluation_dict().values()) ....: return repetitions == [2,3]

A.15. DNOMBREMENT ET COMBINATOIRE sage: est_main_pleine({(5, Carreau ), (6, Carreau ), (6, Coeur ), ....: (5, Pique ), (1, Pique )}) False sage: est_main_pleine({(3, Trefle ), (3, Pique ), (3, Coeur ), ....: (2, Trefle ), (2, Pique )}) True

437

Nous automatisons maintenant lestimation de la proportion de mains pleines. Plus gnralement, la fonction suivante estime la proportion dlments de lensemble ni ensemble satisfaisant predicat. Elle fait lhypothse que lensemble est muni dune mthode random_element implantant un tirage alatoire uniforme. sage: def estimation_proportion(ensemble, predicat, n): ....: compteur = 0 ....: for i in range(n): ....: if predicat(ensemble.random_element()): ....: compteur += 1 ....: return compteur/n sage: float(estimation_proportion(Mains, est_main_pleine, 10000)) 0.0009999999999999998 Faisons maintenant le calcul symboliquement. Choisir une main pleine revient choisir un couple de valeurs distinctes, lune pour le brelan, lautre pour la paire, ainsi quun ensemble de trois symboles pour le brelan et un autre de deux symboles pour la paire : sage: MainsPleines = CartesianProduct(Arrangements(Valeurs, 2), ....: Subsets(Symboles, 3), Subsets(Symboles, 2)) Voici par exemple, une main pleine avec un brelan de deux et une paire de trois : sage: MainsPleines.first() [[2, 3], { Trefle , Pique , Carreau }, { Pique , Trefle }] La probabilit de tirer une main pleine est de : sage: float(MainsPleines.cardinality() / Mains.cardinality()) 0.0014405762304921968 Exercice 51 page 326. (Comptage manuel des arbres binaires complets) Il y a un arbre binaire complet avec une feuille et un avec deux feuilles. Pour n = 3, 4 et 5 feuilles, on trouve respectivement 2, 5 et 14 arbres (pour n = 4, voir Figure 15.1). Exercice 52 page 336. Les compositions de n k parts sont en bijection avec les sous ensembles de taille k de {1, . . . , n} : lensemble {i1 , i2 , . . . , ik } o i1 < i2 < < ik , on associe la composition (i1 , i2 i1 , . . . , n ik ), et rciproquement. Les formules de dnombrement en dcoulent : il y a 2n compositions de n, et parmi elles n k compositions k parts. Pour retrouver si ces formules sont utilises, on peut regarder limplantation de la mthode cardinality : sage: C = Compositions(5) sage: C.cardinality??

438

ANNEXE A. SOLUTIONS DES EXERCICES

Dans le deuxime cas, le nom de la mthode utilise en interne, _cardinality_ from_iterator, donne dj linformation : la cardinalit est calcule inecacement en itrant travers toute les compositions. sage: C = Compositions(5,length=3) sage: C.cardinality <bound method IntegerListsLex...._cardinality_from_iterator ...> Exercice 53 page 339. Quelques exemples : sage: IntegerVectors(5,3).list() [[5, 0, 0], [4, 1, 0], [4, 0, 1], [3, 2, 0], [3, 1, 1], [3, 0, 2], ... [0, 4, 1], [0, 3, 2], [0, 2, 3], [0, 1, 4], [0, 0, 5]] sage: OrderedSetPartitions(3).cardinality() 13 sage: OrderedSetPartitions(3).list() [[{1}, {2}, {3}], [{1}, {3}, {2}], [{2}, {1}, {3}], [{3}, {1}, {2}], ... [{1, 2}, {3}], [{1, 3}, {2}], [{2, 3}, {1}], [{1, 2, 3}]] sage: OrderedSetPartitions(3,2).random_element() [{1, 3}, {2}] sage: StandardTableaux([3,2]).cardinality() 5 sage: StandardTableaux([3,2]).an_element() [[1, 3, 5], [2, 4]] Exercice 54 page 339. En petite taille, on obtient les matrices de permutation : sage: list(AlternatingSignMatrices(1)) [[1]] sage: list(AlternatingSignMatrices(2)) [ [1 0] [0 1] [0 1], [1 0] ] Le premier nouvel lment apparat pour n = 3 : sage: list(AlternatingSignMatrices(3)) [ [1 0 0] [0 1 0] [1 0 0] [ 0 1 0] [0 0 1] [0 1 0] [0 0 1] [0 1 0] [1 0 0] [0 0 1] [ 1 -1 1] [1 0 0] [0 0 1] [0 1 0] [0 0 1], [0 0 1], [0 1 0], [ 0 1 0], [0 1 0], [1 0 0], [1 0 0] ] En regardant les exemples pour n plus grand, on peut voir quil sagit de toutes les matrices coecients dans {1, 0, 1} telles que, sur chaque ligne et chaque

A.15. DNOMBREMENT ET COMBINATOIRE

439

colonne, les coecients non nuls alternent entre 1 et 1, en commenant et nissant par 1. Exercice 55 page 339. Il y a 25 vecteurs dans (Z/2Z)5 : sage: GF(2)^5 Vector space of dimension 5 over Finite Field of size 2 sage: _.cardinality() 32 Pour construire une matrice inversible 3 3 coecient dans Z/2Z, il sut de choisir un premier vecteur ligne non nul (23 1 choix), puis un deuxime vecteur qui ne soit pas dans la droite engendr par le premier (23 2 choix), puis un troisime vecteur ligne qui ne soit pas dans le plan engendr par les deux premiers (23 22 ). Cela fait : sage: (2^3-2^0)*(2^3-2)*(2^3-2^2) 168 Et en eet : sage: GL(3,2) General Linear Group of degree 3 over Finite Field of size 2 sage: _.cardinality() 168 Le mme raisonnement donne la formule gnrale qui sexprime naturellement au moyen de la q -factorielle :
n1

(q n q k ) =
k=0

qn [ n]q ! (q 1)n

Ainsi : sage: from sage.combinat.q_analogues import q_factorial sage: q = 2; n = 3 sage: q^n/(q-1)^n *q_factorial(n,q) 168 Exercice 56 page 342. Dans le premier cas, Python commence par construire la liste de tous les rsultats avant de la passer all. Dans le second cas, litrateur fournit les rsultats all au fur et mesure ; ce dernier peut donc arrter litration ds quun contre-exemple est trouv. Exercice 57 page 342. La premire ligne donne la liste des tous les cubes dentiers t entre 999 et 999 inclus. Les deux suivantes cherchent une paire de cubes dont la somme est 218. La dernire ligne est plus ecace en temps car elle sarrte ds quune solution est trouve : sage: cubes = [t**3 for t in range(-999,1000)] sage: %time exists([(x,y) for x in cubes for y in cubes], ....: lambda (x,y): x+y == 218)

440

ANNEXE A. SOLUTIONS DES EXERCICES

CPU times: user 1.28 s, sys: 0.07 s, total: 1.35 s Wall time: 1.35 s (True, (-125, 343)) sage: %time exists(((x,y) for x in cubes for y in cubes), ....: lambda (x,y): x+y == 218) CPU times: user 0.88 s, sys: 0.02 s, total: 0.90 s Wall time: 0.86 s (True, (-125, 343)) Surtout, elle est plus ecace en mmoire : si n est la longueur de la liste de cubes, la quantit de mmoire utilise est de lordre de n au lieu de n2 . Cela devient particulirement sensible lorsque lon dcuple n. Exercice 58 page 343. Calcule la srie gnratrice sS x|s| des sous-ensembles de {1, . . . , 8} en fonction de leur cardinalit. Calcule la srie gnratrice des permutations de {1, 2, 3} en fonction de leur nombre dinversions. Vrie la tautologie x P, x P pour P lensemble des permutations de {1, 2, 3, 4, 5}. Cest un trs bon test de cohrence interne entre les fonctions ditration et de test dappartenance sur un mme ensemble. Il est dailleurs inclus dans les tests gnriques de Sage ; voir : sage: P = Partitions(5) sage: P._test_enumerated_set_contains?? La tautologie x / P, x / P serait fort utile pour complter le test dappartenance. Cependant il faudrait prciser lunivers ; et surtout il faudrait un itrateur sur le complmentaire de P dans cet univers, ce qui nest pas une opration usuelle. Ache tous les matrices 2 2 inversible sur Z/2Z. Ache toutes les partitions de lentier 3. Ache toutes les partitions dentiers (ne sarrte pas !). Ache tous les nombres premiers (ne sarrte pas !). Recherche un nombre premier dont le nombre de Mersenne associ nest pas premier. Itre parmi tous les nombres premiers dont le nombre de Mersenne associ nest pas premier. Exercice 59 page 345. Construisons Leaf et Node comme suggr : sage: Leaf = var( Leaf ); Node = function( Node , nargs=2) Puis dnissons rcursivement notre itrateur : sage: def C(n): ....: if n == 1: ....: yield Leaf ....: elif n > 1:

A.16. THORIE DES GRAPHES ....: ....: ....: ....: for k in range(1,n): for t1 in C(k): for t2 in C(n-k): yield Node(t1, t2)

441

Voici les petits arbres : sage: list(C(1)) [Leaf] sage: list(C(2)) [Node(Leaf, Leaf)] sage: list(C(3)) [Node(Leaf, Node(Leaf, Leaf)), Node(Node(Leaf, Leaf), Leaf)] sage: list(C(4)) [Node(Leaf, Node(Leaf, Node(Leaf, Leaf))), Node(Leaf, Node(Node(Leaf, Leaf), Leaf)), Node(Node(Leaf, Leaf), Node(Leaf, Leaf)), Node(Node(Leaf, Node(Leaf, Leaf)), Leaf), Node(Node(Node(Leaf, Leaf), Leaf), Leaf)] On retrouve bien la suite de Catalan : sage: [len(list(C(n))) for n in range(9)] [0, 1, 1, 2, 5, 14, 42, 132, 429]

A.16

Thorie des graphes

Exercice 60 page 357. (Graphes circulants ) Deux boucles sont susantes ! sage: def circulant(n,d): ....: g = Graph(n) ....: for u in range(n): ....: for c in range(d): ....: g.add_edge(u,(u+c)%n) ....: return g Exercice 61 page 359. (Graphes de Kneser ) Le plus simple est dutiliser lobjet Subsets de Sage. On numre ensuite toutes les paires de sommets pour dtecter les adjacences, mais cela demande beaucoup de calculs inutiles. sage: def kneser(n,k): ....: g = Graph() ....: g.add_vertices(Subsets(n,k)) ....: for u in g: ....: for v in g: ....: if not u & v: ....: g.add_edge(u,v) ....: return g On peut cependant gagner du temps en nnumrant que les sommets adjacents.

442

ANNEXE A. SOLUTIONS DES EXERCICES

sage: def kneser(n,k): ....: g = Graph() ....: sommets = Set(range(n)) ....: g.add_vertices(Subsets(sommets,k)) ....: for u in g: ....: for v in Subsets(sommets - u,k): ....: g.add_edge(u,v) ....: return g Exercice 62 page 374. (Ordre optimal pour la coloration gloutonne ) La mthode coloring renvoie une coloration comme une liste de listes : la liste des sommets de couleur 0, la liste des sommets de couleur 1, etc. An dobtenir un ordre sur les sommets qui par lalgorithme glouton produit une coloration optimale, il sut de lister les sommets de couleur 0 (dans nimporte quel ordre), puis ceux de couleur 1, et ainsi de suite ! Ainsi, pour le graphe de Petersen, on obtient : sage: g = graphs.PetersenGraph() sage: def ordre_optimal(g): ....: ordre = [] ....: for classe_de_couleur in g.coloring(): ....: for v in classe_de_couleur: ....: ordre.append(v) ....: return ordre sage: ordre_optimal(g) [1, 3, 5, 9, 0, 2, 6, 4, 7, 8]

A.17

Programmation linaire

Exercice 63 page 388. (Subset Sum ) On associe chaque lment de lensemble une variable binaire indiquant si llment est inclus on non dans lensemble de somme nulle, ainsi que deux contraintes : La somme des lments inclus dans lensemble doit tre nulle. Lensemble ne doit pas tre vide. Cest ce que fait le code suivant : sage: sage: sage: sage: sage: sage: 0.0 sage: sage: [-93, l = [28, 10, -89, 69, 42, -37, 76, 78, -40, 92, -93, 45] p = MixedIntegerLinearProgram() b = p.new_variable(binary = True) p.add_constraint(p.sum([ v*b[v] for v in l ]) == 0) p.add_constraint(p.sum([ b[v] for v in l ]) >= 1) p.solve() b = p.get_values(b) print [v for v in b if b[v] == 1] 10, 45, 78, -40]

On note quil nest pas ncessaire de dnir une fonction objectif.

A.17. PROGRAMMATION LINAIRE

443

Exercice 64 page 389. (Ensemble dominant ) Les contraintes de ce programme linaire en nombres entiers correspondent un problme de couverture : un ensemble S de sommets dun graphe est un ensemble dominant si et seulement si, pour tout sommet v du graphe on a {v } NG (v ) S = , o NG (v ) dsigne lensemble des voisins de v dans G. On en dduit le code suivant : sage: g = graphs.PetersenGraph() sage: p = MixedIntegerLinearProgram(maximization = False) sage: b = p.new_variable(binary = True) sage: for v in g: ....: p.add_constraint( p.sum([b[u] for u in g.neighbors(v)]) ....: + b[v] >= 1) sage: p.set_objective( p.sum([ b[v] for v in g ]) ) sage: p.solve() 3.0 sage: b = p.get_values(b) sage: print [v for v in b if b[v] == 1] [0, 2, 6]

444

ANNEXE A. SOLUTIONS DES EXERCICES

Bibliographie
[AP98] Uri M. Ascher et Linda R. Petzold, Computer Methods for Ordinary Dierential Equations and Dierential-Algebraic Equations. Society for Industrial and Applied Mathematics, 1998, ISBN 0898714128. Noga Alon et Joel H. Spencer, The Probabilistic Method. WileyInterscience, 2000, ISBN 0471370460. Bernard Beauzamy, Robust Mathematical Methods for Extremely Rare Events. En ligne, 2009. http://www.scmsa.eu/RMM/BB_rare_ events_2009_08.pdf, 20 pages. Richard P. Brent et Paul Zimmermann, Modern Computer Arithmetic. Cambridge University Press, 2010, ISBN 0521194693. http: //www.loria.fr/~zimmerma/mca/pub226.html. Philippe G. Ciarlet, Introduction lanalyse numrique matricielle et loptimisation. Mathmatiques appliques pour la matrise. Masson, 1982, ISBN 2225688931. David Cox, John Little et Donal OShea, Ideals, Varieties, and Algorithms. Undergraduate Texts in Mathematics. Springer-Verlag, 3e dition, 2007, ISBN 0387946802. Michel Crouzeix et Alain L. Mignot, Analyse numrique des quations direntielles. Mathmatiques appliques pour la matrise. Masson, 1984, ISBN 2225773416. Henri Cohen, A Course in Computational Algebraic Number Theory. Numro 138 dans Graduate Texts in Mathematics. Springer-Verlag, 1993, ISBN 3540556400. Richard Crandall et Carl Pomerance, Prime Numbers: A Computational Perspective. Springer-Verlag, 2001, ISBN 0387947779.

[AS00] [Bea09]

[BZ10]

[Cia82]

[CLO07]

[CM84]

[Coh93]

[CP01]

446 [DGSZ95] [Edm65] [EM07]

ANNEXE B. BIBLIOGRAPHIE Philippe Dumas, Claude Gomez, Bruno Salvy et Paul Zimmermann, Calcul formel : mode demploi. Masson, 1995, ISBN 2225847800. Jack Edmonds, Paths, Trees, and Flowers. Canadian Journal of Mathematics, 17(3):449467, 1965. Mohamed Elkadi et Bernard Mourrain, Introduction la rsolution des systmes polynomiaux. Numro 59 dans Mathmatiques et Applications. Springer-Verlag, 2007, ISBN 3540716467. Philippe Flajolet et Robert Sedgewick, Analytic Combinatorics. Cambridge University Press, 2009, ISBN 0521898065. Jean Charles Faugre et Mohab Safey El Din, De lalgbre linaire la rsolution des systmes polynomiaux. Dans Jacques Arthur Weil et Alain Yger (rdacteurs), Mathmatiques appliques L3, pages 331388. Pearson Education, 2009, ISBN 2744073520. Flix Rudimovich Gantmacher, Thorie des Matrices. ditions Jacques Gabay, 1990, ISBN 2876470357. David Goldberg, What Every Computer Scientist Should Know About Floating Point Arithmetic. ACM Computing Surveys, 23(1):548, 1991. Gene H. Golub et Charles F. Van Loan, Matrix Computations. Johns Hopkins Studies in the Mathematical Sciences. Johns Hopkins University Press, 3e dition, 1996, ISBN 0801854149. Nicholas J. Higham, The Accuracy of Floating Point Summation. SIAM Journal on Scientic Computing, 14(4):783799, 1993, ISSN 1064-8275. Ernst Hairer, Christian Lubich et Gerhard Wanner, Geometric Numerical Integration. Springer-Verlag, 2002, ISBN 3662050200. Florent Hivert et Nicolas M. Thiry, MuPAD-Combinat, an OpenSource Package for Research in Algebraic Combinatorics. Sminaire lotharingien de combinatoire, 51:B51z, 2004. http://www.mat. univie.ac.at/~slc/wpapers/s51thiery.html. Henri Lombardi et Journadi Abdeljaoued, Mthodes matricielles Introduction la complexit algbrique. Springer, 2004, ISBN 3540202471. Patrick Lascaux et Raymond Thodor, Analyse numrique matricielle applique lart de lingnieur, tome 1. Masson, 2e dition, 1993, ISBN 2225841225. Patrick Lascaux et Raymond Thodor, Analyse numrique matricielle applique lart de lingnieur, tome 2. Masson, 2e dition, 1994, ISBN 2225845468. Thierry Massart, Syllabus INFO-F-101 Programmation. En ligne, 2013. http://www.ulb.ac.be/di/verif/tmassart/Prog/, version 3.2.

[FS09] [FSED09]

[Gan90] [Gol91]

[GVL96]

[Hig93]

[HLW02] [HT04]

[LA04]

[LT93]

[LT94]

[Mas13]

447 [Mat03] Ji Matouek, Using the Borsuk-Ulam Theorem: Lectures on Topological Methods in Combinatorics and Geometry. Springer-Verlag, 2003, ISBN 3540003625.

[MBdD+ 10] Jean Michel Muller, Nicolas Brisebarre, Florent de Dinechin, Claude Pierre Jeannerod, Vincent Lefvre, Guillaume Melquiond, Nathalie Revol, Damien Stehl et Serge Torres, Handbook of oating-point arithmetic. Birkhuser, 2010, ISBN 0817647049. [Mor05] Masatake Mori, Discovery of the Double Exponential Transformation and Its Developments. Publications of the Research Institute for Mathematical Sciences, 41:897935, 2005. Sampo Niskanen et Patric R. J. stergrd, Cliquer Routines for Clique Searching. http://users.tkk.fi/pat/cliquer.html. Marko Petkovek, Herbert S. Wilf et Doron Zeilberger, A = B . A K Peters Ltd., 1996, ISBN 1568810636. Michelle Schatzman, Analyse numrique. ISBN 2729603731. InterEditions, 1991,

[NO] [PWZ96] [Sch91] [Swi09] [Swi12] [TMF00] [TSM05]

Grard Swinnen, Apprendre programmer avec Python. Eyrolles, 2009, ISBN 2212124743. http://inforef.be/swi/python.htm. Grard Swinnen, Apprendre programmer avec Python 3. Eyrolles, 2012, ISBN 2212134346. http://inforef.be/swi/python.htm. Grald Tenenbaum et Michel Mends France, Les nombres premiers. Que sais-je ? P.U.F., 2000, ISBN 2130483992. Kenichiro Tanaka, Masaaki Sugihara et Kazuo Murota, Numerical Indenite Integration by Double Exponential sinc Method. Mathematics of Computation, 74(250):655679, 2005. Xavier Viennot, Leonhard Euler, pre de la combinatoire contemporaine. Expos la journe Leonhard Euler, mathmaticien universel , IHS, Bures-sur-Yvette, mai 2007. http://www. xavierviennot.org/xgv/exposes_files/Euler_IHES_web.pdf. Joachim von zur Gathen et Jrgen Gerhard, Modern Computer Algebra. Cambridge University Press, 2e dition, 2003, ISBN 0521826462. http://www-math.uni-paderborn.de/mca. Doron Zeilberger, Proof of the Alternating Sign Matrix Conjecture. Electronic Journal of Combinatorics, 3(2), 1996.

[Vie07]

[vzGG03]

[Zei96]

448

ANNEXE B. BIBLIOGRAPHIE

C
**, 43 +, 43, 59, 73, 164, 360 .., 46 ;, 42 =, 43 ==, 17, 44 ?, 13, 43 #, 42 _, 14 \, 42, 172 , 164 AA, 105, 274 abs, 10, 98, 107 acclration de convergence, 275 add, 64 __add__, 98 add_constraint, 385 add_edge, 355 add_edges, 355, 378 add_vertex, 355 aectation, 14, 43, 50, 70 achage, 59, 78, 361 aide, 8, 13, 100 AlgebraicField, 105 AlgebraicRealField, 105 algbre linaire, 3539, 159182 numrique, 277301 algorithme dEdmonds, 368 de Dijkstra, 367 de Ford-Fulkerson, 367

Index

de multiplication rapide, 158 aliasing, 70 all, 65, 342, 439 AlternatingSignMatrices, 339 and, 108 animate, 78 animation, 78 anneau dentiers, 119121, 125 anneau de polynmes, 112, 132, 183 une innit dindtermines, 186 any, 65, 342 append, 68, 273 approximation de Pad, 149 approximation numrique, 10, 47, 129, 144, 252, 278 quations direntielles, 315320 intgrales, 303315 limites, 32 solutions dquations, 2526, 144, 206, 247, 255276 arbre, 359, 370 de Steiner, 370 arbre dexpression, 17 arte (graphe), 355 arithmtique des polynmes, 137, 187 lmentaire, 8, 106107 modulaire, 119121 par intervalles, 256 Arrangements, 326 arrondi, 242, 246, 251 assert, 42, 263

450
assume, 22, 231 ATLAS, 296 attrcall, 344 augment, 160 automatic_names, 16 automorphism_group, 370 Axiom, 101, 132 bar_chart, 83, 94 base (espace vectoriel), 37, 160 base de Grbner, 194, 196, 207, 210219, 332 cot du calcul, 217 dnition, 212 rduite, 216 base_extend, 160, 164 base_ring, 120, 133, 160, 273 basis, 160 basis_is_groebner, 212 berlekamp_massey, 151, 420 binomial, 10, 333 BLAS, 296 bloc dinstructions, 45 bloc de Jordan, 180 bloc-notes, 5, 8 block_diagonal_matrix, 162 block_matrix, 160, 162 bogues, iii bool, 17, 105 boolens, 13, 108 boucle for (numration), 45 innie, 66, 266 interruption prmature, 48 while (tant que), 46 breadth_first_search, 366 break, 48 calcul de , 31, 32, 35 calcul formel, 3, 113 et calcul numrique, 12, 261 cardinality, 339, 437 cartesian_product, 346 CartesianProduct, 258, 346 catalan, 13 Catalan, constante de, 13 catastrophic cancellation, 246 catgorie, 103, 138 categories, 138 category, 103 CC, 105, 256, 274 CDF, 251, 253, 256, 274 center, 367 cercle osculateur, 93 chane de caractres, 59, 69 change_ring, 135, 160, 164, 213 changement de variable, 228 characteristic, 120

ANNEXE C. INDEX
characteristic_polynomial, 38, 166 charpoly, 141, 166, 176 chemins dans un graphe arte-disjoints, 368 sommet-disjoints, 368 chromatic_number, 358, 369 CIF, 144, 256, 274 circle, 92, 94 class, 42 classe, 97, 101 clique, 368 clique_maximum, 369 Cliquer (programme), 369 clture de Zariski, 197 CoCoA, 207 coecient matrice, 162 polynme, 135, 185 coecient binomial, 10 coecient de tte, 185, 187, 208 coefficients, 135, 185 coeffs, 135 coercition, 99 collect, 19, 20, 134 collections, 273 colonne dune matrice, 162 coloration de graphe, 369, 372, 380 coloring, 363, 369, 374 column_space, 38, 406 combine, 20 combstruct, 330 commentaire, 42 comparaison, 44 de deux expressions, 17 compensation catastrophique, voir catastrophic cancellation complement, 365 CompleteBipartiteGraph, 358 CompleteGraph, 358 compltion automatique, 13, 101 complex_plot, 81, 94 ComplexDoubleField, 251, 256 ComplexField, 105, 252, 253, 256 ComplexIntervalField, 256 composante connexe, 367 comprhension, 63 concatnation, 70 conchode, 80 condition initiale, 222 conditionnement, 278281, 284, 285, 286, 299 conjugate, 137, 165 connected_components, 367 connexit, 367, 368, 371, 374 constante de Masser-Gramain, 128 constantes, 252 prdnies, 13 content, 136, 137

451
continue, 48 contrib_ode, 223 conventions, 8 convergence, 33, 51, 248, 249, 264, 274 acclration de, 275 conversion, 99, 102, 106, 136, 244 coordonnes polaires, 36, 80 copy, 71, 164, 291, 366 corps de nombres, 39, 114, 141 corps ni, 105, 109, 119122, 125 compos, 121 cos, 21, 252 couleur, 77, 362 count, 68 coupe (graphe), 370, 374 couplage, 368, 379, 388 courbe intgrale, 87, 94 courbe paramtre, 80, 91, 94, 200 dans lespace, 96 cover_ring, 141 Cox, David A., 183 cross_product, 36, 404 crt, 124, 137 cryptologie, 121, 196 CSV (comma-separated values), 83 cycle hamiltonien, 369, 391 Cyclic, 195 decomposableObjects, 330 decomposition, 178 dcomposition de matrice, voir factorisation de matrice en lments simples, 20, 147, 232 sans carr, 143 triangulaire (dun idal), 204 dcorateur, 56 def, 42, 53 degree, 135, 185 del, 68, 74 delete_edge, 356 delete_vertex, 356 denominator, 148, 331 depth_first_search, 366 deque, 273 derivative, 33, 135, 185, 261 drive dune expression, 31, 33, 66 partielle, 34, 185, 222 dun polynme, 135, 185 desolve, 24, 222, 235 desolve_laplace, 232, 235 desolve_rk4, 87, 94 desolve_system, 233 dessin, 84, 94 de graphe, 361 det, 171 dterminant, 166, 171, 174 dveloppe dune courbe, 91 dveloppement limit, 30, 31, 110, 155 dveloppeurs de Sage, 4 devinette, 151 diagonalisation, 38, 166 diagramme, 83, 94 diameter, 367 diamtre dun graphe, 367 dichotomie, 265 dict, 74, 135 dictionnaire, 74, 185, 356 diff, 31, 33, 135, 235, 401 DiGraph, 364, 365 dimension dun idal, 189, 197, 203, 215 dune varit, 215 dimension, 189, 197, 198 discriminant, 143 discriminant dun polynme, 26, 146 disjoint_union, 360, 361 distance (dans un graphe), 367 divides, 137, 189 division, 9 entiers, 10 polynmes, 137, 140, 188, 209, 214 suivant les puissances croissantes, 139 documentation, 8 domaine de calcul, 23, 103115 dominating_set, 369 dot_product, 36 double prcision, 243, 251, 276 e, 13 eccentricity, 367 chappement, 42 echelon_form, 38, 166, 169, 170, 406 echelonize, 166, 169 edge_coloring, 369 edge_connectivity, 367, 368 edge_cut, 368 edge_disjoint_paths, 368 Edmonds, Jack, 388 eet Magnus, 90 eigenmatrix_left, 166, 180 eigenmatrix_right, 166, 180 eigenspaces_left, 166, 179 eigenspaces_right, 166, 179 eigenvalues, 38, 179 eigenvectors_left, 166, 179 eigenvectors_right, 38, 166, 179 elementary_divisors, 166, 171 elementwise_product, 164 elif, 53 limination algbrique, 188, 197, 201, 216 de Gauss, 165, 166 de Gauss-Jordan, 166, 168 elimination_ideal, 198

452
Elkadi, Mohamed, 183 ellipse, 36 else, 52 ensemble, 73 ensemble dominant, 369, 389 ensemble indpendant, 362, 368, 375, 379 enveloppe dune famille de courbes, 92, 200 quation, 12, 2427 commandes de rsolution, 24 dune courbe, 80, 81, 200 dune surface, 96 linaire, 22, 24, 25, 172 polynomiale, 143 rsolution numrique, 25, 255276 quation aux drives partielles, 222 de la chaleur, 230 quation direntielle, 24, 87, 154, 221234, 303, 315 coecients constants, 230, 232, 233 paramtre, 229 variables sparables, 223, 225, 227 de Bernoulli, 223 de Clairaut, 224 de Lagrange, 224 de Riccati, 224 exacte, 224 homogne, 224, 227, 229 linaire dordre 1, 223, 225 systme, voir systme dquations trac dune solution, voir graphe dune fonction quation fonctionnelle, 154 quations normales, 285, 286 quirpartition, 85 quivalence (matrices), 165, 168 escalier, 211, 212 espace invariant, 174 espace propre, 166, 174 espace vectoriel, 38 tiquette (graphe), 356, 361 tude de fonction, 22 euler_gamma, 13 excentricit, 367 exec, 42 exists, 342 exp, 21 expand, 19, 20 expand_trig, 21 exponentiation, 9 binaire, 56, 141 modulaire, 121, 126 export dune gure, 78, 364 exposant dun ottant, 241244, 251 Expression, 258 expression rgulire, 70 expression symbolique, 1117, 107, 110 112, 114, 132, 157 fonction, 19 nullit, 23 extend, 68 extension, 39

ANNEXE C. INDEX

facteur invariant, 170, 178 factor, 11, 20, 98, 106, 142, 143, 188, 189 factor_list, 20 factorial, 10, 21, 106 factorielle, 10 programmation, 55 factorisation entier, 98, 127, 142 polynme, 113, 125, 136, 142 factorisation de matrice de Cholesky, 283, 288 de Gauss-Jordan, 168 LU, 169, 281283, 290 QR, 283, 285, 291 False, 13, 108 Faugre, Jean-Charles, 183 fermeture de Zariski, 197, 199, 202 feuille de travail, 5 FieldIdeal, 195 Fields, 103 filter, 63, 68, 70, 72 finance, 83 find_root, 24, 25, 276 FiniteEnumeratedSet, 435 FiniteEnumeratedSets, 347 FiniteField, 105, 121 Firefox, 5 flatten, 65, 70 float, 105 floor, 10 ot, 367, 368, 370, 389 ottant, voir nombre virgule ottante flow, 367 fonction lmentaire, 21 fonction harmonique, 34 fonction objectif, 385 fonction Python, 43, 53 anonyme, 63 fonction symbolique, 19, 235, 399, 417 fonction trigonomtrique, 10, 11, 21, 252 for, 42, 45, 63, 65, 336, 341 forget, 22 forme de Frobenius, 174, 177 de Hermite, 169, 406 de Jordan, 38, 174, 180 de Smith, 170 chelonne, 38, 167, 168 triangulaire, 38, 167, 180 forme normale expression, 20, 23, 103, 115, 132 matrice, 165, 168170, 177 modulo un idal, 194 primaire, 182

453
formule de Bailey-Borwein-Ploue, 35 de Cramer, 281 de Leibniz, 66 de Machin, 31 de Sherman et Morrison, 433 formule close, 191 fourier_series_partial_sum, 79 Frac, 148 fraction rationnelle, 20, 139, 147 frozenset, 394 function, 19, 222, 235 function_factory, 417 galois_group, 143, 146 gcd, 137, 189 gen, 132, 197 gnrateur, 121, 133, 270 dun anneau de polynmes, 183 espace vectoriel, 160 programmation, voir itrateur gnricit, 99 genre, 198, 370 gens, 160, 184 genus, 198, 370 gomtrie, 200, 202 algbrique, 207 get_values, 385 GF, 105, 121, 125 gfun, 330 GL, 161 global, 54 GMP, 256 GMRES, 299, 301 GNU MPFR, 244, 295 GNU/Linux, 6 gradient conjugu, 299 Graph, 355, 356, 364, 365, 369 graphe adjoint, voir line graph alatoire, 359, 368, 374, 376 biparti, 359, 370 circulant, 357, 359 complet, 359 cordal, 366, 370 dintervalles, 370 de Kneser, 359 de Petersen, 357, 358 eulrien, 370 familles de graphes, 358 k-connexe, 367 parfait, 371 petits graphes, 357 planaire, 358 sommet-transitif, 358, 371 graphe dune fonction, 77, 94 complexe, 81 solution dquation direntielle, 87, 226, 318 Graphics, 87, 94 graphique, 16, 7796 groupe, 103 de Galois, 146 linaire GLn , 161 GSL, 87, 310, 311, 317319, 434 guessing, 151 hamiltonian_cycle, 369, 370 hermite_form, 170 histogramme, 83, 94 histoire de Sage, 4 historique de commandes, 14 homogenize, 185, 195 i (unit imaginaire), 13, 107 ideal, 140, 141, 189, 195 idal polynmes, 188, 192 polynmes une innit dindtermines, 186 identicateur, 42 identity_matrix, 160, 290 IEEE 754, 242 if, 52, 63 imag, 107 image, voir graphique dune application linaire, 172 dune fonction, 75 image, 166, 172 immuabilit, 72, 73, 164, 356, 385 implicit_plot, 81, 94 implicit_plot3d, 96 import, 14, 42 in, 61, 73, 74 indentation, 8, 45, 47 independent_set, 362, 369, 379 index, 68 inquation, 25, 383 systme polynomial, 202 inni, 13, 244 InfinitePolynomialRing, 185, 186 Infinity, 28, 334 inject_variables, 423 insert, 68 instance, 97 instruction conditionnelle, 52 int, 105, 334 Integer, 106, 256 integer_kernel, 166, 173 IntegerListsLex, 348350 IntegerModRing, 105, 108, 119, 125 IntegerRing, 105 Integers, 105, 119 IntegerVectors, 339 integral, 34

454
integrate, 31, 34, 310 integrate_numerical, 35 intgration numrique, 35, 303315 symbolique, 31, 34 interpolation de Cauchy, 151 interreduced_basis, 216 intersection, 195, 197 intervalle, 46 arithmtique, voir arithmtique par intervalles introspection, 100, 335 invariant de similitude, 174, 176, 178 inverse compositionnel dune srie, 148 dune matrice, 165 modulaire, 120 inverse_laplace, 232, 235 invite de commande, 8 irrelevant_ideal, 195 is_bipartite, 370 is_cartesian_transitive, 371 is_chordal, 366, 370 is_connected, 367 is_constant, 135 is_eulerian, 370 is_exact, 274 is_hamiltonian, 370 is_integral_domain, 133 is_interval, 371 is_irreducible, 142, 143 is_isomorphic, 360, 370 is_monic, 135 is_noetherian, 138 is_perfect, 371 is_prime, 125 is_pseudoprime, 125 is_regular, 358 is_ring, 138 is_squarefree, 189 is_tree, 370 is_vertex_transitive, 358, 371 is_zero, 23, 261 isomorphisme de graphes, 370 iter, 341 itrateur, 45, 46, 266, 336, 341, 344, 367 itertools, 343 jacobi, 127 jacobian_ideal, 195 jordan_block, 160, 166, 181 jordan_form, 38, 181 Kash, 101 kernel, 166, 173 keys, 74, 346 lagrange_polynomial, 137, 272, 305

ANNEXE C. INDEX
lambda, 42, 63, 68 Lapack, 291, 295 laplace, 235 A L TEX, 78 LattE, 350 LaurentSeriesRing, 148 LazyPowerSeriesRing, 155, 328 lc, 185 lcm, 123, 137, 189 leading_coefficient, 135 left_kernel, 37, 38, 166, 173 left_solve, 24 lemme de Dickson, 212 len, 60, 70, 73, 334 lex_BFS, 366, 370 lhs, 24, 229, 235 lift, 120, 140, 141, 194, 195 ligne dune matrice, 162 ligne de commande, 6 lim, 28 limit, 28, 31, 401 limite, 31 approximation numrique, 49 line, 84, 87, 94 line graph, 365 line3d, 96 linarisation (trigonomtrie), 21 Linux, 6 liste, 60 liste de diusion, 8 Little, John B., 183 lm, 185 log, 21, 128, 252 logarithme discret, 127128 logique, 108 lt, 185 Mac OS X, 6 Macaulay2, 207 Machin, John, 31 Magma, 101, 132 maille (graphe), 358 mantisse, 241244, 251 manuel, 8 map, 62, 65, 70, 72 map_coefficients, 185 Maple, 15, 132, 330 marche alatoire, 84 Massart, Thierry, 41 matching, 379 matrice, 37, 38, 109, 159182, 277301, 383 compagnon, 175, 180 dadjacence, 161, 356 de Hilbert, 279, 293 de Jordan, 181 de passage, 170 de transposition, 165

455
quivalence, voir quivalence (matrices) norme, voir norme de matrice par blocs, 162 similitude, voir similitude (matrices) unimodulaire, 169 matrix, 37, 38, 109, 141 matrix_block, 38 MatrixGroup, 160 MatrixSpace, 105, 109, 159, 160 max_cut, 370 max_symbolic, 313 Maxima, 15, 132, 228, 260, 311, 318, 319 maxspin, 166, 176 membre dune galit, 24 Mends France, Michel, 85 mthode dEuler, 316 de Brent, 276 de dichotomie, 265 de Dormand et Prince, 316 de Gauss-Kronrod, 304, 306 de Gauss-Legendre, 306 de Gear, 316 de la fausse position, 267 de la scante, 270 de Muller, 271 de Newton, 269 de Newton-Cotes, 305 de Runge-Kutta, 316 de sparation des variables, 230 de Steensen, 275 des rectangles, 305 des trapzes, 307 doublement exponentielle, 304, 307 QR, 291 mthode (programmation), 43, 98 Microsoft Windows, 6 mineur dun graphe, 370 interdit, 358 mineur dune matrice, 166 minimal_polynomial, 38, 166 minor, 370 minpoly, 141, 166 MixedIntegerLinearProgram, 384, 385 mod, 120, 141, 188, 195 modle de Verhulst, 229 modle proie-prdateur, 89 module dun nombre complexe, 10, 107 monme de tte, 185, 187, 208 Mourrain, Bernard, 183 moyenne arithmtico-harmonique, 50, 54 MPFR, voir GNU MPFR MPolynomial, 185 mq, 196 Muller, David E., 272 Muller, Jean-Michel, 249 __mult__, 98 multicommodity_flow, 370 multiplication rapide, 158 multiplicit, 193, 255, 261 MuPAD, 101, 132 MuPAD-Combinat, 330, 349 mutabilit, voir immuabilit n, voir numerical_approx n-uplet, voir tuple NaN (Not a Number), 244 new_variable, 386, 389 next, 340, 341 next_prime, 124 nud, 96 nombre virgule ottante, 25, 106, 241 algbrique, 39, 111, 114, 136, 141, 144, 149, 189 complexe, 107, 233 de Carmichael, 126 de Mersenne, 342 dcimal, 106 entier, 105 entier modulaire, 108, 119121 p-adique, 144 premier, 124127 rationnel, 106 nombre chromatique, 358, 359 nombre harmonique, 123, 249 None, 43, 54 norm, 36 normal_basis, 198, 207 norme de vecteur, 36 de matrice, 278, 279, 284, 286, 287 norme IEEE 754, 242 not, 108 notebook, voir bloc-notes NotImplementedError, 136 noyau, 37, 38, 166, 172 nth_root, 21 nuage de points, 84 Nullstellensatz, 194 number_field, 141 NumberField, 39, 111, 141 numer, 98 numerator, 148 numerical_approx, 10, 13, 23, 107 NumPy, 89, 274, 295 objet, 97 ode_contrib, 224 ode_solver, 87, 317 odeint, 87, 94, 411 one, 160 oprations arithmtiques, 8, 17, 99 corps nis, 121 matrices, 164

456
modulo n, 120 polynmes, 134, 187 optimisation, 383395 or, 108 order, 355 OrderedSetPartitions, 339 ordre additif, 120 multiplicatif, 121 ordre des variables, 184 ordre lexicographique, 66, 209 ordre monomial, 185, 187, 188, 208 changement dordre, 217 OS X, voir Mac OS X OShea, Donal, 183 PALP, 350 parametric_plot, 80, 94 paramtrisation, 91, 200 parcours de graphe, 366, 367 parent, 101, 103, 133, 138 parent, 120 paresseux, 155 PARI, 101, 274, 309, 312, 313 partage de donnes, 70 partial_fraction, 20, 232 partial_fraction_decomposition, 148 partie entire, 10, 21 pass, 42 periphery, 367 Permutations, 373 pgcd entiers, 120, 122, 123 polynmes, 137, 261 phnomne de Gibbs, 79 phnomne de Runge, 305 (constante dArchimde), 13 calcul, voir calcul de pi, 13 piecewise, 79 pivot de Gauss, 167 pivot_rows, 166, 171 pivots, 166, 171 plot, 16, 31, 77, 94, 226, 258, 304, 364 plot3d, 16, 93 plot_histogram, 83, 94 plot_points, 77 plot_vector_field, 89 plus court chemin (graphe), 367 point, 84 point dcimal, 10 point xe, 154 points, 94 polar_plot, 80, 94 polygen, 132 polygon, 94 polymorphisme, 99 polynme, 131158, 183219

ANNEXE C. INDEX
de Legendre, 306 de Tchebyche, 139 polynme caractristique, 38, 166, 174, 177 polynme minimal matrice, 38, 166, 175 nombre algbrique, 191 rcurrence linaire, 141 vecteur, 175 polynomial, 185, 186 polynomial_sequence, 196 PolynomialRing, 105, 133, 184, 185 pop, 68, 74 PowerSeriesRing, 110, 148 prec, 152 prcision arbitraire vs xe, 243, 253 calcul numrique, 206 ottant, 241244, 246, 247, 249 perte de, 246 srie, 152 primalit, voir nombre premier prime_range, 126 primitive, 31 print, 42, 55, 59 probabilit, 360 problme de Gauss, 36 procdure, 43, 53 prod, 64 produit, 64 cartsien, 65, 102 de graphes, 365, 371 scalaire, 36 vectoriel, 36 prol de rang, 166, 171 programmation, 4175, 339345 oriente objet, 97100 programmation linaire, 367, 369, 383395 en nombres entiers, 384 projection, 199 pseudo-division, 139 pseudo-primalit, 125 pseudo_divrem, 137 puissance, 9 programmation, 56 puissance inverse, 289 puissance itre, 289290, 300301 Python 3, 41 q -factorielle, 439 QQ, 105, 256, 274 QQbar, 105, 144, 189, 274 QUADPACK, 311 quadrature, 305 quit, 43 quo, 140, 141, 195 quo_rem, 137, 188 quotient anneau de polynmes, 193, 206

457
numrique, voir oprations arithmtiques Z/nZ, 119 quotient, 195, 197 raccourci clavier, 8 racine dun polynme, 143, 246, 255263 isolation, 262 racine n-ime, 10, 21 radical, 143, 195 radical dun idal, 194 radius, 367 Ramanujan, Srinivasa, 32 random, 84 random_element, 135, 373 random_matrix, 160 randrange, 83 rang dune matrice, 166, 171, 174, 284286 range, 46, 341 rank, 171 Rational, 97, 98 rational_argument, 191 rational_reconstruct, 148, 149 rational_reconstruction, 122 RationalField, 105 raw_input, 60 rayon dun graphe, 367 RDF, 136, 243, 253, 256, 274 real, 107 real_root_intervals, 143 real_roots, 143, 274, 276 RealField, 105, 243, 253, 256 RealIntervalField, 256 reconstruction rationnelle, 122, 129, 148, 149 rcurrence, voir suite rcurrente reduce liste, 64 modulo, 140, 148, 194, 195 reduce_trig, 21 rduction des endomorphismes, 38, 166 rduction retarde, 121 rcriture, 210 rgle de Descartes, 262 relation de Bzout, 140 remove, 68 reprsentation des polynmes creuse, 156, 185 dense, 156 factorise, 112 rcursive, 134, 186 rsidu quadratique, 127 rsolution quations numriques, 2427, 255 276 programmation linaire, 385 systmes linaires, 36, 166, 172 systmes polynomiaux, 188 restes chinois, 123 resultant, 143, 189, 198 rsultant, 145, 201 return, 42, 48, 54, 266, 344 reverse, 66, 134, 135 reversion, 148 rhs, 24, 235 RIF, 144, 256, 274 right_kernel, 37, 38, 166, 173, 405 right_solve, 24 RisingFactorial, 238 root_field, 257 roots, 24, 26, 143, 203, 255, 260, 261, 276 row_space, 38 RR, 105, 256, 274 rsolve, 237 sac dos (problme du), 387 Safey El Din, Mohab, 183 sage-support, iii sage:, 8 sagemath.org, 8 sagenb.org, voir serveur public satellite, 36 save, 78 SciPy, 87, 88, 276, 295, 298, 301, 411 squence, voir tuple srie, 28, 31, 32, 249 alterne, 50 de Fourier, 79 de Riemann, 32, 51 srie formelle, 110, 148, 149, 151, 418 series, 31, 110 serveur public, 56 Set, 73, 435 set_binary, 386 set_immutable, 164 set_integer, 386 set_max, 386 set_min, 386 set_objective, 385 set_real, 386 shortest_path, 367 show, 78, 94, 361, 362, 364, 380 signicande, voir mantisse similitude (matrices), 174, 177, 182 simplication, 11, 2123, 113 simplify, 11, 20, 111 simplify_exp, 20 simplify_factorial, 21, 22 simplify_full, 22 simplify_radical, 21, 22 simplify_rational, 2022, 331 simplify_trig, 2123 sin, 21, 252 Singular, 185, 207 size, 355 SL, 161

458
sloane_find, 327 smith_form, 166, 171 Solaris, 6 solve, 22, 24, 91, 188, 228, 385, 386 solve_left, 37, 38, 166, 172 solve_right, 37, 38, 166, 172 sommation numrique compense, 250 programmation, 48 symbolique, 27, 31 somme de sous-ensembles, 388 sommet (graphe), 355 sort, 66 sorted, 67 sous-graphe induit, 360, 376 sous-matrice, 163 split, 70 sqrt, 21, 22, 39 squarefree_decomposition, 143 SR, 105, 157, 258 SR.var, voir var srange, 46 SSP (subset sum problem ), 388 stable (graphe), voir ensemble indpendant stack, 160 StandardTableaux, 339 Stein, William, 4 steiner_tree, 370 str, 70, 105 structure algbrique, 101103 subgraph, 365 subgraph_search, 360, 370, 371, 378 submatrix, 160 SubMultiset, 423 subs, 18, 135, 185, 187 subs_expr, 18 subset sum, 388 Subsets, 423, 441 substitute_function, 418 suite de Fibonacci, 5559 de Syracuse, 52 hypergomtrique, 238 logistique, 235 suite aliquote, 128 suite de Krylov, 174 suite de Sturm, 262 suite numrique, 29 quirpartie, 85 suites adjacentes, 49 suite rcurrente, 45, 4756, 141, 151, 235 238 stabilit numrique, 247 trac, 85, 236 sum, 27, 31, 64, 341 Sun OS, 6 surface de Cassini, 96

ANNEXE C. INDEX
surface paramtre, 94 SVD (singular value decomposition ), voir valeur singulire swap_columns, 166 swap_rows, 166 Swinnen, Grard, 41 sxrange, 46 symbole de Jacobi, 127 symbole de Pochhammer, 238 SymPy, 237 systme dquations, 25, 36, 172, 183, 383 direntielles, 233 table dadjacence, 356 table de hachage, 73, 74 tableau de variations, 22 tableur, 83 tabulation, 13 tangente une courbe, 269 taylor, 31, 150, 399 Tenenbaum, Grald, 85 terme de tte, 185, 187, 208 test, 52 test de Fermat, 125 test de nullit, 23 test_poly, 184 text, 94 thorme de Borsuk-Ulam, 359 de Cayley-Hamilton, 177 de dAlembert-Gauss, 257 de Kuratowski, 358 de Menger, 367 de Pocklington, 125 de Schwarz, 34 timeit, 121 TimeSeries, 83 trac.sagemath.org, iii trace, 278, 287 trace, 141 transformed_basis, 191, 217 transforme de Laplace, 231 transpose, 165, 283, 285, 288 transpose, 165 transvection, 165, 166 traveling_salesman_problem, 370 tree, 359 tri, 66 triangular_decomposition, 191, 198, 204 trig_expand, 400 trig_simplify, 400 trigonalisation, voir forme triangulaire trigonomtrie, 217 troncature dune srie, 148 True, 13, 108 truncate, 31 try, 42, 84

459
tuple, 72 type de base, 105 ulp, 245 ulp (unit in the last place ), 245 union ensembles, 73, 327, 346 graphes, 360 valeur absolue, 10 valeur caractristique, 174 valeur dadhrence, 236 valeur propre, 38, 166, 174, 179, 233 valeur singulire, 284, 286, 287 valuation, 137 values, 74 Vandermonde (dterminant de), 112 var, 15, 235 variable Python, 1314, 43, 54 symbolique, 1516, 22 variable dpendante, 222 indpendante, 222 variable_name, 135 variable_names_recursive, 185 variables, 135, 235 varit algbrique, 192 variety, 189, 198, 203 vecteur, 36 construction, 161 vecteur cyclique, 175 vecteur propre, 38, 166, 179 vector, 36, 161 vector_space_dimension, 198 VectorSpace, 159 vertex_connectivity, 367 vertex_cut, 368 vertex_disjoint_paths, 368 voyageur de commerce, 369, 391 WeightedIntegerVectors, 335 while, 42 Windows, 6 with, 42 worksheet, voir feuille de travail x (variable symbolique), 15 xgcd, 137 xrange, 46, 341 yield, 42, 266, 344 zero, 160 (fonction zta de Riemann), 32, 52 zip, 72 ZZ, 105, 120, 256, 274

Sage est un logiciel libre de calcul mathmatique sappuyant sur le langage de programmation Python. Ses auteurs, une communaut internationale de centaines denseignants et de chercheurs, se sont donn pour mission de fournir une alternative viable aux logiciels Magma, Maple, Mathematica et Matlab. Sage fait appel pour cela de multiples logiciels libres existants, comme GAP, Maxima, PARI et diverses bibliothques scientiques pour Python, auxquels il ajoute des milliers de nouvelles fonctions. Il est disponible gratuitement et fonctionne sur les systmes dexploitation usuels. Pour les lycens, Sage est une formidable calculatrice scientique et graphique. Il assiste ecacement ltudiant de premier cycle universitaire dans ses calculs en analyse, en algbre linaire, etc. Pour la suite du parcours universitaire, ainsi que pour les chercheurs et les ingnieurs, Sage propose les algorithmes les plus rcents dans diverses branches des mathmatiques. De ce fait, de nombreuses universits enseignent Sage ds le premier cycle pour les travaux pratiques et les projets. Ce livre est le premier ouvrage gnraliste sur Sage, toutes langues confondues. Cocrit par des enseignants et chercheurs intervenant tous les niveaux (IUT, classes prparatoires, licence, master, doctorat), il met laccent sur les mathmatiques sous-jacentes une bonne comprhension du logiciel. En cela, il correspond plus un cours de mathmatiques eectives illustr par des exemples avec Sage qu un mode demploi ou un manuel de rfrence. La premire partie est accessible aux lves de licence. Le contenu des parties suivantes sinspire du programme de lpreuve de modlisation de lagrgation de mathmatiques. Ce livre est dius sous licence libre Creative Commons. Il peut tre tlcharg gratuitement ou imprim la demande prix modique depuis http://sagebook.gforge.inria.fr/

cba