M1 MFA année 2013–2014. Algorithmique : notes de cours Version du 8 décembre 2013 Programme. Notion d’algorithme, complexité d’un algorithme. Notation dite de Landau : O, Ω, Θ. Rappels sur la comparaison des fonctions. Algorithmes de tri : tri par insertion, tri rapide. Opérations arithmétiques de base sur les entiers : addition, soustraction, multiplication, exponentiation, division euclidienne avec reste. Algorithmes arithmétiques : calcul du pgcd, algorithme d’Euclide étendu, Bézout, utilisation du théorème chinois. FFT, multiplication rapide. Opérations sur les polynômes (en principe en une variable), algorithme d’Euclide, calcul du pgcd, théorème chinois, multiplication rapide. Algèbre linéaire : solution d’un système d’équation linéaires, calcul d’un déterminant, . . .. Racines d’un polynôme à coefficients réels et complexes : localisation, séparation, approximation. Public visé : agrégation de mathématiques (option C calcul formel, éventuellement utile pour option D info) et math-info (surtout algorithmique en théorie des nombres et cryptologie). Quelques références : Pierre Damphouse : Petite introduction à l’algorithmique, Ellipses (2005). Maurice Mignotte : Mathématiques pour le calcul formel, PUF (1988). Maurice Mignotte : Algèbre concrète, Ellipses, (2003). Joachim von zur Gathen, Jürgen Gerhard : Modern computer algebra, Cambridge University Press, deuxième édition (2003). Donald E. Knuth : The art of computer programming, (4 volumes), Addison Wesley, plusieurs éditions (plus avancé). Notion d’algorithme. Je ne donnerai pas de définition précise. Il s’agit d’une série d’instructions faisant intervenant des opérations simples , dites élémentaires. Sauf indication contraire, les algorithmes sont déterministes, c’est-à-dire, le résultat de chaque opération est uniquement déterminée. Il y a aussi des algorithmes probabilistes, où les opérations font intervenir un choix au hasard (par exemple un entier choisi au hasard). Une autre forme d’algorithme qui font intervenir une hypothèse que nous ne savons pas démontrer dans l’état des connaissances mathématiques actuelles, mais qui, dans la pratique, sont très efficaces. Un exemple est la recherche du plus petit nombre premier supérieur à un entier n donné. Pour cela, on utilise la méthode la plus naı̈ve imaginable : on test successivement pour primalité chacun les entiers n + 1, n + 2, . . .. En pratique, on constate qu’il suffit — en moyenne — de tester environ log n entiers avant de rencontrer un nombre premier, mais nos connaissances mathématiques actuelles permettent seulement de démontrer qu’il suffit de tester au plus nc entiers, où c > 0 est une constante qui, il est vrai, diminue avec le temps. Un tel algorithme est appelé un algorithme heuristique. Exemples (i ) L’instruction factoriser(n) (où n ≥ 2 un entier naturel) n’est pas un algorithme, car l’instruction de factoriser un entier n’est pas une instruction élémentaire (et il y a 1 en fait plusieurs algorithmes de factorisation d’un entier). Un algorithme de factorisation est une séquence d’instructions simples (telles addition, multiplication, division, comparaison de deux entiers) que, si l’on les appliquent à n, fournit la factorisation de n. (ii ) De même, l’instruction trier(L), où L est une liste de mots (par exemple de la langue française), n’est pas un algorithme. Ici, instruction simple pourrait signifier interchangement de deux mots (transposition). (iii ) On peut objecter que l’addition, la multiplication, . . ., de deux entiers ne sont pas des opérations élémentaires, mais deviennent de plus en plus complexes avec les grandeurs. C’est vrai. En réalité, les opérations élémentaires arithmétiques sont l’addition, la multiplication, . . ., de deux puissances de 2. Ici, on peut encore objecter qu’un grand entier est plus complexe qu’un petit. Cela est une question de taille de mémoire, alors que nous nous limiterons à des questions de complexité d’exécution qui influencer surtout le temps de calcul. Nous allons donc parfois supposer que l’addition, la multiplication, . . ., peuvent se faire en temps constant, surtout lorsque les algorithmes ont une complexité beaucoup plus importante que log n (par ex. une puissance de n). Parmi des opérations élémentaires, il faut aussi tenir compte du nombre de cas à exécuter dans un pour ou dans un tantque, le tests élémentaires dans un si, les retourner. Et, bien entendu, si un programme fait appel à un autre, les instructions exécutées par ce dernier. Par exemple, dans le pseudoprogramme (pas de langage de programmation dans ce cours) : pour i de 1 à n si 2 divise i retourner i/2 sinon retourner i finsi finpour chaque valeur de i utilise un test de parité. Lorsque i est pair il faut le diviser par 2 et il y a donc le test plus la division plus le retourner à exécuter, ce qui fait 3 opérations élémentaires. Par contre, lorsque i est impair, il y n’y a que le test et le retourner à exécuter, soit 2 opérations élémentaires. Le nombre total d’opérations élémentaires est donc n + 3Np (n) + 2Ni (n) (Np (n), Ni (n) le nombre d’entiers pairs, impairs entre 1 et n). Ici, j’ai compté le test de parité et la division par 2 comme des opérations élémentaires, car, sur machine, elle correspond à regarder si le dernier bit de i est nul et à décaler tous les bits de i un pas à droite. On pourrait objecter, avec raison, que décaler un bit un pas à droite est une opération élémentaire mais que, comme i est représenté par blog2 ic + 1 bits, la division nécessite ce nombre d’opération élémentaires. Le pseudoprogramme nécessiterait alors n+2Np (n)+ P i pair (blog2 ic + 1) + 2Ni (n) opérations élémentaires. Remarque. L’algorithmique étudie aussi l’existence ou la non existence d’algorithmes. Un exemple célèbre est le Théorème de Matijasevich, qui a pour conséquence qu’il n’existe pas d’algorithme pour décider si oui on non une famille d’équations polynômiales à coefficients entiers possède une solution en entiers. Dans ce cours, nous serons plutôt intéressés par des problèmes qui possèdent un algorithme trivial dont l’existence est en générale évidente (par exemple, il suffit d’effectuer de tests ou d’opérations sur un ensemble fini explicite). Le but est la recherche d’algorithmes plus efficaces, et surtout plus rapide. Un exemple typique est le problème de déterminer si oui ou non un entier naturel n ≥ 2 donné est un nombre premier. L’algorithme trivial consiste alors à tester si n est divisible par un entier m tel que 2 ≤ m ≤ n − 1, et un algorithme trivial consiste donc de tester successivement si 2 divise n, si 3 divise n et ainsi de suite. Ici l’opération de division n’est pas une opération élémentaire, mais peut être réduite à une séquence d’opérations 2 élémentaires, par exemple en appliquant la division euclidienne avec reste et en constatant si le reste est nul ou non. Le but est de trouver un algorithme plus rapide. Complexité, notation de Landau Dans ce cours, log désigne le logarithme népérien, loga le log en base a, a > 0 étant un réel. Il y a donc place pour discussion concernant le nombre exact d’opération élémentaires. Mon point de vue est assez rigoureux ; j’essaie de compter tous qui pourrait compter qui est propre à l’algorithme (c.-à.-d. à l’exclusion de l’entrée et la sortie des données). Complexité d’un algorithme. À nouveau, pas de définition précise toute de suite (à revoir vers la fin du cours). Idée la plus simple : c’est le nombre d’instructions élémentaires executées, vu comme fonction de n (pour factorisation), ou comme fonction du nombre de mots dans L (pour une liste), . . .. En pratique, il n’y a pas de formule exacte explicite pour le nombre d’instruction élémentaires (sauf quelques algorithmes très particuliers). On se contente de l’ordre de magnitude (croissance de la fonction avec n, avec le nombre de mots dans √ lan liste). Combien d’instructions simples faut2 t-il pour factoriser n (à peu près) ? log(n), n , n, e . . . ? Combien en faut-il pour trier une liste à n éléments ? Notations O, Ω, Θ. Soit f : N → R+ une fonction (peut-être non définie en quelques petites n ∈ N). On note O(f ) = {g : N → R+ | g(n) ≤ Cf (n) pour tout n assez grand et une constante convenable C > 0}, Ω(f ) = {g : N → R+ | g(n) ≥ Cf (n) pour tout n assez grand et une constante convenable C > 0}, Θ(f ) = O(f ) ∩ Ω(f ). On utilise une notation analogue pour des fonctions f : [a, +∞[→ R+ , des fonctions f : N2 → R+ etc. Par exemple, si f : N2 → R+ , g : N2 → R+ , alors g ∈ O(f ) s’il existe C > 0 telle que g(m, n) ≤ Cf (m, n) pour tout (m, n) avec ||(m, n)|| assez grand, || . || étant n’importe quelle norme sur R2 . (Toutes les normes sur R2 étant équivalentes, cette définition est indépendente du choix de la norme.) Remarques. (1) C’est la notation dite de Landau, mais déjà utilisée (dans le cas de O) par P. Bachmann en 1894, alors que ni Bachmann ni Landau n’utilisaient les notations Ω(f ) et Θ(f ). (2) La définition de Ω(f ) n’est pas celle utilisée en théorie analytique des nombres, où g ∈ Ω(f ) signifie (f (n), g(n) > 0 pour tout n assez grand) et lim sup g(n)/f (n) > 0. (3) On rencontre souvent l’écriture g = O(f ) à la place de g ∈ O(f ). Cette pratique est à éviter devant un jury de concours. √ 2 Exemples. (i ) n ∈ O(n), (log n)a ∈ O(nc ) quelque soit a, c > 0, O(en ) ⊆ O(en ). (ii ) Le pseudoprogramme ci-dessus s’exécute en n + 3Np (n) + 2Ni (n) opérations élémentaires. Comme Np (n) = b n2 c et Ni (n) = b n+1 c, on constate qu’il est dans Θ(n) (sauf si on prend en 2 compte le temps de division de i par 2 comme blog2 ic + 1). La formule de Stirling. Elle permet d’insérer la fonction factorielle et les coefficients binomiaux dans l’hierarchie des fonctions. Le résultat suivant est un peu plus précis, car elle fournit un encadrement de la fonction factorielle par des fonctions de forme exponentielle. 3 Théorème. Pour tout entier n ≥ 1, on a : n n √ n n √ 2πn e1/(12n+1) ≤ n! ≤ 2πn e1/12n . e e n n √ Corollaire (formule de Stirling). On a n! ∼ 2πn lorsque n → ∞. e La formule de Stirling permet également de donner des équivalences à certaines familles de coefficients binomiaux et de les insérer dans l’hierarchie des fonctions. Par exemple : 2n 22n ∼√ , n! ∈ O(nn ), en ∈ O(n!). n πn La démonstration du théorème relève de l’analyse et elle est donc d’un esprit différent des idées développées dans ce cours. Elle est donc reportée en annexe et se trouve à la fin de ce document. L’étude des algorithmes Pendant le reste de ce cours, nous allons pour la plupart du temps étudier différents algorithmes ou parfois comparer plusieurs algorithmes ayant la même finalité. En règle générale, l’étude d’un algorithme consiste en les points suivants (dont certains pourraient être laissés en partie ou en totalité en exercice) :— (1) déscription informelle de l’algorithme, parfois à l’aide d’exemples ; (2) redaction de l’algorithme en pseudocode , (3) preuve que l’algorithme se termine et estimation de sa complexité ; (4) preuve que l’algorithme fournit effectivement le résultat désiré ; (5) éventuellement, quelques remarques diverses, par exemple comparaison avec d’autres algorithmes ayant la même finalité. Remarque. Le plus souvent, on connaı̂t plusieurs algorithmes ayant la même finalité. Par exemple, on connaı̂t plusieurs algorithmes de factorisation d’entiers. De même, la plupart algorithmes possèdent plusieurs variantes et les discriptions peuvent varier légèrement selon les auteurs. On veillera à ce que le pseudocode dans l’étape (2) correspond bien à l’algorithme décrit informellement au point (1), et non pas à une variante ou à un autre algorithme ayant la même finalité. Algorithmes de tri Il y en a beaucoup. Le choix d’utilisation dépend du contexte. Soit E un ensemble muni d’un ordre total ≤. Un tableau d’éléments de E est une application T : [[1, n]] → E (ou d’un autre ensemble d’entiers consécutifs vers E). Ici, comme ailleurs, [[d, f ]] (où d < f sont deux réels) désigne l’ensemble des entiers i vérifiant d ≤ i ≤ f . Un sous-tableau d’un tableau T est un tableau T 0 paramétré par une partie [[d, f ]] de [[1, n]] formée d’entiers consécutifs tel que T 0 [i] = T [i] lorsque i ∈ [[d, f ]]. Si T est un tableau d’éléments de E, trier T signifie ranger les éléments de T en ordre croissant (ou décroissant), c’est-à-dire trouver (algorithmiquement) une permutation π de [[1, n]] telle que T [π(1)] ≤ T [π(2)] ≤ · · · ≤ T [π(n)]). 4 Les algorithmes qui nous allons décrire s’appliquent à un ensemble totalement ordonné E et à un tableau T dont les coefficients sont des éléments arbitraires de E. Le principe de base de ces algorithmes est le test de comparaison de deux éléments de E et il est sous-entendu qu’on dispose d’une méthode d’effectuer un tel test. Par hypothèse donc, ces algorithmes sont génériques. Voir le paragraphe Quelques autres algorithmes de tri un peu plus loin pour une discussion brève de quelques algorithmes spéciaux, adaptés aux ensembles E possédant des propriétés particulières ou dont les éléments possèdent une représentation particulière. Opérations élémentaires : test de comparaison de deux éléments de E, échange de deux éléments d’un tableau, extraction d’un sous-tableau. Remarque. Une liste L d’éléments d’un ensemble E quelconque est une famille de tableaux d’éléments de E (de longueur variable) indexée par N (ou par les sommets d’un arbre A), tel que L(n+1) est obtenu de L(n) (ou L(s0 ) est obtenu de L(s) si (s, s0 ) est une arête de A) par l’ajout ou la suppression d’un élément de E (y compris la création ou suppression d’une liste à un élément). Ce sont des opérations élémentaires sur une liste. L’échange de deux éléments d’un tableau est fait par la suppression de l’un des éléments, puis de l’autre, puis par l’ajout du deuxième élément dans l’ancienne position du premier et l’ajout du premier élément dans l’ancienne position du second. Cela fait 4 opérations élémentaires sur une liste, un nombre indépendant du tableau. La complexité d’un algorithme de tri est donc mesurée par le nombre de tests de comparaison. Si on y ajoute les échanges necéssaires, on reste dans le même ordre de complexité Θ. Tri par insertion. C’est l’algorithme le plus souvent utilisé par des joueurs de cartes. La première étape est le tri du sous-tableau (T [1], T [2]). On commence donc en comparant T [2] à T [1] : si T [2] < T [1], on échange T [2] et T [1] ; dans le cas contraire, on laisse T [1] et T [2] en place. En général, si j ≥ 2, alors après j − 1 étapes on a une permutation πj−1 de {1, 2, . . . , j − 1} telle que T [πj−1 (1)] ≤ T [πj−1 (2)] ≤ · · · ≤ T [πj−1 (j − 1)] et le reste du tableau est inchangé. Si T [j] ≥ T [πj−1 (i)] pour tout i ≤ j − 1, on ne fait rien. Sinon, on bouge T [j] à gauche pas à pas jusque tous les éléments à gauche de T [j] sont ≤ T [j]. Cela signifie qu’on interchange T [j] et T [πj−1 (j − 1)], puis T [j] et T [πj−1 (j − 2)] et ainsi de suite jusqu’à ce que T [j] arrive en bonne position. (Si celle-ci est la position i, on a alors πj = πj−1 ◦ (j, i, i + 1, · · · , j − 1).) Après n − 1 étapes, on obtient une permutation πn des indices tel que T [πn (1)] ≤ T [πn (2)] ≤ · · · ≤ T [πn (n)] (uniquement déterminé par l’algorithme et unique si les T [i] sont deux-à-deux distincts). Dans la redaction du pseudocode on se sert d’un tableau variable X, (donc X[i] vaut T [i] au début et T [πn (i)] à la fin). procédure: triins(T ) (entrée : T , un tableau à n éléments ; sortie : T trié par ordre croissant) variables locales: X (un tableau à n éléments), j, k (entiers vérifiant 1 ≤ k < j ≤ n) X←T pour j de 2 à n k =j−1 tantque (k > 0 et X[k] > X[k + 1]) échanger X[k + 1] et X[k] k ←k−1 fintantque 5 finpour retourner X Pour chacune des n − 1 valeurs de j, il y a j − 1 valeurs de k = j − 1, j − 2, . . ., 1 et pour chacune de ces valeurs de k il faut faire un test de comparaison entre X[k + 1] et X[k]. Il y a donc au total n X n(n − 1) (j − 1) = 2 j=2 tests, et à l’issu de chaque test on effectue au plus un échange. La complexité de l’algorithme appartient donc à Θ(n2 ). Pour prouver que la sortie de l’algorithme est effectivement ce que l’on attend, il suffit de vérifier que, pour tout j ∈ 2, 3, . . . , n, le sous-tableau (X[1], X[2], ..., X[j − 1]) de X à l’issu de la boucle est trié par ordre croissant. Lorsque j = 2, c’est clair. Si c’est vrai pour une valeur de j, c’est également vrai pour j remplacé par j +1, car la boucle soit laisse X[j] fixe si X[i] ≤ X[j] pour tout i < j soit insère X[j] entre X[i − 1] et X[i] où i est l’unique indice tel que X[i − 1] < X[j] ≤ X[i]. Tri bulle (bubble sort en anglais). Ainsi nommé parce que, le tableau étant écrit verticalement, les éléments remontent vers leur position naturelle par comparaison avec l’élément juste au dessus, comme des bulles dans un aquarium. (À la fin les plus grands éléments seront en haut.) En plus de détail, on commence avec T [1] : si T [1] > T [2] on échange T [1] avec T [2] puis successivement avec T [3], T [4] jusqu’à ce qu’on arrive à un indice i tel que T [1] < T [i]. Si i ≤ n−2, on recommence avec T [i + 1] et T [i + 2], les échangeant si T [i + 1] > T [i + 2] et ainsi de suite. On remonte alors jusqu’à T [n]. Notons qu’à l’issu de ce procès, T [n] ≥ T [j] quelque soit j < n. Ensuite, on recommence avec le nouveau T [1] en le comparant avec T [2] les échangeant si T [1] > T [2] et ainsi de suite. Puisque T [n] ≥ T [j] lorsque j < n, on s’arrête en T [n − 1]. Si on écrit le tableau de gauche à droite, c’est T [1], T [2], . . ., T [n − 1] qui bougent à droite alors que dans l’algorithme de tri par insertion c’est T [2], T [3], . . ., T [n] qui bougent à gauche. Le pseudoprogramme est donc procédure: tribulle(T ) (entrée : T , un tableau à n éléments ; sortie : T trié par ordre croissant) variables locales: X (un tableau à n valeurs), j, k (entiers vérifiant 1 ≤ k ≤ j ≤ n − 1) X←T pour j de n − 1 à 1 pour k de 1 à j si X[k + 1] < X[k] alors échanger X[k + 1] et X[k] finsi finpour finpour retourner X Ici, pour chaque j ∈ {1, 2, . . . , n − 1}, k prend j valeurs et pour chaque k ilPy a un test (si n−1 X[k + 1] > X[k] ou non) et éventuellement un échange. À nouveau donc, il y a j=1 j = n(n−1) 2 tests, et la complexité appartient à Θ(n2 ). À l’issu de l’itération sur j, on voit que X[i] ≤ X[n − j + 1] lorsque i < n − j + 1 et que la partie (X[n − j + 1], · · · , X[n]) du tableau est trié par ordre croissant. En particulier, lorsque j = n − 1, on a X[1] ≤ X[2] et (X[2], X[3], . . . , X[n]) est trié par ordre croissant. Donc T est trié par ordre croissant. 6 Tri par selection. On cherche un indice k tel que T [k] = min1≤i≤n T [i] puis on échange T [k] et T [1]. Ensuite, on cherche un indice ` ≥ 2 tel que T2 [`] = min2≤i≤n T2 [i], puis on échange T2 [`] et T2 [2]. Et ainsi de suite. Cela necéssite savoir calculer un indice i tel que T [i] soit minimal, et d’étudier la complexité de cela. Remarquons que nous avons déjà un algorithme pour trouver le maximum, car dans tribulle, chaque itération sur j a pour effet de ramener un élément maximal d’un sous-tableau à son extrémité droite. Mais l’information sur l’indice de départ est perdue. La procédure suivante fait ce qu’on a besoin. procédure indmin(T ) (entrée : T un tableau à n éléments ; sortie : le plus petit indice i tel que T [i] ≤ T [j] pour tout j ∈ {1, 2, . . . , n}) variables locales: indprov (un entier, valeur provisoire de l’indice cherché) indprov = 1 pour j de 2 à n si T [j] < T [indprov], indprov ← j finsi finpour retourner indprov Ici, il y a n−1 valeurs de j, et pour chacune il y a 1 ou 2 opérations élémentaires. La complexité de la procédure appartient donc à Θ(n). La procédure de tri par sélection est alors fournie par le pseudocode suivant (où on note X[[j,n]] le sous-tableau de X indexé par [[j, n]]) : procédure trisél(T ) (entrée : T , un tableau à n éléments ; sortie : T trié par ordre croissant) variables locales: X (un tableau à n valeurs), j, k (entiers vérifiant 1 ≤ j ≤ n − 1, j ≤ k ≤ n) X←T pour j de 1 à n − 1 k ← indmin(X[[j,n]] ) si j 6= k, échanger X[j] et X[k] finsi finpour retourner X On voit de la même manière que précédemment que la complexité de trisél appartient à O(n2 ) et que l’algorithme retourne bien T trié en ordre croissant. Ces algorithmes ont tous une complexité appartenant à Θ(n2 ). Peux-t-on faire mieux ? La réponse à cette question est oui. L’idée nouvelle de base est de diviser T un deux tableaux plus petits T1 et T2 , puis de diviser T1 et T2 chacun et ainsi de suite, jusqu’à l’obtention de tableaux de petite taille, que l’on tri puis intercale pour retouver les tableaux plus grands déjà triés, puis enfin on intercale T1 et T2 triés pour retrouver T1 trié. Il y a plusieurs algorithmes de ce genre, qui se distinguent surtout selon la méthode de division des tableaux. Puisqu’ils utilisent tous l’intercalage de tableaux déjà triés, nous examinerons d’abord la complexité de cela. Intercalation de deux tableaux triés. Soient T1 , T2 deux tableaux de taille n et m respectivement, triés par ordre croissant. Le tableau T obtenu en intercalant T1 et T2 est donc de taille m + n (on ne supprime pas les éléments communs et, en cas d’égalité, on n’interchange pas l’ordre des valeurs et on place celles provenant de T1 avant celles provenant de T2 ). 7 procédure intercale (T1 , T2 ) (entrée : T1 , T2 deux tableaux triés par ordre croissant, de tailles respectives n et m ; sortie : le tableau obtenu en intercalant T1 et T2 , trié par ordre croissant) variables locales: X (une liste), j, k (des entiers variant respectivement de 1 de 1 à n et de 1 à m) X ← ∅, j ← 1, k ← 1 tantque (j ≤ n et k ≤ m) si T1 [j] ≤ T2 [k]: X ← (X, T1 [j]), j ← j + 1 sinon X ← (X, T2 [k]), k ← k + 1 finsi finpour retourner X Le nombre de tests de comparaison est égal à m + n − 1 et, après chaque test, on ajoute un élément à la liste. Ces deux opérations constituent chacune une opération élémentaire. La complexité de l’algorithme appartient donc à Θ(n + m), La preuve de l’algorithme est claire. Tri fusion. On divise T en 2 parties aussi égales que possible (c’est-à-dire T1 = T[[1,n/2]] , T2 = T[[n/2+1,n]] lorsque n est pair et T1 = T[[1,(n−1)/2]] , T2 = T[[(n+1)/2,n]] lorsque n est impair pour fixer les idées). On continue ainsi par divisions successives jusqu’à ce que tous les tableaux soient formés d’un seul élément. Puis on remonte, en intercalant les deux parties triées pour obtenir le sous-tableau précédent. La situation est mieux décrite en utilisant le langage des arbres binaires. Un arbre binaire entier fini est un ensemble fini A muni d’une structure dont la définition se fait par récurrence sur le cardinal de A. Le cardinal de A est toujours impair et les éléments de A sont appelés les sommets ou nœuds. Le structure est formée d’un élément distingué rA de A, appelé sa racine, d’un sous ensemble de A dont les éléments s’appellent les feuilles et d’un sous-ensemble de A × A dont les éléments s’appellent des arêtes. Lorsque A contient un seul élément, cet élément est à la fois la racine et une feuille, alors que l’ensemble des arêtes est vide. Supposons que A soit de cardinal n ≥ 3. Alors on a une partition de A en trois ensembles, l’un contenant pour seul élément la racine de A et l’autre ou les deux autres, que l’on note B et C étant des sous-arbres binaires de A, qu’on appelle les fils de A. L’ensemble des feuilles de A est alors la réunion des ensembles des feuilles de B et de C. L’ensemble des arêtes de A et la réunion des ensembles des arêtes de B et de C, à laquelle on ajoute deux nouvelles arêtes (rB , rA ) et (rC , rA ) qui joignent respectivement la racine de B à celle de A et la racine de C à celle de A. Soit A un arbre binaire entier et soit x, y deux sommets de A. Un chemin joignant x et y et une séquence de sommets x = x0 , x1 , x2 , . . ., xn = y telle que (xi−1 , xi ) est une arête pour tout 1 ≤ i ≤ n. L’entier n s’appelle alors la longueur du chemin. On voit immédiatement par récurrence sur A que deux sommets sont joints par au plus une arête, et que si x 6= rA est un sommet, il existe un unique chemin joignant x à rA . Par définition, le niveau de rA est 0 et, si x est un sommet autre que rA , le niveau de x est la longueur du chemin que le joint à rA . La hauteur de A est le maximum des niveaux de ses sommets. Un isomorphisme entre deux arbres binaires entiers A et A0 est une bijection de A sur A0 qui induit une bijection entre les arêtes. Un isomorphisme transforme la racine de A en celle de A0 et l’ensemble des feuilles de S en celui de A0 . Un arbre binaire entier a une représentation géométrique simple. Traditionnellement, on met la racine sur une ligne toute seule en haut (et non pas en bas comme chez les arbres végétaux), puis ses deux fils (les racines de ses deux fils) sur la ligne suivante, l’arête entre la racine et chaque fils étant représentée par un segment droit. Ensuite, on répète, en mettant tous les sommets d’un même niveau sur la même ligne. 8 Soit donc T un tableau à n éléments. On lui associe un arbre binaire A construit de la manière suivante par récurrence sur n. Les sommets de A sont certains sous-tableaux de T et la racine de A est T lui même. Si n = 1, A ne contient que le seul sommet T . Si n ≥ 2, les deux fils de la racine T de A sont les arbres associés aux deux sous-tableaux de T indexés par [1, n2 ] et par [ n2 + 1, n] ] et par [ n+1 , n] lorsque n est impair. Les feuilles de A sont les lorsque n est pair et par [1, n−1 2 2 sous-tableaux à un élément T [1], T [2], . . ., T [n]. Il est clair qu’il s’agit d’un arbre binaire entier. Le diagramme suivant montre l’arbre lorsque T a 11 éléments ; T[[a,b]] désigne le sous-tableau de T indexé par les entiers appartenant à l’intervalle [a, b] et (T [i]) désigne le sous-tableau contenant l’unique élément (T [i]). La hauteur est alors égale à 4. T T[[1,5]] T[[1,2]] T[[6,11]] T[[3,5]] T[[6,8]] T[[4,5]] (T [1]) (T [2]) (T [3]) T[[9,11]] T[[7,8]] (T [6]) (T [4]) (T [5]) T[[10,11]] (T [9]) (T [7]) (T [8]) (T [10]) (T [11]) Proposition. (i ) À isomorphisme près, l’arbre A ne dépend que de la taille n de T , en non de T lui-même. (ii ) Si T 0 est un sous-tableau de niveau k, alors la taille de T 0 se situe dans l’intervalle [ n+1 − 2k n−1 1, 2k + 1]. On suppose que n ≥ 2 et on note d l’unique entier tel que 2d < n ≤ 2d+1 . (iii ) On a h(A) = d + 1. (iv ) Si k < h(A), alors A contient 2k sommets de niveau k. En plus, A contient 2(n − 2d ) sommets de niveau h(A). Démonstration. (i ) On voit aussitôt que si T est de taille n, alors A est isomorphe à l’arbre An dont les sommets sont certains entiers ≥ 1 (pas forcément distincts) qui sont précisés (en même temps que les arêtes) inductivement comme suite : (1) A1 est l’arbre avec unique sommet 1. (1) (2) (2) Si n est pair, An est obtenu en prenant deux copies disjointes An/2 et An/2 de An/2 puis (1) en y ajoutant n comme racine, une arête joignant n à la racine de An/2 et une autre joignant n à (1) la racine de An/2 . (3) Si n est impair, An est obtenu en prenant une copie de A(n−1)/2 et une autre de A(n+1)/2 puis en ajoutant n comme racine, une arête joignant n à la racine de A(n−1)/2 et une autre joignant n à la racine de A(n+1)/2 . soit n2 soit n+1 . Elle est donc (ii ) La taille des tableaux situés au niveau 1 de A est soit n−1 2 2 n+1 située entre n−1 et . Par récurrence sur k, on voit que la taille des tableaux situés au niveau k 2 2 n+1 n−1 de A appartient à [ 2k − 1, 2k + 1]. 9 (iii ) et (iv ) Raisonnons par récurrence sur n. D’après le (i ), les valeurs de h(A) et de d ne dépendent que de n : on les note respectivement hn et dn . On note Nn (k) le nombre de sommets de A de niveau k. Lorsque n = 2, on a hn = 1 et dn = 0 ; on trouve N2 (0) = 1 et N2 (1) = 2. Donc tout est en règle. De même pour n = 3. Supposons donc que n ≥ 4. Si n est pair, alors n > n2 ≥ 2 et hn = hn/2 + 1 d’après la construction de An . Puisque 2d +2 ≤ n ≤ 2d+1 , on a également dn = dn/2 +1. Par l’hypothèse de récurrence, on a hn/2 = dn/2 +1, d’où hn = dn +1. De même, la construction de An implique Nn (0) = 2 et que Nn (k) = 2Nn/2 (k −1) pour tout k ≥ 1. Par l’hypothèse de récurrence, Nn/2 (`) = 2` lorsque ` < hn/2 et Nn/2 (hn/2 ) = 2(n/2 − 2dn/2 ). Les formules prévues pour Nn (k) en découlent. ≥ 2, n+1 < n et hn = max(h(n−1)/2 + 1, h(n+1)/2 + 1) d’après la Si n est impair, alors n−1 2 2 n+1 construction de An . Puisque 2 = n−1 + 1, l’hypothèse de récurrence implique que h(n+1)/2 = 2 n−1 h(n−1)/2 sauf lorsque 2 est une puissance de 2, auquel cas h(n+1)/2 = h(n−1)/2 + 1. Dans tout les cas, donc, hn = h(n+1)/2 + 1. Comme 2dn + 1 ≤ n ≤ 2dn +1 − 1, on a dn = d(n+1)/2 + 1. Par l’hypothèse de récurrence, on a h(n+1)/2 = d(n+1)/2 + 1, d’où hn = dn + 1. Le cas exceptionnel n−1 2 une puissance de 2 équivaut en fait à n = 2dn + 1. Dans ce cas, on voit directement que Nn (k) = 2k pour tout k < hn et que Nn (hn ) = 2. (L’arbre A2b +1 se construit à partir de A2b en ajoutant deux arêtes à la base du sommet en bas à droite.) Puisque n − 2dn = 1, on obtient la formule prévue pour Nn (hn ). Dans les autres cas, h(n−1)/2 = h(n+1)/2 et on trouve comme dans le cas n pair que Nn (k) = 2k lorsque k < hn et que n − 1 n + 1 Nn (hn ) = N n−1 (h n−1 ) + N n+1 (h n+1 ) = 2 − 2dn −1 + 2 − 2dn −1 = 2(n − 2dn ) 2 2 2 2 2 2 comme prévu. Théorème. La complexité de tri fusion appartient à Θ(n log n). Démonstration. D’après l’étude de l’algorithme d’intercalation de deux tableaux triés, le nombre de tests de comparaison necéssaires pour intercaler deux tableaux triés de tailles n1 et n2 est égal à n1 + n2 − 1. Soit h la hauteur de l’arbre associé au tri d’un tableau à n éléments en utilisant le tri fusion. Si 1 < k < h, il y a 2k sous-tableaux de niveaux k, ce qui fait 2k−1 couples de tableaux à intercaler. La taille de chaque sous-tableau de niveau k appartient à l’intervalle [ n+1 − 1, n−1 + 1] 2k 2k n+1 n−1 et l’intercalation de deux tableaux de niveaux k nécessite donc entre 2k−1 − 3 et 2k−1 + 1 tests de comparaison. Le nombre de tests de comparaison nécessaires pour intercaler les 2k−1 couples de sous-tableaux de niveau k est donc situé entre n + 1 − 3 · 2k−1 et n − 1 + 2k−1 . Les sous-tableaux de niveaux h sont des feuilles. Ils sont en nombre 2(n − 2h−1 ). Alors n − 2h−1 tests de comparaison sont nécessaires pour créer les sous-tableaux à deux éléments de niveau h−1. Soit C(n) le nombre de tests de comparaison utilisé par le tri fusion pour trier un tableau à n éléments. On tire de la discussion précédente l’encadrement h−1 X k−1 (n + 1 − 3 · 2 h−1 ) + (n − 2 ) ≤ C(n) ≤ k=1 h−1 X (n − 1 + 2k−1 ) + (n − 2h−1 ), k=1 ce qui, après simplification, donne h(n + 1) − 2h+1 + 2 ≤ C(n) ≤ h(n − 1). Puisque 2h−1 < n ≤ 2h , on en conclut que la complexité de tri fusion appartient bien à Θ(n log n). 10 Tri par tas (heapsort en anglais). L’idée s’inspire de la stratégie d’une compétition par élimination. L’équipe T [1] joue contre l’équipe T [2] et le gagnant joue ensuite contre le gagnant parmi les équipes T [3] et T [4]. Cela peut être représenté par un arbre : ici, on veut trier le tableau à 11 éléments (535, 102, 917, 283, 756, 835, 512, 729, 067, 610, 345). Comme T [1] > T [2], T [1] bat T [2] qui doit alors affronter le gagnant entre 917 et 283, soit 917. Il est clair que le plus grand élément (ici 917) sera le gagnant ; on remarque toutefois que l’autre finaliste est 729, ce qui n’est pas le deuxième élément du tableau par ordre de magnitude (ce qui devrait faire réfléchir les organisateurs de tournois par élimination . . .). On pourrait régler ce problème en rejouant le tournoi sans le gagnant ; alors le deuxième remontera à la position suprême, puis rejouer le tournoi sans le gagnant ni le deuxième pour déterminer le troisième, et ainsi de suite. On obtient ainsi effectivement un algorithme de tri. Mais un tournoi à k concurrents a besoin de k − 1 jeux ou comparaisons P pour déterminer le gagnant : si donc on commence avec un tableau à n éléments, il faudrait nk=1 (k − 1) = n(n−1) comparaisons 2 2 pour le trier jusqu’au bout, et l’algorithme est donc à nouveau de complexité Θ(n ). Afin d’obtenir un algorithme plus rapide, il faudra donc introduire une autre idée. On remarquera que l’arbre du tournoi a la propriété que toute chaı̂ne (lue du bas vers le haut) est croissante, ou encore que chaque fils est plus petit que son père. On peut donc l’interpréter comme un tri partiel du tableau. Par ailleurs, il se calcule en n − 1 comparaisons et son hauteur est dlog2 ne. Il a toutefois l’inconvénient que la plupart des éléments du tableau y sont répétés plusieurs fois : la première étape de l’algorithme de tri par tas est donc de le remplacer par un tas, c’est-àdire un arbre binaire où chaque fils est strictement plus petit que son père. Il y a plusieurs manières de construire un tas à partir d’un tableau. Par exemple, on peut procéder par une méthode de condensation de l’arbre précédent, mais ce n’est pas facile à décrire rigoureusement. Une autre méthode consiste à d’abord construire l’arbre binaire associé à T , dont la racine est T [1], ses deux fils sont T [2] et T [3] et, en général, les deux fils de T [i] sont T [2i] et T [2i + 1]. Contrairement au cas de l’arbre utilisé dans la discussion du tri fusion, il ne s’agit pas, en général, d’un arbre binaire entier ; ce sera le cas si et seulement si n est impair. Dans le cas où n est pair, le sommet T [ n2 ] a l’unique fils T [n]. Le tri par tas procède alors en deux étapes, dont la première consiste en la conversion en un tas de l’arbre binaire qui vient d’être décrit. La deuxième étape consiste en la création du tableau à partir de ce tas. On convertit l’arbre binaire en tas en travaillant du bas vers le haut. Considérons d’abord le cas d’un ’arbre binaire avec racine a et deux feuilles b et c. Il est converti en tas à l’aide de deux 11 tests de comparaison. D’abord, on test si a < b et on échange a et b si la réponse est affirmative. Ensuite, on compare le plus grand de a et de b (qui est devenu racine) avec c, et on les échange si besoin. Si T [i] est tel que T [2i] et T [2i + 1] sont déjà les racines d’un tas, on construit un tas avec racine en position T [i] de la manière suivante. Si T [i] > T [2i] et si T [i] > T [2i + 1], il s’agit d’èj d’un tas. Si T [i] < T [2i], on les échange ; si T [i] > T [2i] mais T [i] < T [2i + 1], on échange T [i] et T [2i + 1]. En procédant ainsi, on descend T [i] par échanges successifs jusqu’il trouve une position où l’arbre redevient un tas. Ce sera le cas lorsque T [i] est plus grand que ces fils (ou se trouve en position de feuille). Le nombre de tests de comparison nécessaires est égal au plus à la hauteur h := blog2 nc de l’arbre. Puisque l’arbre possède n sommets, la complexité de cette première étape appartient à O(n log n). La deuxième étape de l’algorithme de tri par tas est donc de créer le tableau trié à partir du tas ainsi construit. On sait que la racine du tas est le plus grand élément de T et on la place dans une liste qui devriendra au fur et à la mesure le tableau T trié. On crée alors un nouvel arbre binaire à n − 1 sommets, obtenu du premier en remplaçant sa racine par l’une des feuilles, qui est alors supprimée de sa position initiale. Le point essentiel est que les fils de la racine sont encore des tas. À partir de cet arbre on crée à nouveau un tas, ce qui se fait en descendant la racine dans l’arbre par échanges entre pères et fils. À l’issu de ces échanges, dont il y a au plus h, la nouvelle racine est à nouveau le plus grand élément du tas, donc le deuxième élément de T et on le place dans la liste qui deviendra T trié. Ensuite, on recommence la procédure en créant un arbre à n − 2 sommets en remplaçant la racine du précédent par l’une de ces feuilles. En continuant ainsi, on tri le tableau après au plus hn tests de comparaison. Puisque h = blog2 nc, on a hn ∈ O(n log n). La complexité de la première étape de l’algorithme appartenant ègalement O(n log n), la complexité totale du tri par tas appartient, comme celle du tri fusion, à O(n log n). Une borne inférieure pour la complexité d’un algorithme de tri par tests de comparaison Rappelons que tous les algorithmes décrits jusqu’ici utilisent les tests de comparaison entre différents éléments de l’ensemble E. Théorème. Tout algorithme de tri générique qui procède par tests de comparaison a une complexité d’au moins Ω(n log n). La démonstration est proposée en exercice (voir la feuille 2, Exercice 3). Ensuite, certains algorithmes procèdent par l’échange de deux éléments qui sont dans le mauvais ordre. Au niveau des permutations, cela correspond à effectuer une transposition. Proposition. Toute permutation π de n objets s’écrit comme produit de n − c(π) transpositions, où c(π) désigne le nombre de cycles disjoints de π (en comptant les éléments fixes comme des 1-cycles). Autrement dit, puisque c(n) ≥ 1, au plus n − 1 échanges sont en principe nécessaires pendant le tri. Les démonstrations sont proposées en exercice (voir les feuilles 2 et 3). 12 Cela semble conduire à un paradoxe, dans le sens que Θ(n log n) comparaisons sont nécessaires mais, ou bien seulement n − 1 entre elles puissent conduire à des échanges ou bien on effectue davantage d’échanges que nécessaire. Remarque. En fait, la démonstration du théorème montre que tout algorithme de tri de n objets par tests de comparaison nécessite au moins S(n) := dlog2 n!e tests (voir l’Exercice 3 de la feuille 2). La question se pose donc de connaı̂tre le nombre minimal de tests nécessaires, comme fonction de n. Il est facile de construire des algorithmes de tri utilisant dlog2 ne tests lorsque n ≥ 4. Pour tout entier n ≥ 2, il existe un algorithme, appelé (appelé parfois ou Pn insertion-fusion 3 algorithme de Ford-Johnson) dont le nombre de tests de comparaison est k=1 dlog2 4 k e, somme que nous désignerons par F (n). On trouve que F (n) = S(n) quelque soit n ≤ 11 et pour n = 21, n = 22. L’algorithme est donc optimal (du point de vue du nombre de tests de comparaison) pour ces valeurs de n. On a S(12) = 29 alors que F (n) = 30 et on peut montrer (à l’aide de calculs sur ordinateur) qu’il n’y a pas de méthode de trier 12 objets avec seulement 29 tests. Donc l’algorithme de Ford-Johnson est optimal aussi lorsque n = 12. Mais on connaı̂t des valeurs de n pour lesquels cet algorithme n’est pas optimal, dont n = 47 est la plus petite. En général, on ne connaı̂t pas le nombre minimal Smin (n) de comparaisons nécessaires pour trier n objets. Bien évidemment, S(n) ≤ Smin (n) ≤ F (n) quelque soit n. Le tri rapide L’algorithme appelé aujourd’hui tri rapide (quicksort en anglais) a été développé à partir du début des années 1960. Le principe derrière cet algorithme est l’utilisation d’un pivot p ∈ E convenablement choisi, c’est-à-dire on réarrange le tableau T en deux sous-tableaux T[[1,k]] (appelé tableau à gauche) et T[[k+1,n]] (appelé tableau à droite). Par exemple, on peut supposer que T[[1,k]] contient tous les coefficients T [i] de T tels que T [i] ≤ p alors que T[[k+1,n]] contient tous les coefficients tels que T [i] > p. La manière la plus naı̈ve d’effectuer cette opération est de créer deux listes L− et L+ puis, pour tout i = 1, 2, . . ., n, d’insérer T [i] dans L− ou dans L+ selon que T [i] ≤ p ou T [i] > p. À la fin, on a L− = T[[1,k]] et L+ = T[[k+1,n]] . La complexité de cette opération appartient donc à Θ(n). Ensuite, on répète avec chacun des deux sous-tableaux. La rapidité de l’algorithme dépend du choix du pivot. S’il est choisi de telle façon qu’à chaque étape le tableau est divisé en deux parties à peu près égales, sa complexité appartient à O(n log n). Si on ne connaı̂t rien a priori sur les éléments de T , on pourrait choisir T [1] comme pivot (puis l’élément à gauche de chaque sous-tableau). Mais dans le cas où T est déjà trié par ordre croissant, on constate que le tableau à gauche ne contient que l’élément T [1] alors que celui à droite contient les n−1 éléments restants. En répétant, on voit que dans ce cas l’algorithme effectue n−1 divisions du tableau et que la complexité appartient à Θ(n2 ). On se retrouve donc dans une situation où le cas d’un tableau déjà trié figure parmi les pires des cas ! Une situation encore plus délicate se produit lorsque T [1] > T [i] pour tout i ∈ {2, . . . , n}. Tel qu’il vient d’être décrit, l’algorithme tournera éternellement en boucle dans ce cas car le tableau à droite est alors vide. Pour éviter un problème de cette nature, il faut modifier l’algorithme en ajoutant des instructions indiquant comment procéder lorsque l’élément le plus grand d’un sous-tableau se trouve à gauche de ce sous-tableau. Cette remarque suggère que l’implémentation pratique de l’algorithme est assez délicate. Malgré ces complications, le tri rapide est, en pratique, l’un des algorithmes les plus utilisés. Une analyse mathématique assez délicate montre (et l’expérience le confirme) que le tri rapide est en moyenne plus rapide que les autres algorithmes si les éléments du tableau sont tirés au hasard 13 dans E. Quelques autres algorithmes de tri Les algorithmes décrits jusqu’ici supposent que les éléments de T appartiennent à un ensemble très grand (en principe infini) et sans structure particulière mise à part l’ordre total. Mentionnons brièvement quelques algorithmes spéciaux, c’est-à-dire adaptés à des ensembles spécifiques ou qui ont des propriétés supplémentaires. Si les éléments de T appartiennent à un petit ensemble E, de cardinalité r fixé disons, on peut les trier en complexité Θ(n). En effet, si x1 < x2 < · · · < xr sont les différents éléments de E, il suffit de prendre chacun des éléments de E l’un après l’autre, compter le nombre d’apparitions dans T puis reconstruire le tableau T trié par ordre croissant comme (x1 , x1 , . . . , x1 , x2 , . . . , xr ). Cela nécessite rn tests de comparaison. Afin d’éviter toute ambigüité lors de la discussion d’autres algorithmes de tri basés sur cette procédure, nous le décrivons par le pseudocode suivant : procédure tripetitE (T ) (entrée : T un tableau dont les éléments appartiennent à un ensemble totalement ordonné E de cardinal r et dont les éléments sont x1 < x2 < · · · < xr ; sortie : le tableau T trié) variables locales: X (une liste), i, j (des entiers avec 1 ≤ i ≤ r et 1 ≤ j ≤ n) X←∅ pour i de 1 à r pour j de 1 à n: si T [j] = xi , X ← (X, T [j]) finpour finpour retourner X Il s’agit d’un tri stable, c’est-à-dire l’ordre des éléments répétés est respecté. Tri par ordre lexicographique, tri radix. Rappelons que l’ordre lexicographique sur R2 est défini par (x, y) < (x0 , y 0 ) ssi soit x < x0 soit x = x0 est alors y < y 0 . Il s’agit d’un ordre total sur R2 et le principe de sa définition s’étend aisément à un produit cartésien E1 × E2 × · · · × Er d’ensembles totalement ordonnés Ei . Les tris lexicographiques et tris par radix sont utiles lorsque les ensembles Ei sont finis et de petit cardinal. Pour tout i ∈ {1, 2, . . . , r}, on note ri le cardinal de Ei . Le tri lexicographique tri des tableaux dont les éléments appartiennent à un produit E1 × E2 × · · · × Er en triant d’abord par rapport à la première coordonnée, puis par rapport à la deuxième, et ainsi de suite. Pour être plus précis, on applique tripetitE d’abord à la première coordonnée, puis on divise T en r1 sous-tableaux selon la première coordonnée. Ensuite, on applique tripetitE à chacun de ces sous-tableaux et ainsi de suite. Le tri radix (ou tri par base), tri d’abord par rapport à la dernière coordonnée, puis par rapport à l’avant dernière et ainsi de suite. Autrement dit, on applique d’abord tripetitE à la dernière coordonnée. Ensuite, on l’applique à l’avant-dernière coordonnée du tableau ainsi obtenu (qui n’est donc pas divisé en sous-tableaux), et ainsi de suite. Le nom tri par base a pour origine l’application au tri d’un tableau d’entiers naturels selon leur écriture en une base b. Ici, Ei est l’ensemble des chiffres {0, 1, . . . , b − 1} en base b et les entiers à trier sont présentés sous la forme t = ak−1 bk−1 + ak−2 bk−2 + · · · + a0 , les ai étant des chiffres, t s’identifiant avec (ak−1 , ak−2 , . . . , a0 ) ∈ E1 × E2 × · · · × Ek (tous les entiers t sont supposés majorés par bk − 1). 14 Exemple de tri radix. Soit à trier par ordre croissant les nombres (écrits en base 10) : T = (354, 270, 123, 70, 770, 193). (a) Première étape : tableau obtenu de T en appliquant tripetitE aux chiffres des unités. T1 = (270, 70, 770, 123, 193, 354) ; (b) Deuxième étape : tableau obtenu de T1 en appliquant tripetitE aux chiffres des dizaines. T2 = (123, 354, 270, 70, 770, 193) ; (c) Troisième étape : tableau obtenu de T2 en appliquant tripetitE aux chiffres des centaines. (70, 123, 193, 270, 354, 770), c’est-à-dire T trié par ordre croissant. Il est clair que les tris léxicographique et radix utilisent r1 r2 · · · rk n tests de comparaison. Leur complexité appartient donc à Θ(n). Puisque ce ne sont pas des algorithmes génériques, il n’y a pas de contradiction avec la borne inférieure de dlog2 ne pour le nombre de tests de comparaison pour un algorithme générique. En général, on préfère le tri radix au tri lexicographique. Un désavantage des deux est qu’ils nécessitent O(n) espace mémoire de stockage. Les algorithmes classiques d’arithmétique de base Nous étudierons ici les algorithmes classiques (c’est-à-dire ceux qui sont enseignés à l’école) d’addition, de soustraction, de multiplication et de division euclidienne avec reste, appliqués aux entiers naturels. On s’intéresse ici donc aux calculs exacts, en non aux calculs approchés effectués avec de l’arithmétique flottante. Ce point est traité dans les cours d’analyse numérique (ou devrait l’être). Un entier relatif peut être représenté comme un couple (ε, n) avec n ≥ 0 et le signe ε ∈ {0, +, −}. Puisque les règles de détermination du signe son faciles (en faisant attention au cas de zéro) et le signe n’occupe qu’un seul bit, la complexité est, pour l’essentiel, mesurée par les calculs avec des entiers naturels. Pour cela, on travaille P en base b fixée (b > 1 un entier). Tout entier naturel n a donc une i représentation unique n = ∞ 0 ai b , avec 0 ≤ ai ≤ b − 1 et ai = 0 pour tout n assez grand. Dans ce contexte, les ai sont appelés les chiffres. Si n 6= 0, on note k − 1 le plus grand entier i tel que ai 6= 0 et n est alors traditionnellement écrit sous la forme (ak−1 ak−2 · · · a0 )b (on omettra les parenthèses et la base b lorsque b = 10). On a alors soit n = 0 soit bk−1 ≤ n < bk et alors k = blogb nc + 1. Mise à part l’ajout ou la suppression d’un élément d’une liste (ou l’échange de deux membres), les opérations élémentaires sont : (a) Comparaison de deux chiffres (c’est-à-dire des entiers dans l’intervalle [0, b − 1]). (b) Addition et multiplication des chiffres. On remarque que la somme de deux chiffres appartient à l’intervalle [0, 2(b − 1)] et que le produit de deux chiffres appartient à l’intervalle [0, (b − 1)2 ]. (c) La soustraction d’un chiffre d’un entier appartenant à l’intervalle [0, 2b − 1]. (d ) La division euclidienne (quotient et reste) d’un entier naturel dans l’intervalle [0, b2 − 1] par un chiffre non nul. (e) multiplication et division euclidienne par une puissance de b. En effet la multiplication par r b fait déplacer tous les chiffres r places, en ajoutant des zéros dans les places bs , 0 ≤ s ≤ r − 1. De même, la division euclidienne de m par br coupe de développement en base b de m en deux morceaux, le quotient étant (ak−1 ak−2 · · · ar )b et le reste étant (ar−1 ar−2 · · · a0 )b . 15 En informatique, b sera généralement une puissance de 2 (le plus souvent 2, 8 ou 16 ou, dans le cas d’un processeur 32 ou 64 bits, b = 232 et b = 264 ). Si b est petit, les opérations élémentaires peuvent se limiter à chercher les valeurs dans un tableau. Un processeur P programmé pour faire des calculs rapides avec des entiers longs (c’est-à-dire de la forme i ai bi avec b = 232 ou 264 ) travaille donc à deux niveaux, dont l’un exécute les opérations élémentaires sur les chiffres en base b, et l’autre exécutes les vraies opérations sur les entiers longs. Remarque. Puisque 210 = 1024 ce qui dépasse de peu 103 = 1000, le nombre de chiffres d’un fois le nombre de chiffres en base 10. Cela permet entier n en base 2 est un peu moins que 10 3 notamment de se donner une idée approximative du nombre de chiffres décimaux d’une puissance de 2 et du nombre de chiffres en base 2. d’une puissance 10. Comparaison de deux entiers naturels. Soient m, n deux entiers naturels. On a m ≥ n si et seulement si, en utilisant l’ordre lexicographique, la liste des chiffres de m est supérieure à celle des chiffres de n. Ainsi, les entiers naturels m et n peuvent être comparés en appliquant le tri par ordre lexicographique (ou le tri radix) à leurs chiffres. Il y a max(blogb (m)c + 1, blogb (n)c + 1) comparaisons de chiffres à faire, et la comparaison de deux chiffres est une opération élémentaire. La complexité de la comparaison des deux entiers naturels m et n appartient donc à Θ(max(log(m), log(n))). Addition. Voici un pseudoprogramme. procédure add(m, n) (entrée : deux entiers naturels écrits en base b, m = (ak−1 ak−2 · · · a0 )b et n = (a0k−1 a0k−2 · · · a00 )b ; sortie : m + n écrit en base b.) variables locales : i (indice), γ ∈ {0, 1}, a (chiffre), S (résultat intermédiaire). si m = n = 0, retourner 0, sinon, k = blogb max(m, n)c + 1, i ← 0, γ ← 0, S ← 0, tantque i < k, si ai + a0i + γ < b, a ← ai + a0i + γ, γ ← 0, sinon a ← ai + a0i + γ − b, γ ← 1, finsi S ← S + abi , i ← i + 1, fintantque retourner S + γbk , finsi Dans ce pseudo-code, on nous demande d’additioner S et abi . Mais, en répétant la boucle tantque, on voit que S prend successivement les valeurs 0, (a000 )b , (a001 a000 )b , . . ., (a00k−1 a00k−2 · · · a000 )b = m+n et donc S ← S +abi signifie tout simplement ajouter a00i au début de la liste (a00i−1 a00i−2 · · · a000 )b . Il s’agit donc d’une opération élémentaire. Il est clair que la complexité de l’algorithme est proportionnelle au nombre d’itérations de la boucle tantque, soit k ; par conséquent, l’addition de deux entiers naturels m et n se fait en complexité Θ(log max(m, n)). Soustraction. On se limite au cas m ≥ n. Voici un pseudoprogramme pour le calcul de m−n. Cela nécessite un peu d’attention (penser au calcul de 305 − 286 ou de 1000 − 287, par exemple). La présentation qui suit est légèrement différente de celle que l’on apprend à l’école. procédure sub(m, n) (entrée : deux entiers naturels écrits en base b, m = (ak−1 ak−2 · · · a0 )b et n = (a0k−1 a0k−2 · · · a00 )b ; sortie : m − n écrit en base b.) variables locales : i (indice), γ ∈ {0, 1}, a (chiffre), D (résultat intermédiaire). si m = n, retourner 0, sinon, k = blogb mc + 1, γ ← 0, i ← 0, D ← 0, 16 tantque i < k, si ai − a0i − γ < 0, a ← ai − a0i − γ + b, γ ← 1, sinon a ← ai − a0i − γ, γ ← 0, finsi D ← D + abi , i ← i + 1, fintantque retourner D, finsi Lorsque m 6= n, on a m > 0 et donc ak−1 > 0, et l’hypothèse que m > n assure alors que ak−1 ≥ a0k−1 et que, si j et le plus grand indice tel que aj 6= a0j , alors aj > a0j . On en tire que a ≥ 0 quelque soit la valeur de i (et que a = 0 lorsque i > j). Il est clair que la complexité appartient à Θ(log m). Multiplication. À l’école, on apprend d’abord à multiplier n par a0 , puis par a1 b (c’est-à-dire par a1 puis décaler tous les chiffres à gauche par une place et ajouter un zéro à la fin), et ainsi de suite. À la fin, on additionne le tout. Les procédures qui suivent multiplient m par a00 , puis par a01 en décalant les chiffres à gauche Sur machine, il est plus simple d’intercaler les additions parmi les multiplications. procédure mult0(m, n) (entrée : deux entiers naturels écrits en base b, m = (ak−1 ak−2 · · · a0 )b et n = (a0k−1 a0k−2 · · · a00 )b ; sortie : mn écrit en base b.) variables locales : i, j, (entiers naturels), M (résultat intermédiaire). si (m = 0 ou n = 0), retourner 0, sinon, i ← 0, j ← 0, M ← 0, tantque i ≤ k − 1, tantque j ≤ ` − 1, M ← add(M, ai a0j bi+j ), j ← j + 1, fintantque i ← i + 1, fintantque retourner M finsi L’utilisation de la fonction add permet de garder les résultats intermédiaires déjà en base b. La complexité de l’algorithme tel qu’il est rédigé est donc la somme des complexités des add(M, ai a0j bi+j ) lorsque i varie de 0 à k et j de 0 à `, ce qui est majoré par kl max(k, `), ce qui est dans O(log m log n max (log m, log n)). Il est donc clair que l’algorithme se termine. Par ailleurs, sa preuve est immédiate : à la fin de chaque boucle sur i, M est égal au produit (ai ai−1 · · · a0 )b n ; il est écrit en base b car obtenu en application la procédure add. En modifiant l’algorithme un peu, on peut obtenir une complexité dans O(log m log n). Pour cela, il faut remplacer la ligne M ← add(M, ai a0j bi+j ) par une procédure qui ne change que le chiffre de bi+j et calcule la quantité à reporter sur le chiffre suivant. Dans le pseudoprogramme qui suit, on note respectivement quo(u, b) et rem(u, b) le quotient et le reste de division de u par b, u ayant au plus deux chiffres. (Rappelons qu’il s’agit alors d’opérations élémentaires.) procédure mult(m, n) (entrée : deux entiers naturels écrits en base b, m = (ak−1 ak−2 · · · a0 )b et n = (a0k−1 a0k−2 · · · a00 )b ; sortie : mn écrit en base b.) variables locales : i, j, N (entiers naturels), M (résultat intermédiaire, un entier naturel dont le chiffre devant bh est noté Mh ), γ (chiffre). si (m = 0 ou n = 0), retourner 0, 17 sinon, i ← 0, M ← 0, tantque i ≤ k, j ← 0, γ ← 0, tantque j ≤ `, N ← Mi+j + ai a0j + γ, Mi+j ← rem(N, b), γ ← quo(N, b), j ← j + 1, fintantque i ← i + 1, fintantque retourner M finsi On vérifie par double récurrence que Mi+j et γ sont bien des chiffres. Au début, c’est clair à partir des initialisations. Il suffit alors de constater que si Mi+j et γ sont des chiffres, alors Mi+j + ai a0j + γ < b2 . Mais les inégalités Mi+j ≤ b − 1, ai a0j ≤ (b − 1)2 et γ ≤ b − 1 entraı̂nent Mi+j + ai a0j + γ < b2 ≤ (b − 1) + (b − 1)2 + (b − 1) ≤ b2 − 1, d’où l’affirmation. Illustrons la procédure avec le calcul de 345 fois 377, avec b = 10. On a k = ` = 3. À l’issu de la boucle sur j lorsque i = 0, M vaut 5 × 377 = 1885 ; c’est donc aussi la valeur de M au début de la boucle sur j lorsque i = 1. Alors j vaut 0, i + j = 1, M1 = 8 et γ = 0, a1 = 4 et a00 = 7. Par conséquent, Mi+j + ai a0j + γ = 8 + 28 + 0 = 36, et donc M1 devient 6 et γ devient 3. Lorsque j augmente à 1, i + j = 2, M2 = 8 et γ = 3, a1 = 4 et a01 = 7. Par conséquent, Mi+j +ai a0j +γ = 8+28+3 = 39, et donc M2 devient 9 et γ est encore égal à 3. Ensuite, j augmente à 2, i + j = 3, M3 = 1 et γ = 3, a1 = 4, a02 = 3. Par conséquent, Mi+j + ai a0j + γ = 1 + 12 + 3 = 16, et donc M3 devient 6 et γ devient 1. On voit maintenant pourquoi il est nécessaire de continuer la boucle jusqu’à j = `, alors que dans la procédure mult0 il suffisait de s’arrêter en j = ` − 1. Lorsque j = 3, on a M4 = 0, a1 = 4, a03 = 0 et γ = 1. Par conséquent, M4 devient 1. La boucle sur j est donc terminée, et M est devenu 16965, ce qui est bien 45 × 377. L’étape suivante est donc d’augmenter i à 2 alors que j et γ sont réinitialisés en 0. Alors M2 = 9, a2 = 3, a00 = 7 et γ = 0, et donc M2 + a2 a00 + γ = 9 + 21 + 0 = 30, et donc M2 devient 0 et γ devient 3. En continuant ainsi, on trouve le résultat final 345 × 377 = 130065. La preuve de l’algorithme consiste à vérifier que, à l’issu de chaque boucle sur i, M est égal au produit de m et de (a0i a0i−1 · · · a00 )b . Pour chaque valeur de i et de j, il y a cinq opérations élémentaires (calcul de ai a0j , de Mi+j +ai a0J puis de Mi+j + ai a0j + γ puis du quotient et du reste après division par b), auquels s’ajoutent un nombre limité d’initialisations. Comme i varie de 0 à k et j de 0 à `, l’algorithme est toujours en temps Θ((k + 1)(` + 1)) soit Θ(log m log n). En particulier, si m ' n, alors la complexité du calcul de mn appartient à O((log n)2 ). Peuxt-on faire mieux et, par exemple, multiplier deux entiers inférieurs ou égaux à n dans un temps O((log n)c ) avec une constante c < 2 ? La réponse est oui ! (voir plus loin). Division euclidienne avec reste. On suppose m > 0 (et toujours n ≥ 0) et on cherche les entiers q, r tels que n = qm + r et 0 ≤ r < m. Rappelons que q et r sont uniquement déterminés. En effet, q est l’unique entier tel que qm ≤ n < (q + 1)m et, une fois q connu, r et déterminé par n la formule r = n − qm. On a également q = b m c et nous obtenons au passage un algorithme de calcul de la partie entière bxc pour tout nombre rationnel x. On suppose que n ≥ m ; dans le cas contraire on a q = 0 et r = n. On pose encore k = blog mc + 1 et ` = blog nc + 1, de sorte que ` ≥ k. À la différence des algorithmes précédents, on commence par la recherche du chiffre dominant de q. Alors m a k chiffres, et on commence en regardant l’entier formé des k chiffres dominants de n c. n, c’est-à-dire b b`−k 18 – Si ce nombre est supérieur ou égal à m, le chiffre dominant de q est celui de b`−k : on a n alors mb`−k ≤ n < mb`−k+1 , et il existe un unique chiffre c 6= 0 tel que cm ≤ b b`−k c mais n 1 n (c + 1)m > b b`−k c. Alors c est le chiffre dominant de q : explicitement, on a c = b m b b`−k cc. – Dans le cas contraire, on regarde l’entier formé des k + 1 chiffres dominants de n, soit n b b`−k−1 c. Le chiffre dominant de q est alors celui de b`−k−1 : on a alors mb`−k−1 ≤ n < mb`−k , n n et le chiffre cherché est l’unique chiffre c tel que cm ≤ b b`−k−1 c mais (c + 1)m > b b`−k−1 c. 1 n Explicitement, on a c = b m b b`−k+1 cc. Par exemple, si on cherche le quotient et le reste de division euclidienne de n = 130165 par m = 377, on constate que le nombre formé des 3 premiers chiffres de n, soit 130, et inférieur à m. On est donc dans le deuxième cas, et on constate que 3 × 377 = 1131 ≤ 1301 < 4 × 377 : le chiffre dominant de q est donc 3. Ensuite, on répète en remplaçant n par n0 , où n0 = n − cmb`−k dans le premier cas et par 0 n = n − cmb`−k+1 dans le second. Dans les deux cas, le nombre de chiffres baisse strictement, et on a un algorithme récursif. La seule nouveauté est la présence éventuelle de chiffres nuls. On a toujours n0 < b`−1 ; le chiffre après c sera nul si et seulement si n0 < mb`−k−1 dans le premier cas et n0 < mb`−k dans le second. n Nous n’avons pas encore discuté du calcul de c. Les formules explicites c = b m1 b b`−k cc et 1 n c = b m b b`−k cc font intervenir des divisions par m, et leur utilisation ne constituerait donc pas une opération élémentaire. Une possibilité serait de d’essayer successivement c = 1, c = 2 jusqu’à n n ce qu’on trouve c tel que cm ≤ b b`−k c < (c + 1)m ou cm ≤ b b`−k+1 c < (c + 1)m. Une autre n n possibilité serait d’effectuer une recherche dichotomique, en comparant b b`−k c ou b b`−k+1 c avec {m, 2m, · · · , (b − 1)m} (voir l’exercice 3 de la feuille 2). Ici encore, le calcul d’un produit cm, où 1 ≤ c ≤ b − 1, n’est pas une opération élémentaire mais, comme b est fixé, la procédure mult permet son calcul en temps O(log m). De même, le nombre total de produits cm à calculer est majoré uniquement en fonction de b. Il s’ensuit que c peut être calculé en temps O(log m). Dans le pseudoprogramme qui suit, on suppose disposer d’une procédure chif tel que, étant donnés deux entiers m > 0 et 0 ≤ A ≤ mb − 1, chif(m, A) retourne le chiffre c tel que cm ≤ A < (c + 1)m. procédure div(n, m) (entrée : deux entiers naturels m et n avec m > 0 et écrits en base b ; sortie : le couple (q, r) des deux entiers naturels q et r tels que n = qm + r et 0 ≤ r < m.) variables locales : i, k, `, N (entier naturels), c (chiffre), Q (résultat intermédiaire) si n < m, retourner (0, n), sinon, k = blogb mc + 1, ` = blogb nc + 1, si n ≥ mb`−k , i ← ` − k, sinon, i ← ` − k − 1, finsi N ← n, Q ← 0, tantque i ≥ 0, Q ← Q + chif(m, bN/bi c)bi , N ← N − chif(m, bN/bi c)mbi , i ← i − 1, fintantque retourner(Q, N ), finsi La preuve de l’algorithme consiste à remarquer que, à chaque étape, on a n = Qm + N , et que à la fin on a 0 ≤ N < m. On note que, à chaque étape, on a N < mbi+1 , ce qui implique que bN/bi c ≤ mb − 1, et on a le droit d’appliquer chif. La complexité est gouvernée par le nombre de fois que l’on applique 19 chif, ce qui à peu près ` − k ≈ logb (n/m). Puisque chif a une complexité dans O(log m) et la multiplication chif(m, bN/bi c)mbi est la multiplication de m par un chiffre puis par une puissance de b, la complexité de la mise à jour de Q et de N appartient à O(log m). Il s’ensuit que la complexité de div appartient à O(log m log (n/m)). Calcul du pgcd de deux entiers Soient encore m, n deux entiers naturels. Notre premier but est d’estimer la complexité du calcul du pgcd de m et de n à l’aide de divisions euclidiennes successives. On supposera que n ≥ m (dans le cas contraire, on interchange m et n). Le cas m = 0 étant trivial, on supposera également que m ≥ 1. Rappelons que l’algorithme se décrit ainsi : on pose r−1 = n, r0 = m. Les suites qi (i ≥ 0) et ri (i ≥ 1) sont alors définies récursivement par r−1 = q0 r0 + r1 et 0 ≤ r1 < r0 , puis, si ri 6= 0, par ri−1 = qi ri + ri+1 et 0 ≤ ri+1 < ri . On a alors r0 > r1 > · · · > ri > · · · et, les ri étant des entiers naturels, il existe donc un indice, que nous noterons k(m, n) (ou tout simplement k si aucune confusion n’est à craindre), tel que rk−1 6= 0 mais rk = 0. À ce stade la suite s’arrête et rk−1 est le pgcd de m et de n, que nous noterons pgcd(m, n). Une première question est d’estimer k(m, n) en fonction de (m, n). Pour cela, on remarque d’abord que ri−1 = qi ri + ri+1 ≥ ri + ri+1 quelque soit i, car qi ≥ 1. Cela suggère comparer la suite (ri ) avec une suite (si ) vérifiant si−1 = si +si+1 pour tout i ∈ {0, 1, . . . , k − 1} et sk−1 = 1, sk = 0. Une telle suite est déterminée par les dernières conditions sk = 0, sk−1 = 1, qui entraı̂ne que sk−2 = sk−1 +sk = 1+0 = 1, puis sk−3 = sk−2 +sk−1 = 1+1 = 2, puis sk−4 = 2 + 1 = 3, sk−5 = 3 + 2 = 5 et ainsi de suite. Autrement dit, sk , sk−1 , sk−2 , . . ., s0 est le début de la suite de Fibonacci (Fi )i≥1 définie par F0 = 0, F1 = 1 et par Fi+2 = Fi+1 + Fi pour tout i ≥ 2. Elle commence par 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, . . . . Elle est strictement croissante à partir du terme F1 . La proposition suivante est donc une conséquence immédiate de la discussion précédente. Proposition. Si k = k(m, n), alors m ≥ Fk . Démonstration. En effet, avec les notations qui viennent d’être introduites, on a successivement rk = sk = 0 = F0 , rk−1 ≥ sk−1 = 1 = F1 , rk−2 ≥ sk−2 = F2 puis, en général, rk−i ≥ sk−i = Fi pour tout i ∈ {0, 1, . . . , k} et donc en particulier m = r0 ≥ s0 = Fk . Afin d’estimer k(m, n), il suffit donc de savoir estimer les nombre de Fibonacci Fk . Proposition. Soit √ 5+1 = 1.6180339887498948482 . . . 2 le nombre d’or. Alors pour tout k ≥ 0, on a φ= 1 (−1)k−1 Fk = √ φk + . φk 5 Le résultat peut se vérifier par récurrence sur k ou mieux, en l’interprétant comme un cas particulier de la résolution de suites récurrentes linéaires à coefficients constants. En effet, on sait 20 que si p et q sont deux complexes, alors toute suite vérifiant une relation de récurrence de la forme un+1 = pun + qun−1 est de la forme un = Aθn + Bψ n , où θ et ψ sont les racines (supposées distinctes et au moins une entre elles non-nulle) du polynôme x2 − px − q, et A et B sont des constantes, qui sont déterminées par les valeurs de u0 et de u1 par exemple. (Si x2 − px − q a une racine double θ 6= 0, alors la suite est de la forme un = (An + B)θn , où A et B sont encore des constantes.) Théorème. Il existe des constantes C > 0 et D telles que k(m, n) ≤ C log m + D quelque soit m ≥ 1 et quelque soit n ≥ m. k−1 Démonstration. Puisque φ > 1, on a | (−1) φk | ≤ 1 pour tout k ≥ 0 et donc 1 Fk ≥ √ φk − 1 5 pour tout k ≥ 0. Il s’ensuit que si k = k(m, n), alors m ≥ Fk ≥ √15 (φk − 1). Le théorème en découle en prenant les logarithmes et après un peu de simplification. Théorème. La complexité du calcul du pgcd de deux entiers m et n avec 0 < m ≤ n appartient n . à O (log m)2 + log m log m Démonstration. Soit k = k(m, n). D’après notre étude de la division euclidienne avec reste, chaque étape ri−1 = ri qi + ri+1 a une complexité dans O(log ri log ri−1 ). La complexité totale ri appartient donc à k−1 X ri−1 O . log ri log ri i=0 (∗) n Ici, le terme avec i = 0 appartient à O(log m log m ) car r−1 = n et r0 = m. L’étude de la somme k−1 X log ri log i=1 ri−1 ri c pour tout i, ce qui entraı̂ne que ri−1 ≤ qi +1 peut être effectuée ainsi. Tout d’abord, on a qi = b ri−1 ri ri ri−1 et donc que log ri ≤ log (qi + 1) ce qui est majoré par log qi + 1 comme en voit en appliquant le théorème des accroissements finis à la fonction x 7→ log x sur l’intervalle [qi , qi + 1]. D’autre part, ri est majoré par m lorsque i ≥ 0. Il s’ensuit que log ri ≤ log m et donc k−1 X i=1 k−1 k−1 X X ri−1 log ri log ≤ log m (log qi + 1) = log m log qi + (k − 1) log m. ri i=1 i=1 On sait déjà que k ∈ O(log m). Afin de conclure, il suffit donc de démontrer que log m, ce qui est une conséquence du lemme suivant. Q Lemme. On a k−1 i=1 qi ≤ m. Pk−1 i=1 log qi ≤ Démonstration du lemme. On a rk−2 = rk−1 qk−1 ≥ qk−1 car rk−1 est un entier naturel non nul. Ensuite rk−3 = rk−2 qk−2 + rk−1 ≥ qk−2 qk−1 et doncQrk−4 = rk−3 qk−3 + rk−2 ≥ qk−3 qk−2 qk−1 . En remontant ainsi, on trouve successivement rk−j ≥ j−1 i=1 qi pour j = 1, 2, . . ., k et donc, en Qk−1 particulier, m = r0 ≥ i=1 qi . Remarque. Nous avons donc majoré le nombre k de divisions euclidiennes avec reste nécessaires pour calculer le pgcd de m et de n lorsque n ≥ m ≥ 1 par C log m + D pour certaines constantes 21 C > 0 et D. On peut se demander si, dans le pire des cas, il faut effectivement Ω(log m) divisions. La réponse est oui, et un exemple est fourni par le cas des nombres de Fibonacci m = F` et n = F`+1 . Remarquons que si i ≥ 3, alors Fi+1 < 2Fi , comme on le voit par récurrence sur i. On en tire que le quotient de la division euclidienne avec reste de Fi+1 par Fi est 1 et le reste est donc Fi+1 − Fi = Fi−1 . Il s’ensuit que, si ` ≥ 3, alors qi = 1 et que ri = F`−i pour tout i ≤ ` − 2. Puisque F2 = 1, le dernier reste non-nul est F2 = r`−2 et on a donc k(F` , F`+1 ) = ` − 1. Puisque F` ∼ √15 φ` lorsque ` → +∞, on voit bien que dans ce cas le nombre de divisions nécessaires appartient à Ω(log m). L’équation de Bézout et l’algorithme d’Euclide étendu Passons maintenant à l’étude du calcul d’une solution (u, v) de l’identité de Bézout un + mv = d, où d = pgcd(m, n). Cela peut se faire en remontant le calcul des ri et des qi . Tout d’abord, on a d = rk−1 et donc rk−3 − qk−2 rk−2 = d. En substituant rk−2 = rk−4 − qk−3 rk−3 dans cette équation, on obtient une relation de la forme uk−4 rk−4 + vk−3 rk−3 = d. De même, en substituant rk−3 = rk−5 − qk−4 rk−4 on obtient une relation de la forme uk−5 rk−5 + vk−4 rk−4 = d. En répétant, on arrive à une relation de la forme ur−1 + vr0 = d comme voulu. C’est une méthode que l’on rencontre très souvent dans les cours d’arithmétique en licence. Mais, présentée ainsi, elle a l’inconvient de nécessiter la garde en mémoire de toutes les étapes intermédiaires. L’algorithme d’Euclide étendu définit inductivement des suites (si ) et (ti ) en même temps que les suites (qi ) et (ri ) de telle manière que à la fin de l’algorithme, u = si et v = ti sont des solutions de un + vm = d. En voici un pseudoprogramme. procédure EE(n, m) (entrée : n et m deux entiers naturels tels que n ≥ m ≥ 1 ; sortie : (u, v, d) ∈ Z2 × N∗ tel que un + vm = d) variables locales: i (indice), ri , qi , si , ti (entiers) r−1 ← n, r0 ← m, s−1 ← 1, s0 ← 0, t0 ← 1, t−1 ← 0, i ← 0, tantque ri 6= 0, qi ←quo(ri−1 , ri ), ri+1 ← ri−1 − qi ri , si+1 ← si−1 − qi si , ti+1 ← ti−1 − qi ti , i ← i + 1, fintantque retourner(si−1 , ti−1 , ri−1 ) Ici, le quotient quo(ri−1 , ri ) de la division euclidienne avec reste de ri−1 par ri est calculé à l’aide de la procédure div(ri−1 , ri ) décrite plus haut. Cette procédure donne également le reste ri+1 =rem(ri−1 , ri ) mais la redaction ri+1 ← ri−1 − qi ri permet de souligner la similarité entre les rélations de récurrence satusfaites par les ri , les si et les ti . La preuve de l’algorithme consiste à vérifier que si n + ti m = ri quelque soit i. C’est vrai lorsque i = −1 et i = 0 d’après l’initialisation de s−1 , de s0 , de t−1 et de t0 . Si l’on sait que si−1 n + ti−1 m = ri−1 et que si n + ti m = ri , alors on constate que si+1 n + ti+1 m = (si−1 − qi si )n + (ti−1 − qi ti )m = si−1 n + ti−1 m − qi (si n + ti m) = ri−1 − qi ri = ri+1 . En particulier, si k = k(m, n), on a sk−1 n + tk−1 m = rk−1 = d. Tel qu’il est présenté, l’algorithme calcule également sk et tk vérifiant sk n + tk m = rk = 0, ce qui paraı̂t inutile. Mais on verra (voir la feuille d’exercices 4) que si et ti sont premiers entre eux quelque soit la valeur de i, ce qui démontre le corollaire suivant : Corollaire. On a sk tk 6= 0, et |tk | |sk | est l’écriture de 22 n m comme fraction réduite. On montrera en exercice (voir également la feuille 4), que la solution (sk−1 , tk−1 ) trouvée par l’algorithme EE est la même que celle obtenue par la méthode rencontrée en licence. L’analyse de la complexité nécessite un peu de soin. À l’étape i, le calcul de qi et de ri appartient toujours à O(log ri log ri−1 ). Mais il faut y ajouter désormais le coût des calculs de si+1 ri et de ti+1 , et pour cela il faut savoir majorer ces entiers. Lemme. On reprend les notations qui précèdent. On a les majorations n m , |ti | ≤ |si | ≤ ri−1 ri−1 quelque soit i ∈ {0, 1, . . . , k}. La démonstration de ce lemme est proposée en exercice (voir l’Exercice 2 de la feuille 4). Lorsque i = 0, la boucle calcule (q0 , r1 , s1 , t1 ). Ici, la complexité du calcul de q0 et de r0 n appartient à O(log m log m ), comme déjà expliqué. Mais s1 = 1 et t1 = −q0 et donc le calcul de s1 et de t1 n’ajoute pas à la complexité. Lorsque i ≥ 1, la complexité du calcul de si+1 comme si−1 − qi si appartient donc à l’ensemble O(max(log |si−1 |, log qi log |si |)). D’après le Lemme, on a |si−1 | ≤ m et |si | ≤ m : on peut donc majorer max(log |si−1 |, log qi log |si |) par max(log m, log qi log m) puis par (log qi + 1) log m. Par conséquent, la contribution du calcul des si appartient à k−1 X O (log qi + 1) log m ⊆ O((log m)2 ) i=1 Qk−1 car on a vu précédemment que i=1 qi ≤ m. Par un argument semblable, lorsque i ≥ 1, le calcul de ti+1 comme ti−1 − qi ti a un coût appartenant à O((log qi + 1) log n). On en tire que la complexité du calcul de l’ensemble des ti appartient à k−1 X O (log qi + 1) log n ⊆ O((log m log n)). i=1 Puisque n ≥ m et n ≥ n , m le résultat suivant est une conséquence de ce qui précède. Théorème. L’algorithme d’Euclide étendu EE qui calcule une solution de l’équation de Bézout um + vn = d, d = pgcd(m, n), (u, v) ∈ Z2 a une complexité appartenant à O(log m log n). L’ensemble O(log m log n) étant symétrique en m et en n, ce résultat est également valable lorsque n ≤ m. L’arithmétique dans le corps des rationnels n Tout nombre rationnel s’écrit de façon unique sous la forme m avec n ∈ Z et m ≥ 1 premiers n entre eux. (En particulier, m = 1 lorsque n = 0.) On identifie m avec le couple d’entiers (n, m). Si plus généralement (n, m) appartient à Z2 et m et n sont écrites en base b, une mesure de la complexité de (n, m) est la somme du nombre de chiffres Cb (n) + Cb (m) de m et de n en base b, soit logb |n| + 1 + logb |m| + 1 lorsque mn 6= 0. Plus généralement, si on fixe une norme ||.|| sur R2 , on peut mesurer la complexité de (n, m) par ||(Cb (n), Cb (m))|| lorsque mn 6= 0. Puisque toutes les normes sur R2 sont équivalentes, on se 23 rend compte très rapidement que le choix de la norme est peu importante dans les questions de complexité. n avec n et m premiers entre eux, on appelle parfois ||(log |n|, log m)|| Si α ∈ Q× , α = m la hauteur (logarithmique) de α associée à ||.||, et on la note h||.|| (α). Il est commode de poser h||.|| (0) = 0. Le fait que toutes les normes soient équivalentes implique que Θ(h||.|| ) est indépendante de la norme choisie. On écrira donc h à la place de h||.|| si le choix de la norme est claire, ou si ce choix est immatériel. Les opérations de l’arithmétique élémentaire se réduisent à celles sur les entiers grâce aux formules n −1 m n q np ± mq nq nq ± = , = , = , m p mp mp mp m n la dernière formule n’étant valable que lorsque m 6= 0. Leur complexité est facilement mesurée en n termes de h(α) et de h(β), où α = m et β = pq . Considérons par exemple le cas de l’addition. En général, il y a trois multiplications (np, mq, mp) à effectuer, puis une addition (np + mq) et, enfin, la simplification du numérateur et du dénominateur, ce qui nécessite le calcul de leur pgcd, puis la division du numérateur et du dénominateur par ce pgcd. Les trois multiplications ont des complexités appartenant respectivement à O(log n log p), à O(log m log q) et à O(log m log p), qui sont tous des sous-ensembles de O(h(α)h(β). La complexité de l’addition np + mq appartient ègalement à cet ensemble. Par contre, la complexité du calcul du pgcd de np + mq et de mp appartient, dans le pire des cas, à O((max(h(α), h(β))2 ). Par un calcul semblable mais plus simple, on voit que la complexité de la multiplication appartient également à O((max(h(α), h(β))2 ). Par contre, le calcul de 1/α est une opération élémentaire : il suffit d’échanger m et n et rappeler que pgcd(m, n) = pgcd(n, m). On remarque donc une différence fondamentale par rapport aux opérations arithmétiques classiques dans Z. L’addition a une complexité appartenant à O((max(h(α), h(β))2 ) alors que, lorsque α, β ∈ Z, la complexité de l’addition appartient à O(max(h(α), h(β)). Concrètement, cela signifie que le nombre de chiffres du numérateur et du dénominateur augmente rapidement lorsque on effectue des additions successives. Par exemple, les dénominateurs des rationnels α1 , α2 , . . ., αn sont premiers entre eux deux-à-deux, le dénominateur de α1 + α2 + · · · + αn est le produit de ceux des αi . Cela a comme conséquence que la complexité des calculs avec des rationnels ont tendance à augmenter très rapidement. À titre d’exemple, la division euclidienne avec reste du polynôme x10 par x2 − 61 x + 15 donne x10 = (x2 − 61 x + 15 )q(x) + r(x), où 7 6 5 q(x) = x8 + x6 − 31x − 67x + 180 1080 875501x 198059 r(x) = 1259712000 + 5248800000 . 781x4 32400 + 3193x3 194400 − 12151x2 5832000 − 127099x 34992000 − 198059 , 1049760000 L’expérience montre que la situation est si grave que nous sommes amenés à donner le conseil suivant, qui pourrait sembler un peu dramatique au premier regard : Dans la mesure du possible, on évitera des calculs avec les nombres rationnels qui ne sont pas les entiers. Il y a toutefois un exemple où l’utilisation des rationnels peut être intéressante. Il s’agit de l’utilisation de la méthode de Newton, par exemple pour calculer une racine carrée. 24 Rappelons le principe de la méthode de Newton. Soit f une fonction de classe C (2) sur un intervalle ouvert I. On suppose qu’il existe α ∈ I tel que f (α) = 0 mais f 0 (α) 6= 0. On peut montrer que si x ∈ I est suffisamment proche à α, alors la suite (xn ) définie par x0 = x et n) xn+1 = xn − ff0(x converge vers α. En outre, cette convergence est quadratique, dans le sens qu’il (xn ) existe une constante C > 0 telle que |xn+1 − α| ≤ C|xn − α|2 pour tout n assez grand. Cela signifie, grosso modo, que le nombre de chiffres décimaux corrects de l’approximation xn de α double à chaque itération. Supposons par exemple que f est un polynôme à coefficients rationnels. Si x ∈ Q, alors xn ∈ Q pour tout n et le calcul de le suite (xn ) appartient au domaine du calcul exact. En prenant pour f le polynôme x2 − a, avec a ∈ Q∗+ , par √ exemple, on obtient une méthode de calcul très efficace d’une valeur approchée rationnelle de a. √ Cette idée peut être utilisée, par exemple, pour calculer la partie entière de n lorsque n est un entier naturel. Lorsque n est très grand, cette procédure √ sera beaucoup plus rapide qu’une procédure dichotomique, où on détermine k tel que bk ≤ n < bk+1 (n étant écrit en base b), puis on élève au carré successivement bk , bk + bk−1 , bk + 2bk−1 , jusqu’à ce qu’on trouve le chiffre ck−1 tel que (bk + ck−1 bk−1 )2 ≤ n < (bk + (ck−1 + 1)bk−1 )2 , puis on élève au carré successivement bk + ck−1 bk−1 , bk + ck−1 bk−1 + bk−2 , bk + ck−1 bk−1 + 2bk−2 jusqu’à ce qu’on trouve le chiffre ck−2 tel que (bk + ck−1 bk−1 + ck−2 bk−2 )2 ≤ n < (bk + ck−1 bk−1 + (ck−2 + 1)bk−2 )2 et ainsi de suite. Par ailleurs, comme nous allons voir plus loin, l’idée derrière la méthode de Newton a d’autres applications en calcul exact. Calculs modulo un entier naturel. La situation ici est beaucoup plus agréable que dans le corps des nombres rationnels. En fait, nous verrons très vite que les calculs (mod m) ont des applications aux algorithmes utilisant des entiers et même des nombres rationnels. Notation. Si m ≥ 1 est un entier naturel, on note Zm l’anneau Z/mZ. Lorsque m = p, un nombre premier, on le notera souvent Fp . (On trouve également la notation Zp , mais cela peut semer de la confusion.) Si a ∈ Z, on note am (ou tout simplement a si aucune confusion n’est à craindre) sa classe dans Zm . Si α ∈ Zm , on note α̃ ou (α)˜ l’unique représentant a ∈ Z de α qui vérifie 0 ≤ a < m. On identifie α avec α̃, dans le sens qu’on considère que α soit connu si et seulement si α̃ soit connu, et le passage entre α et α̃ est considéré comme une opération élémentaire. Par conséquent, la détermination de la classe (mod m) d’un entier quelconque a n’est pas une opération élémentaire. Sa complexité est celle du calcul de α̃, où a = α. Or, α̃ est le reste de la division de a par m ; la complexité de la détermination de α est donc celle du calcul de ce reste, soit O(log m log |a| ). m Soient α, β ∈ Zm . Alors α̃ ± β̃ 6= (α ± β)˜ en général, et le calcul de (α + β)˜ nécessite le calcul du reste de la division de α̃ ± β̃ par m. On a 1 − m ≤ α̃ ± β̃ ≤ 2m − 1 et, comme l’addition ou la soustraction de deux entiers a et b se fait en temps O(max(log |a|, log |b|)) et la division euclidienne de a par m en temps O(log m log |a| ), on voit que le calcul de α ± β se fait en temps m O(log m) quelque soient les valeurs de α et de β. Considérons de la même façon le calcul de αβ. Ici, 0 ≤ αβ ≤ (m − 1)2 et (αβ)˜ est le reste après division par m d’un entier positif ne dépassant pas m2 . Le calcul de αβ a un coût dans 25 2 O((log m)2 ), alors que la division euclidienne a un coût dans O(log m log mm ) ce qui est encore égal à O((log m)2 ). Passons au calcul de α/β. Cela suppose que β soit inversible, c’est-à-dire qu’il existe γ ∈ Zm tel que βγ = 1. Alors α/β = αγ et le calcul de α/β est réduit au calcul de γ puis du produit αγ. Rappelons que β est inversible si et seulement si pgcd(β̃, m) = 1, ou encore si et seulement si l’équation de Bézout uβ̃ + vm = 1 possède une solution (u, v) ∈ Z2 . Lorsque c’est le cas, on a γ = u. Le calcul de u se fait avec l’algorithme d’Euclide étendu EE ; son temps de calcul est donc dans O(log m log β̃) ⊆ O((log m)2 ). D’après l’Exercice 2 de la feuille 4, on sait que |u| < m. Par conséquent, γ̃ = u si u ≥ 0 et γ̃ = u + m is u < 0. Le calcul de u + m est dans O(log m), donc n’ajoute rien de significatif. Par conséquent, le calcul de γ se fait en temps O((log m)2 ) et, d’après notre discussion du calcul du produit, αγ se calcule encore en temps O((log m)2 ). Au total, donc, α/β se calcule en temps O((log m)2 ). Aux algorithmes d’addition, de soustraction, de multiplication et de division, il convient de mentionner ici le calcul de puissances. Afin de calculer αn , où n ≥ 1 est un entier, la méthode de carrés successifs et la plus efficace. En voici le pseudoprogramme. procédure puiss(α, n) (entrée : α ∈ Zm , n entier naturel ; sortie : αn ) variables locales : ` entier naturel, β, γ éléments de Zm ` ← n, β ← 1, γ ← α, tantque ` > 0, si ` pair, γ ← γ 2 , ` ← 2` , sinon, β ← βγ, γ ← γ 2 , ` ← `−1 , 2 finsi fintantque retourner β Le nombre d’étapes est égal au nombre de chiffres de n écrit en base 2. À chaque étape, il y a un plus deux multiplications à effectuer, qui se font en temps O((log m)2 ). Il s’agit donc d’un algorithme à complexité appartenant à O((log m)2 log n) ; il est donc beaucoup plus rapide que l’algorithme naı̈f , qui calcule successivement α, α2 = αα, α3 = α2 α, . . ., αk+1 = αk α, . . ., αn = αn−1 α qui a une complexité appartenant à O((log m)2 n). Afin de prouver l’algorithme, il est utile de le généraliser un peu. Nous verrons que si, au lieu d’initialiser β en 1, nous l’initialisons en un élément quelconque ζ de Zm , alors l’algorithme a pour sortie ζαn et non αn . Pour cela, on raisonne par récurrence sur n, le cas n = 0 étant clair. Supposons donc que n ≥ 1. Si n est pair, on applique d’abord l’instruction si ` pair, γ ← γ 2 , ` ← 2` , avec ` = n et γ = α. L’hypothèse de récurrence implique alors que la sortie de l’algorithme sera alors la même n que lorsque n est remplacé par n2 , α par α2 , et β par ζ, soit ζ(α2 ) 2 = ζαn . De même, lorsque n est impair, la sortie de l’algorithme sera la même que lorsque n est remplacé par n−1 , α par α2 et 2 n−1 β par αζ, soit αζ(α2 ) 2 = ζαn . Rappelons pour mémoire le résultat suivant. Théorème (appelé souvent théorème d’Euler). Soit α ∈ Zm un élément inversible. Alors αφ(m) = 1, 26 où φ est la fonction indicatrice d’Euler, c’est-à-dire φ(m) est le nombre d’entiers k ∈ {0, 1, . . . , m− 1} premiers à m. Si r dśigne le reste après division euclidienne de n par φ(m), alors αn = αr . Si donc φ(m) est connu, et n est plus grand que φ(m), une méthode alternative de calculer αn serait de calculer r puis de calculer αr . Puisque la complexité de la division euclidienne appartient à O(log n log φ(m) ⊆ O(log n log m), cela présente des avantages si n est grand par rapport à m. Lorsque α est inversible, on a la formule 1/α = αφ(m)−1 . Elle permet de calculer 1/α comme une puissance positive de α. Le temps de calcul appartient à O((log(m)2 φ(m)) en général, ce qui n’est pas aventageux. Par contre, si l’on connaı̂t l’ordre e de α et s’il est relativement petit, le calcul de 1/α comme αe−1 peut être relativement intéressant. Malheureusement, on ne connaı̂t pas d’algorithme rapide de calcul de l’ordre de α en général. Et de φ(m) non plus. Il y a une formule explicite pour φ(m), à savoir Y 1 , φ(m) = m 1− p p|m le produit étant pris sur tous les nombres premiers p divisant m. Le calcul de φ(m) nécessite donc une connaissance de l’ensemble des nombres premiers divisant m. Mais si p est un nombre premier divisant m, alors l’exposant f de la puissance exacte de p divisant m est majoré par logp m : si donc on connaı̂t l’ensemble des diviseurs premiers de m, il est facile de déterminer la factorisation complète de m. Autrement dit, connaı̂tre φ(m) équivaut essentiellement à connaı̂tre la factorisation de m. Mais nous ne connaissons pas d’algorithme de factorisation d’un entier m dont la complexité appartient à O((log m)c ), quelque soit la valeur de c. Quelques remarques sur les calculs dans les anneaux Par anneau, on entendra toujours anneau commutatif unitaire. On écrit respectivement 0 ou 0A , 1 ou 1A pour les éléments zéro et l’unité. Jusqu’ici, nous nous limités aux calculs dans Z, dans Q et dans les anneaux Zm = Z/mZ. Désormais, nous allons nous intéresser aux calculs dans des anneaux plus généraux. Soit donc A un anneau. Un premier problème est de comparer les temps de calculs dans certains anneaux construits à partir de A avec les temps de calcul dans A. Si A est un anneau, voici trois méthodes de construire un autre anneau à partir de A : (i ) L’anneau (ou algèbre) des polynômes A[x], x une indéterminée ; (ii ) Lorsque A est intègre, le corps de fractions de A, que nous noterons Fr(A). (iii ) L’anneau quotient A/I, I étant un idéal sur A ; On pourrait y a ajouter : l’anneau produit A × B, B étant un second anneau, ou Ad , (d ≥ 1), ou encore Mn (A), l’algèbre des matrices carrées d’ordre n à coefficients dans A. Par ailleurs, la construction du corps de fractions peut être généralisée ainsi, A étant toujours supposé intègre. Une partie S ⊆ A est dite multiplicative si (a) 1 ∈ S, (b) si s, t ∈ S, alors st ∈ S. L’anneau des fractions à dénominateurs dans S, noté S −1 A, est l’ensemble A × S quotienté par la relation d’équivalence (a, s) ∼ (b, t) si et seulement si at = bs. La classe d’équivalence de (a, s) sera notée a/s, as ou as−1 . On munit S −1 A des lois d’addition, de soustraction est de multiplication suivantes : a b at + bs + = , s t st a b at + bs − = , s t st 27 ab ab = . st st L’élément 0 est la classe de (0, 1), l’unité est celle de (1, 1). La classe de (a, s) est inversible si et seulement s’il elle contient un élément (b, t) tel que b ∈ S ; son inverse est alors la classe de (t, b). On obtient le corps de fractions de A en prenant pour S l’ensemble des éléments non-nuls de A. Lorsque A n’est pas intègre, la relation ∼ n’est plus une relation d’équivalence en général. On la remplace alors par : (a, s) ∼ (b, t) si et seulement s’il existe u ∈ S tel que (at − bs)u = 0. Les définitions de l’addition, de la soustraction et de la multiplication sont inchangées. Dans ce cours, on ne considérera que le cas où A est intègre. Grosso modo, les anneaux dans lesquels on sait programmer des calculs exacts sont ceux qui peuvent être construits à partir de l’anneau Z par une suite finie de constructions de type (i), (ii ) (généralisé à l’anneau des fractions) et (iii ). Nous allons discuter cas-par-cas les problèmes posés par les calculs de base dans ces anneaux, en supposant programmés les calculs de base dans A. Dire que nous savons programmer les calculs de base dans A signifie que nous disposons de : (∗) une ensemble S dont les éléments représentent les éléments de A. On dispose d’un algorithme testant si oui ou non deux éléments de S représenent le même élément de A. Parfois, S contient un sous-ensemble R contenant un et un seul représentant de chaque élément de S, que l’on convien d’appeler représentant distingué. (∗∗) des programmes permettant le calcul de la somme, la différence et le produit de deux éléments de A, dont les entrées et la sortie sont les représentants distingués appartenant à R. Par exemple, si A = Z, on utilise comme représentation d’un élément n de A le couple (ε, (ak−1 ak−2 · · · a0 )b ) où ε ∈ {−, 0, +} est le signe de n et (ak−1 ak−2 · · · a0 )b ) est l’écriture en base b de |n|. Ici, cette représentation est unique, et R = S. Si A = Zm , où m ≥ 1, on prend S = Z et R est l’ensemble des entiers compris entre O et m − 1. Lorsque A = Q, on prend S = Z × (Z \ {0}) et, si l’on suit les conventions du paragraphe consacré au calculs avec des nombres rationnels, R est composé des couples (n, m) ∈ S avec m > 0 et pgcd(m, n) = 1. Cette dernière construction se généralise aux anneaux de fractions S −1 A. Si S est un ensemble de représentants des éléments de A et si T est un sous-ensemble de S représentant des éléments de S, alors tout élément de S −1 A est représenté par un couple appartenant à S × T et les opérations d’addition, de soustraction et de multiplication dans S −1 A revient à des opérations arithmétiques dans A. Bien entendu, il faut disposer d’un algorithme testant si un élément de S appartient à T , ce qui sera le cas notamment lorsque S = A \ {0}. En particulier, si les opérations arithmétiques de base dans A sont programmables, ceux dans le corps de fractions de A peuvent l’être aussi. Calculs dans l’algèbre de polynômes A[x] Nous nous limiterons au cas d’une indéterminée, qui est notée x. On note deg f le degré d’un polynôme non nul f ∈ A[x] et on pose deg 0 = −∞. Un polynôme de degré d a donc d + 1 coefficients. On note A≤d [x] le A-module des polynômes de degré au plus d à coefficients dans A. Nous mesurerons la complexité en termes du nombre d’additions ou de soustractions, le nombre de multiplications dans A et de divisions par un élément inversible de A. Si f , g ∈ A≤d [x], f ± g se calculent à l’aide d’au plus d + 1 additions ou soustractions dans A. 28 P P Considérons le cas de la multiplication. Si f = di=0 fi xi et si g = dj=0 gj xj , alors le coefficient P de xk dans f g est ki=0 fi gk−i . Si k ≤ d, son calcul nécessite donc k + 1 multiplications (calcul de fi gk−i pour i ∈ {0, 1, . . . , k}) puis k additions. Sinon, on aPd + 1 ≤ k ≤ 2d et il y a 2d − k + 1 P2d d multiplications et 2d − k additions. Il y a donc un total de k=0 (k + 1) + k=d+1 (2d − k + 1) = P P 2 (d + 1)2 multiplications et dk=0 k + 2d k=d+1 (2d − k) = d additions. Comme dans le cas de la multiplication des entiers relatifs, on peut se demander si on peut faire mieux. À nouveau, la réponse est oui (voir plus loin). En ce qui concerne la division par un élément inversible de A[x], on rappelle que f ∈ A[x] est inversible si et seulement si f est constant et inversible dans A. Diviser par un élément inversible de A[x] revient donc à diviser par un élément inversible de A. Il convient de dire quelqus mots sur l’évaluation d’un polynôme en un élément de A. Si l’on pose f (x) = f0 + f1 x + f2 x2 + · · · + fd xd et si on souhaite calculer f (a), où a ∈ A, on peut bien évidemment calculer successivement a, a2 , a3 , . . ., ad puis les produits fk ak et enfin la somme f0 + f1 a + f2 a2 + · · · + fd ad . Cela nécessite d − 1 multiplications pour calculer les puissances ak , 2 ≤ k ≤ d puis encore d multiplications pour calculer les produits fk ak (1 ≤ k ≤ d) et enfin d additions pour déterminer f (a). Le schéma de Horner est nettement plus efficace. Définissons la séquence (φi )0≤i≤d d’éléments de A par φ0 = fd et par φk = fd−k + φk−1 a lorsque 0 < k ≤ d. Alors φ0 = fd , φ1 = fd−1 + fd a, φ2 = fd−2 + fd−1 a + fd a2 , ... et à la fin on trouve φd = f0 + f1 a + f2 a2 + · · · + fd−1 ad−1 + fd ad = f (a). Cela nécessite seulement d multiplications et d additions et évite le stockage en mémoire de résultats intermédiaires. La division euclidienne avec reste existe elle aussi chez les polynômes : Proposition. Soient f , g ∈ A[x] avec f 6= 0. On suppose que le coefficient directeur de f soit inversible. Alors il existe un unique couple (q, r) ∈ A[x]2 tel que g = qf + r et deg r < deg f . Démonstration. Si deg g < deg f , on prend q = 0 et r = g. C’est la seule possibilité, car si (q, r) 6= (0, g) vérifie g = qf + r, alors forcément q 6= 0 et donc deg (qf ) = deg q + deg f ≥ deg f , d’où deg r = deg (g − qf ) = deg (qf ) ≥ deg q. Supposons donc que deg g ≥ deg f . On écrit alors deg g = d et deg f = c. Il est clair Pd que iq (s’il existe) est de degré d − c. Afin de montrer l’existence de (q, r), on écrit donc g = i=0 gi x , Pc Pd−c i i f = P i=0 fi x , puis on cherche des coefficients qi et ri tels que si on pose q(x) = i=0 qi x , c−1 r(x) = i=0 ri xi , alors g = qf + r. Explicitement, cette équation donne : gd xd + gd−1 xd−1 +gd−2 xd−2 + · · · + gc xc + · · · = qd−c fc xd + (qd−c−1 fc + qd−c fc−1 )xd−1 + + (qd−c−2 fc + qd−c−1 fc−1 + qd−c−2 fc )xd−2 + · · · · · · + (q0 fc + q1 fc−1 + · · · + qc f0 )xc + termes de degré au plus c − 1. La comparaison successive des coefficients de xd , xd−1 , xd−2 , . . ., xc donne gd = qd−c fc , gd−1 = qd−c−1 fc + qd−c fc−1 , gd−2 = qd−c−2 fc + qd−c−1 fc−1 + qd−c−2 fc , . . ., gc = q0 fc + q1 fc−1 + · · · + qc f0 . Par hypothèse, fc est inversible, et la première équation implique donc que qd−c = gd /fc . Les équations suivantes déterminent successivement qd−c−1 , qd−c−2 , . . ., q0 . Le polynôme q est ainsi uniquement déterminée et on a forcément r = g − qf . 29 Ici, la comparaison des coefficents de xi , (c ≤ i ≤ d), fait intervenir d − i + 1 multiplications puis le calcul du membre droit de l’équation réarrangée qi−c = (gi −qi−c+1 fc−1 −qi−c+2 fc−2 −· · · )/fc fait intervenir d − i soustractions et une division par l’élément inversible fc . EnP prenant la somme d de i = c jusqu’à i = d, on voit que pour calculer q l’algorithme a besoin de i=c (d − i + 1) = Pd−c+1 Pd j = (d − c + 1)(d − c + 2)/2 multiplications, de i=c (d − i) = (d − c)(d − c + 1)/2 additions j=1 ou soustractions et de d − c + 1 divisions par fc . Corollaire. Dans la division euclidienne de g par f , où d = deg g ≥ deg f = c, le calcul de q nécessite donc O((d − c + 1)2 ) opérations arithmétiques dans A. Le calcul de r comme g − qf nécessite O((d − c)c) opérations arithmétiques dans A. Groupe des éléments inversibles, idéaux, anneaux quotients En règle général, nous aimerions allons maintenant aborder brièvement des questions liées au groupe des éléments inversibles et d’appartenance ou non d’un élément à un idéal de l’anneau A. Dans un premier temps, on pourra ajouter aux programmes (∗) et (∗∗) déjà mentionnés les programmes suivants : (∗∗∗) un programme testant si un élément a ∈ A est inversible ou non et, dans le cas affirmatif, de calculer 1/a, l’entrée et la sortie utilisant les représentants dans l’ensemble S (ou, le cas échéant, l’ensemble R). (∗∗∗∗) un programme testant si, étant donné un élément a ∈ A et un idéal I de A, l’élément a appartient à I ou non. Remarquons que (∗∗∗∗) permet, comme cas particulier, de tester la divisbilité exacte d’un élément par un autre : étant donné a ∈ A et b ∈ A, on veut savoir s’il existe c ∈ A tel que a = bc. En effet, cela revient à tester si a appartient à l’idéal engendré par b. Le plus souvent, l’idéal I est défini par une famille de générateurs GI , et tester is a appartient à I revient à déterminer s’il existe n ≥ 1, b1 , b2 , . . ., bn ∈ GI et c1 , c2 , . . ., cn ∈ A tels que a = b1 c 1 + b2 c 2 + · · · + bn c n . Par ailleurs, le programme (∗∗∗∗) permet les calculs dans l’anneau quotient A/I. Un élément α de A/I est une classe a + I = {a + i | i ∈ I}, où a est un élément de A. Ainsi, deux éléments a et b sont dans la même classe modulo I si et seulement si a − b ∈ I. On peut alors utiliser comme ensemble de représentants le même ensemble que pour les calculs dans A. Soit par exemple A un anneau. Soit f (x) ∈ A[x] un polynôme unitaire (ou au moins à coefficient dominant inversible) de degré d ≥ 1 et soit I l’idéal de A[x] engendré par f (x). Soit α ∈ A[x]/I et soit g ∈ A[x] un élément de α. Alors le reste r(x) de la division euclidienne de g(x) par f (x) appartient également à α. On en tire que toute classe de A[x]/I est représentée par une unique polynôme de degré au plus d − 1. L’addition et la soustraction dans A[x]/I s’effectue donc à l’aode de l’addition et la soustraction de polynômes de degrés au plus d − 1. Pour calculer le représentant d’un produit, il est en général nécessaire de prendre le reste après division euclidienne par f (x) du produit des deux polynômes. Ces remarques s’appliquent notamment aux corps de nombres, c’est-à-dire aux corps K qui sont des Q-espaces vectoriels de dimension finie d ≥ 1. On sait que si K est un corps de nombres, il existe un polynôme irréductible f (x) ∈ Q[x] de degré d tel que K soit isomorphe à Q[x]/(f (x)). Alors tout élément de K est représenté par un unique polynôme de degré au plus d − 1 et on peut effectuer des calculs dans K par les méthodes qui viennent d’être expliquées. 30 De même, si p est un nombre premier, si Fp désigne le corps à p éléments et si f (x) ∈ Fp [x], on peut effectuer des calculs dans l’anneau quotient Fp [x]/(f (x)). En particulier, tous les corps finis sont décrits de cette manière, ce qui permet d’effectuer les calcus dans ces corps, ce qui a des applications importantes de cryptographie. Le problème du calcul du groupe des éléments inversibles A× de A est, en général, beaucoup plus difficile. Mentionnons pour la culture générale le résultat suivant, qui est un cas spécial d’un théorème de Dirichlet. Théorème. Soit f (x) ∈ Z[x] un polynôme unitaire, irréductible en tant qu’élément de Q[x] et soit A = Z[x]/I. Notons respectivement r et s le nombre de racines réelles de f et le nombre de couples de racines conjuguées complexes non réelles de f (x). Alors il existe un groupe cyclique fini C tel que le groupe A× est isomorphe au produit direct C × Zr+s−1 . La démonstration du théorème (et encore plus la description d’un algorithme calculant A× ) est hors de portée d’un cours de M1. En ce qui concerne les calculs dans les anneaux quotients, le cas le plus fréquent est celui d’un quotient d’une algèbre de polynômes. Le cas de A[x]/(f (x)), où f (x) est un polynôme unitaire, a déjà été traité. Le cas où f n’est pas unitaire peut souvent être ramené au précédent en remplaçant A par l’anneau de fractions S −1 A, où S est l’ensemble des puissances {fdn }n≥0 , où fd est le coefficient directeur de f . Par contre, lorsque n ≥ 2, le cas d’un quotient de A[x1 , x2 , . . . , xn ]/I nécessite la notion de base de Groebner, dont l’étude à nouveau dépasse les limites de ce cours. Le théorème chinois Dans le paragraphe précédent, nous avons discuté quelques cas de passage d’un anneau A à un anneau quotient A/I. Par extension, on peut donc passer de A à plusieurs anneaux quotient puis à leur produit cartésien. Le théorème chinois permet d’aller en sens inverse : utiliser des algorithmes dans des anneaux quotients pour calculer un élément de A. Dans le cas où A = Z le principe est simple et est justifié par le lemme suivant : Lemme. Soit a ∈ Z, soit B ∈ R+ et soit m un entier. Si |a| ≤ uniquement déterminé par sa classe modulo m. B 2 et si m > B, alors a est Démonstration. En effet, si b est un second entier tel que |b| ≤ B2 , alors |a − b| ≤ B. Et si encore a ≡ b (mod m), alors ou bien a = b ou bien |a − b| ≥ m. Mais comme m > B, la deuxième possibilité est incompatible avec le l’inégalit |a − b| ≤ B. Donc a = b. Ce lemme est utilisé de la manière suivante. Supposons on cherche un algorithme dont la sortie est un entier a, disons, et on connaı̂t : (i ) un majorant B de 2|a| et (ii ) un la valeur de a (mod m), m étant un entier. Alors on connaı̂t a. Les calculs (mod m) peuvent être avantageux si les étapes de l’algorithme font intervenir des entiers a priori beaucoup plus grands que m, et les calculs (mod m) suffisent. Une extension de ce principe est d’utiliser une factorisation de m. Si on sait que m = m1 m2 · · · mk avec les entiers mi deux-à-deux premiers entre eux, alors une classe (mod m) est uniquement déterminée par des classes (mod mi ) pour tout 1 ≤ i ≤ k. C’est un cas particulier du théorème chinois. En pratique, cela ne signifie pas qu’il faut savoir factoriser m, car il ne joue qu’un rôle de majorant ; on peut donc agrandir m si besoin. Par exemple, on peut calculer les produits des 31 premiers nombres premiers (2 × 3 × 5 × 7 × · · · ) jusqu’à ce que ce produit dépasse m, puis remplacer m par ce produit. Les calculs (mod m) peuvent alors être remplacé par des calculs (mod 2), (mod 3), (mod 5), (mod 7), . . .. Théorème. Il existe x0 > 0 tel que pour tout x ≥ x0 assez grand, on ait X 1 x≤ log p ≤ 2x log 2. 2 p premier p≤x Une démonstration est proposée dans l’Exercice 4 de la feuille 6. On pourra aussi consulter G. Tenenbaum, Introduction à la théorie analytique et probabiliste des nombres, Belin, 2008, pages 29–30. La constante x0 peut être calculée explicitement. Voici un autre résultat concernant la distribution des nombres premiers qui sera utilisé par la suite dans l’estimation des complexités : Théorème (postulat de Bertrand). Étant donné x ≥ 2, il existe un nombre premier p tel que x < p ≤ 2x. Si x ≥ x0 , ce résultat découle du théorème précédent. En effet, on a alors X X log p ≥ x et log p ≤ 2x log 2. p≤2x p≤x P Puisque log 2 < 1, on conclut que x<p≤2x log p > 0, ce qui n’est possible que s’il existe un nombre premier dans l’intervalle ]x, 2x]. Le cas des petites valeurs de x se fait par un calcul explicite. Voir à nouveau l’Exercice 4 de la feuille 6. Nous appliquerons ces idées dans le paragraphe suivant pour calculer des déterminants de matrices à coefficients entiers. Pour l’instant, nous nous contenterons d’énoncer et de démontrer le théorème chinois dans un cadre plus général, car il sert aussi pour les calculs avec des polynômes. Deux idéaux I et J de A sont dits comaximaux si I + J = A (c’est-à-dire s’il existe i ∈ I, j ∈ J tels que i + j = 1. Théorème. Soit A un anneau et soit I1 , I2 , . . ., Ik une famille finie d’idéaux comaximaux de A. Alors l’homomorphisme canonique π : A → A/I1 × A/I2 × · · · × A/Ik est surjectif, et son noyau est I1 ∩ I2 ∩ · · · ∩ Ik . Démonstration. Ici, π est le produit cartésien des homomorphismes canoniques A → A/Ir (1 ≤ r ≤ k). Puisque le noyau de l’homomorphisme canonique A → A/Ir est Ir , il est clair que le noyau de π est I1 ∩ I2 ∩ · · · ∩ Ik . Montrons donc la surjectivité. Soient r, s deux éléments distincts de {1, 2, . . . , k}. Q La condition Ir + Is = A signifie qu’il existe ir,s ∈QIr , is,r ∈ Is tels que ir,s + is,r = 1. Posons ir = s6=r is,r . Alors ir ∈ Is pour tout s 6= r et ir − 1 = s6=r (1 − ir,s ) − 1 ∈ Ir . Il s’ensuit que si (a1 , a2 , . . . , ak ) ∈ Ak , alors (a1 + I1 , a2 + I2 , . . . ak + Ik ) = π(a1 i1 + a2 i2 + · · · + ak ik ). La démonstration fournit explicitement une valeur a ∈ A telle que π(a) = (a1 + I1 , a2 + I2 , . . . , ak + Ik ), sous reserve de connaı̂tre des solutions ir,s , is,r de ir,s + is,r = 1. Lorsque A = Z, dire que deux idéaux mZ et nZ sont comaximaux équivaut à dire que les entiers m et n sont premiers entre eux ; la solution de l’équation i + j = 1 avec i ∈ mZ, j ∈ nZ revient alors à la 32 solution de l’équation de Bézout um + vn = 1, donc à une application de l’algorithme d’Euclide étendu. Estimons le nombre d’opérations dans A qui sont nécessaires pour exécuter un algorithme implémentant la preuve, en supposant connus les éléments ir,s lorsque s 6= r. Alors ir se calcule avec k − 1 multiplications et alors la détermination de a = a1 i1 + a2 i2 + · · · + ak ik nécessite encore k multiplications et k − 1 additions, d’où un total de k − 1 additions et 2k − 1 multiplications. Ce calcul suppose que l’on connaı̂t des solutions ir,s ∈ Ir de l’équation ir,s + is,r = 1. Leur détermination dépendent évidemment de l’anneau A. Lorsque A = Z, on peut estimer la taille des entiers ir construits au cours de la démonstration. Notons pour cela mr le générateur positif de l’idéal Ir . On sait que chacune des équations de Bézout ur,s mr + us,r ms = 1, 1 ≤ r < s ≤ k a une solution (ur,s , us,r ) avec |ur,s | < ms et |us,r | < mr . On pose alors ir,s = uQ ms , ce qui implique que |ir,sQ | ≤ mr ms et |is,r | ≤ mr ms . Il r,s mr et is,r = us,rQ k k−2 s’ensuit que |ir | = s6=r |ir,s | ≤ mk−1 m = m m, où m = s r r s6=r r=1 mr est le module produit. Puisque |ar | ≤ mr quelque soit r, on en tire que |a| ≤ k X |ar ir | ≤ r=1 k X m) mr (mk−2 r =m k X mrk−1 . r=1 r=1 Supposons par exemple que tous les mr soient d’environ la même grandeur. Leur produit étant égal à m, cela signifie que chacun des mr est d’une grandeur comparable avec m1/k . On en tire que 1 la majoration de |a| est comparable avec km2− k . Mais si les grandeurs des mr sont plus dispersées, la majoration sera moins bonne. Voici une autre construction de a qui peut être Q utilisée lorsque A est un anneau principal. Notons alors mr un générateur de Ir et posons m = kr=1 mr . Lorsque r ≤ s, la condition que Ir et Is soient comaximaux signifie que mr et ms sont premiers entre eux. Il s’ensuit que mr et mmr sont premiers entre eux quelque soit r ∈ {1, 2, . . . , k}. L’équation de Bézout ur mr + vr mmr = 1 a donc une solution (ur , vr ) et on constate alors que si l’on pose m m m + a2 v2 + · · · + ak vk , m1 m2 mk Q alors a ≡ ar vr mmr ≡ ar (mod Ir ) car mms = t6=s mt est divisible par mr lorsque s 6= r et premier à mr lorsque s = r, et vr mmr ≡ 1 (mod Ir ). Nous noterons CHIN(m1 , m2 , . . . , mk ; a1 , a2 , . . . , ak ) la procédure ainsi obtenue, dont la sortie est l’entier rem(a, m). Cherchons donc à majorer |a|. D’après notre étude de l’équation de Bézout, on sait calculer une solution (ur , vr ) avec |vr | < mr . Si les valeurs ar vérifient |ar | ≤ mr pour tout r, alors on trouve que a = a1 v 1 |a| ≤ |a1 ||v1 | m m m + |a2 ||v2 | + · · · + |ak ||vk | ≤ m(m1 + m2 + · · · + mk ) ≤ km2 . m1 m2 mk Le cas k = 2 est évidemment particulièrement important, et le cas général peut être réduit à celui-ci par récurrence. Dans ce cas, les deux méthodes fournissent la même valeur de a. Proposition. Soit k ≥ 2 et soient mr , (1 ≤ r ≤ k), une famille d’entiers naturels deux-àdeux premiers entre eux. Posons m = m1 m2 · · · mk . Soit (a1 , a2 , . . . , ak ) ∈ Zk . Si |ar | ≤ mr pour tout r ∈ {1, 2, . . . , k}, alors la complexité de la procédure CHIN(m1 , m2 , . . . , mk ; a1 , a2 , . . . , ak ) appartient à O(k(log m)2 ). 33 Démonstration. Le calcul de m a une complexité appartenant à O(k(log m)2 ). Une fois m connue, il faut calculer les k quotients mmr : la complexité du calcul de chacun des ses quotients appartient à O(log mmr log mr ) ⊆ O((log m)2 ) et la complexité du calcul des k quotients appartient à O(k(log m)2 ). Ensuite, le calcul de chacun des couples (ur , vr ), 1 ≤ r ≤ k, solutions de l’équation de Bézout ur m + vr mmr = 1 a une complexité appartenant à O((log mmr )(log mr )) ⊆ O((log m)2 ). La complexité du calcul de l’ensemble des k couples (ur , vr ) appartient donc encore à O(k(log m)2 ). Ensuite, le calcul de a s’effectue à l’aide de 2k multiplications et k−1 additions de nombres tous majorés en valeur absolue par m ; ce calcul se fait donc en complexité appartenant à O(k(log m)2 ). Le résultat n’est pas forcément réduit (mod m), mais la division euclidienne de a par m qui 2 détermine rem(a, m) a une complexité appartenant à O((log km )(log m)), ce qui ne modifie pas m la complexité totale. Quelques algorithmes de base en algèbre linéaire Avant d’étudier une première application du théorème chinois au calcul du déterminant d’une matrice à ceofficients entiers, nous étudierons rapidement dans ce paragraphe quelques algorithmes de base en algèbre linéaire. Soit donc K un corps commutatif : si d, e ≥ 1 sont des entiers, nous noterons Md,e (K) (ou Md,e si aucune confusion n’est à craindre) le K-espace vectoriel des matrices avec d lignes et e colonnes à coefficients dans K et nous écrivons Md (K) pour Md,d (K). Nous compterons le nombre d’opérations arithmétiques (additions, multiplications et inversions) dans K nécessaire pour exécuter l’algorithme. (Rappelons qu’une soustraction est considérée comme un cas particulier d’une addition.) La complexité de chacune de ces opérations en terme d’opérations élémentaires variant avec le corps K, il est impossible de décrire la complexité de l’algorithme de manière indépendante de K. Le nombre d’opérations nécessaire s’exprime donc en fonction de la taille des matrices concernées. Dans la plupart des cas, nous exprimerons nos conclusions comme une borne de la forme O(f (d)) pour des matrices ayant au plus d lignes et d colonnes. A.) Somme de deux matrices. Toute matrice de Md,e possède de coefficients et la somme de deux matrices se calculent coefficient par coefficient. Le nombre d’opérations arithmétiques nécessaires est donc de additions dans K. B.) Produit de deux matrices. Soit M ∈ Md,e et soit N ∈ Me,f . Écrivons M = (mij ) et N = (njk ) où mij (resp. njk ) est le coefficient de M (resp. de N ) situé à l’intersection de la i-ème ligne et la j-ème colonne de M (resp. à l’intersection de la j-ème ligne et la k-ème colonne deP N ). Alors le coefficient à l’intersection de la i-ème ligne et la k-ème colonne de M N est égal à ej=1 mij njk . Son calcul nécessite e multiplications et e − 1 additions. Enfin, M N contient df coefficients, et le nombre total d’opérations est d(e − 1)f additions et def multiplications. De ces remarques on retiendra surtout la conclusion suivante : Proposition. Le calcul de la somme de deux matrices dont le nombre de lignes et le nombre de colonnes ne dépassent pas d peut s’effectuer avec O(d2 ) opérations arithmétiques. Le calcul de leur produit peut s’effectuer avec O(d3 ) opérations arithmétiques. C.) Opérations sur les lignes et les colonnes. Nous considérons l’échange de deux lignes ou de deux colonnes comme une opération élémentaire. Soit M ∈ Md,e . – La multiplication d’une ligne de M par un scalaire (un élément de K) nécessite e multiplications. Par conséquent, l’addition d’un multiple d’une ligne de M à une autre ligne nécessite e additions et e multiplications. 34 – De même, l’addition d’un multiple d’une colonne de M à une autre colonne nécessite d additions et d multiplications. Rappelons que les opérations sur les lignes et les colonnes peuvent être interprétées en termes de multiplications de matrices. Notons Id ∈ Md la matrice unité et, pour tout couple d’entiers (d) (i, j) avec 1 ≤ i, j ≤ d, par Eij la matrice de Md dont le coefficient à l’intersection de la i-ième ligne et la j-ème colonne vaut 1 et tous les autres coefficients sont nuls. Soit M ∈ Md,e et soit λ ∈ K. (L) Ajouter λ fois la i-ème ligne à la j-ème ligne de M équivaut à calculer le produit (Id + (d) λEji )M , et (C) Ajouter λ fois la colonne i-ème colonne à la j-ème colonne de M équivaut à calculer le (e) produit M (Ie + λEij ). (d) Notons de même Pij désigne la matrice de transposition, définie succinctement par la (d) (d) (d) formule Pij = Id + Eij + Eji − Eii − Ejj . Notons que Pij = Pji . Alors : (d) (PL) Échanger les lignes i et j de M équivaut à calculer le produit Pij M , et (e) (PC) Échanger les colonnes i et j de M équivaut à calculer le produit M Pij . D.) Décomposition LU. Rappelons que son nom est inspiré de l’anglais, L pour lower (inférieure) et U pour upper (supérieure). Notons Ld la K-algèbre des matrices triangulaires (1) infériures dans Md et cLd le sous-ensemble des matrices dont tous les coefficients sur la diagonale principale sont égaux à 1. Notons Ud,e la K-algèbre de matrices triangulaires supérieures (1) dans Md,e . L’idée de départ est alors de tenter d’écrire M ∈ comme un produit LU , où L ∈ Ld et U ∈ Ud,e . Soit donc M ∈ Md,e ; on écrit M = (mij ) comme précédemment. (a) Supposons d’abord que m11 6= 0. Soit i ∈ {2, . . . , d}. La première étape est créer une matrice U 0 dont la première colonne est nulle, sauf le coefficient en haut à gauche. Afin d’effectuer mi1 cette étape, on soustrait, pour tout i ∈ {2, 3, . . . , d}, m fois la ligne 1 de la ligne i de M . Cela 11 revient calculer le produit de matrices md1 (d) md−1,1 (d) m21 (d) U 0 = (Id − Ed1 )(Id − Ed−1,1 ) · · · (Id − E )M. m11 m11 m11 21 (d) (d) En remarquant que (Id + λEij )−1 = (Id − λEij ), on constate que M = L0 U 0 , où on a écrit L0 = (Id + m21 (d) m31 (d) md1 (d) E21 )(Id + E31 ) · · · (Id + E ). m11 m11 m11 d1 On remarquera que L0 est bien une matrice triangulaire inférieure et que tous ses coefficients sur la diagonale principale sont égaux à 1. En fait, tous les coefficients non-nuls en dehors de la diagonale principale se situent dans la première colonne de L0 . Explicitement, 1 0 0 ··· 0 m11 m12 m13 · · · m1e m21 1 0 · · · 0 0 u22 u23 · · · u2e m 11 m31 0 1 · · · 0 0 0 0 u32 u33 · · · u3e , L = m11 U = , .. .. .. . . .. .. .. .. .. ... . . . . . . . . . md1 m11 0 0 ··· 1 0 ud1 ud2 · · · ude mi1 où, pour tout i ∈ {2, 3, . . . , d}, j ∈ {2, 3, . . . , e}, on a écrit uij = mij − m m1j . 11 (b) Si m11 = 0 il y a deux possibilités. Ou bien tous les coefficients de la première colonne de M sont nuls. Dans ce cas, on prend 0 L = Id et U 0 = M ; on a alors encore M = L0 U 0 . 35 Ou bien il existe un indice i ∈ {2, 3, . . . , d} tel que mi1 6= 0. On prend alors le plus petit indice (d) i avec cette propriété et on échange les lgnes 1 et i de M , ce qui équivaut à remplacer M par Pi1 . (d) On peut alors appliquer la procédure du cas (a) pour trouver une décomposition Pi1 M = L0 U 0 . (d) En remarquant que Pi1 est égal à son inverse, on a donc (d) M = Pi1 L0 U 0 . (d) Puisque P1,1 est la matrice unité, cette formule est vraie même dans le cas où m11 6= 0. En itérant cette procédure, on obtient une décomposition (d) (d) (d) M = Pi1 ,1 L1 Pi2 ,2 L2 · · · Pir ,r Lr U, où r = min(d, e) − 1, la matrice U est appartient à Ud,e et, pour tout k ∈ {1, 2, . . . , r}, ik ≥ k. (1) Quant aux matrices Lk , elles appartiennent à Ld et, mise à part la diagonale principale, tous les coefficients non-nuls sont situés dans la k-ième colonne. (d) (d) (d) Nous noterons L la matrice Pi1 ,1 L1 Pi2 ,2 L2 · · · Pir ,r , malgré le fait qu’elle n’appartient pas à Ld en général. On a donc M = LU et nous appellerons cette décomposition la décomposition LU de la matrice M ; elle est uniquement déterminée par la procédure qui vient d’être décrite. Remarque. Le lecteur prendra garde de ne pas déduire de cette appellation que toute matrice (1) M ∈ Md,e s’écrit de façon unique sous la forme LU avec L ∈ Ld et U ∈ Ud,e . Il se peut qu’il n’y ait aucune décomposition de cette forme, ou s’il y en a, quelle ne soit pas unique. Éstimons donc le nombre d’opérations arithmétiques nécessaires pour calculer L et U , sans tenir compte des échanges de lignes. Considérons d’abord le calcul de L0 et de U 0 . Le calcul de 1/m11 se fait une fois pour toutes. Il s’agit donc d’une inversion. mi1 Les quotients m , où 2 ≤ i ≤ d, apparaissent dans la première colonne de L0 et aussi dans le 11 calcul des coefficients uij de U 0 . Leur calcul nécessite d − 1 multiplications. mi1 Ensuite, pour calculer U , il faut calculer les (d − 1)(e − 1) coefficients uij = mij − m m1j , 11 mi1 où 2 ≤ i ≤ d et 2 ≤ j ≤ e. Les d − 1 quotients m11 ayant déjà été calculés, il reste à calculer les mi1 m1j et enfin le même nombre de soustractions sont nécessaires pour (d − 1)(e − 1) produits m 11 calculer l’ensemble des uij . Le nombre total d’opérations nécessaires pour calculer les matices L0 et U 0 est donc : – une inversion, – (d − 1) + (d − 1)(e − 1) = d(e − 1) multiplications, – (d − 1)(e − 1) additions. Afin de calculer la décomposition LU, cette procédure doit être exécutée r = min (d, e)−1 fois, successivement sur des matrices de taille (d, e), (d − 1, e − 1), . . .}. Le nombre total d’opérations arithmétiques est donc – min Pr (d, e) − 1 inversions, – Pk=1 (d + 1 − k)(e − k) multiplications, – rk=1 (d − k)(e − k) additions. À nouveau, le point principal à retenir de ces calculs est le suivant. Théorème. La décomposition LU d’une matrice à au plus d lignes et d colonnes peut être calculée en utilisant au plus O(d3 ) opérations arithmétiques. E.) Calcul du déterminant d’une matrice. Notons det M le déterminant de la matrice M ∈ Md . Rappelons que si M est triangulaire, alors det M est le produit des coefficients sur la diagonale principale de M . En outre le déterminant de produit de deux matrices est le produit de 36 leurs déterminants. Ces remarques suggèrent l’utilisation de la décomposition LU pour calculer det M . En effet, si M = LU , alors det M = det L det U = det U et, U étant triangulaire supérieure, det M est le produit dss coefficients sur la diagonale principale de U . On déduit de la discussion du calcul de la décomposition LU le résultat suivant. Théorème. Le déterminant d’une matrice carrée d’ordre d peut être calculé avec un nombre d’opérations arithmétiques appartenant à O(d3 ). Remarques. (1) Si det M 6= 0 est inversible, alors tous les coefficients de la diagonale principale de U sont inversible. Cela implique que, si det M 6= 0, aucune échange de ligne de sera nécessaire. Par conséquent, la matrice L est triangulaire. (2) Il existe beaucoup d’autres formules pour le déterminant d’une matrice. Par exemple la formule X det M = (−1)ε(π) m1,π(1) m2,π(2) · · · md,π(d) , π∈Sd où Sn est le groupe des permutations de {1, 2, . . . , d} et ε(π) est le signe de la permutation π ∈ Sd . Cette formule est la somme des d! produits de la forme m1,π(1) m2,π(2) · · · md,π(d) , et son exécution nécessite a priori d!(d − 1) multiplications et d! − 1 additions. Vue la formule de Stirling, il est clair que, même pour d assez grand, elle est plus complexe que la méthode basée sur le calcul de la décomposition LU. Par contre, elle est plus agréable pour les calculs à la main pour les matrices d’ordre deux ou trois. F.) Déterminer si oui ou non une famille de vecteurs est libre. Soit M ∈ Md,e . On constate que les colonnes de M forment une famille libre si et seulement si tous les coefficients sur la diagonale principale de U sont non-nuls. En général, si la famille (x1 , x2 , . . . , xe ) d’éléments du K-espace vectoriel V est donnée sous forme Pd de combinaisons linéaires des membres d’une base (b1 , b2 , . . . , bd ) de V , par exemple xj = i=1 λij vi pour tout j ∈ {1, 2, . . . , e}, on forme la matrice associée M = (λij ) et on cherche la décomposition LU de M . Vue la discussion précédent, le nombre d’opérations arithmétiques nécessaires appartient à O(d3 ) dans le cas d’une famille d’au plus d éléments d’un espace vectoriel de dimension au plus d. G.) Inversion d’une matrice. Soit M ∈ Md une matrice inversible. À nouveau, l’inverse de M se calcule facilement à l’aide de la décomposition LU. En effet, si M = LU alors U est inversible et M −1 = U −1 L1 . Ainsi, on est réduit au calcul de l’inverse d’une matrice triangulaire. Considérons le calcul de U −1 . Cela revient à résoudre pour V ∈ Md l’équation U V = Id . La matrice V est alors triangulaire supérieure. Si U = (uij ) avec uij = 0 lorsque i > j , alors V = (vij ) avec vij = 0 lorsque i > j et la diagonale principale de V est déterminée par les équations u11 v11 = 1, u22 v22 = 1, ..., udd vdd = 1, puis la diagonale vi,i+1 (1 ≤ i ≤ d − 1) par les équations u11 v12 + u12 v22 = 0, u22 v23 + u23 v33 = 0, ..., ud−1,d−1 vd−1,d + ud−1,d vdd = 0, et ainsi de suite. Un calcul montre que le nombre d’opérations arithmétiques nécessaires pour calculer U −1 appartient à O(d3 ). Il en est de même pour le nombre d’opérations arithmétiques nécessaires pour calculer L−1 . Enfin, le calcul du produit U −1 L−1 nécessite encore un nombre d’opérations appartenant à O(d3 ). Nous avons donc démontré le résultat suivant : 37 Théorème. Le calcul de l’inverse d’une matrice inversible d’ordre d peut s’effectuer avec un nombre d’opérations arithmétiques appartenant à O(d3 ). H.) Méthode d’élimination de Gauss. Soit encore M ∈ Md,e . En général, nous savons que la matrice U = (uij ) de la décomposition LU est une matrice triangulaire supérieure. En outre, M est de rang maximal min (d, e) si et seulement si tous les coefficients ukk sur la diagonale principale de U sont non-nuls. Pour des questions plus délicates, comme le calcul du rang ou la résolution d’un système linéaire, ces informations sont insuffisantes. Par exemple, rien n’empêche U d’être truffé de zéros comme un morceau de gruyère. Si par exemple 0 u12 u13 u14 0 0 0 u23 u24 0 , 0 0 u u 0 U0 = 33 34 0 0 0 0 0 0 0 0 0 u55 où seuls les coefficents uij indiqués peuvent être non-nuls, alors le rang de U0 dépend entre autre u23 u24 du rang de la sous-matrice qui, quant à elle, n’est pas une matrice triangulaire. u33 u34 Ce problème ne se poserait pas si la matrice U avait la propriété que le premier coefficient non∗ (K) le sous-ensemble nul se situe strictement à droite de celui de la ligne précédente. Notons Ud,e de Ud,e (K) formé des matrices avec cette propriété. La méthode d’élimination de Gauss suit une démarche semblable à celle de la décomposition LU, mais introduit des échanges supplémentaires de lignes (et éventuellement de colonnes) qui assurent que la matrice U à la fin possède cette propriété. Si M = (mij ) ∈ Md,e , on note, pour tout i ∈ {1, 2, . . . , d}, par µM (i) le plus petit indice j ∈ {1, 2, . . . , e} tel que mij 6= 0. Si la i-ème ligne de M ne contient aucun coefficient non-nul, on pose µM (i) = e + 1. (a) Supposons que la première colonne de M contienne au moins un coefficient non-nul. Alors on échange des lignes de M afin que toutes lignes dont le premier coefficient est non-nul sont situés au dessus de celles dont le premier coefficient est nul. Si le premier coefficient des k premières lignes est non-nul, et si k ≥ 2, on soustrait un multiple convenable de la ligne 1 de chacune des lignes 1 à k. Comme dans la déscription de la décomposition LU, cela revient à écrire M sous la forme (d) (1) L0 U 0 , où L est un produit de matrices de la forme Pij et d’une matrice de Ld . (b) Si la première colonne de M ne contient que des zéros, on échange cette colonne avec la (e) dernière colonne non-nulle de M . Cela revient remplacer M par M P1j pour j convenable. On (e) peut alors appliquer la méthode de (a) à M P1j . On obtient ainsi une décomposition de la forme (e) M = L0 U 0 P1j . Dans les deux cas, si M 6= 0, le coefficient en haut à gauche de U 0 est non-nul, et tous les autres coefficients de la première colonne de U 0 sont nulles. En itérant, on obtient une décomposition de M de la forme M = LU P, (e) ∗ où U ∈ Ud,e et P ∈ Me est un produit de matrices de la forme Pij . Nous appelerons cette représentation la décomposition gaussienne de M . Théorème. La décomposition gaussienne d’une matrice ayant au plus d lignes et d colonnes peut être calculée avec un nombre d’opérations arithmétiques appartenant à O(d3 ). 38 I.) Calcul du rang d’une matrice. Soit M ∈ Md,e et soit M = LU P la décomposition gaussienne de M . Puisque L et P sont inversibles, le rang de M est égal au rang de U . Mais le ∗ rang d’une matrice appartenant à Ud,e est égal au nombre de ses lignes qui sont non-nulles. Théorème. Le rang d’une matrice ayant au plus d lignes et d colonnes peut être calculé avec un nombre d’opérations arithmétiques appartenant à O(d3 ). J.) Solution d’un système linéaire d’équations. Le système linéaire de d équations en e inconnues x1 , x2 , . . ., xe : a11 x1 + a12 x2 + · · · + a1e xe = b1 , a21 x1 + a22 x2 + · · · + a2e xe = b2 , .. . ad1 x1 + ad2 x2 + · · · + ade xe = bd , où aij ∈ K et bi ∈ K pour tout i, j, peut être assimilée à l’équation matricielle Ax = b, où A = (aij ), x = t (x1 , x2 , . . . , xe ) ∈ Me,1 et b = t (b1 , b2 , . . . , bd ) ∈ Md,1 . ∗ Si la matrice A appartient à Ud,e , la solution peut s’effectuee par itération, en commençant avec l’équation correspondant à la dernière ligne non-nulle de A. Si la i-ème ligne est la dernière ligne non-nulle, l’équation est de la forme aij xj + ai,j+1 xj+1 + · · · + ai,e xe = bi , aij 6= 0, On considère xj+1 , . . ., xe comme de paramètres et résoudre l’équation permet d’exprimer xj en fonction de ces paramètres : xj = − a1ij (bi − ai,j+1 xj+1 − · · · − ai,e xe ). Cette valeur de xj est ensuite substituée dans l’équation correspondant à la ligne i − 1, et ainsi de suite. En général, on décompose le problème en la solution de trois systèmes en utilisant la décomposition gaussienne LU P de A. L’équation matricielle devient alors LU P x = b, qui est équivalente au système de trois équations Lz = b, U y = z et P x = y. Comme dans les algorithmes déjà décrits, on constate que le calcul de l’ensemble des solutions d’un système triangulaire d’au plus d équations avec au plus d inconnus nécessite O(d3 ) opérations arithmétiques. Puisque la solution d’un système linéare quelconque peut être réduite à la solution de deux systèmes, le nombre d’opérations arithmétiques nécessaires en général appartient encore à O(d3 ). En résumé : Théorème. La solution d’un système linéaire d’au plus d équations en au plus d inconnues par la méthode d’élimination de Gauss peut s’effectuer avec un nombre d’opérations arithmétiques appartenant à O(d3 ). Calcul du déterminant d’une matrice à coefficients entiers Comme première application de l’utilisation du théorème chinois pour effectuer des calculs avec les entiers, nous allons étudier le calcul du déterminant d’une matrice à coefficients entiers. 39 Lorsque les coefficients de M sont des entiers, alors le déterminant de M est un entier, mais en général la méthode décrite basée sur la décomposition LU fera intervenir des dénominateurs dans les coefficients des matrices intermédiaires. Une méthode alternative serait de réduire M modulo les nombres premiers successifs p = 2, 3, 5, 7, . . ., calculer son déterminant (mod p) puis retrouver M à l’aide du théorème chinois. Pour cela, il faut connaı̂tre une borne pour le déterminant d’une matrice en fonction de ces coefficients. Une méthode évidente de trouver une telle borne est d’utiliser la formule det M = P (π) m1π(1) m2π(2) · · · mdπ(d) : si b est un majorant des valeurs absolues des coefficients π∈Sd (−1) mij on trouve alors que | det M | ≤ d!bd car il y a d! termes dans la somme et chaque produit m1π(1) m2π(2) · · · mdπ(d) est majoré par bd . Une meilleure borne est donnée par le résultat suivant : Théorème (inégalité de Hadamard). Soit M une matrice carrée d’ordre d à coefficients réels. Alors | det M | ≤ ||M1 || ||M2 || · · · ||Md || ≤ dd/2 bd , où Mk (1 ≤ k ≤ d) est la k-ième ligne de M , ||.|| désigne la norme euclidienne et b est un majorant des valeurs absolues des coefficients de M . Bien évidemment, on pourrait utiliser les colonnes de M à la place de ces lignes. On identifie les lignes de M avec des éléments de Rd . Quant à la démonstration du théorème, on peut clairement se limiter au cas où les lignes de M sont linéairement indépendantes, car dans le cas contraire on a det M = 0. On peut alors faire intervenir la procédé de Gram-Schmidt, qui construit à partir de la base P (M1 , M2 , . . . , Md ) de Rd une base orthogonale (M1∗ , M2∗ , . . . , Md∗ ) où Mk∗ est de la forme Mk − k−1 j=1 λj Mj pour tout ∗ k ∈ {1, 2, . . . , d}. En replaçant successivement la ligne M1 de M par M1 , la ligne M2 par M2∗ et ainsi de suite, le déterminant reste inchangé. Par conséquent, si M ∗ désigne la matrice dont les lignes sont M1∗ , M2∗ , . . ., Md∗ , alors | det M | = | det M ∗ | = ||M1∗ || ||M2∗ || · · · ||Md∗ ||, car les lignes de M ∗ forment une base orthogonale de Rd . En outre, si on désigne par Ek le sous-espace de Rd engendré par (M1 , M2 , . . . , Mk ), alors on ⊥ sait que Mk∗ est la projection orthogonale de Mk sur Ek−1 . Par conséquent, ||Mk∗ || ≤ ||Mk || pour tout k ∈ {1, 2, . . . , d}. Il s’ensuit que d | det M | = ||M1∗ || ||M2∗ || · · · ||Md∗ || ≤ ||M1 || ||M2 || · · · ||Md || ≤ d 2 bd , √ où la deuxième inégalité découle des inégalités ||Mk || ≤ db, k ∈ {1, 2, . . . , d}. Exemples (i ) Si 1 2 3 M = 4 5 6 , 7 8 9 √ √ √ alors on trouve que | det M | ≤ 12 + 22 + 32 42 + 52 + 62 72 + 82 + 92 ≤ 457, 31. (Si l’on utilise les colonnes de M , on obtient la borne | det M | ≤ 879, 43.) Par conséquent, det M est déterminé par sa classe (mod m) si m ≥ d2 × 457, 31e, soit si m ≥ 915. On a 2×3×5×7 < 915 < 2×3×5×7×11. Afin de déterminer det M , il suffit de le calculer (mod p) pour p ∈ {2, 3, 5, 7, 11}. (ii ) Si d = 4 et si b = 100, alors on a dd/2 100d = 1, 6 × 109 . Par conséquent, le déterminant d’une matrice (4, 4) dont tous les coefficients sont inférieurs à 100 en valeur absolue est déterminé 40 par sa classe (mod m) lorsque m ≥ 3, 2 × 109 . Après un calcul, on trouve que ce déterminant est déterminé par ses classes (mod p) lorsque p parcourt les nombres premiers jusqu’à 29 inclus. Proposition. La complexité de l’algorithme précédent qui calcule le déterminant d’une matrice carrée d’ordre d à coefficients entiers et majorés en valeur absolue par b appartient à O d4 (log d + log b)(log (log d + log b))2 . Démonstration. Rappelons d’abord que la méthode du pivot de Gauss utilise O(d3 ) opérations dans le corps K. En outre, si p est un nombre premier, on sait, d’après l’étude des opérations arithmétiques dans les anneaux Z/mZ, que chacune de ces opérations a un coût appartenant à O((log p)2 ). Par conséquent, le coût du calcul du déterminant d’une matrice (d, d) à coefficients dans Z/pZ appartient à O(d3 (log p)2 ). La complexité du calcul de l’ensemble des déterminants (mod p), p ≤ x appartient donc à X (log p)2 , O d3 p≤x Q D’après ce qui précède, x est à choisir de telle sorte que p≤x p dépasse 2dd/2 bd . Comme nous avonsQdéjà expliqué, le théorème des nombres premiers (ou l’Exercice 4 de la 1 feuille 6) implique que p≤x p ≥ e 2 x pour tout x assez grand. Il suffit donc de prendre x tel que 1 e 2 x = 2dd/2 bd , soit x = 2 log 2 + d(log d + 2 log b). Puisqu’il y a au plus x nombres premiers inférieurs ou égaux à x et puisque la fonction log P est croissante, on peut majorer p≤x (log p)2 par x(log x)2 . On en tire que la complexité du calcul des déterminants (mod p) pour tout p ≤ x appartient à O d4 (log d + log b)(log (log d + log b))2 . Q Il reste à estimer la complexité du calcul du déterminant (mod p≤x p), en utilisant le théorème chinois. D’une part, il y a au plus x nombres premiers inférieurs ou Q égaux à x. De l’autre x part, comme il existe un nombre premier entre x et 2x, on peut majorer p≤x p par 2xe 2 . La Q x complexité du calcul du déterminant (mod p≤x p) appartient donc à O(x(log 2xe 2 )2 ). Puisque x = 2 log 2+d(log d+2 log b), on voit que cette complexité est négligeable devant celle du calcul du déterminant pour tout p ≤ x ; elle appartient donc aussi à O d4 (log d + log b)(log (log d + log b))2 . D’où le résultat. Cette complexité est meilleure que celle de l’algorithme qui consiste à calculer le déterminant en réduisant modulo un seul nombre premier p un peu plus grand que 2dd/2 bd . D’après le postulat de Bertrand, on peut alors choisir le nombre premier p majoré par 4dd/2 bd . Le calcul de det M (mod p) a alors une complexité appartenant à O(d3 (log p)2 ) ⊆ O(d5 (log d + log b)2 ), où la croissance avec d est plus rapide par un facteur de d par rapport à l’estimée de la proposition. Une dernière remarque : nous n’avons pas abordé le problème du calcul des nombres premiers dont nous avons besoin. En ce qui concerne la méthode appliquant le théorème chinois, ce la ne pose pas de problème pratique. Il est facile de constituer une liste de tous les nombres premiers jusqu’à une limite raisonnable. Par exemple, le logiciel pari.gp contient une liste de tous les nombres premiers jusqu’à environ 500000 (la limite précise dépend de l’installation). D’après le théorème des nombres premiers Y p ≈ e500000 p≤500000 P et, en fait, un calcul avec pari.gp donne p≤500000 log p ≈ 499318.120. On a donc Y p ≈ e499318.120 ≈ 10216851.10 ≈ 2720363.78 . p≤500000 41 Même si on connaı̂t quelques nombres premiers plus gros que 2720363 , il s’agit surtout de nombres premiers d’une forme très particulière (par exemple les nombres de Mersenne 2` − 1 avec ` premier). Il est hors de question avec les méthodes et la technologie actuelles de déterminer un nombre premier dans l’intervalle [2720363 , 2720364 ] dont l’existence est prévue par le postulat de Bertrand. Rappelons que dans les applications cryptographiques, les entiers rencontrés actuellement dépassent rarement quelques dizaines de milliers de bits. Multiplication rapide : la méthode de Karatsuba Nous allons aborder dans les paragraphes qui suivent le sujet de la multiplication rapide. Notre étude des algorithmes habituels de multiplication dans Z et dans A[x] a montré que le produit de deux entiers m > 0 et n > 0 peut être calculé en temps O(log m log n) et celui de deux polynômes f 6= 0 de g 6= 0 degrés respectifs d et e avec O(de) opérations arithmétiques (addition, soustractions et multiplications) dans l’anneau A. Nous supposerons par la suite que m ' n et e ' d, de sorte que ces estimations puissent être simplifiées respectivement en O((log n)2 ) et O(d2 ). La question est de savoir si l’exposant 2 puisse être amélioré : existe-t-il une constante c < 2 et des algorithmes de multiplication dans Z qui ont un temps de calcul appartenant à O((log n)c ) ? ou des algorithmes de multiplication dans A[x] dont le nombre d’opérations arithmétiques dans A appartient à O(dc ) ? Les premiers algorithmes qui permettait de donner une réponse affirmative à ces questions étaient proposés par Karatsuba en 1963. L’idée est simple : dans le produit (pZ + q)(rZ + s) = prZ 2 + (ps + qr)Z + qs, par la méthode naı̈ve, on calcule les quatre produits apparaissant dans le membre droit pr, ps, qr et qs, puis on calcule la somme ps + qr. (Dans les applications, Z sera une puissance d’une indéterminée ou d’un radix et la multiplication par une puissance de Z sera une opération élémentaire.) Le point est que la détermination des trois coefficients peut également être effectuée avec trois multiplications, deux additions et deux soustractions : on calcule pr, qs et (p + q)(r + s), le coefficient de Z étant alors égal à (p + q)(r + s) − pr − qs. Considérons donc le cas du produit de deux polynômes f et g ∈ A[x], que l’on suppose de degré 2d − 1, où d ≥ 1. (Si ce n’est pas le cas, on ajoute des puissances de x dont les coefficients sont nuls.) On écrit alors f (x) = p(x)xd + q(x), g(x) = r(x)xd + s(x), où p, q, r et s sont des polynômes de degré au plus d − 1. (Par exemple, si f (x) = f0 + f1 x + f2 x2 + · · · + f2d−1 x2d−1 , alors p(x) = fd + fd+1 x + · · · + f2d−1 x2d−1 et q(x) = f0 + f1 x + · · · + fd−1 xd−1 .) Le calcul du produit f g des polynômes de degré 2d − 1 est alors réduit au calcul de trois produits de polynômes de degré au plus d − 1, ainsi que les additions p + q, r + s qui utilisent 2d opérations dans A, les soustractions (p + q)(r + s) − pq − rs qui utilisent 2(2d) opérations dans A, et enfin l’addition de ((p + q)(r + s) − pq − rs)xd à p(x)r(x)x2d + q(x)s(x), qui nécessite encore 2d additions dans A. Si donc T (d) désigne le nombre maximal d’opérations dans A nécessaires pour calculer le produit de deux polynômes de degré d, on trouve que T (2d) ≤ 3T (d) + 8d, 42 pour tout d ≥ 1 et donc, en raisonnant par récurrence sur k, que k k T (2 ) ≤ 3 T (1) + 8 k−1 X 3i · 2k−1−i = 3k T (1) + 8(3k − 2k ) i=0 pour tout k ≥ 0. Puisque T (1) = 1, on en tire le résultat suivant. Théorème. Soit k ≥ 0 un entier et soit A un anneau. Alors le produit de deux polynômes à coefficients dans A[x] de degré au plus 2k − 1 peut être calculé en effectuant au plus 9 · 3k − 2k+3 opérations arithmétiques dans A. Lorsque d n’est pas forcément une puissance de 2, on tire le corollaire suivant en prenant pour k l’entier vérifiant 2k−1 < d ≤ 2k : Corollaire La multiplication de deux polynômes de degré d − 1 à coefficients dans l’anneau A peut s’effectuer en utilisant O(dlog2 3 ) opérations arithmétiques dans A. Puisque log2 3 ' 1, 585, on a une amélioration très nette par rapport à la multiplication naı̈ve dans A[x]. Un algorithme semblable existe pour la multiplication de deux entiers écrits en base b. Si m > 0 et n > 0 ont pour chiffre dominant celui de b2d−1 , on écrit m = pbd + q, n = rbd + s, 0 ≤ p, q, r, s ≤ bd − 1. (Si m et n sont écrits en base b, les calculs de p, q, r et s sont des opérations élémentaires.) À nouveau, on écrit mn = pqb2d + ((p + q)(r + s) − pq − rs)bd + rs. Si T (d) désigne le temps de calcul en base b du produit de deux entiers inférieurs à bd , alors on a encore une inégalité de la forme T (2d) ≤ 3T (d) + Cd, aves unc constante C > 0, car si on connaı̂t pq, rs et (p + q)(r + s) en base b, le reste du calcul consiste en des additions et les soustractions dont la complexité appartient à O(d) = O(log n)). On trouve alors par récurrence sur k que k k T (2 ) ≤ 3 T (1) + C k−1 X 3i 2k−1−i = 3k T (1) + C(3k − 2k ), i=0 ce qui implique encore un temps de calcul appartenant à O(dlog2 3 ) = O((log n)log2 3 ). Théorème. Le produit de deux entiers inférieurs ou égaux à n peut être calculé en temps O((log n)log2 3 ). Remarque. Soit r ≥ 2 un entier. En découpant les polynômes de degré rd − 1 en r blocs de d termes, on obtient un algorithme du calcul du produit de deux polynômes de degré au plus d dont la complexité appartient à O(log d)logr (2r−1) . Puisque logr (2r − 1) → 1 lorsque r → +∞, on peut, en fait, réaliser un temps de calcul appartenant à O(d(1+) ) quelque soit le réel > 0. Mais la constante C telle que T (d) ≤ Cd(1+) pour tout d assez grand, ainsi que la valeur minimale de d sous-entendue par le assez grand , tendent vers +∞ lorsque → 0+ , et l’algorithme n’est guère utilisé lorsque r ≥ 3. Il y a des algorithmes semblables pour la multiplication de deux entiers. La transformée de Fourier rapide, que nous allons bientôt expliquer, permet d’obtenir des algorithmes plus pratiques et d’une meilleure complexité, au moins dans le cas d’anneaux particuliers. 43 Calcul rapide du produit de deux matrices Soit donc encore A un anneau ; on note Md,e (A) le A-module de matrices à d lignes et e colonnes à coefficients dans A. Nous allons mentionner brièvement le calcul rapide du produit de deux matrices par un algorithme semblable à celui de Karatsuba. Pe Si M = (Mij ) ∈ Md,e (A) et si N = (Nij ) ∈ Me,f (A), la matrice produit M N a mp coefficients k=1 Mik Nkj , (1 ≤ i ≤ d, 1 ≤ j ≤ f ). Chaque somme fait intervenir e multiplications et e − 1 additions dans A. La méthode naı̈ve de calcul de M N fait donc intervenir def multiplications et d(e − 1)f additions. En particulier, si d = e = f , on voit que le calcul du produit M N nécessite n3 multiplications et d2 (d − 1) additions, et la complexité appartient donc à O(d3 ). En s’inspirant de l’algorithme de Karatsuba, on peut diminuer l’exposant 3. À nouveau, l’idée est de réduire la multiplication de deux matrices de taille 2d à la multiplication de matrices de taille d, et de procéder récursivement. (Si la matrice est d’ordre impair, on peut l’agrandir en une matrice d’ordre pair en ajoutant une ligne et une colonne de zéros ; on peut donc supposer sans perte de généralité que d est pair.) On écrit alors les matrices M et N de taille 2d en blocs : M1 M2 N1 N2 M= , N= , M3 M4 N3 N4 où Mi et Ni (1 ≤ i ≤ 4) sont des matrices carrées de taille d. Alors le produit matriciel M1 N1 + M2 N3 M1 N2 + M2 N4 MN = M3 N1 + M4 N3 M3 N2 + M4 N4 fait intervenir 8 produits et 4 additions de matrices d’ordre d. Le point est que les 4 matrices d’ordre d peuvent être écrits comme combinaisons linéaires de seulement sept produits. En effet, si l’on pose P1 = M1 N1 , P2 = M2 N3 , P4 = M4 (N1 − N2 − N3 + N4 ), P6 = (−M1 + M3 + M4 )(N1 − N2 + N4 ), P3 = (M1 + M2 − M3 − M4 )N4 , P5 = (M3 + M4 )(−N1 + N2 ) P7 = (M1 − M3 )(−N2 + N4 ), alors on constate que MN = P1 + P2 P1 + P3 + P5 + P6 P1 − P 4 + P6 + P 7 P1 + P5 + P6 + P7 En prenant soin à la programmation des additions, on en tire que si T (d) désigne le temps de calcul du produit de deux matrices carrées d’ordre d, alors T (2d) ≤ 7T (d) + 15d2 pour tout d ≥ 1. En raisonnant par récurrence sur k et en remarquant que T (1) = 1, on trouve que T (2k ) ≤ 6 · 7k quelque soit k ≥ 0 et donc T (d) ∈ O(dlog2 7 ) au moins lorsque d parcourt les puissances de 2. En bordant une matrice de taille quelconque de zéros, on trouve le résultat suivant. Théorème. Soit A un anneau. Le produit de deux matrices carrées d’ordre d à coefficients dans A peut être calculé en utilisant O(dlog2 7 ) opérations arithmétiques dans A. 44 Puisque log2 7 ' 2, 807, cela améliore l’exposant 3 de l’algorithme naı̈f. L’algorithme qui vient d’être décrit est une variante d’un algorithme proposé par Strassen en 1969. La transformée de Fourier rapide La transformée de Fourier rapide (FFT pour Fast Fourier Transform en anglais) est une méthode de multiplication rapide basée sur la transformée de Fourier finie. Dans sa forme de base, elle nécessite la présence, dans l’anneau A de racines de l’unités appropriées. Elle ne peut donc pas s’appliquer directement à l’arithmétique des entiers ou dans A[x] lorsque A est arbitraire ; une solution serait de l’appliquer dans certains anneaux quotients (corps finis, anneaux de la forme A[x]/(xd − 1), . . .,) puis utiliser le théorème chinois pour déduire le résultat cherché. Soit d ≥ 1 un entier et soit f ∈ A[x] un polynôme de degré au plus d − 1. Si A est un corps, on peut récupérer f à partir de ses valeurs en d points deux-à-deux distincts a1 , a2 , . . ., ad ∈ A en utilisant la formule d’interpolation de Lagrange f (x) = d X f (ar )Pr (x), où r=1 Q s6=r (x − as ) Pr (x) = Q . s6=r (ar − as ) Remarquons que les polynômes Pr apparaissant dans la formule de Langrange ne dépendent que des éléments ar (1 ≤ r ≤ d). Ainsi, une fois les Pr calculés, chaque coefficient du polynôme f peut être calculé avec d multiplications et d − 1 additions. Puisque f est de degré au plus d − 1, son, calcul à partir des Pr nécessite d(d + 1) multuplications et d(d − 1) additions. Si g ∈ A[x] est un second polynôme de degré au plus d − 1, alors f g est déterminé par 2d − 1 produits f (ar )g(ar ), où {ar }1≤r≤2d−1 sont des éléments deux-à-deux distincts de A. Cela suggère une procédure de calcul de f g : on calcule les 2(2d − 1) éléments f (ar ) et g(ar ), 1 ≤ r ≤ 2d − 1, puis les 2d − 1 produits f (ar )g(ar ) puis de récupére f g à l’aide de la formule de Lagrange. Si l’on avait une méthode rapide de calcul les f (ar ) et les g(ar ), puis de reconstruire f g à partir des produits f (ar )g(ar ), on aurait réduit le calcul de f g au calcul des 2d − 1 produits f (ar )g(ar ), (1 ≤ r ≤ 2d − 1). On pourrait ainsi espérer obtenir un algorithme plus rapide du calcul de f g. En rappelant notre discussion de l’évalution d’un polynôme et le schéma de Horner, on voit que le calcul de l’une des valeurs f (ar ) et g(ar ) nécessite 2(d − 1) opérations dans A. Par conséquent, le calcul de l’ensemble de ces 2(2d − 1) valeurs lorsque r parcourt {1, 2, . . . , 2d − 1} nécessite 4(d − 1)(2d − 1) ∈ Θ(d2 ) opérations dans A, et cette partie du calcul aura encore une complexité dans Θ(d2 ). Afin d’obtenir un algorithme plus efficace, on fait un choix particulier des ar . Et c’est là où intervient des racines de l’unité. Enfin, afin de simplifier la notation, nous noterons d − 1 une majoration des degrés de f , de g et de f g : si deg f g ≥ d, nous algorithmes le reste de la division euclidienne de f (x)g(x) par xd . Soit donc R 6= {0} un anneau (commutatif et unitaire, comme toujours), soit d ∈ N, d ≥ 1 et soit ζ ∈ R. On dit que ζ est une racine d-ième de l’unité si ζ d = 1. On dit que ζ est une racine primitive d-ième de l’unité s’il s’agit d’une racine d-ième de l’unité et, pour tout entier t vérifiant 1 ≤ t < d, ζ t − 1 n’est pas un diviseur de 0 dans R (dans ce cours, 0 est compté comme un diviseur de zéro). 45 Ces définitions sont bien connues lorsque R est un corps ou un anneau intègre. Dans ce cas, la condition que ζ t − 1 ne soit pas un diviseur de zéro équivaut à la condition habituelle ζ t 6= 1. Par contre, en algorithmique, il est fort utile d’utiliser des anneaux qui ne sont pas nécessairement intègres, même si le résultat final concerne un anneau intègre. Les racines d-ièmes de l’unité appartenant à R forme un sous-groupe du groupe des éléments inversibles de R, qui nous noterons µd (R). (Cette notation s’inspire de celle utilisée en géométrie algébrique ; je ne connais pas d’autre notation dont l’usage est répandu.) En particulier, si r ∈ Z et si ζ ∈ µd (R), alors ζ r ne dépend que du résidu de r (mod d). On note µ∗d (R) l’ensemble des racines primitives d-ièmes de l’unité appartenant à R. 2 Exemple. Si R = Z/8Z, alors 3 = 1, 3 6= 1 mais 3 n’appartient pas à µ∗2 (R), car 3 − 1 est un diviseur de zéro. Lemme 1. Soit ζ ∈ µ∗d (R) et soit ` un entier, 0 ≤ ` < d. Alors ( d−1 X d, si ` = 0, ζ k` = 0, sinon. k=0 Démonstration. Il est clair que d−1 X k=0 ζ k` =1+ Pd−1 d−1 X k=0 ζ k=1 k` ζ k` = 1 lorsque ` = 0. Si ` 6= 0, alors d` =ζ + d−1 X ζ k` = k=1 d X k=1 ζ k` =ζ ` d−1 X ζ k` k=0 P d−1 k` = 0. On conclut grâce à l’hypothèse que 1 − ζ ` n’est pas un diviseur ζ et donc (1 − ζ ` ) k=0 de zéro. Supposons donc que R contienne une racine primitive d-ième de l’unité ζ. Soit donc f ∈ R[x] de degré au plus d−1. On identifie f (x) = f0 +f1 x+· · ·+fd−1 xd−1 avec l’élément (f0 , f1 , . . . , fd−1 ) de Rd et on considère la transformée de Fourier discrète (DFT pour discrete Fourier transform en anglais), qui est l’endomorphisme Tζ du R-module Rd défini par Tζ (f0 , f1 , . . . , fd−1 ) = f (1), f (ζ), f (ζ 2 ), . . . , f (ζ d−1 ) Alors la matrice de Tζ dans la base standard de Rd est la 1 1 1 ··· 2 1 ζ ζ ··· 4 1 ζ 2 ζ ··· Vζ = .. .. .. ... . . . 1 ζ d−1 ζ 2(d−1) · · · matrice de Vandermonde 1 ζ d−1 ζ 2(d−1) , .. . (d−1)2 ζ dont le terme à l’intersection de la i-ième ligne et la j-ième colonne est ζ (i−1)(j−1) . Lemme 2. Soit ζ ∈ µ∗d (R). Alors Vζ Vζ −1 = dId , Id étant la matrice identité d’ordre d. Ce Lemme découle immédiatement du Lemme 1. On tire de la discussion qui précède le résultat suivant : 46 Proposition 1. Soit R un anneau, soit d ≥ 1 un entier et soit ζ ∈ µ∗d (R). On suppose en plus que d soit un élément inversible de R. Alors la transformée de Fourier discrète Tζ est un automorphisme de Rd , et l’homomorphisme inverse Tζ−1 est égal à d−1 Tζ −1 . Si f et g ∈ R[x] sont de degré au plus d − 1, alors leur convolée d’ordre d est, par définition, le polynôme f (x)g(x) (mod xd − 1) (c’est-à-dire le reste de la division euclidienne de f (x)g(x) par xd − 1). On la note f ∗d g. On remarque que, lorsque deg f g < d, alors f ∗d g = f g. Proposition 2. On reprend les hypothèses de la Proposition 1. Pour tout f , g ∈ R[x] de degré au plus d − 1, on a Tζ (f ∗d g) = Tζ (f )Tζ (g). Ici, Tζ (f )Tζ (g) désigne le produit composante par composante des éléments Tζ (f ) et Tζ (g) de Rd . Grâce à la linéarité de Tζ et du reste de la division euclidienne par un polynôme fixé, il suffit de vérifier la formule lorsque f (x) = xa et g(x) = xb sont des monômes, 0 ≤ a < d et 0 ≤ b < d. On a Tζ (xa ) = (1, ζ a , ζ 2a , . . . , ζ (d−1)a ), Tζ (xb ) = (1, ζ b , ζ 2b , . . . , ζ (d−1)b ), d’où Tζ (xa )Tζ (xb ) = (1, ζ a+b , ζ 2(a+b) , . . . , ζ (d−1)(a+b) ). Si a + b < d, alors (1, ζ a+b , ζ 2(a+b) , . . . , ζ (d−1)(a+b) ) = Tζ (xa+b ) et si a + b ≥ d, alors (1, ζ a+b , ζ 2(a+b) , . . . , ζ (d−1)(a+b) ) = (1, ζ a+b−d , ζ 2(a+b−d) , . . . , ζ (d−1)(a+b−d) ) = Tζ (xa+b−d ). Pour conclure, il suffit de remarquer que le reste de la division euclidienne de xa+b par xd est égal à xa+b lorsque a + b < d et à xa+b−d lorsque a + b ≥ d. Tout cela est de la belle théorie mais, afin d’obtenir un algorithme rapide, il faut encore savoir comment calculer rapidement Tζ (f ) = (f (1), f (ζ), . . . , f (ζ d−1 )). L’idée est, comme chez l’algorithme de Karatsuba, de procéder de façon récursive. L’algorithme présenté dans les lignes qui suivent et l’une des variantes de la transformée de Fourier rapide. Supposons que d soit pair. Alors xd − 1 = (xd/2 − 1)(xd/2 + 1) et on note respectivement f (x) = q1 (x)(xd/2 − 1) + r1 (x), f (x) = q2 (x)(xd/2 + 1) + r2 (x) les divisions euclidiennes avec reste de f (x) par xd/2 −1 et par xd/2 −1, de sorte que deg r1 , deg r2 < d − 1. Vue la forme très particulière des polynômes xd/2 ± 1, le calcul de r1 et de r2 est aisé : si l’on 2 écrit f (x) = f1 (x)xd/2 +f2 (x) avec deg f1 , deg f2 < d2 −1, on a f (x) = f1 (x)(xd/2 ±1)∓f1 (x)+f2 (x), d’où r1 (x) = f1 (x) + f2 (x) et r2 (x) = −f1 (x) + f2 (x). Ainsi, le calcul de r1 et de r2 nécessite au plus d additions dans R. Soit a ∈ N. Si a est pair, a = 2`, alors (ζ a )d/2 = ζ `d = 1 et donc f (ζ a ) = q1 (ζ a )((ζ a )d/2 − 1) + r1 (ζ a ) = r1 (ζ a ). Si a est impair, a = 2` + 1, alors (ζ a )d/2 = ζ `d ζ d/2 = ζ d/2 . En outre, (ζ d/2 − 1)(ζ d/2 + 1) = ζ − 1 = 0. Puisque ζ est une racine primitive d-ième de l’unité, ζ d/2 − 1 n’est pas un diviseur de zéro. Par conséquent, ζ d/2 + 1 = 0 et donc ζ d/2 = −1. Il s’ensuit que d f (ζ a ) = q2 (ζ a )((ζ a )d/2 + 1) + r2 (ζ a ) = q2 (ζ a )(ζ d/2 + 1) + r2 (ζ a ) = r2 (ζ a ). Si l’on pose ω = ζ 2 , alors ω ∈ µ∗d/2 (R) et l’on a f (ζ a ) = r1 (ω a/2 ) (a pair), f (ζ a ) = r2∗ (ω (a−1)/2 ) (a impair), 47 où r2∗ (x) = r2 (ζx). Le calcul de r2∗ (x) se fait à partir de r2 (x) en multipliant les coefficients de r2 par des puissances de ζ ; puisque deg r2 < d2 − 1, il y a d2 multiplications par des puissances de ζ à effectuer. En faisant varier a de 0 à d − 1, on trouve que d d f (1), f (ζ), f (ζ 2 ), f (ζ 3 ) . . . , f (ζ d−2 ), f (ζ d−1 ) = r1 (1), r2∗ (1), r1 (ω), r2∗ (ω), . . . , r1 (ω 2 −1 ), r2∗ (ω 2 −1 ) . Quitte à permuter les termes, le calcul du d-tuple f (1), f (ζ), f (ζ 2 ), f (ζ 3 ) . . . , f (ζ d−2 ), f (ζ d−1 ) d est alors réduit au calcul des deux d2 -tuples de la même forme r1 (1), r1 (ω), . . . , r1 (ω 2 −1 ) et d r2∗ (1), r2∗ (ω), . . . , r2∗ (ω 2 −1 ) . Le coût de ce calcul est le coût du calcul de r1 et de r2∗ , soit d additions et d/2 multiplications par des puissances de ζ. Supposons donc que d soit une puissance de 2, d = 2k . On peut alors appliquer récursivement la procédure qui vient d’être décrite. À partir de f de degré (au plus) 2k −1, on obtient 2 polynômes de degré au plus 2k−1 − 1, puis 4 polynômes de degré au plus 2k−2 − 1, et ainsi de suite. Après k étapes, on trouve 2k polynômes constants dont les valeurs sont f (ζ a ) avec 0 ≤ a ≤ 2k − 1. Le coût de chacune des étapes est encore 2k additions et 2k−1 multiplications, et on en déduit donc le résultat suivant. Théorème. Soit R un anneau, soit k ≥ 1 un entier. On suppose que µ∗2k (R) 6= ∅. Alors la transformée de Fourier discrète d’un polynôme f ∈ R[x] de degré au plus 2k − 1 peut être calculée à l’aide de k2k additions et k2k−1 multiplications dans R. Corollaire 1. On reprend les hypothèses du Théorème et on suppose en plus que 2 est inversible dans R. Si f , g ∈ R[x] sont de degré au plus 2k − 1, alors la convolée f ∗2k g peut être calculée à l’aide de 3k2k additions et 3k2k−1 + 2k multiplications dans R. Démonstration du Corollaire. Soit ζ ∈ µ∗2k (R). En utilisant la Proposition 2, on voit que 1 f ∗2k g = k Tζ −1 Tζ (f )Tζ (g) . 2 D’après le Théorème, le calcul de Tζ (f ) nécessite k2k additions et k2k−1 multiplications. De même pour Tζ (g). Le produit Tζ (f )Tζ (g) se calcule alors avec 2k multiplicatione et, enfin, le calcul de Tζ −1 (Tζ (f )Tζ (g)) nécessite encore k2k additions et k2k−1 multiplications. Corollaire 2. La multplication de deux polynômes de degré au plus d − 1 et à coefficients dans un anneau R où 2 est inversible et contenant une racine primitive 2n -ième de l’unité avec 2n ≥ 2d peut être effectuée à l’aide d’au plus O(d log d) opérations dans l’anneau R. n/` C’est une conséquence de ce qui précède, en notant que si ζ ∈ µ∗2n (R), alors ζ 2 ∈ µ∗2` (R) lorsque 0 ≤ ` ≤ n. On prend pour ` le plus petit entier tel que 2` ≥ 2d. Si f et g ∈ R[x] sont de degré au plus d, alors f g = f ∗2` g. Quelques applications de la transformée de Fourier rapide Dans le ce paragraphe, nous indiquons la FFT puissent être appliquée aux calculs dans des anneaux ne contenant pas les racines de l’unité requises. 2πi Tout d’abord le cas K = C. Alors on prend traditionnellement ζd = e− d . Ainsi dans les cours de théorie du signal, par exemple, la transformée de Fourier discrète est le plus souvent définie par la formule d−1 X 2πikt ˆ f (t) = fk e − d , k=0 48 où (f0 , f1 , . . . , fd−1 ) ∈ Cd est souvent vu comme une sous-famille extraite d’une suite (fk ) indexée par k ∈ N ou par k ∈ Z. Si a est un entier, on a alors fˆ(a) = Tζd (a). La formule Tζ−1 = d1 Tζ −1 est d d équivalente à la formule d’inversion : d−1 2πika 1X ˆ f (k)e d , fa = d k=0 (0 ≤ a ≤ d − 1). Parmi des exemples d’anneaux les plus utiles en algorithmique qui contiennent des racines de l’unité on trouve les corps finis, et certains anneaux de la forme A[x]/(xd − 1), ou A[x]/P (x), où P est le polynôme minimal d’une racine de l’unité. Considérons d’abord le cas d’un corps fini. Notons Fq un corps fini à q éléments. Lemme 1. Soit d ≥ 1 un entier. Le corps Fq contient une racine primitive d-ième de l’unité si et seulement si d divise q − 1. Démonstration. En effet, le groupe multiplicatif F× q des éléments non nuls de Fq est alors cyclique d’ordre q − 1. Il suffit alors de rappler le résultat général suivant concernant les groupes cycliques. Lemme 2. Soit n ≥ 1 un entier et soit G un groupe d’ordre n. Alors l’ordre d’un élément de G divise n. Si de plus G est cyclique et si d ≥ 1 est un diviseur de n, alors G contient φ(d) éléments d’ordre d. Ici, comme auparavant, φ désigne la fonction indicatrice d’Euler, c’est-à-dire le nombre d’entiers a ∈ {1, 2, . . . n} premiers à n, ou encore le cardinal du groupe des éléments inversible (Z/nZ)× de l’anneau Z/nZ. On trouvera la démonstration du Lemme 2 dans n’importe quel cours d’algèbre niveau L3 ou M1. Il résulte du Lemme 1 que les nombres premiers p de la forme 2k t + 1 avec t petit ont un intérêt particulier, car le corps Fp contient alors une racine primitive 2k -ième de l’unité et on peut appliquer FFT pour calculer le produit de deux polynômes de Fp [x] de degré au plus 2k−1 − 1. (Je ne donnerai pas de sens précis à l’expression t petit , mais il faut rappeler que la complexité des calculs dans Fp augmentent avec p ; il y a donc souvent intérêt à supposer (p − 1)/2k aussi petit que possible.) Supposons maintenant qu’on veut multiplier deux polynômes f , g ∈ Z[x] de degré au plus 2 −1 et dont les coefficients sont bornés en valeur absolue par un nombre B > 0. Les coefficients de f g sont alors bornés par 2k−1 B 2 . Si donc on choisit un nombre premier p ≡ 1 (mod 2t ) et vérifiant p ≥ 2k−2 B 2 , on peut calculer le produit f g (mod p) avec FFT puis remonter et trouver ainsi f g. Puisque tous les coefficients concernés sont inférieurs à p, le coût de la redaction (mod p) et du remontage appartiennent à O(2k ), et on a un algorithme qui, en principe, calcule f g avec O(k2k ) opérations arithmétiques dans Fp . Cette analyse est correcte en principe, mais cache un certain nombre de difficultés. Le premier problème est, étant donnés k et B, de trouver un nombre premier p avec les propriétés requises. Or, on a le résultat suivant. k−1 Théorème (Dirichlet). Soit n ≥ 1 un entier et soit a ∈ Z premier à n. Alors il existe une infinité de nombres premiers p vérifiant p ≡ a (mod n). Plus précisément, si π(x) désigne le nombre de nombres premiers inférieurs ou égaux à x et si π(x; n, a) désigne le nombre de nombres premiers p ≤ x tels que p ≡ a (mod n), alors π(x; n, a) 1 = . x→+∞ π(x) φ(n) lim 49 Ce résultat dit que les nombres premiers sont équidistribués entre les φ(n) classes d’entiers (mod n) qui sont premiers à n. (On remarquera que si a n’est pas premier à n, il n’y a qu’un nombre fini de nombres premiers p tels que p ≡ a (mod n).) On trouvera la démonstration du théorème de Dirichlet dans de nombreux cours de théorie analytique des nombres. Voir par exemple le chapitre II.8 du livre de G. Tenenbaum déjà cité. Elle est tout à fait accessible à des étudiants de niveau M1-M2, mais la détailler en cours prendra trop de temps. On tire du théorème de Dirichlet l’existence d’un nombre premier p satisfaisant aux deux conditions p ≡ 1 (mod 2k ) et p ≥ 2k−2 B 2 . Mais, malheureusement, nous ne disposons pas, lorsque k ≥ 2, d’une majoration du plus petit nombre premier p répondant à ces conditions aussi explicite et simple que celle fournit par le postulat de Bertrand lorsque k = 1. Quelques algorithmes heuristiques et probabilistes À la fin de la dernière section, nous avons remarqué que nous ne disposons pas d’estimée aussi précise que le postulat de Bertrand pour le plus petit nombre premier p ≡ 1 (mod 2k ) supérieur à une borne donnée. (On pourra consulter la page consacrée au Théorème de Linnik dans Wikipédia pour des informations succinctes sur ce problème.) Par ailleurs, le postulat de Bertrand montre que si n ≥ 1, il existe un nombre premier dans l’intervalle ]n, 2n]. Dans les applications en vue, nous avons besoin d’un seul nombre premier plus grand que n, et dane le pire des cas, ce nombre premier pourrait a priori être proche de 2n. Or, tester tous les n entiers entre n + 1 et 2n nécessite n tests de primalité, alors que nous sommes habitués à des algorithmes de complexité appartenant à O(log n) ou à O((log n)2 ). Et nous n’avons pas (encore) discuté des tests de primalité et leur complexité. . .. (Bien entendu, on pourrait enlever tous les entiers divisibles par des petits nombres premiers, mais il en restera toutefois un nombre proportionnel à n à tester.) Toutefois, le théorème des nombres premiers suggèrent que les nombres premiers sont beaucoup plus fréquents. En effet, il suggère que, si h ≥ 0, le nombre de nombres premiers contenu dans l’intervalle ]n, n/h] devrait être à peu près égal à n+h n − . log(n + h) log n Si h est petit par rapport à n, cette quantité est à peu près égale à logh n ; autrement dit, dans un intervalle de longueur h commençant avec n + 1, le nombre de nombres premiers devrait êtrev égal à environ logh n . En moyenne donc, on s’attend à ce qu’il fait essayer environ log n entiers n + 1, n + 2, . . ., avant de tomber sur un nombre premier. On pourrait également dire que la probabilité que l’entier n soit un nombre premier est log1 n . Les deux points importants à retenir sont : (a) d’une part, on ne sait absolument pas rendre rigoureux cet argument avec nos connaissances mathématiques actuelles et : (b) en pratique, ça marche, c’est-à-dire, si on se donne un entier naturel n et si on teste pour primalité successivement les entiers n + 1, n + 2, . . ., on rencontre en moyenne un nombre premier après au plus environ log n essais, et il est rare qu’on soit obligé d’aller bien au-delà. Ainsi, l’algorithme qui consiste à tester successivement n + 1, n + 2, . . ., jusqu’à ce qu’on trouve un nombre premier et très souvent utilisé lorsqu’on cherche un nombre premier un peu plus grand que n. En pratique, le nombre de tests de primalité dont on a besoin appartient à O(log n), alors que le postulat de Bertrand affirme qu’en principe on a besoin d’un nombre de tests appartenant à O(n). 50 Cette question est manifestement liée au problème de la différence entre deux nombres premiers successifs. Pour une résumé de nos connaissances actuelles sur cette question on pourrait à nouveau consulter Wikipédia. La détermination du plus petit nombre premier est donc un exemple d’un problème algorithmique dont la complexité en pratique est beaucoup meilleure que celle qui peut être démontrée avec les techniques mathématiques d’aujourd’hui. Il en est de même pour le calcul du plus petit nombre premier plus grand que n et appartenant à une suite arithmétique vérifiant les hypothèses du théorème de Dirichlet. Si n0 est le plus petit membre de la progression plus grand que n, on constate qu’il suffit, en moyenne de tester log n éléments de la progression en commençant par n0 , au moins si n est grand par rapport au rapport de la progression. Ce genre d’algorithme est souvent dénommé un algorithme heuristique et on parle de sa complexité heuristique. La notion d’algorithme heuristique est à distinguer de celle d’algorithme probabiliste, qui est généralement réservée aux algorithmes qui font appel à des données tirées au hasard. Des algorithmes probabilistes sont souvent utilsés en cryptographie et, sans entrer dans les détails de ces applications, nous allons décrire quelques exemples de base. Voici donc un exemple simple d’un algorithme probabiliste, qui est utilisé dans la pratique. Soit p un nombre premier impair. Comment trouver un entier a premier à p qui n’est pas un carré (mod p) ? Si p ≡ 1 (mod 4) il suffit de prendre a = −1 (voir l’Exercice 3 de la feuille 8), mais si p ≡ 3 (mod 4), il n’y a pas de formule aussi simple fournissant un entier a qui est un non carré (mod p). Il s’avère alors que la méthode la plus simple de construire a est de le choisir au hasard. Il y (p − 1)/2 carrés non nuls et (p − 1)/2 non-carrés (mod p). La probabilité que a soit un non carré est donc 1/2. La probabilité donc qu’au bout de k essais on n’a toujours pas trouvé un non-carré est donc 1/2k , ce qui est déjà inférieure à une millième lorsque k = 10. Rappelons comment tester si a est un carré (mod p) ou non : Proposition. Soit p un nombre premier impair. On note Fp le corps Z/pZ et F× p son groupe multiplicatif. p−1 p−1 (i) F× p contient 2 carrés et 2 non carrés. Soit α ∈ F× p. p−1 p−1 (ii ) On a soit α 2 = 1 soit α 2 = −1. p−1 2 (iii ) Pour que α soit un carré de F× = 1. p , il faut et il suffit que α Démonstration. (i ) Considérons le morphisme de groupe × ψ : F× p → Fp , ψ(α) = α2 . Alors le noyau ker ψ de ψ est formé des éléments α tels que α2 = 1, c’est-à-dire ker ψ est l’ensemble des racines du polynôme x2 − 1. Ce polynôme étant de degré deux, il possède au plus deux racines dans le corps Fp . Mais 1 et −1 sont manifestement des racines, qui sont distinctes, car p est impair. Par conséquent, ker ψ est composé des deux éléments 1 et −1 ; il est donc d’ordre deux. p−1 Par conséquent, l’image de ψ est un groupe d’ordre p−1 , ce qui signifie que F× p contient 2 carrés. 2 p−1 p−1 Puisque F× p est d’ordre p − 1, il contient (p − 1) − 2 = 2 non carrés. p−1 p−1 (ii ) Puisque F× = 1. Par conséquent, (α 2 )2 = 1 et p est un groupe d’ordre p − 1, on a α p−1 (α 2 )2 est une racine du polynôme x2 − 1, donc égal à 1 ou à −1. p−1 2 2 (iii ) Si α est un carré de F× = β p−1 = 1. Afin de démontrer la réciproque, p , α = β , alors α p−1 p−1 2 on interprète les éléments α de F× = 1 comme des racines de x 2 − 1. D’après p qui vérifient α p−1 p−1 2 le (i ), F× − 1. Les carrés p contient 2 carrés, que nous venons de voir sont des racines de x 51 p−1 fournissent donc p−1 racines du polynôme x 2 − 1. Ce polynôme étant de degré 2 p−1 pas d’autres racines. On conclut que si α n’est pas un carré, alors α 2 6= 1. p−1 , 2 il ne possède Le crible d’Ératosthène Soit n ≥ 1 un entier. Comment tester n pour savoir si n est un nombre premier ou non ? Comment factoriser calculer la factorisation d’un entier naturel n comme produit de nombres premiers ? Rappelons d’abord la méthode apprise au lycée, en relation avec le crible d’Ératosthène. Si n n’est pas premier, il s’écrit comme produit n = k`√avec 2 ≤ k ≤ ` ≤ n − 1. Alors k 2 ≤ n et donc n est √ divisible par un entier inférieur ou égal à n. Par conséquent, si aucun √ des entiers 2, 3, . . ., b nc ne divise n, alors n est premier. L’algorithme exige donc au plus b nc − 1 tests de divisibilité et sa complexité mesurée en termes du nombre de tests de divisibilité appartient donc √ à O( n). On remarque que cet algorithme n’est que la première étape d’un algorithme de factorisation. Soit n ≥ 2 un entier. On teste n pour divisibilité d’abord par 2, puis par 3, et ainsi de suite jusqu’à ce qu’on trouve le plus petit entier p1 ≥ 2 divisant n. Alors 1 est forcément un nombre premier, et c’est le plus √ petit nombre premier divisant n. Si n n’est divisible par aucun nombre premier inférieur à n, on conclut que n est premier. Dans le cas contraire, on calcule le quotient pn1 et on teste s’il est divisible par p1 . Si n = pr11 n1 avec p1 ne divisant pas n1 , alors le plus petit nombre premier p2 divisant p1 est strictement plus grand que p1 . On continue de manière récursive, la factorisation de n étant déduite de celle de n1√ . La récursion s’arrête lorsqu’on trouve un diviseur n0 de n qui n’est pas divisible par un entier ≤ n0 : on conclut alors que n0 est un nombre premier et la factorisation de n est terminée. Proposition. Afin de factoriser √ l’entier n ≥ 2 par l’algorithme de factorisation qui vient d’être décrit on a besoin d’au plus n + log2 n tests de divisibilité. Démonstration. Écrivons la factorisation de n sous la forme n= k Y pri i , p1 < p2 < · · · < pk des nombres premiers et ri > 0 pour tout i ∈ {1, 2, . . . , k}. i=1 Démonstration. Afin de déterminer p1 , on teste successivement la divisibilité de n par 2, 3, . . ., p1 − 1 et p1 , ce qui nécessite p1 − 1 tests. Ensuite, la détermination de r1 nécessite r1 − 1 tests de divisibilité supplémentaires par p1 . Le calcul de p1 , de r1 et de pnr1 nécessite donc (p1 − 1) + (r1 − 1) 1 tests de divisibilité. De même, si i ≤ k − 1 et si ni−1 = pr1 pr2n···pri−1 , on détermine pi , ri et ni en testant ni−1 pour 1 2 i−1 divisibilité par pi−1 + 1, pi−1 + 2, . . ., pi , puis par ri − 1 tests de division par pi . Cela nécessite (pi − pi−1 + 1) + (ri − 1) tests de divisibilité. √ √ Remarquons que si k > 1, alors pi < n pour tout i ≤ k − 1. En effet, si pk−1 ≥ n, alors pk pk−1 > p2k−1 ≥ n ce qui est absurde. Dans le cas i√ = k il y a deux donc possibilités :— (a) Si pk ≤ n, alors le calcul de pk et de rk nécessite (pk − pk−1 + 1) + (rk − 1) tests de divisibilité. Le nombre total de tests de divisibilité est donc (p1 − 1) + (r1 − 1) + k X k X √ (pi − pi−1 + 1) + (ri − 1) = pk − 2 + ri ≤ n + log2 n. i=2 i=1 52 √ (b) Si pk > n, alors rk = 1 et on√en tire que nk−1 = pk . On se trouve √ dans ce cas si aucun des nombres pk−1 + 1, pk−1 + 2, . . ., b nc ne divisent nk−1 . Cela nécessite b nc − pk−1 + 1 tests de divisibilité. Le nombre total de tests de divisibilité est donc (p1 − 1) + (r1 − 1) + k−1 X k X √ √ (pi − pi−1 + 1) + (ri − 1) + (b nc − pk−1 + 1) = b nc − 2 + ri i=2 i=1 Dans les deux cas, on conclut que le nombre de tests de divisibilité est au plus Mais comme pi ≥ 2 pour tout i, on a P √ n + ki=1 ri . 2r1 +r2 +···+rk = 2r1 2r2 · · · 2rk ≤ pr11 pr22 · · · prkk = n, d’où Pk i=1 ri ≤ log2 n √ Le nombre de tests de divisibilité nécessaires pour factoriser n appartient donc à O( n) ; en tenant compte de la complexité des tests de divisibilité, on arrive à un algorithme dont le com√ plexité appartient à O( n(log n)2 . Les meilleurs algorithmes connus actuellement pour factoriser 1 +ε un entier n ont une complexité heuristique appartenant à O(e(log n) 2 ) pour tout ε > 0. Nous ne connaissons donc pas, actuellement, un algorithme de complexité polynômiale de factorisation, c’est-à-dire dont la complexité appartient à O((log n)c ) pour une certaine constante c > 0. Le teste de primalité de Miller-Rabin Par contre, nous connaissons des tests de primalité qui, vu comme algorithmes probabilistes, ont une complexité polynômiale en moyenne. Après quelques préliminaires, nous présenterons le test de primalité de Miller-Rabin. Commençons en rappelant le petit théorème de Fermat. Proposition. Soit n ≥ 1 un nombre premier et soit a un entier premier à n. Alors an−1 ≡ 1 (mod n). On en tire le corollaire suivant : Corollaire. Soit n ≥ 1 un entier. S’il existe un entier a premier à n tel que an−1 6≡ 1 (mod n), alors n n’est pas un nombre premier. Ce corollaire est parfois appelé le test de Fermat (ou même le test de primalité de Fermat, ce qu’il n’est sûrement pas). Pour montrer que n n’est pas premier, on choisit au hasard un entier a premier à n et on calcule an−1 (mod n). Si après un certain nombre d’essais, on trouve a tel que an−1 ≡ 1 (mod n), on conclut que a n’est pas premier. Notons que si on choisit a entre 1 et n − 1, alors la complexité du calcul de pgcd(a, n) appartient à O((log n)2 ), puis le calcul de an−1 (mod n) par exponentiation rapide appartient à O((log n)3 ). Le test peut alors être effectué en complexité polynômiale en log n. Que conclure si on ne trouve pas a premier à n tel que an−1 6≡ 1 (mod n) ? On en peut pas conclure que n est premier, car il existe des entiers n ≥ 2 qui ne sont pas premiers mais qui vérifiant an−1 ≡ 1 (mod n) pour tout entier a premier à n. Un tel entier s’appelle un nombre de Carmichael. Le plus petit nombre de Carmichael est 561 (voir l’Exercice 1 de la feuille 9). 53 On a le raffinement suivant du petit théorème de Fermat : Théorème. Soit n ≥ 3 un nombre premier impair. On écrit n − 1 = 2t u, avec t ≥ 1 et u impair. Soit a un entier premier à n. Alors ou bien (i) au ≡ 1 (mod n), ou bien m (ii ) il existe un entier m tel que 0 ≤ m ≤ t − 1 et a2 u ≡ −1 (mod n). Démonstration. Puisque n est un nombre premier, (Z/nZ)× est un groupe d’ordre n − 1. D’après le théorème de Lagrange, l’ordre de la classe de a (mod n) divise n − 1 ; il s’écrit donc 2r v avec 0 ≤ r ≤ t et v un entier impair qui divise u. Supposons que r = 0. Alors av ≡ 1 (mod n) d’où au ≡ 1 (mod n), car v divise u. On est alors dans le cas (i). r−1 r Supposons que r ≥ 1, alors (a2 v )2 ≡ a2 v ≡ 1 (mod n) et, Z/nZ étant un corps, on a ou r−1 r−1 bien a2 v ≡ 1 (mod n) ou bien a2 v ≡ −1 (mod n). La première possibilité est exclue, car 2r v est l’ordre de la classe de a. Par conséquent, si on pose m = r − 1, on a 0 ≤ m ≤ t − 1 et, comme v divise u et v et u sont impairs, mu a2 m u u ≡ (a2 v ) v ≡ (−1) v ≡ −1 (mod n). On se trouve alors dans le cas (ii ). Le théorème permet de montrer que 561 n’est pas un nombre premier. Notons que 560 = 24 ×35 et prenons par exemple a = 2. On trouve 235 ≡ 263 (mod 561), de sorte que la conclusion (i ) n’est pas vérifiée. De même, 270 ≡ 263 (mod 561), 2140 ≡ 166 (mod 561), et 2280 ≡ 67 (mod 561), et la conclusion (ii ) n’est pas vérifiée. Soit n ≥ 3 un entier impair et soit a un entier. On écrit n − 1 = 2t u, avec t ≥ 1 et u un entier impair. Si n n’est pas premier, alors on dit que n est un nombre pseudopremier fort en base a, si l’une des deux conditions (i ), (ii ) du théorème précédent est satisfaite, c’est-à-dire si ou bien m (i ) au ≡ 1 (mod n), ou bien (ii ) il existe un entier m tel que 0 ≤ m ≤ t − 1 et a2 u ≡ −1 (mod n). Théorème (Monier, Rabin). Soit n ≥ 3 un entier impair. On suppose que n ne soit pas premier et on note S(n) le nombre d’entiers a ∈ {1, 2, . . . , n} tels que n est un nombre pseudopremier fort en base a. Alors S(n) ≤ 41 ϕ(n), où ϕ est la fonction indicatrice d’Euler. On trouvera une démonstration de ce résultat dans le chapitre 3 du livre Prime Numbers, a Computational Perspective de R. Crandall et C. Pomerance. Le théorème de Monier et Rabin montre que, si n ≥ 3 n’est pas premier, pour plus de trois quarts des entiers a entre 1 et n−1 et premiers à n, n n’est pas un pseudopremier fort en base a. En supposant que les bases a de pseudoprimalité de n sont uniforément distribuées dans l’intervalle [1, n − 1], on conclut que, si n n’est pas premier et si a ∈ {1, 2, . . . , n − 1} est choisi au hasard, la probabilité que n soit un pseudopremier fort en base a est au plus 14 . Le test de primalité de Miller-Rabin consiste donc en choisissant au hasard une séquence d’entiers a dans l’intervalle [1, n − 1] et en testant si n vérifie les deux conditions (i ) et (ii ). Un tel test s’appelle un test de Miller-Rabin. Si k entiers a sont ainsi testés et tous vérifient les deux conditions, on déclare que n est premier avec un probabilité d’au moins 1 − 41k . Remarques. (1) À vrai dire, l’appelation test de primalité est, sur le plan logique, impropre, car il s’agit d’un test qui, en cas d’echec, prouve que n n’est pas premier, mais dont le succès ne garantit pas que n soit premier. (2) Sous une version étendue de l’hypothèse de Riemann, on peut montrer que, si n n’est pas premier, alors il existe au moins un entier a < 2(log n)2 pour lequel n n’est pas un pseudopremier 54 fort en base a. Ainsi, si tous les entiers a inférieurs à cette borne vérifient les conditions (i ) et (ii ), alors n est premier. Ainsi, on aurait un test déterministe de primalité en complexité polynômiale. (3) En fait, il existe un test déterministe de primalité en complexité polynômiale, le test d’Agrawal, Kayal et Saxena (AKS). En pratique, il est peu implémenté car moins beaucoup moins rapide que le test de Miller-Rabin. (4) Le test de Miller-Rabin est très utilisé pour construire des nombres premiers de taille cryptographique , c’est-à-dire ayant, grosso modo, entre 192 et 4096 bits. Typiquement, entre 20 et 60 entiers a sont testés. Ainsi, les nombres premiers utilisés en cryptographie ne le sont, parfois, qu’avec une probabilité d’au moins 1 − 4120 soit environ 1 − 10112 . . .. (5) Un nombre RSA est un entier naturel qui est le produit de deux nombres premiers distincts mais à peu près de la même taille. Les protocols cryptographiques RSA sont basés sur le principe qu’il est facile de fabriquer des nombres RSA mais difficile de les factoriser. En effet, pour créer un nombre RSA il suffit de trouver deux nombres premiers d’une taille convenable, puis de calculer leur produit. D’après ce qui précède, cela peut se faire en complexité heuristique O(log n)5 . Le nombre RSA ainsi crée est alors la clé publique. Mais la factorisation d’un nombre RSA a une complexité beaucoup plus élevée, ce qui la rend impossible avec les techniques actuelle, au moins si les deux nombres premiers ont été choisis suffisament au hasard. Ici, R est pour Rivest, S est pour Shamir et A est pour Adleman. Étude des racines d’un polynôme à coefficients réels ou complexes : généralités Dans les sections qui suivent nous allons étudier, d’un point de vue algorithmique, la localisation et l’approximation des racines d’un polynôme à coefficients réels ou complexes. En réalité, il est extrêmement difficile de construire un algorithme déterministe et efficace pour calculer numériquement les racines d’un polynôme. Nous nous limiterons à en discuter certains de ces ingrédients. Quatre problèmes, de nature assez différentes, apparaissent alors :— (i ) La localisation des racines. Par localisation des racines, on entend obtenir des informations générales sur la position des racines (sur la droite réelle ou dans le plan complexe) en fonction des coefficients ou d’autres propriétés du polynôme. Un problème lié est la détermination du nombre des racines dans un ensemble donné. (ii ) La séparation des racines. Par séparation des racines, on entend la détermination d’une famille d’ensembles explicites de nombres complexes deux-à-deux disjoints et contenant chacun une et une seule racine. (iii ) La recherche d’une première approximation, en principe assez grossière, d’une racine, à partir des informations obtenues par les méthodes de (ii ). Cela s’effectue à l’aide d’un algorithme récursif, qui a donc besoin d’une approximation initiale. En général ces algorithmes convergent assez lentement vers la racine, mais leur convergence est assurée pour un large choix de valeurs intiales. (iv ) La recherche d’une approximation précise de la racine à l’aide d’un algorithme à convergence rapide. À nouveau, il s’agit d’un algorithme récursif, mais sa convergence n’est assurée que si l’approximation initiale appartient à un ensemble plus restreint que les ensembles utilisables dans les algorithmes de (iii ). On dispose de méthodes différentes selon que les polynômes sont à coefficients réels ou à coefficients complexes. 55 Rappelons pour mémoire que le théorème de Gauss-d’Alembert affirme que, si f est un polynôme de degré n ≥ 1 à coefficients complexes, alors f sécrit de façon unique sous la forme Y f (x) = c (x − ρ)nρ , ρ∈Z(f ) où c ∈ C× , Z(f ) est l’ensemble des racines de f et, pour tout ρ ∈ Z(f ), l’entier nρ est la multiplicité de ρ. En prenant la dérivée logarithmique, on obtient la formule X nρ f 0 (x) = , f (x) x−ρ ρ∈Z(f ) qui sera utilisée plus tard. Q Par définition, le radical de f est le polynôme ρ∈Z(f ) (x − ρ), c’est-à-dire le polynôme ayant les mêmes racines que f , mais avec multiplicité un. Puisqu’il est souvent utile de pouvoir se restreindre aux polynômes sans racines multiples, il est important de savoir calculer le radical de f sans connaı̂tre les racines de f . Ceci est accompli par le résultat suivant : Théorème. Soit f ∈ C[x] un polynôme de degré au moins un. On note f 0 la dérivée de f . Alors, à une constante multiplicative près, le radical de f est égal à f (x) . pgcd(f (x), f 0 (x)) Q Démonstration. Posons d(x) = pgcd(f (x), f 0 (x)). Il s’agit de montrer que d(x) = ρ∈Z(f ) (x − ρ)ρa −1 . Puisque d(x) divise f (x), toute racine de d est une racine de f , et il suffit donc vérifier que la multiplicité de chaque racine ρ de f comme racine de d est égale à nρ − 1. Soit donc ρ ∈ Z(f ). Alors f (x) = (x − ρ)nρ u(x), où u(x) ∈ C[x] et u(ρ) 6= 0. Par conséquent, f 0 (x) = (x − ρ)nρ −1 (nρ u(x) + (x − ρ)u0 (x)) et on en tire que (x − ρ)nρ −1 divise f 0 (x) et donc divise aussi d(x). Montrons par l’absurde que (x−ρ)nρ ne divise pas d(x). En effet, dans le cas contraire (x−ρ)nρ f 0 (x) 0 diviserait f 0 (x), et x − ρ diviserait alors (x−ρ) nρ −1 = nρ u(x) + (x − ρ)u (x). On en tirerait que x − a diviserait nρ u(x). Or, x − ρ ne divise pas u(x) et nρ ≥ 1, ce qui donne une contradiction. Remarques (1). Supposons que les coefficients de f appartiennent à un sous-corps K de C. Alors il en de même pour les coefficients de f 0 . Par conséquent, les coefficients de pgcd(f (x), f 0 (x)) appartiennent également à K et on conclut que le coefficients du radical de f appartiennent encore à K. (2). Nous venons de voir que le calcul du radical d’un polynôme f à coefficients complexes se réduit au calcul du pgcd de f et de sa dérivée f 0 . Par contre, nous ne connaissons aucune méthode pour calculer le radical d’un entier naturel sans connaı̂tre sa factorisation comme produit de nombres premiers. Localisation des racines d’un polynôme Commençons avec le résultat général suivant : Théorème. Soit f (x) = f0 + f1 x + · · · + fn−1 xn−1 + xn un polynôme unitaire de degré n ≥ 1 à coefficients complexes. Soit ρ une racine de f . 56 (i ) Soit r > 0 un réel tel que rn ≥ |f0 | + |f1 |r + · · · + |fn−1 |rn−1 . Alors |ρ| ≤ r. (ii ) On pose M = max(|f0 |, |f1 |, . . . |fn−1 |). Alors |ρ| ≤ 1 + M. Démonstration. (i ) Supposons pour une contradiction que |ρ| > r. Alors |ρ|n > rn et donc |f (ρ)| ≥ |ρ|n − |f0 | + |f1 ||ρ| + · · · + |fn−1 ||ρ|n−1 > rn − |f0 | + |f1 |r + · · · + |fn−1 |rn−1 ≥ 0, d’où f (ρ) 6= 0, ce qui est la contradiction cherchée. (ii ) Puisque M ≥ 0, le résultat est évident si |ρ| ≤ 1. Supposons donc que |ρ| > 1. Puisque ρ est une racine de f , on a ρn = −(f0 + f1 ρ + f2 ρ2 + · · · + fn−1 ρn−1 ), d’où |ρ|n ≤ |f0 | + |f1 ||ρ| + |f2 ||ρ|2 + · · · + |fn−1 ||ρ|n−1 ≤ M 1 + |ρ| + |ρ|2 + · · · + |ρ|n−1 |ρ|n − 1 =M |ρ| − 1 |ρ|n ≤M . |ρ| − 1 Puisque |ρ| > 1, on peut simplifier le |ρ|n , ce qui donne 1 ≤ M puis |ρ| ≤ 1 + M . |ρ| − 1 Corollaire. Soit f (x) = f0 + f1 x + · · · + fn−1 xn−1 + xn un polynôme unitaire de degré n ≥ 1 à coefficients réels. Si M = max(|f0 |, |f1 |, . . . , |fn−1 |), alors toutes les racines réelles de f sont situées dans l’intervalle [−1 − M, 1 + M ]. Le théorème de Rolle affirme comme cas particulier que si ρ1 < ρ2 sont deux racines réelles d’un polynôme f à coefficients réels de degré n ≥ 1, alors l’intervalle ]ρ1 , ρ2 [ contient une racine de la dérivée f 0 de f . On en tire que si ρmin et ρmax désignent respectivement la plus grande et la plus petite racine de f , et si f a n racines réelles distinctes, alors toutes les racines réelles de f 0 sont réelles et elles appartiennent à l’intervalle ]ρmin , ρmax [. Gauss a découvert un résultat semblable concernant les racines complexes de la dérivée d’un polynôme à coefficients complexes. Rappelons que si E est un R-espace vectoriel, un sous-ensemble X de E est dit convexe (ou un convexe) si, quelque soient x, y ∈ X, le segment droit {(1 − t)x + ty | t ∈ [0, 1]} est contenu dans X. On voit que toute intersection de convexes de E est convexe. Si X est convexe, si X0 est un P sous ensemble fini de X et si {tx | x ∈ X0 } est une famille de nombres réels et positifs telle que x∈X0 tx = 1, alors X tx x ∈ X. x∈X0 57 Soit Z un sous-ensemble de E. Puisque E est lui-même convexe, l’intersection de tous les convexes de E qui contiennent Z est un convexe contenant Z, et c’est plus petit convexe contenant Z. On l’appelle l’enveloppe convexe de Z. Théorème (Gauss, F. Lucas). Soit f ∈ C[x] un polynôme de degré au moins un. Alors l’ensemble des racines de f 0 est contenu dans l’enveloppe convexe de l’ensemble des racines de f . Démonstration. Notons Z(f ) l’ensemble des racines de f . On écrit Y f (x) = (x − ρ)nρ , ρ∈Z(f ) où nρ est la multiplicité de la racine ρ. Alors X f 0 (x) nρ = . f (x) x0 − ρ ρ∈Z(f ) Soit alors x0 une racine de f 0 . Le résultat est évident si x0 est également une de f . Supposons donc que cela ne soit pas le cas. Alors 0= X X nρ (x̄0 − ρ̄) f 0 (x0 ) nρ = = , f (x0 ) x0 − ρ |x0 − ρ|2 ρ∈Z(f ) d’où X ρ∈Z(f ) ρ∈Z(f ) X nρ ρ̄ nρ x̄ = . 0 2 |x0 − ρ| |x0 − ρ|2 ρ∈Z(f ) En prenant le conjugué complexe en en divisant par X ρ∈Z(f ) x0 = X tρ ρ, nρ , on trouve une égalité |x0 − ρ|2 où tρ ≥ 0 pour tout ρ ∈ Z(f ) et ρ∈Z(f ) X tρ = 1, ρ∈Z(f ) d’où le résultat. Séparation des racines réelles d’un polynôme à coefficients réels Dans ce paragraphe, on considère des polynômes à coefficients complexes. Comme précédemment, on note f 0 la dérivée de f et par Z(f ) l’ensemble des racines complexes de f . On note ZR (f ) l’ensemble de ses racines réelles. Diverses méthodes, en commençant par Descartes, ont été élaborées pour déterminer le nombre de racines réelles de f appartenant à un intervalle ]a, b[, où a < b appartiennent à R ∪ {−∞, +∞}. Nous nous limiterons ici au théorème de Sturm, en suivant la présentation dans F. Gantmacher, Théorie des matrices, Vol II, chapitre 15, § 2. En remplaçant le polynôme par son radical, il suffit de traiter le cas où les racines de f sont deux-à-deux distinctes. Soit R ∈ R(x) une fonction rationnelle, c’est-à-dire le quotient de deux polynômes à coefficients réels. On suppose que R 6= 0. Si ρ ∈ C, alors il existe un unique entier νρ tel que la limite limx→ρ (x − ρ)−νρ R(x) est finie et non-nulle. On dit que a est un pôle de R si νρ > 0, et l’entier 58 νρ s’appelle alors l’ordre du pôle ρ de R. Les pôles de R sont en nombre fini, car tout pôle est forcément une racine du polynôme dénominateur de R. On peut alors écrire R(x) = Pρ (x) + R1 (x), νρ (x − ρ) ρ pôle réel X où la somme parcourt l’ensemble des pôles réels de R et la fonction rationnelle R1 (x) est sans pôle réel. Ici, le polynôme Pρ est de degré au plus νρ − 1 et ne s’annule pas en a. Si a < b sont deux éléments de R ∪ {−∞, +∞}, on appelle alors indice de Cauchy de R sur ]a, b[ l’entier X Iab (R) = sign(Pρ (ρ)), a<ρ<b νρ impair où sign(u) ∈ {0, −1, 1} désigne le signe du nombre réel u. La somme parcourt tous les pôles d’ordre impair appartenant à l’intervalle ouvert ]a, b[. Si par exemple f ∈ R[x] est un polynôme non nul, alors on a X f 0 (x) nρ = + R1 (x), f (x) x−ρ ρ∈ZR (f ) où à nouveau R1 est sans pôle réel et nρ est la multiplicité de la racine ρ de f . Puisque nρ > 0 pour tout ρ ∈ Z(f ), on constate que Iab (f 0 /f ) est égal au nombre de racines réelles de f situées dans l’intervalle ]a, b[. En général, si ρ est un pôle réel de R, Iab (R) mesure la contribution des pôles au nombre de changements de signe de R(x) lorsque x parcourt ]a, b[. Rappelons que ρ est un pôle de R et si νρ est pair, alors R(x) a le même signe les deux côtés de ρ, alors que si νρ est impair, R(x) change de signe lorsque x passe par ρ. C’est pour cette raison que dans la définition de Iab (R), la somme est restreinte aux pôles d’ordre impair. Par définition, une suite de Sturm sur ]a, b[ est une famille finie de polynômes (f1 , f2 , . . . , fm ) à coefficients réels telle que : (1) Pour tout x ∈]a, b[, si k ∈ {2, 3, . . . , m − 1} est un indice tel que fk (x) = 0, alors fk−1 (x) et fk+1 (x) sont non nuls et de signes opposés ; (2) On a fm (x) 6= 0 pour tout x ∈]a, b[. Si (f1 , f2 , . . . , fm ) est une suite de Sturm et si x ∈]a, b[, on note V(f1 ,f2 ,...,fm ) (x) (ou tout simplement V (x)) le nombre de changement de signe dans la séquence f1 (x), f2 (x), . . ., fm (x), les termes nuls ayant été supprimés. Remarquons que le signe de la valeur d’un polynôme en x reste constant lorsque x est assez grand. On définit alors V (+∞) comme étant la valeur de V (x) lorsque x est assez grand et V (−∞) de façon semblable. Théorème (Sturm). Soit (f1 , f2 , . . . , fm ) une suite de Sturm sur ]a, b[. Alors Iab (f2 /f1 ) = V (a) − V (b). Démonstration. On considère les fonctions x 7→ Iax (f2 /f1 ) et x 7→ V (a) − V (x) lorsque x parcourt l’intervalle ]a, b[. D’après la définition de Iab , la fonction x 7→ Iax (f2 /f1 ) est constante sur tout intervalle ouvert ne contenant pas de pôle de f2 /f1 , c’est-à-dire une racine de f1 . D’autre part, la valeur de V (x) ne peut changer que lorsque x passe par une valeur x0 pour laquelle il existe un indice k tel que fk (x) = 0. Or, la condition (2) implique que k < m et la condition (1) implique 59 que si k ∈ {2, 3, . . . , m − 1}, alors V (x) ne change pas lorsque x passe par x0 . Par conséquent, V (x) ne peut changer que lorsque x passe par une racine de f1 . En particulier, Iax (f2 /f1 ) = 0 et V (x) = V (a) lorsque x se trouve dans l’intervalle situé entre a et la plus petite racine de f1 supérieure à a. Par conséquent, Iax (f2 /f1 ) = V (a) − V (x) pour tout x > a et suffisament proche de a. Pour conclure la démonstration, il suffit de vérifier que Iax (f2 /f1 ) et −V (x) changent de la même façon lorsque x augmente en passant par une racine de f1 . La condition (1) appliquée avec k = 2 signifie que si ρ est une racine de f1 , alors f2 6= 0 : on en tire que l’ensemble des pôles de f2 /f1 est égal à l’ensemble des zéros de f1 , et que la multiplicité de ρ en tant que pôle de f2 /f1 est égale à la multiplicité de ρ en tant que racine de f1 . Si la multiplicité de ρ est paire, alors les signes de f1 et de f2 /f1 ne changent pas lorsque x passe par ρ. Par conséquent, ni Iax (f2 /f1 ) ni V (x) ne sont modifiés. Si la multiplicité de ρ est impaire, alors les signes de f2 /f1 et de f1 changent lorsque x passe par ρ. Supposons que Pρ (ρ) > 0. Alors Iaρ+ε (f2 /f1 ) = Iaρ−ε (f2 /f1 ) + 1 pour tout ε > 0 suffisament petit. En plus, f2 (ρ − ε)/f1 (ρ − ε) < 0 et f2 (ρ + ε)/f1 (ρ + ε) > 0. Par conséquent, f1 (ρ − ε) et f2 (ρ − ε) sont de signes opposés alors f1 (ρ + ε) et f2 (ρ + ε) ont le même signe lorsque ε > 0 est suffisament petit. La suite de Sturm perd alors un changement de signe au début, et −V (x) augmente par 1 tout comme Iax (f2 /f1 ). Un argument semblable montre que lorsque Pρ (ρ) < 0, Iax (f2 /f1 ) et −V (x) diminuent par 1. D’où le résultat. Pour que ce résultat puisse être utile, il faut savoir construire une suite de Sturm dont les deux premiers termes sont f1 et f2 . Proposition. Soient f1 , f2 deux polynômes qui ne s’annulent pas simultanément sur ]a, b[. Si deg(f2 ) ≤ deg(f1 ), alors il existe une suite de Sturm dont les deux premiers termes sont f1 et f2 . Démonstration. On construit f3 , f4 , . . ., par une variante de l’algorithme d’Euclide : −f3 est le reste de la division de f1 , par f2 , −f4 est le reste de la division de f2 par f3 , et ainsi de suite. Alors les degrés successifs deg f2 , deg f3 , deg f4 , . . . décroissent strictement : il existe donc un entier m ≥ 2 tel que fm 6= 0 mais fm+1 = 0. Si fm s’annule en x0 ∈]a, b[, on voit en remontant que tous les fk s’annulent en x0 , ce qui contredit l’hypothèse que f1 et f2 ne s’annulent pas simultanément. De même, si fk (x0 ) = 0, alors fk−1 (x0 ) = −fk+1 (x0 ) est non-nul, car si fk−1 (x0 ) = 0, alors f` (x0 ) = 0 pour tout ` ∈ {1, 2, . . . , m}, contrairement aux hypothèses. On peut utiliser le théorème et la proposition pour calculer le nombre de racines réelles d’un polynôme f à coefficients réelles dans différents intervalles. On suppose que f est sans racine multiple, ce qui équivaut à f et f 0 n’ayant pas de facteur en commun. On forme alors la suite de Sturm dont les premiers termes sont f1 = f , f2 = f 0 selon la recette de la proposition. On remarque que fm est un pgcd de f1 et de f2 , qui sera donc sous nos hypothèses une constante non nulle. Séparation des racines : cas d’un polynôme à coefficients complexes Le problème de la séparation des racines complexes est nettement plus délicat que celui de la séparation des racines réelles. Nous nous limiterons donc à signaler quelques pistes, sans les approfondir, et qui peuvent êgalement être appliquées aux polynômes à coefficients complexes. 60 Soit donc f (x) ∈ C[x] un polynôme non nul. Alors f est une fonction analytique, et si γ est un lacet dans le plan complexe, alors Z 0 1 f (z) dz 2πi γ f (z) est un entier relatif qui, dans des cas simples, est égal à la somme des résidus des pôles de f 0 /f situés dans la région D du plan complexe dont γ est le bord. C’est le cas notamment lorsque γ(t) = a + re2πit (où t ∈ [0, 2π]) paramètre un cercle, ou γ est une fonction affine par morceaux paramétrant les côtés successifs d’un rectangle. Or, la décomposition X nρ f 0 (x) = f (x) x−ρ ρ∈Z(f ) montre que les pôles de f 0 /f sont tous simples, situés aux racines de f , et que le résidu d’un pôle est égal à la multiplicité de la racine correspondante. On en tire le résultat suivant. Proposition. Soit γ un lacet simple, bordant le domaine D. Alors Z 0 X 1 f (z) dz = nρ . 2πi γ f (z) ρ∈D∩Z(f ) Autrement dit, l’intégrale calcule le nombre de racines de f situées dans D, comptées avec multiplicité. Une stratégie pour déterminer ce nombre sera alors le calculer une valeur approchée de l’intégale par des méthodes d’intégration numérique. Un problème intéressant, et important notamment dans la théorie des équations différentielles, est de donner des conditions sur un polynôme pour que toutes ses racines soit de partie réelle négative. Plus généralement, on peut chercher à compter le nombre de racines dont la partie réelle est négative, ou dont la partie réelle appartient à un demi-plan donnée. C’est le problème de Routh-Hurwitz, qui est traité dans le chapitre 15 du livre de Gantmacher déjà cité. Une approche est de prendre pour γ le lacet formé par un segment de longueur r > 0 de la demi-droite bordant le demi-plan, suivi par le demi-cercle du même rayon qui retourne au point de départ, puis de faire tendre r → +∞. Recherche d’une première approximation d’une racine Nous arrivons donc au problème (iii ) de notre étude des racines d’un polynôme, à savoir trouver une première approximation suffisament proche d’une racine pour que les méthodes d’approximation rapide, qui seront discutées dans la section suivante, puissent être appliquées. Ici, la méthode la plus simple est d’utiliser le principe de recherche par dichotomie. Considérons d’abord le cas d’un polynôme f à coefficients réels. Si a et b sont deux réels tels que f (a)f (b) ≤ 0, alors le théorème des valeurs intermédiaires implique que f possède une racine ρ dans l’intervalle [a, b]. On peut alors chercher une première approximation à une racine ρ contenue dans l’intervalle en posant ρ1 = a, ρ2 (b). Si f (ρ1 ) = 0 ou si f (ρ2 ) = 0, on a gagné. Sinon, on pose 3 3 ρ3 = a+b . Si f (ρ3 ) = 0, on a gagné. Sinon, on pose ρ4 = ρ1 +ρ si f (ρ1 )f (ρ3 ) < 0 et ρ4 = ρ2 +ρ si 2 2 2 f (ρ2 )f (ρ3 ) < 0. En continuant ainsi obtient une suite (ρn )n≥1 où ρn appartient à un intervalle In de longueur |b−a| chacun emboı̂té dans le précédent et dans lequel f prend à la fois des valeurs 2n 61 positives et des valeurs négatives. La suite qui converge vers un élément ρ de [a, b]. On a alors f (ρ) = 0, car si par exemple f (ρ) > 0, alors la continuité de f entraı̂nerait que f prend des valeurs strictement positives sur un intervalle ouvert J contenant ρ. Mais In ⊆ J pour tout n assez grand, ce qui est contredirait le fait que f change de signe sur In . Il est clair que ρn est une valeur approchée de ρ avec une erreur d’au plus |b−a| . Autrement 2n dit, la qualité de l’approximation augmente linéairement avec n. Si par exemple, on travaille en base 10, on gagne un chiffre décimal après un nombre constant d’itérations. Remarquons que la condition f (a)f (b) ≤ 0 à elle seule n’entraı̂ne pas l’unicité de la racine ρ dans l’intervalle [a, b]. Cela sera assuré si, par exemple f est monotone sur [a, b], ce qui sera le cas par exemple si la dérivée de f est de signe constante sur [a, b], une condition qui peut être appréciée en appliquant le théorème de Sturm à f 0 . Une principe semblable peut être appliquée pour approximer les racines complexes d’un polynôme à coefficients complexes. On suppose pour simplifier que f soit unitaire et sans racine multiple. Soit M le maximum des valeurs absolues des coefficients de f . On sait alors que toute racine ρ de f vérifie |ρ| ≤ 1 + M . Soit alors γ1 le carré centré à l’origine du plan complexe et dont les côtés sont de longueur 1 + M et parallèles aux axes réels et imaginaires. On sait alors que Z 1 f 0 (z) dz = deg f, 2πi γ1 f (z) l’intégrale étant prise en contourant l’origine dans le sens contraire des aiguilles d’une montre. Si on partitionne la région bordée par γ1 en quatre parties égales, onR obtient quatre régions f 0 (z) dz 1+M 1 chacune bordée par un carré de côté 2 . En calculant l’intégrale 2πi sur chacun de f (z) ces quatres carrés, on obtient la répartition des racines entre les quatre régions. En partionnant chacune de ces quatres régions de la même manière à son tour, on obtient la répartition des racines entre les seize régions. En partionnant encore, on trouve au bout d’un certain temps deg f carrés contenant chacun une et une seule racine de f , les autres carrés ne contenant aucune racine de f . Soit ρ une racine de f . En partionnant encore le carré contenant ρ de la même maniére, et en notant ρn le centre du carré obtenu après n itérations, on voit que la suite (ρn ) converge vers ρ et . que max(|Re(ρn − ρ)|, |Im(ρn − ρ)|) ≤ 1+M 2n À nouveau donc, la qualité de l’approximation augment linéairement avec n. Comme remarqué précédement, les intégrales peuvent être calculés par des méthodes d’intégration numérique. Par ailleurs, dans cette discussion, nous avons laissé à côté la possibilité que f possède une racine sur le bord de l’une des carrés ou même proche du bord de l’un des carrés, car cela engendre de l’instablilité numérique dans l’évaluation de l’intégrale. Ce problème va de toute façon se rencontrer lorsque n augmente. Une méthode de pallier ce problème et de remplacer le calcul de l’intégral par l’étude des polynômes réels Re(f ) et Im(f ), vus comme fonction des deux variables réelles x = Re(z) et y = Im(z). Sur chacun des côtés des carrés, qui sont parallèles aux axes réel et imaginaire, l’une de ces variables est en fait constante, et on y est ramené à l’étude d’un polynôme à coefficients réels en une seule variable réelle. Si K est un tel carré dont l’intérieur contient une unique racine simple ρ, on peut montrer, si K est suffisament petit, que la courbe décrite implicitement par l’équation Ref (x, y) = 0 coupe le bord du carré en deux points, qui alternent avec les deux points d’intersection du bord avec la courbe implicite Imf (x, y) = 0. Par contre, si K ne contient pas ρ, une telle configuration des points d’intersection ne peut pas se produire. Ainsi, si on divise K en quatre carrés, une connaissance des configurations des points d’intersection de Ref (x, y) = 0 et de Imf (x, y) = 0 avec les quatre petits carrés permet de déterminer lequel contient ρ. 62 Approximation rapide d’une racine, la méthode de Newton La méthode de Newton d’approcher une racine simple ρ du polynôme f est résumée par la 0) phrase : si x0 est une première approximation de ρ, alors x0 − ff0(x devrait en être une meilleure. (x0 ) Cette idée a sans doute déjà été rencontrée dans le cadre de fonctions dérivables d’une variable réelle. Elle a également un sens pour les fonctions analytiques d’une variable complexe ; dans ce cas f 0 (x0 ) signifie la dérivée en x0 par rapport à la variable complexe. L’utilité de la méthode de Newton peut être résumée par le fait que si la première l’approxi0) mation x0 de ρ est déjà très proche de ρ, alors la nouvelle approximation x1 = x0 − ff0(x vérifie (x0 ) |x1 − ρ| ≤ |x0 − ρ|2 , ce qui signifie que la convergence est quadratique c’est-à-dire qu’à chaque itération, le nombre de chiffre décimaux correcte est à peu près doublé. Cela se voit déjà de manière frappante sur l’exemple où f (x) = x2 − 2. À partir de ρ0 = 1, la suite des approximations (ρn ) est définie pour n ≥ 1 par f (ρn−1 ) 1 2 ρn = ρn−1 − 0 = ρn−1 + . f (ρn−1 ) 2 ρn−1 Alors 3 17 577 665857 886731088897 ρ0 = 1, ρ1 = , ρ2 = , ρ3 = , ρ4 = , ρ5 = , ... 2 12 408 470832 627013566048 √ n−1 On constate que |ρn − 2| ≤ 10−2 lorsque n ∈ {1, 2, 3, 4, 5} et, en fait si n ≥ 1, √ √ √ √ ρ2n−1 − 2 2ρn−1 + 2 (ρn−1 − 2)2 ρn − 2 = = ≤ (ρn−1 − 2)2 2ρn−1 2ρn−1 √ n−1 car 1 ≤ ρn ≤ 2 pour tout n. On en déduit par récurrence sur n que |ρn − 2| ≤ 10−2 pour tout n ≥ 1. Le résultat suivant implique des conditions suffisantes pour que la suite (ρn ) des approximations de ρ définies à partir d’une valeur initiale ρ0 = z converge vers la racine ρ. Théorème. Soit f une fonction analytique sur domaine contenant le disque fermé D de centre ρ et de centre r > 0. Soit m1 et M2 deux réels strictement positifs. On suppose que (a) f (ρ) = 0, (b) |f 0 (z)| ≥ m1 pour tout z ∈ D, (c) |f 00 (z)| ≤ M2 pour tout z ∈ D. Pour tout z ∈ D, on pose w = z − ff0(z) . (z) (i ) On suppose que 3M2 r ≤ m1 . Alors 1 |w − ρ| ≤ |z − ρ|. 2 (ii ) On suppose que A > 0 vérifie 3M2 ≤ 2m1 A. Alors |w − ρ| ≤ A|z − ρ|2 . Démonstration. Quitte à effectuer une translation, on peut supposer que ρ = 0, de sorte que f (0) = 0. Alors f 0 (z)w = f 0 (z)z − f (z) = f 0 (0)z − f (z) + (f 0 (z) − f 0 (0))z. 63 Or, D étant étoilé par rapport à l’origine, la formule de Taylor d’ordre deux implique que |f 0 (0)z − f (z)| ≤ M22 |z|2 pour tout z ∈ D. De même, la formule de Taylor d’ordre d’ordre un appliquée à f 0 implique que |f 0 (z) − f 0 (0)| ≤ M2 |z| pour tout z ∈ D. Par conséquent, m1 |w| ≤ |f 0 (z)w| = | f 0 (0)z − f (z) + (f 0 (z) − f 0 (0))z| ≤ |f 0 (0)z − f (z)| + |(f 0 (z) − f 0 (0))z| 3M2 2 M2 2 |z| + M2 |z|2 = |z| . ≤ 2 2 Afin de montrer le (i ), on remarque que |z|2 ≤ r|z|, d’où m1 |w| ≤ 3M22 r |z| puis |w| ≤ Le (ii ) se démontre d’une manière semblable grâce à l’hypothèse 3M2 ≤ 2m1 A. 3M2 r 2m1 ≤ 12 |z|. Corollaire. On reprend les notations et les hypothèses du théorème. Si ρ0 vérifie |ρ0 − ρ| ≤ m1 n−1 ) , alors la suite (ρn )n≥0 définie à partir de ρ0 par ρn = ρn−1 − ff0(ρ r ≤ 3M converge vers ρ. (ρn−1 ) 2 Démonstration. C’est clair, car le (i ) du théorème implique que |ρn − ρ| ≤ r 2n pour tout n. On utilise le (ii ) du théorème pour justifier que la méthode e Newton converge quadratiquement à partir d’un certain rang. En effet, on peut supposer A > 1, car l’hypothèse 3M2 ≤ 2m1 A n’est pas modifiée si on augmente A. Soit alors n0 un indice tel que |ρn0 − ρ| ≤ A1 . Alors pour tout k ≥ 1, on a k k |ρn0 +k − ρ| ≤ Ak |ρn0 − ρ|2 ≤ Ak−2 → 0. En prenant A = chaque itération. 1 , 10 on voit que le nombre de chiffres décimaux corrects est presque doublé à Voici une autre application de la méthode de Newton. Soit a > 0 un réel. À partir du développement en base 10 de a, on cherche à calculer le développement en base 10 de a1 . On utilise alors la fonction f (x) = x1 − a. La suite de la méthode de Newton vérifie la relation de récurrence ρn = 2ρn−1 − aρ2n−1 . Ainsi, le calcul de a1 est réduit à une suite de multiplications. Cette même méthode peut être appliquée pour calculer l’inverse d’une série formelle. Il y aussi une application à la division euclidienne avec reste des polynômes qui, utilisée en conjonction avec la transformée de Fourier rapide, fournit un algorithme algorithme plus rapide que l’algorithme usuel décrit plus tôt dans ce cours. (Voir l’Exercice 4 de la feuille 7). Notons enfin que si ρ est une racine du polynôme f , l’ensemble des ρ0 ∈ C qui sont les termes initiaux d’une suite de la méthode de Newton qui converge vers ρ peut être très complexe sur le plan géométrique. Ce sont des exemples de fractales. En suivant successivement les quatre étapes de l’étude des racines d’un polynôme (voir la page 55), on obtient une méthode qui, dans la pratique, permet de calculer les valeurs numériques des racines d’un polynôme à coefficients réels ou complexes avec une précision élevée. Mais il est difficile d’en faire un algorithme précis, le problème le plus important se situant au niveau de l’estimation du nombre d’étapes nécessaires pour séparer les racines et initier les méthodes d’approximation. La raison est l’absence d’une minoration satisfaisante de la différence entre deux racines distinctes d’un polynôme. Pour obtenir un algorithme déterministe dont la complexité peut être calculée, d’autres techniques doivent être introduites. Annexe : démonstration de la formule d’encadrement de n!. 64 Il s’agit de démontrer le résultat suivant. Théorème. Pour tout entier n ≥ 1, on a : n n √ n n √ 1/(12n+1) 2πn e ≤ n! ≤ 2πn e1/12n . e e La fonction exponentielle étant une fonction croissante, il suffit de démontrer l’inégalité n+ 1 1 1 1 1 1 log n − n + log 2π + ≤ log n! ≤ n + log n − n + log 2π + . 2 2 12n + 1 2 2 12n Commençons par le lemme suivant : R k+1 Lemme. Pour tout entier k ≥ 1, on pose Ck = k log t dt − 21 log (k + 1) + log k . Si n ≥ 1 est un entier, alors n−1 X 1 log n! = n + log n − n + 1 − Ck . 2 k=1 donc que n ≥ 2. Alors R k+1Démonstration du lemme. L’égalité est claire lorsque n = 1. Supposons 1 log t dt = (k + 1) log (k + 1) − k log k − 1 et donc Ck = (k + 2 ) log (k + 1) − (k + 12 ) log k − 1, k Pn−1 P (n + 12 ) log n − nk=2 log k − (n − 1) et l’égalité en découle aussitôt en utilisant la d’où k=1 Ck = P formule log n! = nk=2 log k. Pour conclure la démonstration du théorème, il suffit donc de démontrer que 1− n−1 X Ck → log √ 2π lorsque n → +∞ k=1 (et, en particulier, que la série P∞ k=1 Ck converge) et que ∞ X 1 1 Ck < < 12n + 1 k=n 12n quelque soit n. Commençons par le deuxième point. Après calcul, on trouve Z k+1 1 + x 1 1 1 1 log (k + 1) + log k = k + log 1 + −1= log −1 Ck = log t dt − 2 2 k 2x 1−x k où x = 1/(2k + 1). Puisque log 1 + x 1−x lorsque |x| < 1, on a Ck = = 2(x + ∞ X p=1 x3 x5 + + ···) 3 5 1 (2p + 1)(2k + 1)2p ce que l’on peut majorer par ∞ X p=1 ∞ X 1 1 1 1 1 1 1 = = = − 3(2k + 1)2p 3(2k + 1)2 p=0 (2k + 1)2p 12k(k + 1) 12 k k + 1 65 et minorer par ∞ X 1 p=1 3p (2k + 1)2p ∞ X 1 1 1 1 1 1 > = = 1 − 2 p 2p 2 3(2k + 1) p=0 3 (2k + 1) 12k + 12k + 2 12 k + 12 k+1+ Par conséquent, 1 12 . ∞ X 1 1 1 1 = < , Ck < 1 12n + 1 12 n + 12 12n k=n comme prévu. P Il s’ensuit que ∞ k=1 Ck converge et, en prenant l’exponentielle, que P∞ √ (∗) lim n!/ (n/e)n n existe et vaut e1− k=1 Ck . n→+∞ √ √ Posons donc K = limn→+∞ n!/ (n/e)n n . Pour conclure il faut montrer que K = 2π. Pour cela, on utilise la formule de Wallis : si Z π/2 cosn θ dθ, Jn = 0 alors Jn > 0 quelque soit n ≥ 0 et la suite (Jn ) est décroissante. En intégrant par parties on trouve, lorsque n ≥ 2, que : Z π/2 Z π/2 n cos θ cosn−1 θ dθ cos θ dθ = Jn = 0 0 Z π/2 h iθ=π/2 n−2 = − (n − 1) cos θ sin θ cos θ + (n − 1) sin2 θ cosn−2 θ dθ θ=0 0 Z π/2 = 0 + (n − 1) (1 − cos2 θ) cosn−2 θ dθ 0 = (n − 1)(Jn−2 − Jn ). En réarrangeant, on en tire que Jn vérifie la relation de récurrence n−1 Jn = Jn−2 , pour tout n ≥ 2. n Par ailleurs, on a J0 = π2 et J1 = 1. En raisonnant par récurrence, on en déduit les formules 1 · 3 · 5 · · · · · (2n − 1) π 2 · 4 · · · · · (2n) , J2n+1 = , 2 · 4 · · · · · (2n) 2 1 · 3 · 5 · · · · · (2n + 1) pour tout n ≥ 0 puis, comme J2n+1 < J2n < J2n−1 , que J2n = (2 · 4 · · · · · (2n))2 π (2 · 4 · · · · · (2n − 2))2 (2n) < < . (3 · 5 · · · · · (2n − 1))2 (2n + 1) 2 (3 · 5 · · · · · (2n − 1))2 Le rapport entre les deux membres extrêmes tend vers 1 ; les membres extrêmes tendent donc vers π2 et obtient la formule de Wallis : (2 · 4 · · · · · (2n − 2))2 (2n) 24n (n!)4 = lim , n→+∞ n→+∞ n((2n)!)2 (3 · 5 · · · · · (2n − 1))2 où on déduit l’égalité à droite en multipliant le numérateur et le dénominateur du membre au milieu par (2 · 4 · · · · · (2n))2 . n n √ D’après (∗), on a n! = K nern , avec rn → 0 lorsque n → +∞. En substituant cette e formule pour n! et la formule correspondante pour (2n)! dans la √ formule de Wallis et en simplifiant, 2 on trouve que π = K /2. Puisque K > 0, on trouve bien K = 2π. π = 2 lim 66