Retour à la page principale de Giac/Xcas.
Algorithmes de calcul formel
B. Parisse
Institut Fourier
UMR 5582 du CNRS
Université de Grenoble I
|
Résumé:
Ce document décrit une partie des algorithmes de calcul formel
utilisés pour le logiciel de calcul formel Giac/Xcas, cf.
http://www-fourier.ujf-grenoble.fr/~parisse/giac_fr.html
Table des matières
1 Calculer sur ordinateur
1.1 Problèmes spécifiques au calcul formel
1.1.1 Calcul exact et approché, types, évaluation.
Dans les langages de programmation traditionnel (C, Pascal,...), il existe
déjà des types permettant une représentation
exacte des données (type entier) ou une représentation approchée
(type flottant). Mais ces types de donnée de base
occupent une taille fixe en mémoire, le type entier est donc
limité à un intervalle d'entiers (par exemple [0,232−1] pour un entier
non signé sur une machine utilisant un processeur 32 bits) alors que le
type flottant peut représenter des nombres réels, mais est
limité à une précision en nombre de digits de la mantisse et de l'exposant
(par exemple 12 chiffres significatifs et un
exposant compris entre -499 et 499).
En calcul formel, on souhaite pouvoir calculer rigoureusement d'une part,
et avec des paramètres dont la valeur n'est
pas connue d'autre part ; il faut donc s'affranchir de ces limites :
-
pour les entiers relatifs, on utilise des entiers de
précision arbitraire
dont la taille en mémoire est dynamique (déterminée pendant l'exécution et non
à la compilation),
- pour les nombres complexes, on utilise un couple de nombres réels,
- pour les rationnels, on utilise un couple d'entiers relatifs,
- pour les irrationnels algébriques (par exemple √2),
on utilise un polynôme irréductible dont ils sont racines,
- pour les paramètres (x,y,z,t...), on utilise un type
structuré contenant un champ de type chaine de caractères pour
représenter le nom du paramètre et
un champ pour attribuer une valeur à (ou une hypothèse sur) ce paramètre,
- pour les nombres transcendants (par exemple π), on est obligé
d'introduire un paramètre auquel on attribue une valeur numérique,
qui ne sera utilisée qu'au moment où on veut une
approximation numérique d'une expression contenant ce nombre transcendant,
on parle de constante,
- lorsqu'on a besoin d'une approximation numérique d'un nombre,
on peut utiliser des conversions de ces types en un type flottant. On peut
aussi pour lutter contre les erreurs
d'arrondi utiliser des nombres flottants étendus dont la précision est
dynamique ou même des intervalles de flottants étendus,
- il faut aussi
un nouveau type, appelé expression ou symbolique, permettant d'appliquer
une fonction qu'on ne peut évaluer directement sur les objets précédents,
par exemple sin(x). Il
doit s'agir d'une opération de clôture, au sens où appliquer une fonction à
un objet symbolique ne nécessite pas la création d'un nouveau type
(en général on renvoie un objet symbolique).
Enfin, il faut pouvoir évaluer un objet (en particulier symbolique) :
par exemple évaluer sin(x) lorsqu'on assigne une valeur à x.
Dans cet exemple, on voit qu'il faut d'abord remplacer x par
sa valeur avant de lui appliquer la fonction sinus. C'est le mécanisme
général de l'évaluation, mais il y a quelques exceptions où
on souhaite empêcher l'évaluation d'un ou plusieurs arguments
d'une fonction avant l'évaluation de la fonction. Par exemple si on
veut calculer la valeur numérique d'une intégrale par des méthodes
de quadrature, on ne souhaitera pas rechercher une primitive de la
fonction à intégrer. Dans le jargon, on parle alors de “quoter” un argument
(l'origine du terme vient probablement de la notation '
du langage
Lisp). Certaines fonctions doivent toujours quoter leurs arguments
(par exemple la fonction qui permet de purger le contenu d'un paramètre),
on parle parfois d'autoquotation.
1.1.2 Forme normale et reconnaissance du 0.
Une fois défini ces types de base représentant les nombres d'un système de
calcul formel, il faut pouvoir comparer ces
nombres, en particulier décider si deux représentations distinctes
correspondent au même nombre ou, ce qui revient au
même, par soustraction décider quand un nombre est nul.
Par exemple 4/2 et 2 représentent le même nombre.
Lorsqu'on dispose d'un algorithme permettant de représenter un nombre
d'une manière unique, on parle de forme normale.
C'est par exemple le cas pour les nombres rationnels, la forme normale
usuelle est la fraction irréductible de
dénominateur positif. C'est aussi le cas pour les fractions rationnelles
de polynômes à coefficients entiers représentées par une fraction
irréductible, avec au dénominateur un coefficient de plus haut degré
positif.
Malheureusement, il n'est pas toujours possible de trouver une forme normale
pour diverses raisons théoriques ou pratiques :
-
on ne connaît pas toujours le statut de certaines constantes
(par exemple la constante d'Euler),
- il n'existe pas d'algorithmes permettant de déterminer
s'il existe des relations algébriques entre constantes,
- il n'existe pas forcément une seule forme plus simple, par exemple :
Ce cas se présente fréquemment avec les extensions algébriques.
- en pratique il peut être trop coûteux d'utiliser une forme
normale, par exemple le polynôme x1000−1/x−1 possède 1000 monômes
En résumé, au mieux on a une forme normale, au pire on risque de ne pas
reconnaître un zéro, entre les deux on peut ne
pas avoir de forme normale mais être capable de reconnaître à coup sûr
une expression nulle (par contre, si le système
de calcul formel détermine qu'une expression est nulle, alors elle l'est).
Il n'existe pas d'algorithme solution
pour le problème de la reconnaissance du zéro pour une classe
d'expressions "assez générale". Heureusement,
dans la plupart des cas pratiques on sait résoudre ce problème, en
se ramenant le plus souvent au cas des polynômes et fractions rationnelles.
Par exemple, pour simplifier une expression trigonométrique,
on remplace les fonctions trigonométriques sin(x), cos(x), tan(x)
par leur expression en fonction de t=tan(x/2), on est ainsi ramené
à une fraction rationnelle en t que l'on écrit sous forme normale.
Les polynômes ont un rôle central dans tout système de calcul formel
puisque sauf dans les cas les plus simples (fractions d'entiers par exemple),
la simplification d'expressions
fait appel à un moment ou à un autre à des calculs
de PGCD de polynômes. Le PGCD de polynômes est un algorithme
très sollicité auquel nous consacrerons le prochain article. En effet,
l'application brutale de l'algorithme d'Euclide pose des problèmes
d'efficacité ce qui a obligé à inventer des méthodes plus efficaces.
Anticipons rapidement sur un exemple qui montre l'un des problèmes
majeurs des algorithmes de calcul formel, l'explosion combinatoire
(ici des coefficients des restes successifs).
Voici donc les restes successifs lorsqu'on applique l'algorithme
d'Euclide pour calculer le PGCD de P(x)=(x+1)7−(x−1)6 avec
sa dérivée (les deux polynômes sont premiers entre eux) :
7 (x+1)6−6 (x−1)5 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
( |
469345063045455 |
|
129411872 |
|
x+ |
−47641670106615 |
|
129411872 |
|
) |
|
|
|
5497465490623352995840 |
|
209648836272383412129 |
|
Le lecteur voulant tester d'autres exemples pourra utiliser le programme
giac
(cf. l'appendice) suivant :
pgcd(a):={
local b,r,res;
b:=diff(a,x);
res:=[];
for (;b!=0;){
res:=append(res,b);
r:=rem(a,b);
a:=b;
b:=r;
}
return(res);
}
1.1.3 Valeur générique des variables et hypothèses
Lorsqu'on utilise un symbole sans lui affecter de valeurs en mathématiques
on s'attend à une discussion en fonction du
paramètre représenté par ce symbole. Ce qui nécessiterait de créer un
arborescence de calculs (on retrouve ici les problèmes
d'explosion combinatoire évoqués dans la section précédente).
La plupart des systèmes de calcul formel contournent la difficulté en
supposant que le paramètre possède une valeur
générique (par exemple la solution de (t2−1)x=t−1 sera x=1/(t+1)) ou
choisissent une branche pour les fonctions
possédant un point de branchement (par exemple pour résoudre x2=t
en fonction de t). Certains systèmes demandent de
manière interactive à l'utilisateur si la variable est par exemple positive
ou différente de 1 mais cela s'oppose à un
traitement automatique.
On peut aussi anticiper ce type de décision en faisant des hypothèses
sur une paramètre, la plupart des systèmes de calcul formel actuel
proposent cette possibilité.
1.2 Structures de données
On a vu plus haut qu'on souhaitait manipuler des entiers de taille non
fixe, des réels de précision fixe ou non, des
fractions, des nombres complexes, des extensions algébriques, des
paramètres, des expressions symboliques. Il faut un type générique
recouvrant ces divers types de scalaire.
On peut utiliser un type structuré comportant un champ
type et la donnée ou un pointeur sur la donnée (avec dans ce cas un
pointeur sur un compteur de références de la donnée
pour pouvoir la détruire dès qu'elle n'est plus référencée1).
En programmation orientée objet, on utiliserait plutôt un
type abstrait dont dérivent ces différents scalaires.
Il faut aussi un type pour les vecteurs, les matrices et les
listes. On peut se poser la question de savoir s'il faut inclure
ces types dans le type générique ; en général la
réponse est affirmative, une des raisons étant que les
interpréteurs qui permettront de lire des données dans un
fichier texte sont en général basé sur le couple de logiciels
lex(flex)/yacc(bison)
qui ne peut compiler qu'à destination d'un
seul type. Ceci permet également d'unifier en un seul type symbolique
les fonctions ayant un ou plusieurs arguments en
voyant plusieurs arguments comme un vecteur d'arguments.
Les fonctions sont le plus souvent elle-même incluses dans le
type générique permettant ainsi à l'utilisateur de saisir des
commandes ou programmes fonctionnels (on peut
utiliser une fonction comme argument d'une commande).
Pour des raisons d'efficacité, les systèmes de calcul formel
utilisent souvent des représentations particulières pour les polynômes
dont on a dit qu'ils jouaient un rôle central.
Pour les polynômes à une variable,
on peut utiliser la liste des coefficients du polynôme, on parle
alors de représentation dense. On peut aussi décider de ne stocker
que les coefficients non nuls, on parle alors de représentation creuse
(on stocke alors un couple formé par le coefficient et le degré
du monôme correspondant). Pour les polynômes à plusieurs variables,
on peut les considérer comme des polynômes à une variable à
coefficients polynomiaux, on parle alors de représentation récursive.
On peut aussi décider de ne pas briser la symétrie entre les
variables (pas de variable principale), on parle alors de représentation
distribuée, le plus souvent les représentation distribuées
sont creuses car les représentations
denses nécessitent très vite beaucoup de coefficients. Les méthodes
de représentation creuses sont parfois aussi utilisées pour les
matrices ayant beaucoup de coefficients nuls.
Voyons maintenant plus précisément sur quelques exemples de logiciels
de calcul formel répandus quelles structures de données sont
utilisées. Plusieurs éléments entrent en compte dans les choix faits :
-
le(s) profil(s) d'utilisation (enseignement, ingéniérie,
calcul intensif, recherche)
- les ressources disponibles (mémoire, puissance du processeur...)
- la facilité d'implémentation (choix du langage, outils
disponibles en particulier débuggueurs, ...)
- l'histoire du système (un système conçu avec les outils
disponibles aujourd'hui est forcément différent d'un système
conçu il y a 20 ans)
Nous allons d'abord parler des calculatrices formelles HP
et TI (le lecteur pourra facilement les tester grâce aux émulateurs gratuits
pour PC). Ce sont des systèmes plutôt destinés à l'enseignement, soumis
à de fortes contraintes en termes de taille mémoire, et destinés
à traiter des petits problèmes.
Puis nous présenterons des systèmes pour ordinateur où les ressources
(par exemple mémoire) sont moins limitées ce qui permet
d'utiliser des langages de programmation de plus haut niveau.
1.2.1 Calculatrices formelles HP
Les langages utilisés pour programmer ces calculateurs sont l'assembleur
et le RPL (Reverse Polish Lisp) adapté à l'écriture de code
en mémoire morte très compact.
Le type générique est implémenté avec un champ type appelé prologue (qui est
en fait un pointeur sur la fonction chargée d'évaluer ce type d'objet)
suivi de la donnée elle-même (et non d'un pointeur sur la donnée, on
économise ainsi la place mémoire du compteur de référence).
Le type entier en précision arbitraire est codé par le nombre de digits
(sur 5 quartets2) suivi du signe sur un
quartet et de la représentation BCD (en base 10) de la valeur absolue de
l'entier. Le choix de la représentation BCD a été fait pour optimiser
les temps de conversion en chaîne de caractères pour l'affichage. La mémoire
vive disponible est de 256K, c'est elle qui limite la taille des entiers
et non le champ longueur de l'entier. Il n'y a pas de type spécifique
pour les rationnels (on utilise un objet
symbolique normal).
Les fonctions internes des HP49 et HP40 utilisent
le type programme pour représenter les entiers de Gauß (complexes
dont la partie réelle et imaginaire est entière).
Les nombres algébriques ne sont pas implémentés, sauf les racines carrées
(représentée de manière interne par le type programme).
Il y a un type spécifique prévu pour les flottants en précision arbitraire,
mais l'implémentation des opérations sur ces types
n'a pas été intégrée en ROM à ce jour.
Les types listes, programmes et objet symbolique sont composés du prologue
(champ type) suivi par la succession d'objets situés en
mémoire vive ou de pointeurs sur des objets situés en mémoire en lecture
seule (ROM) et se terminent par un pointeur sur une
adresse fixe (appelée SEMI
). Ces types sont eux-mêmes des
objets et peuvent donc être utilisés de manière
récursive. La longueur des types listes, programmes, symboliques
n'est stockée nulle part, c'est le délimiteur final
qui permet de la connaître, ce qui est parfois source d'inefficacité.
On utilise de manière interne les listes pour représenter les
polynômes denses (avec
représentation récursive pour les polynômes à plusieurs variables).
Les calculatrices HP4xG utilisent une pile3, c'est-à-dire une liste
de taille non fixée d'objets. On place les objets sur la pile,
l'exécution d'une fonction prend ces arguments sur
la pile et renvoie un ou plusieurs résultats sur la pile (ce qui est
une souplesse du RPN comparé aux langages où on ne peut renvoyer
qu'une valeur de retour). Il faut donc
donner les arguments avant d'appeler la fonction correspondante. Par
exemple pour calculer a+b on tapera a b +
. C'est
la syntaxe dite polonaise inversée (RPN). Un avantage de cette syntaxe
est que le codage d'un objet symbolique par cette syntaxe est évidente,
il suffit de stocker la liste précédente {a b +}
.
Les objets symboliques sont donc représenté par une suite d'objets écrit
en syntaxe polonaise inversée. L'évaluation d'un objet symbolique se fait
dans l'ordre polonaise inversé : les arguments sont évalués
puis les fonctions leur sont appliqués. Pour des raisons d'efficacité,
on représente souvent les objets composites (listes, symboliques) par
leurs composants placés sur la pile (appelé meta-objets).
Une rigidité de la syntaxe polonaise est
que les fonctions ont toujours un nombre fixe d'arguments4, par
exemple l'addition a toujours 2 arguments, ainsi
a+b+c est obtenu par (a+b)+c ou par a+(b+c)
c'est-à-dire respectivement a b + c +
ou a b c + +
ce qui
brise parfois artificiellement la symétrie de certaines opérations. En
polonaise inversée, le système doit de plus jongler avec l'autoquote puisque
les arguments sont évalués avant l'opérateur qui éventuellement demanderait
à ne pas évaluer ses arguments. À noter l'existence d'une commande
QUOTE
permettant à l'utilisateur de quoter une sous-expression.
Les hypothèses sur des variables réelles sont regroupées dans une liste
stockée dans la variable globale REALASSUME
, on peut supposer
qu'une variable est dans un intervalle. Il n'y a pas à ce jour
de possibilité de supposer qu'une variable est entière (ni à fortiori
qu'une variable à une valeur modulo un entier fixé), bien qu'il ait été
décidé de réserver la variable globale INTEGERASSUME
à cet effet.
Il n'y a pas de possibilité de faire des hypothèses ayant une portée
locale.
1.2.2 Calculatrices formelles TI
Le langage utilisé pour programmer ces calculatrices est le langage C
(on peut aussi bien sur écrire du code en assembleur).
On retrouve ici les différents types de données regroupé en un
type générique qui est un tableau d'octets (aussi appelé quantum).
Le champ type
est appelé tag dans la documentation TI. Contrairement à ce qui
précède, ce champ type est placé en mémoire à la fin de l'objet,
ce qui est possible car la longueur d'un objet est toujours indiquée
au début de l'objet. Ceci est fait afin de faciliter l'évaluation (cf.
infra).
Les entiers en précision arbitraire sont codés par deux tags possibles (pour
différencier le signe), un octet pour la longueur, puis la valeur
absolue de l'entier (en base 256). Ils sont donc limités par le
champ longueur à 255 octets, le plus grand entier représentable est
5 (256255−1).
Il existe un tag spécifique pour les rationnels, pour les constantes
réelles et entières qui apparaissent par exemple en résolvant une équation.
Il existe des tags utilisés de manière interne, par exemple
pour les nombres complexes.
Il n'y a pas de tag prévu pour les flottants en précision arbitraire.
ni pour les nombres algébriques (racines carrées par
exemple).
Les listes sont codées par la succession de leurs éléments. En principe
elles ne peuvent pas contenir des listes (sauf pour représenter
une matrice).
Quelques fonctions utilisent les listes pour représenter des polynômes
denses à une variable, mais probablement pas pour représenter de manière
récursive des polynômes à plusieurs variables (puisque le type liste
n'est en principe pas récursif).
Comme sur les HP, les TI utilisent une pile (non visible par
l'utilisateur) appelée expression stack
afin de traduire un expression mathématique sous forme d'un texte
en un objet symbolique codé exactement comme ci-dessus en syntaxe
polonaise. Toutefois, la présence du champ longueur
permet d'évaluer un objet symbolique sans perdre en efficacité
en partant de l'opérateur
final et en redescendant ensuite sur ces arguments, c'est la stratégie
adoptée par ces calculatrices. C'est pour cela que le tag d'identification
se trouve à la fin de l'objet. L'utilisation de cette méthode
facilite grandement l'autoquotation (on peut toutefois regretter
que le système n'ait pas prévu d'instruction permettant à l'utilisateur
d'empêcher l'évaluation d'une sous-expression).
On ne peut pas faire d'hypothèse globale sur un paramètre par
contre on peut faire des hypothèses de type appartenance à un intervalle
ayant une portée locale.
1.2.3 Maple, MuPAD, Mathematica, ...
Ces systèmes ont un noyau fermé, au sens où l'utilisateur n'a pas
accès du tout, ou en tout cas pas facilement, aux structures de données
de base. Je ne dispose donc pas d'information sur les structures de données
utilisées par le noyau (pour MuPAD, on pourrait sans doute en savoir
plus en achetant de la documentation sur la programmation des
modules dynamiques).
L'interaction système-utilisateur se fait quasiment toujours en utilisant le
langage de programmation propre au système, langage interprété
par le noyau du système (ce qui ralentit l'exécution). Ces langages
utilisateurs sont essentiellement
non typés : on travaille avec des variables du type générique sans pouvoir
accéder aux types sous-jacents. On ne bénéficie donc pas des
vérifications faites lors de la compilation avec un langage typé,
de plus ces systèmes ne sont pas toujours fourni avec de bon outils de
mise au point. Enfin ces langages ne sont pas standardisés d'un
système à l'autre et il est en général impossible
d'utiliser ces systèmes comme des librairies depuis un langage
de programmation traditionnel. Leur intérêt principal réside donc
dans une utilisation interactive en profitant de la librairie de
fonctions accessibles.
Il s'agit du système de calcul formel que j'implémente actuellement sous
forme d'une bibliothèque C++ (ce qui
permettra aux programmes tiers d'utiliser beaucoup plus facilement du
calcul formel qu'avec les systèmes précédents). L'objectif est
d'avoir un système facile à programmer directement en C++, proche
du langage utilisateur, lui-même compatible avec Maple ou MuPAD,
tout cela sans trop perdre en performances comparativement aux
librairies spécialisées écrites en C/C++. Ce qui explique un choix
de type générique (gen
) non orienté objet, avec un champ type
et soit une donnée immédiate pour les nombres flottants par exemple,
soit un pointeur vers un objet du type correspondant au champ type pour
les données de taille non fixe (on pourrait donc se
contenter du langage C, mais le langage C++ permet de redéfinir
les opérateurs sur des types utilisateurs ce qui
améliore considérablement la lisibilité du code source).
Les données dynamiques ne sont pas dupliquées, Giac
utilise un pointeur sur un compteur de référence pour détruire
ces données lorsqu'elles ne sont plus référencées.
Les entiers en précision arbitraire sont hérités de la bibliothque
GMP (écrite en C) du projet GNU. Les flottants en précision arbitraire
utiliseront aussi GMP (plus précisément MPFR).
Il y a un type fraction, structure C composé d'un champ numérateur
et d'un champ dénominateur, et un type nombre complexe.
Les listes, vecteurs, matrices utilisent le type paramétré vector<>
de la librairie standard C++ (Standard Template Library).
Les objets symboliques sont des structures composés d'un champ sommet
qui est une fonction prenant un argument de type gen
et renvoyant un résultat
de type gen
, et d'un champ feuille qui est de type gen
.
Lorsqu'une fonction possède plusieurs arguments, ils sont rassemblés
en une liste formant le champ feuille de l'objet symbolique.
Les programmes sont aussi des objets symboliques, dont le champ
sommet est la fonction évaluation d'un programme.
Les listes sont aussi utilisées pour représenter vecteurs, matrices
et polynômes en une variable en représentation dense. Les polynômes
en représentation creuse ou en plusieurs indéterminées sont également
disponibles.
L'évaluation d'un objet symbolique se fait en regardant d'abord si
la fonction au sommet doit évaluer ou non ses arguments (autoquote),
on évalue les arguments si nécessaire puis on applique la fonction.
Une hypthèse sur un paramètre est simplement une valeur spéciale
affectée au paramètre, valeur ignorée par la routine d'évaluation.
1.3 Algorithmes et complexité.
On va présenter dans la suite quelques algorithmes que l'on peut
considérer comme classiques dans le domaine du calcul formel. Avant
d'implémenter ce type d'algorithmes, on a besoin des algorithmes de base
en arithmétique. Le lecteur trouvera en appendice une brève présentation
de certains de ces algorithmes, mes références en la matière sont le livre
de Henri Cohen, et les livres de Donald Knuth (cf. appendice).
La plupart des problèmes posés en calcul formel nécessitent des
calculs dont la taille croit de manière exponentielle voire
doublement exponentielle en fonction de la taille des données et
ce même si le résultat est lui aussi de taille petite. Un
exemple est la réduction des systèmes de plusieurs équations polynomiales
(bases de Groebner).
Dans certains cas, l'application de théories mathématiques
parfois sophistiquées permet de réduire la complexité (par exemple,
M. Van Hoeij a découvert récemment qu'un algorithme très utilisé en théorie des
nombres, l'algorithme LLL, permettait d'améliorer la complexité d'une des
étapes de la factorisation des polynomes à coefficients entiers sur les
entiers). Heureusement, dans de nombreux cas, on peut réduire la
complexité (donc le temps de calcul) par des adaptations au
problème d'une même idée à condition de faire des
hypothèses sur les données (autrement dit en abandonnant la volonté
d'implémenter un algorithme générique).
Par exemple lorsqu'on travaille
avec des entiers (ou des polynômes à coefficients entiers, ou
des matrices à coefficients entiers...) on utilise souvent des algorithmes
modulaires et p-adiques. Comme le calcul exact nécessite
presque toujours de calculer avec des entiers, ces méthodes
ont un rôle central en calcul formel, nous les présentons donc
maintenant brièvement. Dans les prochains articles, nous utiliserons
ce type de méthode, par exemple pour le calcul de PGCD ou la factorisation
de polynômes à coefficients entiers.
Les méthodes modulaires consistent à réduire un problème dans
Z à son équivalent dans Z/nZ pour une ou
plusieurs valeurs de n, nombre premier. Le calcul dans Z/nZ
a l'avantage de se faire avec des entiers dont la taille est bornée.
Ensuite à l'aide d'estimations
à priori sur la taille des solutions
éventuelles du problème initial, on reconstruit la solution au problème
initial avec le théorème des restes chinois.
Par exemple, on peut calculer un déterminant d'une matrice
à coefficients entiers en cherchant ce déterminant dans Z/nZ
pour plusieurs premiers n, dont le produit est plus grand qu'une
estimation à priori de la taille du déterminant
(donnée par exemple par l'inégalité d'Hadamard, cf. Cohen, p. 50).
Les méthodes p-adiques commencent de manière identique par un
calcul dans Z/nZ, on augmente ensuite la
précision de la solution en la liftantde Z/nk Z vers
Z/nk+1Z ou vers Z/n2kZ (lift
linéaire ou lift quadratique), on s'arrête lorsque k est assez grand
(à l'aide d'estimations à priori) et on
reconstruit alors la solution initiale. L'étape de liftest en
général un lemme de Hensel dont on verra quelques exemples dans les
prochains articles. L'algorithme
commun au lemme de Hensel et au théorème des restes chinois est
l'identité de Bézout, que l'on retrouve
d'ailleurs un peu partout (par exemple pour le calcul de primitives).
Illustrons cette méthode sur un exemple simple, la recherche de
racines rationnelles d'un polynôme P(X)=ad Xd + ⋯ + a0
à coefficients entiers ou polynomiaux, avec ad et a0 non nuls.
L'algorithme générique (assez connu) consiste
à chercher les diviseurs de a0 et de ad et à tester toutes
les fractions de ces diviseurs, on montre en effet
aisément que si X=p/q fraction irréductible est racine de P
alors q divise ad et p divise a0. Cet
algorithme est très inefficace si ad ou a0 est un grand entier
(car on ne sait pas forcément le factoriser) ou
s'il a beaucoup de facteurs premiers (la liste des diviseurs à tester
est alors très grande).
Lorsque les coefficients de P sont entiers, la recherche précédente
revient à trouver un facteur à
coefficients entiers qX−p de P, on peut donc réduire le problème
modulo un entier premier n qui ne divise pas ad : si un tel facteur
existe dans Z alors ce facteur (réduit modulo n) est un facteur
de P dans Z/nZ
donc P admet une racine dans Z/nZ (puisque q est inversible
modulo n car on a choisi n premier ne divisant pas ad). On
évalue maintenant P en les n éléments de Z/nZ. S'il n'y a pas
de 0, alors P n'a pas de racine rationnelle. S'il y a des racines, on va
les lifter de Z/nkZ dans Z/n2kZ.
On suppose donc que pour k≥ 1, il existe un entier pk tel que
P(pk)=0 (mod nk )
Il s'agit de trouver un entier x tel que pk+1=pk+nk x
vérifie
P(pk+1)=0 (mod n2k )
On applique la formule de Taylor à l'ordre 1 pour P en pk, le
reste est nul modulo n2k, donc :
P(pk)+ nk x P'(pk)=0 (mod n2k )
soit finalement :
x=− |
|
( P'(pk) (mod nk )) −1 |
On reconnaît au passage la méthode de Newton, pour qu'elle fonctionne
il suffit que P'(pk) ≠ 0 (mod n ) ce qui
permet de l'inverser modulo nk (et c'est ici qu'intervient
l'identité de Bézout). En pratique quand on factorise
un polynôme, on commence par retirer les multiplicités,
on peut donc supposer que P est sans facteur multiple dans
Z. Ceci n'entraîne pas forcément qu'il le reste dans Z/nZ
ce qui crée une contrainte supplémentaire sur le choix
de n, à savoir que P et P' restent premier entre eux dans Z/nZ
(il existe forcément de tels n, par exemple
n premier plus grand que le plus grand entier intervenant dans le calcul
du PGCD de P et P' dans Z).
Reste donc à revenir dans Z à partir d'une racine pk dans Z/(nk Z)
(où on peut choisir k).
On va maintenant utiliser la représentation modulaire symétrique :
on prend comme représentant modulaire d'un entier z dans Z/nkZ
l'unique entier congru à z modulo n qui est strictement compris entre
−nk/2 et nk/2 (si n est pair, la deuxième inégalité
est choisie large).
Si qX−p est un facteur de P, alors adX−ad/qp est encore
un facteur de P (le quotient de P par adX−ad/qp
est à coefficients rationnels mais le facteur est à coefficients entiers).
Si on a choisi k tel que nk>2|ad a0|, l'écriture en représentation
modulaire symétrique de adX−ad/qp est inchangée,
en effet on a des estimations à priori sur les entiers p et q :
|q|≤ |ad| et |p| ≤ |a0| puisque q
divise ad et p divise a0.
Comme adX−ad/qp est égal à ad(X−pk) dans Z/(nk Z),
il nous suffit d'écrire en représentation modulaire
symétrique ad(X−pk)=ad X−p'.
Pour conclure, on sait que ad X−p' est un multiple entier de qX−p.
On divise donc le facteur ad X−p' par le pgcd de ad et p' et on
teste la divisibilité de P par ce facteur réduit.
Exemple
Considérons le polynôme 2 X3−X2−X−3 qui est sans facteur carré.
On ne peut pas choisir n=2 car on réduirait le degré, pour n=3,
on a P'=X−1 qui est facteur de P, pour n=5, P'=6X2−2X−1,
on vérifie que P et P' sont premiers entre eux (par exemple
avec GCDMOD
sur une HP49 où on aura fixé la variable MODULO
à 5).
On teste ensuite les entiers de -2 à 2 sur P. Seul -1 est racine
modulo 5 (P(−1)=−5), on va maintenant lifter p1=−1.
L'estimation à priori est 2|ad||a0|=12 donc k=2 (52=25>12),
une itération suffira. On a P'(−1)=7, l'inverse de P'(−1) (mod 5 )
est -2 donc:
x= − |
|
(−2) = −(−1) (−2)=−2 |
et p2=−1+5×(−2)=−11 est racine de P dans Z/25Z.
On calcule ensuite ad(X−pk)=2(X+11)=2X+22=2X−3 en représentation
symétrique, le PGCD de 2 et -3 est 1 donc on teste le facteur
2X−3, ici il divise P donc P admet un unique facteur entier
de degré 1 qui est 2X−3.
2 Quelques algorithmes d'arithmétique de base.
-
Les algorithmes de multiplication et division dit rapides
des entiers et polynômes (Karatsuba, FFT, ...). Cf. par exemple Knuth.
ou pour les entiers la documentation de GMP.
- Au lieu de la division euclidienne, on utilise très souvent la
pseudo-division pour les polynômes : étant donné deux polynômes A
et B de degrés a et b à coefficients dans un anneau contenu dans un corps
(par exemple Z), on multiplie A par une puissance du coefficient
dominant Bb de B, plus précisément par Bba−b+1, ce qui permet
d'effectuer la division par B sans que
les coefficients sortent de l'anneau.
Bba−b+1 A= B Q + R
On utilise cette méthode lorsqu'on peut multiplier les polynômes par
des constantes sans changer le problème (par exemple pour l'algorithme
d'Euclide).
- L'algorithme d'Euclide est un algorithme génériquede calcul
de PGCD. Il n'est en général pas utilisé tel quel. Pour les entiers
on utilise une variation adaptée à la
représentation binaire des entiers (cf. Cohen ou le manuel de GMP version 4
pour plus de détails). Nous décrirons des
algorithmes de PGCD plus efficaces pour les polynômes dans le prochain article.
- l'identité de Bézout, aussi appelée PGCD étendu. Étant donné
deux entiers ou deux polynômes a et b on calcule u, v et
d tels que au+bv=d. On écrit la matrice :
où on remarque que pour chaque ligne le coefficient de la 1ère colonne
est égal à a multiplié par le coefficient de la
2ème colonne additionné à b multiplié par le coefficient de la
3ème colonne. Ce qui reste vrai si on effectue des
combinaisons linéaires de lignes (type réduction de Gauß).
Comme on travaille dans les entiers ou les polynômes, on remplace la
réduction de Gauß des matrices à coefficients réels par une combinaison
linéaire utilisant le quotient euclidien q
de a par b. On obtient alors le reste r en 1ère colonne :
L3=L1−qL2 |
⎛
⎜
⎜
⎝ |
|
|
⎞
⎟
⎟
⎠ |
et on recommence jusqu'à obtenir 0 en 1ère colonne.
L'avant-dernière ligne obtenue est l'identité de Bézout (la dernière
ligne donne le PPCM de a et b). Si l'on veut l'inverse de a modulo
b on remarque qu'il n'est pas utile de calculer les coefficients
appartenant à la 3ème colonne. Enfin, les lignes intermédiaires
peuvent servir à reconstruire une fraction d'entier représentée
par un entier de Z/nZ lorsque le numérateur et le dénominateur
sont de valeur absolue inférieure à √n/2.
- Le théorème des restes chinois. Si on connaît x=a (mod m )
et x= b (mod n ) avec m et n premiers entre eux,
on détermine c tel que
x=c (mod m× n ) (c=a+mu=b+nv et on applique
Bézout pour trouver u et v, on en déduit c).
- Les tests de pseudo-primalité. Il est essentiel d'avoir une
méthode rapide permettant de générer des nombres premiers pour appliquer
des méthodes modulaires et p-adiques. On utilise par exemple le
test de Miller-Rabin, qui prolonge le petit théorème de Fermat
(si p est premier, alors ap=a (mod p )).
2.1 Pour en savoir plus.
Sur des aspects plus théoriques :
-
Knuth: TAOCP (The Art of Computer Programming), volumes 1 et suivants
- Henri Cohen: A Course in Computational Algebraic Number Theory
- Davenport, Siret, Tournier: Calcul formel: Systèmes et algorithmes
de manipulations algébriques
Sur des aspects plus pratiques, quelques références en ligne,
la plupart sont accessibles gratuitement :
-
le code source de Giac disponible à l'URL :
http://www-fourier.ujf-grenoble.fr/~parisse/giac.html
- le code source de GiNaC, cf. :
http://www.ginac.de
- le site
http://www.hpcalc.org
pour les calculatrices HP,
on y trouve tout, de la documentation, des émulateurs de
calculatrices HP, des outils de développement pour Windows
et Unix/Linux, ... Pour ce qui concerne cet article, je conseille de lire
http://www.hpcalc.org/hp48/docs/programming/rplman.zip
- le site
http://www.ticalc.org
, on y trouve le portage
tigcc du compilateur C de GNU, des émulateurs, etc. Des informations de
cet article ont leur source dans le guide du
développeur TI89/92
http://education.ti.com/
- la librairie du système
MuPAD
(archivée dans le fichier
share/lib.tar
des distributions Unix),
cf. www.sciface.com
pour obtenir une licence
d'utilisation.
- en Maple, il est possible de
décompiler une instruction
Maple
avec la commande
eval(instruction);
après avoir tapé
interface(verboseproc=2);
- le source du plus ancien système de calcul formel
maxima
(devenu logiciel libre) pour les personnes familières du langage Lisp
http://sourceforge.net/projects/maxima
de même pour le système Axiom
- le source de librairies plus spécialisées (GMP, GP-PARI, Singular,
NTL, Zen, ALP, GAP, Cocoa, ...), rechercher ces moms sur google.
3 Exercices sur types, calcul exact et approché, algorithmes de bases
Pour lancer xcas sous Unix, ouvrir un fenêtre terminal et
taper la commande
xcas &
Lors de la première exécution, vous devrez choisir entre
différents types de syntaxe (compatible C, maple ou TI89). Vous
pouvez changer ce choix à tout moment en utilisant le menu
Configuration->mode (syntaxe).
Pour lancer maple, taper xmaple à la place de xcas.
L'aide en ligne est accessible en tapant ?nom_de_commande
sur
les 2 logiciels. Elle est en francais pour Xcas, en anglais pour
maple. Avec Xcas, vous pouvez aussi taper le début d'un
nom de commande puis la touche de tabulation (à gauche du A sur
un clavier francais), sélectionner la commande dans la boite
de dialogues puis cliquer sur Details pour avoir une aide plus
complète dans votre navigateur. Pour plus de détails sur
l'interface de Xcas, consultez le manuel (Aide->Interface).
Si vous n'avez jamais utilisé de logiciel de calcul formel,
vous pouvez commencer par lire le tutoriel (menu Aide->Debuter en
calcul formel->tutoriel) et faire certains des exercices
proposés (des corrigés sous forme de sessions Xcas sont
dans Aide->Debuter en calcul formel->solutions)
Il peut être interessant de tester ces exercices
en parallèle avec Xcas et maple, ou aussi avec des calculatrices
formelles....
-
Utiliser la commande type ou whattype ou équivalent
pour déterminer la représentation
utilisée par le logiciel pour représenter
une fraction, un nombre complexe, un flottant en précision machine,
un flottant avec 100 décimales, la variable x, l'expression sin(x)+2,
la fonction x->sin(x), une liste, une séquence, un vecteur,
une matrice. Essayez d'accéder aux parties de
l'objet pour les objets composites (en utilisant op par exemple).
- Comparer le type de l'objet
t
si on effectue
la commande t[2]:=0;
après avoir purgé t
ou après avoir affecté t:=[1,2,3]
?
- Comparer l'effet de l'affectation dans une liste et dans un
vecteur ou une matrice sur votre logiciel (en Xcas, on peut utiliser
=<
au lieu de :=
pour stocker par référence).
- Voici un programme écrit en syntaxe compatible maple
(menu Cfg->Mode->maple dans Xcas) qui calcule la base utilisée
pour représenter les flottants.
Base:=proc()
local A,B;
A:=1.0; B:=1.0;
while evalf(evalf(A+1.0)-A)-1.0=0.0 do A:=2*A; od;
while evalf(evalf(A+B)-A)-B<>0 do B:=B+1; od;
B;
end;
Testez-le et expliquez.
- Déterminer le plus grand réel positif x de la forme
2−n (n entier)
tel que (1.0+x)−1.0 renvoie 0 sur PC avec la précision par
défaut puis avec
Digits:=30
.
- Calculer la valeur de a:=exp(π √163) avec 30 chiffres
significatifs, puis sa partie fractionnaire. Proposez une commande
permettant de décider si a est un entier.
- Déterminer la valeur et le signe de la fraction rationnelle
F(x,y)= |
|
y6 + x2 (11x2 y2−y6 −121y4−2) +
|
|
y8 + |
|
en x=77617 et y=33096 en faisant deux calculs, l'un en mode approché et
l'autre en mode exact. Que pensez-vous de ces résultats?
Combien de chiffres significatifs faut-il pour obtenir un résultat
raisonnable en mode approché?
- À quelle vitesse votre logiciel multiplie-t-il des
grands entiers (en fonction du nombre de chiffres)?
On pourra tester le temps de calcul du produit
de a(a+1) où a=10 000!, a=15000!, etc.
- Comparer le temps de calcul de an (mod m ) par la fonction
powmod
et la méthode prendre le reste modulo m après avoir
calculé an.
Programmez la méthode rapide et la méthode lente.
Que se passe-t-il si on essaie d'appliquer l'algorithme de la
puissance rapide pour calculer (x+y+z+1)32 ? Calculer le nombre
de termes dans le développement de (x+y+z+1)n et expliquez.
- Déterminer un entier c tel que c=1 (mod 3 ),
c=3 (mod 5 ), c=5 (mod 7 ) et c=2 (mod 1 )1.
- Programmation de la méthode de Horner
Il s'agit d'évaluer efficacement un polynôme
P(X) = an Xn + ... + a0
en un point.
On pose b0=P(α ) et on écrit :
P(X)−b0=(X−α )Q(X)
où :
Q(X) = bn Xn−1 + ... +b2 X + b1
On calcule alors par ordre décroissant bn, bn−1, ..., b0.
-
Donner bn en fonction de an puis pour i≤ n−1, bi
en fonction de ai et bi+1. Indiquez le détail des calculs
pour P(X)=X3−2X+5 et une valeur de α non nulle.
- Écrire un fonction
horn
effectuant ce calcul:
on donnera en arguments le polynôme sous forme de la
liste de ces coefficients (dans l'exemple [1,0,-2,5]
) et la
valeur de α et le programme renverra P(α ).
(On pourra aussi renvoyer les coefficients de Q).
- En utilisant cette fonction, écrire une fonction qui calcule
le développement de Taylor complet d'un polynôme en un point.
4 Le PGCD
Comme on l'a remarqué dans le premier article, l'algorithme d'Euclide est
inefficace pour calculer le pgcd de deux polynômes à coefficients entiers. On
va présenter ici les algorithmes utilisés habituellement par les systèmes de
calcul formel: sous-résultant (PRS), modulaire (GCDMOD), p-adique (EEZGD) et
heuristique (GCDHEU). Le premier est une adaptation de l'algorithme d'Euclide
et s'adapte à des coefficients assez génériques. Les trois autres ont en
commun d'évaluer une ou plusieurs variables du polynôme (dans ce dernier cas
il est nécessaire de bien distinguer le cas de polynômes à plusieurs
variables) et de reconstruire le pgcd par des techniques distinctes, la
plupart du temps ces algorithmes fonctionnent seulement si les coefficients
sont entiers.
Soit donc P et Q deux polynômes à coefficients dans un corps. Le
pgcd de P et Q n'est défini qu'à une constante près. Mais lorsque les
coefficients de P et Q sont dans un anneau euclidien comme par exemple
Z ou
Z [ i ], on appelle pgcd de P et Q un polynôme D tel
que P / D et Q / D soient encore à coefficients dans l'anneau, et que D
soit optimal, c'est-à-dire que si un multiple μ D de D vérifie P / μ
D et Q / μ D sont à coefficients dans l'anneau, alors μ est
inversible. La première étape d'un algorithme de calcul de pgcd consiste donc
à diviser par le pgcd des coefficients entiers de chaque polynôme.
Exemple: P = 4 X2 − 4 et Q = 6 X2 + 12 X + 6. Le polynôme
X + 1 est un pgcd de P et Q puisqu'il est de degré maximal divisant P
et Q mais le pgcd de P et Q est 2 ( X + 1 ). Remarquons qu'avec notre
définition − 2 ( X + 1 ) convient aussi. Par convention on appelera pgcd le
polynôme ayant un coefficient dominant positif.
Définition: On appelle contenu c ( P ) d'un polynôme P le
pgcd des coefficients de P. On définit alors la partie primitive de P:
pp( P ) = P / c ( P ). Si c(P)=1, on dit que P est primitif.
On montre que :
D = pgcd ( P, Q ) = pgcd ( c ( P ), c ( Q )) pgcd (
pp ( P ), pp ( Q ))
4.1 Le sous-résultant.
La première idée qui vient à l'esprit pour améliorer l'efficacité de
l'algorithme d'Euclide consiste à éviter les fractions qui sont créées par les
divisions euclidiennes. On utilise à cet effet la pseudo-division: au lieu de
prendre le reste R de la division euclidienne du polynôme P par Q, on
prend le reste de la division de P qδ + 1 par Q, où q désigne le
coefficient dominant de Q et δ la différence entre le degré de P et
de Q.
Exercice: En utilisant votre système de calcul formel préféré,
calculez les restes intermédiaires générés dans l'algorithme d'Euclide
lorsqu'on utilise la pseudo-division par exemple pour les polynômes P ( x ) =
( x + 1 )7 − ( x − 1 )6 et sa dérivée.
Une solution avec giac/xcas:
// -*- mode:C++ -*- a,b 2 polynomes -> pgcd de a et b
pgcd(a,b):={
local P,p,Q,q,R,g,h,d;
// convertit a et b en polynomes listes et extrait la partie primitive
P:=symb2poly1(a);
p:=lgcd(P); // pgcd des elements de la liste
P:=P/p;
Q:=symb2poly1(b);
q:=lgcd(Q);
Q:=Q/q;
if (size(P)<size(Q)){ // echange P et Q
R:=P; P:=Q; Q:=R;
}
// calcul du contenu du pgcd
p:=gcd(p,q);
g:=1;
h:=1;
while (size(Q)!=1){
q:=Q[0]; // coefficient dominant
d:=size(P)-size(Q);
R:=rem(q^(d+1)*P,Q);
if (size(R)==0) return(p*poly12symb(Q/lgcd(Q),x));
P:=Q;
Q:=R;
// ligne suivante a decommenter pour prs
// Q:=R/(g*h^d);
print(Q);
// ligne suivante a decommenter pour prs
// g:=q; h:=q^d/h^(d-1);
}
return(p);
}
On s'aperçoit que les coefficients croissent de manière exponentielle. La
deuxième idée qui vient naturellement est alors à chaque étape de rendre le
reste primitif, donc de diviser R par le pgcd de ces coefficients. Cela
donne un algorithme plus efficace, mais encore assez peu efficace car à chaque
étape on doit calculer le pgcd de tous les coefficients, on peut imaginer le
temps que cela prendra en dimension 1 et à fortiori en dimension supérieure.
L'idéal serait de connaitre à l'avance une quantité suffisamment grande qui
divise tous les coefficients du reste.
C'est ici qu'intervient l'algorithme du sous-résultant: après chaque
pseudo-division euclidienne, on exhibe un coefficient "magique" qui divise les
coefficients du reste. Ce coefficient n'est pas le pgcd mais il est
suffisamment grand pour qu'on évite la croissance exponentielle des
coefficients.
Algorithme du sous-résultant
Arguments: 2 polynômes P et Q primitifs. Valeur de retour: le pgcd de P
et Q.
Pour calculer le coefficient "magique" on utilise 2 variables auxiliaires g
et h initialisées a 1.
Boucle à effectuer tant que Q est non nul:
-
on note δ =degre(P)-degre(Q) et q le coefficient dominant
de Q
- on effectue la division euclidienne (sans fraction) de qδ + 1
P par Q, soit R le reste
- Si R est constant, on sort de l'algorithme en renvoyant 1 comme pgcd
- on recopie Q dans P puis R / ( g hδ ) dans Q
- on recopie q dans g et h1 − δ qδ dans h.
Si on sort normalement de la boucle, Q est nul, on renvoie donc la partie
primitive de P qui est le pgcd cherché.
Pour tester l'algorithme avec xcas, il suffit de décommenter les
deux lignes Q:=R/(g*h^d); et g:=q; h:=q^d/h
(d-1); ci-dessus.
La preuve de l'algorithme est un peu longue et par ailleurs très bien faite
dans le 2ème tome de Knuth (The Art of Computer Programming, Semi-numerical
Algorithms), on y renvoie donc le lecteur intéressé. L'idée générale (et le
nom de la méthode) est de considérer la matrice de Sylvester des polynômes de
départ P et Q (celle dont le déterminant est appelé résultant de P et
Q) et de traduire les pseudo-divisions qui permettent de calculer les restes
successifs du sous-résultant en opération de ligne sur ces matrices. On
démontre alors que les coefficients de R divisés par g hδ peuvent
être interprétés comme des déterminants de sous-matrices de la matrice de
Sylvester après réduction et c'est cela qui permet de conclure qu'ils sont
entiers.
4.2 Le pgcd en une variable
.
4.2.1 Le pgcd heuristique.
On suppose ici que les coefficients sont entiers ou entiers de Gauss.
On peut donc se ramener au cas où les polynômes sont primitifs.
L'idée consiste à évaluer P et Q en un entier z et à extraire des
informations du pgcd g des entiers P ( z ) et Q ( z ). Il faut donc un
moyen de remonter de l'entier g à un polynôme G tel que G ( z ) = g. La
méthode consiste à écrire en base z l'entier g, avec une particularité
dans les divisions euclidiennes successives on utilise le reste symétrique
(compris entre − z / 2 et z / 2). Cette écriture donne les coefficients
d'un polynôme G unique. On extrait ensuite la partie primitive de ce
polynôme G. Lorsque z est assez grand par rapport aux coefficients des
polynômes P et Q, si pp ( G ) divise P et Q, on va montrer
que le pgcd de P et de Q est D = pp ( G ).
On remarque tout d'abord que d : = D ( z ) divise g. En effet D divise
P et Q donc pour tout entier (ou entier de Gauss) z, D ( z ) divise P
( z ) et Q ( z ). Il existe donc une constante a telle que
g = a d
On a aussi pp ( G ) divise D. Il existe donc un polynôme C tel
que :
D = pp ( G ) C
Nous devons prouver que C est un polynôme constant. On suppose dans la suite
que ce n'est pas le cas. Evaluons l'égalité précédente au point z, on
obtient
Finalement
La procédure de construction de G nous donne une majoration de ces
coefficients par | z | / 2, donc de c ( G ) par | z | / 2, donc C ( z
) divise un entier de module plus petit que | z | / 2, donc
On considère maintenant les racines complexes z1, … ., zn du polynôme
C (il en existe au moins une puisqu'on a supposé C non constant). On a:
C ( X ) = cn ( X − z1 ) … . ( X − zn )
Donc, comme cn est un entier (ou entier de Gauss) non nul, sa norme est
supérieure ou égale à 1 et :
| C ( z ) | ≥ |
|
( | z | − | zj | ) |
Il nous reste à majorer les racines de C pour minorer | C ( z ) |. Comme
C divise D il divise P et Q donc les racines de C sont des racines
communes à P et Q. On va appliquer le:
Lemme 1
Soit x une racine complexe d'un polynôme P = an Xn + … . + a0.
Alors
| x | < | P |/| an | + 1, | P | = max0 ≤ i
≤ n ( | ai | )
Application du lemme à C(X) : on a 1/|cn|≤ 1
donc si on a choisi z tel que | z | ≥ 2 min( | P |, | Q | ) + 2,
alors pour tout j, | zj | < | z | / 2 donc
| C ( z ) | > |
⎛
⎜
⎜
⎝ |
|
|
⎞
⎟
⎟
⎠ |
|
qui contredit notre majoration de | C ( z ) |.
Théorème 1
Soit P et Q deux polynômes à coefficients entiers. On
choisit un entier z tel que | z | ≥ 2 min( | P |, | Q | ) + 2,
si la partie primitive du polynôme G reconstruit à partir du pgcd de P (
z ) etQ(z) par écriture en base z (avec comme reste euclidien le
reste symétrique) divise P et Q alors c'est le pgcd de P et Q.
Pour finir la démonstration du théorème, il nous faut encore montrer le lemme.
On a
− an xn = an − 1 xn − 1 + … . + a0
Donc
| an | | x |n ≤ | P | ( 1 + … . + | x |n − 1 ) = | P |
|
|
Ici on peut supposer que | x | ≥ 1, sinon le lemme est démontré,
donc | x | − 1 est positif et
| an | ( | x | − 1 ) ≤ | P | |
|
⇒ | x | − 1 < |
|
Remarques
Exemple 1
Si P0 = 6 ( X2 − 1 ) et Q0 = 4 ( X3 − 1 ).
Le contenu de P0 est 6, celui de Q0 est 4.
On a donc pgcd des contenus = 2, P = X2 − 1, Q = X3 − 1. La valeur
initiale de z est donc 2 ∗ 1 + 2 = 4. On trouve P ( 4 ) = 15, Q ( 4
) = 63. Le pgcd entier de 15 et 63 est 3 que nous écrivons symétriquement
en base 4 sous la forme 3 = 1 ∗ 4 − 1, donc G = X − 1, sa partie
primitive est X − 1. On teste si X − 1 divise P et Q, c'est le cas,
donc c'est le pgcd de P et Q et le pgcd de P0 et Q0 est 2 ( X − 1
).
Algorithme gcdheu
En arguments deux polynômes P0 et Q0 à coefficients entiers ou entiers
de Gauss. Retourne le pgcd de
P0 et Q0 ou faux en cas d'échec.
-
Calculer le contenu de P0 et Q0. Vérifier que les coefficients
sont entiers de Gauss sinon retourner faux.
- Extraire la partie primitive P de P0 et Q de Q0, calculer le
pgcd c des contenus de P0 et Q0
- Déterminer z = 2 min( | P |, | Q | ) + 2.
- Début de boucle: initialisation du nombre d'essais à 1, test d'arrêt
sur un nombre maximal d'essais, avec changement de z entre deux itérations
(par exemple z ← 2 z).
- Calculer le pgcd g de P ( z ) et Q ( z ) puis son écriture
symétrique en base z dont on extrait la partie primitive G.
- Si G ne divise pasP passer à l'itération
suivante. De même pour Q.
- Retourner c G
- Fin de la boucle
- Retourner faux.
On remarque au passage qu'on a calculé le quotient de P par G et le
quotient de Q par G lorsque la procédure réussit. On peut donc passer à la
procédure gcdheu deux paramètres supplémentaires par référence, les deux
polynômes que l'on affectera en cas de succès, ce qui optimise la
simplification d'une fraction de 2 polynômes.
4.2.2 Le pgcd modulaire
On part du fait que si D est le pgcd de P et Q dans Z (ou
Z [ i ] ) alors après réduction modulo un nombre premier n qui ne
divise pas les coefficients dominants de P et Q, D divise le pgcd G de
P et Q dans Z / n Z (par convention, le pgcd dans
Z / n Z est normalisé pour que son coefficient dominant
vaille 1). Comme on calcule G dans Z / n Z, les
coefficients des restes intermédiaires de l'algorithme d'Euclide sont bornés,
on évite ainsi la croissance exponentielle des coefficients. Il faudra ensuite
reconstruire D à partir de G.
On remarque d'abord que si on trouve G = 1, alors P et Q sont premiers
entre eux. En général, on peut seulement dire que le degré de G est
supérieur ou égal au degré de D. En fait, le degré de G est égal au degré
de D lorsque les restes de l'algorithme d'Euclide (calculé en effectuant des
pseudo-divisions, cf. l'exercice 1) ont leur coefficient dominant non
divisible par n. Donc plus n est grand, plus la probabilité est grande de
trouver G du bon degré.
Dans la suite, nous allons déterminer une borne b à priori majorant
les coefficients de
D. On utilisera ensuite la même méthode que dans l'algorithme modulaire de
recherche de racines évidentes: on multiplie G dans Z / n
Z par le pgcd dans Z des coefficients dominants p et
q de P et Q. Soit D = pgcd ( p, q ) G le résultat écrit
en représentation symétrique. Si n ≥ b pgcd ( p, q ) et si
G est du bon degré, on montre de la même manière que D = D. Comme
on ne connait pas le degré de D, on est obligé de tester si D
divise P
et Q. Si c'est le cas, alors D divise D donc D = D
puisque degre ( D ) = degre ( G ) ≥
degre ( D ). Sinon, n est un nombre premier malchanceux pour ce
calcul de pgcd (degre ( G ) ≥ degre ( D )), il faut
essayer un autre premier.
Remarque: On serait tenté de dire que les coefficients de D
sont bornés par le plus grand coefficient de P. C'est malheureusement faux,
par exemple ( X + 1 )2 dont le plus grand coefficient est 2 divise ( X + 1
)2 ( X − 1 ) dont le plus grand coefficient (en valeur absolue) est 1.
Soit P = Σpi Xi un polynôme à coefficients entiers. On utilise la
norme euclidienne
| P |2 = Σ| pi |2
(1)
On établit d'abord une majoration du produit des racines de norme supérieure à
1 de P à l'aide de | P |. Ensuite si D est un diviseur de P, le
coefficient dominant d de D divise le coefficient dominant p de P et
les racines de D sont aussi des racines de P. On pourra donc déterminer une
majoration des polynômes symétriques des racines de D et donc des
coefficients de D.
Lemme 2
Soit A = Σj = 0a aj Xj un polynôme et α ∈ C.
Alors
| ( X − α ) A | = | ( α X − 1 ) A |
Pour prouver le lemme 2, on développe les produits de polynômes.
On pose a−1 = aa + 1 = 0 et on note ℜ la partie réelle.
| ( X − α ) A |2 = Σj = 0a + 1 |
| aj − 1 − α
aj |2 = |
|
| aj − 1 |2 + | α |2 | aj |2 − 2
ℜ ( aj − 1 |
|
) |
| ( α X − 1 ) A | |
2 = |
|
|
|
|
aj − 1
− aj |2 = |
|
| α |2 | aj − 1 |2 + | aj |2 −
2 ℜ ( |
|
aj − 1 |
|
) |
Les deux donnent bien le même résultat.
Soit P ( X ) = p Π( X − αj ) la factorisation de P sur
C. On introduit le polynôme
P |
= p |
|
( X − αj )
|
|
( |
|
X − 1 ) |
qui d'après le lemme a la même norme que P. La norme de P majore donc le
coefficient constant de P d'où:
Π
j / | αj | ≥ 1 | α
j |
≤ |
P |/|
p |
(2)
On remarque que (2) reste vraie si on considère les
racines δj de norme plus grande que 1 d'un diviseur D de P puisque
le produit porte alors sur un sous-ensemble. On écrit maintenant l'expression
des coefficients dj de D à l'aide des racines δj de D:
| dm − j | = | d | |
|
|
|
| |
|
Σ |
choix de j racines
parmi les m racines de D |
|
|
|
δk |
|
|
|
| |
Pour majorer | dm − j |, on commence par majorer | δk | par
βk = max( 1, | δk | ). On est donc ramené à majorer
σj, m ( β ) = |
|
Σ |
choix de j parmi m
valeurs βk |
|
|
|
βk |
avec pour hypothèse une majoration de M = Πk = 1m βk donnée par
la relation (2). Pour cela, on cherche le maximum de σj,
m ( β ) sous les contraintes M fixé et βk ≥ 1.
On va montrer que le maximum ne peut être atteint que si l'un des βk =
M (et tous les autres βk = 1 ). Sinon, quitte à réordonner supposons
que les βk sont classés par ordre croissant. On a donc βm − 1
≠ 1, on pose βk = βk pour k ≤ m − 2,
βm − 1 = 1 et βm = βm − 1 βm.
Comparons σj, m ( β ) et σj, nm ( β
). Si le choix de j parmi m comporte k = m − 1 et k = m, le produit
est inchangé. Sinon on a la somme de deux produits, l'un contenant k = m − 1
et l'autre k = m. On compare donc B ( βm − 1 + βm ) et B ( 1
+ βm − 1 βm ) avec B = Πβk ∈ reste du
choix βk. Comme
1 + βm − 1 βm ≥ βm − 1 + βm
puisque la différence est le produit (1−βm)(1−βm−1) de deux
nombres positifs, on arrive à la contradiction souhaitée.
Ensuite on décompose les choix de σm, j en ceux contenant M et
des 1 et ceux ne contenant que des 1, d'où la majoration
σj, m ( β ) ≤ |
⎛
⎝ |
|
⎞
⎠ |
M + |
⎛
⎝ |
|
⎞
⎠ |
et finalement
| dm − j | ≤ | d | |
⎛
⎜
⎜
⎝ |
⎛
⎝ |
|
⎞
⎠ |
|
+ |
⎛
⎝ |
|
⎞
⎠ |
⎞
⎟
⎟
⎠ |
(3) |
On peut en déduire une majoration indépendante de j sur les coefficients de
D, en majorant | d | par | p | (puisque d divise p) et les
coefficients binomiaux par 2m − 1 (obtenue en développant ( 1 + 1 )m −
1). D'où le
Théorème 2
(Landau-Mignotte) Soit P un polynôme à coefficients entiers (ou entiers de
Gauss) et D un diviseur de P de degré m. Si | P | désigne la norme
euclidienne du vecteur des coefficients de P et p le coefficient
dominant de P alors les coefficients dj de D satisfont l'inégalité
| dj | ≤ 2m − 1 ( | P | + | p | )
(4)
Avec cette estimation, on en déduit que si n est un premier plus grand que
min( 2
degre ( P ) − 1 ( |
P | + |
p | ),
2
degre ( Q ) − 1 ( |
Q | + |
q | ) ),
(5)
alors le pgcd trouvé dans Z / n Z va se reconstruire en un
pgcd dans Z si son degré est le bon.
Malheureusement la borne précédente est souvent très grande par rapport aux
coefficients du pgcd et calculer dans Z / n Z s'avèrera
encore inefficace (surtout si le pgcd est 1). Cela reste vrai même si on
optimise un peu la majoration (5) en repartant de (3).
L'idée est donc de travailler modulo plusieurs nombres premiers plus petits et
reconstruire le pgcd des 2 polynômes à coefficients entiers à partir des pgcd
des polynômes dans Z / n Z et du
théorème des restes chinois. En pratique on prend des nombres premiers
inférieurs à la racine carrée du plus grand entier hardware de la machine
(donc plus petits que 216 sur une machine 32 bits) ce qui permet
d'utiliser l'arithmétique hardware du processeur sans risque de débordement.
Algorithme du PGCD modulaire en 1 variable:
En argument: 2 polynômes primitifs P et Q à coefficients entiers. Le
résultat renvoyé sera le polynôme pgcd.
Variable auxiliaire: un entier N initialisé à 1 qui représente le produit
des nombres premiers utilisés jusqu'ici et un polynôme H initialisé à 0 qui
représente le pgcd dans Z / N Z.
Boucle infinie :
-
Chercher un nouveau nombre premier n qui ne divise pas les
coefficients dominants p et q de P et Q
- Calculer le pgcd G de P et Q dans Z / n Z.
Si G=1, renvoyer 1.
- Si H = 0 ou si le degré de G est plus petit que le degré
de H, recopier G dans H et n dans N, passer à la 6ème étape
- Si le degré de G est plus grand que celui de H passer à
l'itération suivante
- Si le degré de G est égal au degré de H,
en utilisant le théorème des restes chinois, calculer un polynôme
H tel que H = H modulo N et H = G modulo
n. Recopier H dans H et n N dans N.
- Ecrire pgcd ( p, q ) H en représentation symétrique. Soit
H le résultat rendu primitif. Tester si H divise P et
Q. Si c'est le cas, renvoyer H, sinon passer à l'itération
suivante.
Finalement on n'a pas utilisé b, la borne de Landau-Mignotte.
On peut penser que l'étape
6 ne devrait être effectuée que lorsque N est plus grand que pgcd (
p, q ) b. En pratique, on effectue le test de l'étape 6 plus tôt parce que
les coefficients du pgcd sont rarement aussi grand que b. Mais pour éviter
de faire le test trop tôt, on introduit une variable auxiliaire H' qui
contient la valeur de H de l'itération précédente et on ne fait le test que
si H' = H (ou bien sûr si on a dépassé la borne).
Remarque:
L'algorithme ci-dessus fonctionne également pour des polynômes à plusieurs
variables.
Exemple 1:
Calcul du pgcd de ( X + 1 )3 ( X − 1 )4 et ( X4 − 1 ). Prenons pour
commencer n = 2. On trouve comme pgcd X4 + 1 (en effet − 1 = 1 donc on
cherchait le pgcd de ( X + 1 )7 et de X4 + 1 = ( X + 1 )4). On teste si
X4 + 1 divise P et Q, ce n'est pas le cas donc on passe au nombre
premier suivant. Pour n = 3, on trouve X2 − 1. Donc n = 2 n'était pas un
bon nombre premier pour ce calcul de pgcd puisqu'on a trouvé un pgcd de degré
plus petit. On teste si X2 − 1 divise P et Q, c'est le cas ici donc on
peut arrêter, le pgcd cherché est X2−1.
Exemple 2 :
Calcul du pgcd de ( X + 1 )3 ( X − 1 )4 et ( X4 − 1 )3.
Pour n = 2, on trouve un polynôme de degré 7.
Pour n = 3, on trouve X6 − 1 donc n = 2 était une mauvaise réduction.
Comme X6 − 1 ne divise pas P et Q, on passe à n = 5. On trouve X6 +
2 X4 − 2 X2 − 1. On applique le théorème des restes chinois qui va nous
donner un polynôme dans Z / 15 Z. On cherche donc un
entier congru à 2 modulo 5 et à 0 modulo 3, -3 est la solution (écrite en
représentation symétrique), donc le polynôme modulo 15 est X6 − 3 X4 + 3
X2 − 1 = ( X2 − 1 )3. Ce polynôme divise P et Q, c'est donc le pgcd de
P et de Q.
4.3 Le pgcd à plusieurs variables.
4.3.1 Le pgcd heuristique.
On suppose comme dans le cas à une variable que les polynômes sont primitifs,
donc qu'on a simplifié les polynômes par le pgcd entier de leurs coefficients
entiers.
Le principe est identique à celui du PGCD à 1 variable, on évalue les deux
polynômes P et Q de k variables X1, … ., Xk en un Xk = z et
on calcule le pgcd g des 2 polynômes P ( z ) et Q ( z ) de k − 1
variables. On remonte ensuite à un polynôme G par écriture symétrique en
base z de g et on teste si pp ( G ) divise P et Q. Il s'agit
à nouveau de montrer que si z est assez grand, alors pp ( G ) est
le pgcd cherché. On sait que d = D ( z ) divise g. Il existe donc un
polynôme a de k − 1 variables tel que g = a d. On sait aussi que
pp ( G ) divise D, donc il existe un polynôme C de k variables
tel que D = C ∗ pp ( G ) . On évalue en z et on obtient d = C (
z ) g / c ( G ), où c ( G ) est un entier, donc
c ( G ) = a ∗ C ( z )
Comme c ( G ) est un entier, a et C ( z ) sont des polynômes constants.
Comme précédemment, on a aussi | C ( z ) | ≤ | z | / 2 puisque | c
( G ) | ≤ | z | / 2.
-
Premier cas: si C ne dépend que de la variable Xk. On continue le
raisonnement comme dans le cas unidimensionnel.
- Deuxième cas: si C dépend d'une autre variable, par exemple X1.
On regarde le coefficient de plus haut degre de C par rapport a X1. Ce
coefficient divise le coefficient de plus haut degre de P et de Q par
rapport a X1. Comme C ( z ) est constant, on en deduit que le
coefficient de plus haut degre de P et Q par rapport a X1 est
divisible par Xk − z donc le coefficient de plus bas degre en Xk de
ces coefficients de plus haut degre est divisible par z, ce qui contredit
la majoration de ce coefficient.
En pratique, cet algorithme nécessite le calcul récursif de pgcd sans
garantie de réussite. On l'évite donc s'il y a beaucoup de variables (la
limite est par exemple de 5 pour MuPAD).
4.3.2 Le pgcd modulaire multivariables.
Ici, on travaille modulo Xn − α, où X1, … ., Xn désignent
les variables des polynômes. On considère donc deux polynômes P et Q comme
polynômes de la variables Xn avec des coefficients dans Z [ X1,
… ., Xn − 1 ]. On évalue en Xn = α, on obtient deux polynômes
en n − 1 variables dont on calcule le pgcd (récursivement).
Il s'agit de reconstruire le pgcd par interpolation. Tout d'abord, on a une
borne évidente sur le degré du pgcd par rapport à la variable Xn, c'est le
minimum δ des degrés par rapport à Xn des polynômes P et Q. A
première vue, il suffit donc d'évaluer les polynômes
en δ + 1 points α.
Il faut toutefois prendre garde aux mauvaises évaluations et à la
normalisation des pgcd avant d'interpoler. En effet, si D ( X1, … .,
Xn ) désigne le pgcd de P et Q et G ( X1, … ., Xn − 1 ) le
pgcd de P ( X1, … ., Xn − 1, α ) et de Q ( X1, … .,
Xn − 1, α ),
on peut seulement dire D ( X1, … ., Xn − 1, α )
divise G. Plusieurs cas sont donc possibles lorsqu'on évalue en un nouveau
point α:
-
l'un des degrés de G est plus petit que le degré du polynôme D'
reconstruit par interpolation jusque là. Dans ce cas, toutes les évaluations
qui ont conduit à reconstruire D' étaient mauvaises. Il faut recommencer
l'interpolation à zéro ou à partir de G (si tous les degrés de G sont
inférieurs ou égaux aux degrés du D' reconstruit).
- l'un des degrés de G est plus grand que le degré du D' reconstruit
jusque là. Il faut alors ignorer α.
- Tous les degrés de G sont égaux aux degrés du D' reconstruit
jusque là. Dans ce cas, G est un multiple entier du polynôme D'
reconstruit jusque là et évalué en Xn = α. Si on suppose qu'on a pu
s'arranger pour que ce multiple soit 1, on ajoute le point α aux
points d'évaluation précédents αj en posant:
On voit que les mauvaises évaluations se détectent simplement par les degrés.
Pour la normalisation, on utilise une petite astuce: au lieu de reconstruire
le pgcd D, on va reconstruire un multiple du pgcd D (ce
multiple appartiendra à Z [ Xn ] ). On voit maintenant P et Q
comme des polynômes en n − 1 variables X1, … ., Xn − 1 à
coefficients dans Z [ Xn ]. Alors lcoeff(D),
le coefficient dominant de D
(relativement à l'ordre lexicographique sur les variables X1,...,Xn−1),
est un polynôme en Xn qui divise le coefficient dominant de P et de Q
donc divise le coefficient dominant du pgcd des coefficients dominants de P
et de Q. On va donc reconstruire le polynôme :
D' = D |
Δ ( Xn ) |
|
lcoeff ( D ) ( Xn ) |
|
, Δ ( Xn ) =
pgcd ( lcoeff ( P ) ( Xn ), lcoeff ( Q ) ( Xn )) |
c'est-à-dire D multiplié par un polynôme qui ne dépend que de Xn.
Revenons à G en un point α de bonne évaluation. C'est un multiple
entier de D ( X1, … ., Xn − 1, α ):
G = β D ( X1, … ., Xn − 1, α )
Donc, comme polynômes de X1,...,Xn−1 à coefficients dans
Z[Xn] ou dans Z,
lcoeff ( G ) = β lcoeff ( D )| Xn = α. Comme
lcoeff ( D ) divise Δ ( Xn ), il en est de même en Xn =
α donc lcoeff(G) divise β Δ(α).
On en déduit que Δ ( α) G qui
est divisible par Δ (α) β est
divisible par lcoeff ( G ). On va donc considérer le polynôme
Δ (α) G / lcoeff ( G ) :
ses coefficients sont entiers et son coefficient dominant est
Δ ( α) = lcoeff(D'( X1, … ., Xn − 1, α ))
donc
Δ (α) G / lcoeff ( G )=
D'( X1, … ., Xn − 1, α )
Algorithme du pgcd modulaire à plusieurs variables (interpolation
dense):
Arguments: 2 polynômes primitifs P et Q de n variables X1, … .,
Xn à coefficients entiers. Renvoie le pgcd de P et Q.
-
Si n = 1, renvoyer le pgcd de P et Q en une variable.
- Test rapide de pgcd trivial par rapport à Xn. On cherche des n −
1-uplets α tels que P ( α, Xn ) et Q ( α, Xn )
soient de même degré que P et Q par rapport à la variable Xn. On
calcule le pgcd G de ces 2 polynômes en une variable. Si le pgcd est
constant, alors on retourne le pgcd des coefficients de P et Q.
- On divise P et Q par leur contenu respectifs vu comme polynômes en
X1, … ., Xn − 1 à coefficients dans Z [ Xn ], on note
C ( Xn ) le pgcd des contenus. On calcule aussi le pgcd Δ ( Xn )
des coefficients dominants de P et de Q.
- On initialise D' le pgcd reconstruit à 0, I ( Xn ) le polynôme
d'interpolation à 1, δ=(δ1,...,δn−1)
la liste des degrés partiels du pgcd par
rapport à X1, … ., Xn − 1 au minimum des degrés partiels de P
et Q par rapport à X1, … ., Xn − 1, e le nombre d'évaluation
à 0 et E l'ensemble des points d'interpolation à la liste vide.
- Boucle infinie:
-
Faire α=entier aléatoire n'appartenant pas à E jusqu'à ce
que
degre(P ( X1, … ., Xn − 1, α
))=degreXn ( P ( X1, … ., Xn ) |
|
|
degre ( Q ( X1, … ., Xn − 1, α )) =
degreXn ( Q ( X1, … ., Xn )) |
|
- Calculer le pgcd G ( X1, … ., Xn − 1 ) en n − 1
variables de P ( X1, … ., Xn − 1, α ) et Q ( X1, …
., Xn − 1, α ).
- Si degre ( G )i < δi pour un indice au moins.
Si degre ( G ) ≤ δ, on pose δ =
degre ( G ), D' = G Δ ( α )/lcoeff ( G
), I = Xn − α, e = 1 et E = [ α ], sinon on pose δ
= min( δ, degre ( G )), D' = 0, I = 1, e = 0, E = [ ].
On passe à l'itération suivante.
- Si degre ( G ) > δ, on passe à l'itération suivante.
- Si degre ( G ) = δ, on interpole:
-
G := G Δ ( α )/lcoeff ( G )
- D' := D' + I ( Xn )/Παj ∈ E ( α −
αj ) ( G − D' ( X1, … ., Xn − 1, α ))
- I := I ∗ ( Xn − α )
- e := e + 1 et ajouter α à E
- Si e est strictement plus grand que le minimum des degrés
partiels de P et Q par rapport à Xn, on pose D la
partie primitive de D' (vu comme polynôme à coefficients dans
Z [ Xn ]), on teste si P et Q sont divisibles par
D, si c'est le cas, on renvoie D = C ( Xn ) D
On observe que dans cet algorithme, on fait le test de divisibilite de
D par P et Q. En effet, même après avoir évalué en suffisamment
de points, rien n'indique que tous ces points sont des points de bonne
évaluation. En pratique cela reste extrêmement improbable. En pratique, on
teste la divisibilité plus tôt, dès que D' n'est pas modifié par l'ajout
d'un nouveau point à la liste des αj.
Il existe une variation de cet algorithme, appelé SPMOD (sparse modular), qui
suppose que seuls les coefficients non nuls du pgcd en n − 1 variables sont
encore non nuls en n variables (ce qui a de fortes chances d'être le cas).
L'étape d'interpolation est alors remplacée par la résolution d'un
sous-système d'un système de Vandermonde. Cette variation est intéressante si
le nombre de coefficients non nuls en n − 1 variables est petit devant le
degré. Si elle échoue, on revient à l'interpolation dense.
Notons enfin qu'on peut appliquer cette méthode lorsque les coefficients de
P et Q sont dans Z / n Z mais il faut alors vérifier
qu'on dispose de suffisamment de points d'interpolation. Ce qui en combinant
avec l'algorithme modulaire à une variable donne un algorithme doublement
modulaire pour calculer le pgcd de 2 polynômes à coefficients entiers. C'est
cette méthode qu'utilise par exemple MuPAD (en essayant d'abord SPMOD puis
l'interpolation dense).
Exemple:
Dans cet exemple, on donne F et G sous forme factorisée, le but étant de
faire comprendre l'algorithme. En utilisation normale, on n'exécuterait cet
algorithme que si F et G étaient développés.
P = (( x + 1 ) y + x2 + 1 ) ( y2 + x y + 1 ), Q = (( x + 1 ) y +
x2 + 1 ) ( y2 − x y − 1 ).
Prenons x comme variable X1 et y comme variable X2. Les coefficients
dominants de P et Q sont respectivement y et − y donc Δ = y.
En y = 0, P ( x, 0 ) = x2 + 1 n'est pas du bon degré.
En y = 1, P ( x, 1 ) = ( x + x2 + 2 ) ( x + 2 ) et Q ( x, 1 ) = ( x +
x2 + 2 ) ( − x ) sont du bon degré. Leur pgcd est G = x2 + x + 2, Δ
( 1 ) = 1, donc D' = x2 + x + 1. On teste la divisibilité de P par D',
le teste échoue.
En y = 2, P ( x, 2 ) = ( x2 + 2 x + 3 ) ( 2 x + 5 ) et Q ( x, 2 ) = (
x2 + 2 x + 3 ) ( − 2 x + 3 ) donc G = x2 + 2 x + 3, Δ ( 2 ) = 2.
On interpole:
D' = x2 + x + 2 + |
|
( 2 ( x2 + 2 x + 3 ) − ( x2 + x +
2 )) = y ( x2 + 3 x + 4 ) − ( 2 x + 2 ) |
On teste la divisibilité de P par D', le test échoue.
En y = 3, P ( x, 3 ) = ( x2 + 3 x + 4 ) ( 3 x + 10 ) et Q ( x, 3 ) = (
x2 + 3 x + 4 ) ( − 3 x + 8 ) donc G = x2 + 3 x + 4, Δ ( 3 ) = 3.
On interpole:
D' |
= |
y ( x2 + 3 x + 4 ) − ( 2 x + 2 ) + |
|
|
( y − 2 ) ( y − 1 ) |
|
( 3 − 2
) ( 3 − 1 ) |
|
|
⎛
⎝ |
3 ( x2 + 3 x + 4 ) − ( 3 ( x2 + 3 x + 4 ) − ( 2 x + 2
)) |
⎞
⎠ |
|
donc
D' = y ( x2 + 3 x + 4 ) − ( 2 x + 2 ) + |
|
( −
2 x − 2 ) = x2 y + x y2 + y2 + y |
On divise D' par son contenu et on trouve x2 + x y + y + 1 qui est bien
le pgcd de P et Q.
Il s'agit d'une méthode p-adique. On évalue toutes les variables sauf une,
on calcule le pgcd en une variable et on remonte au pgcd variable par variable
(EEZGCD) ou toutes les variables simultanément (EZGCD) par un lemme de Hensel.
Il semble qu'il est plus efficace de remonter les variables séparément.
Soit donc F et G deux polynômes primitifs dépendant des variables X1,
…, Xn de pgcd D, on fixe une des variables qu'on appelera X1 dans
la suite. Soient lcoeff ( F ) et lcoeff ( G ) les
coefficients dominants de F et G par rapport à X1. On évalue F et G
en un n − 1 uplet b tel que le degré de F et G par rapport à X1
soit conservé après evaluation en b. On suppose que Db ( X1 ) =
pgcd ( F ( b ), G ( b )) a le même degré que D ( b ). On a donc
l'égalité:
( F ∗ lcoeff ( F )) ( b ) = |
⎛
⎜
⎜
⎝ |
Db |
lcoeff ( F (
b )) |
|
lcoeff ( Db ) |
|
|
⎞
⎟
⎟
⎠ |
∗ |
⎛
⎜
⎜
⎜
⎜
⎜
⎝ |
|
|
|
|
⎞
⎟
⎟
⎟
⎟
⎟
⎠ |
et de même en remplaçant F par G.
Pour pouvoir lifter cette égalité (c'est-à-dire généraliser à plusieurs
variables), il faut que Db et F ( b )/Db
soient premiers entre eux. Sinon, on peut essayer de lifter l'égalité analogue
avec G. En général, on montre qu'il existe un entier j tel que Db et
F ( b ) + j G ( b )/Db soient premiers entre eux. En effet, sinon
au moins un des facteurs irréductibles de Db va diviser F ( b ) + j
G ( b )/Db pour deux valeurs distinctes de j et va donc diviser à la
fois F ( b )/Db et G ( b )/Db en contradiction avec la
définition de Db = pgcd ( F ( b ), G ( b )). On lifte alors
l'égalité obtenue en remplaçant F par ( F + k G ) ci-dessus. Dans la
suite, on suppose qu'on peut prendre j = 0 pour alléger les notations.
On va aussi supposer que b = 0. Sinon, on fait un changement d'origine sur
les polynômes F et G pour que b = 0 convienne, on calcule le pgcd et on
lui applique la translation d'origine opposée.
On adopte ensuite la notation suivante: si k est un entier, on dit qu'un
polynôme P est un O ( k ) si la valuation de P vu comme polynôme en
X2, … ., Xn à coefficients dans Z [ X1 ] est supérieure
ou égale à k, ou de manière équivalente si
P ( X1, h X2, … ., h Xn ) = Oh → 0 ( hk )
L'égalité à lifter se réécrit donc:
F lcoeff ( F ) = P0 Q0 + O ( 1 )
où P0 =Db lcoeff ( F ( b ))/lcoeff ( Db ) et
Q0 = F ( b )/Db lcoeff ( F ) ( b )/lcoeff (
F ( b )/Db ) sont premiers entre eux et de degré 0 par rapport aux
variables X2, … ., Xn. Cherchons P1 = O ( 1 ) et Q1 = O ( 1 )
de degré 1 par rapport aux variables X2, … ., Xn tels que
F lcoeff ( F ) = ( P0 + P1 ) ( Q0 + Q1 ) + O ( 2 )
Il faut donc résoudre
F lcoeff ( F ) − P0 Q0 = P0 Q1 + Q0 P1 + O ( 2 )
On peut alors appliquer l'identité de Bézout qui permet de déterminer des
polynômes P1 et Q1 satisfaisant l'égalité ci-dessus (avec comme reste O
( 2 ) nul) puisque P0 et Q0 sont premiers entre eux. De plus, on
choisit P1 et Q1 tels que degreX1 P1 ≤
degreX1 ( F ) − degre ( Q0 ) = degre ( P0 ) et
degreX1 ( Q1 ) ≤ degre ( Q0 ) et
lcoeffX1 ( P0 + P1 ) + O ( 2 ) = lcoeffX1 ( Q0 + Q1
) + O ( 2 ) = lcoeffX1 ( F ). On tronque ensuite P1 et Q1 en
ne conservant que les termes de degré 1 par rapport à X2, … ., Xn.
On trouve de la même manière par récurrence Pk et Qk homogènes de degré
k par rapport à X2, … ., Xk, de degré par rapport à X1
respectivement inférieur aux degrés de Q0 et de P0 et tels que
F lcoeff (
F ) = (
P0 + … . +
Pk ) (
Q0 + … . +
Qk ) +
O (
k + 1 )
(6)
et lcoeff ( F ) = lcoeffX1 ( P0 + … . + Pk ) + O ( k
+ 1 ) = lcoeffX1 ( Q0 + … . + Qk ) + O ( k + 1 ).
Si on est bien en un point de bonne évaluation et si k est plus grand que le
degré total (par rapport aux variables X2, … ., Xn) du polynôme
F lcoeff ( F ) on va vérifier que P0 + … . + Pk = D
lcoeff ( F )/lcoeff ( D ). En effet, si on a deux
suites de polynômes P et P' et Q et Q' satisfaisant (6) avec
les même termes de degré zéro P0 et Q0, alors en prenant la différence,
on obtient:
( P0 + P1 … + Pk ) ( Q0 + Q1 … + Qk ) = ( P0 + P1'
… + Pk' ) ( Q0 + Q1' … + Qk' ) + O ( k + 1 )
On égale alors les termes homogènes de degré j, pour j = 1, on obtient
P0 ( Q1 − Q1' ) = Q0 ( P1 − P1' ), donc Q0 divise Q1 − Q1' qui
est de degré strictement inférieur au degré de Q0 par rapport à X1 (car
on a l'inégalité large et les termes de plus haut degré sont égaux),
donc Q1 = Q1' et P1 = P1'. On montre de la même manière que Qj =
Qj' et Pj = Pj'. L'écriture est donc unique, c'est donc l'écriture en
polynôme homogène de degré croissant de D lcoeff ( F
)/lcoeff ( D ) que l'on reconstruit.
Cet algorithme permet donc de reconstruire D, il suffit de tester à chaque
étape si P0 + … . + Pk divise F lcoeff ( F ). On appelle
cette méthode de remontée lemme de Hensel linéaire. Il existe une variante
dite lemme de Hensel quadratique qui consiste à passer de O ( k ) à O ( 2 k
). Elle nécessite toutefois un calcul supplémentaire, celui de l'identité de
Bézout à O ( 2 k ) près pour les polynômes P0 + … . + Pk − 1 et
Q0 + … . + Qk − 1. Ce calcul se fait également par lifting.
Algorithme EZGCD (Hensel linéaire)
Arguments: 2 polynômes F et G à coefficients entiers et primitifs. Renvoie
le pgcd de F et G ou false.
-
Evaluer F et G en ( X2, … ., Xn ) = ( 0, … ., 0 ),
vérifier que les coefficients dominants de F et de G ne s'annulent pas.
Calculer le pgcd Db de F ( 0 ) et de G ( 0 ). Prendre un autre point
d'évaluation au hasard qui n'annule pas les coefficients dominants de F et
de G et vérifier que le pgcd a le même degré que Db. Sinon, renvoyer
false (on peut aussi faire une translation d'origine de F et de G en un
autre point mais cela diminue l'efficacité de l'algorithme).
- On note lcF et lcG les coefficients dominants de F
et de G par rapport à X1.
- Si degre ( F ) ≤ degre ( G ) et degre
( Db ) = degre ( G ) et F divise G renvoyer F
- Si degre ( G ) < degre ( F ) et degre ( Db )
= degre ( F ) et G divise F renvoyer G
- Si degre ( F ) = degre ( Db ) ou si degre ( G
) = degre ( Db ) renvoyer false
- Boucle infinie sur j entier initialisé à 0, incrémenté de 1 à chaque
itération: si pgcd ( Db, F ( 0 ) + j G ( 0 )/Db ) = C
constant, alors arrêter la boucle
- Lifter l'égalité ( F + j G ) ( lcF + j lcG ) ( 0 ) =
( Db ( lcF + j lcG ) ( 0 )/lcoeff ( Db
) ) ∗ … . par remontée de Hensel linéaire ou quadratique.
Si le résultat est false, renvoyer false. Sinon renvoyer le premier polynôme
du résultat divisé par son contenu vu comme polynôme en X1 à coefficients
dans Z [ X2, … ., Xn ].
Remontée de Hensel linéaire:
Arguments: F un polynôme, lcF=lcoeff(F)
son coefficient dominant, P0 un
facteur de F ( 0 ) ayant comme coefficient dominant lcF ( 0 ) et
dont le cofacteur Q0 est premier avec P0.
Renvoie deux polynômes P et Q tels que F lcF = P Q et P ( 0 ) =
P0 et lcoeff ( P ) = lcoeff ( Q ) = lcF.
-
Soit G = F lcF, , Q0 = G ( 0 ) / P0, P = P0, Q =
Q0.
- Déterminer les deux polynômes U et V de l'identité de Bézout
(tels que P0 U + Q0 V = d où d est un entier).
- Boucle infinie avec un compteur k initialisé à 1, incrémenté de 1 à
chaque itération
Exemple:
F = (( x + 1 ) y + x2 + 1 ) ( y2 + x y + 1 ), G = (( x + 1 ) y + x2 + 1 )
( y2 − x y − 1 )
On a F ( 0, y ) = ( y + 1 ) ( y2 + 1 ) et G ( 0, y ) = ( y + 1 ) ( y2 − 1
), le pgcd est donc Db = ( y + 1 ). On remarque que Db est premier avec
le cofacteur de F mais pas avec le cofacteur de G. Si on évalue en un
autre point, par exemple x = 1, on trouve un pgcd D1 de même degré, donc
0 est vraissemblablement un bon point d'évaluation (ici on en est sûr puisque
le pgcd de F et G se calcule à vue...). On a lcoeff ( F ) = x +
1, on va donc lifter G = (( x + 1 ) y + x2 + 1 ) ( y2 + x y + 1 ) ( x + 1
) = P Q où P0 = ( y + 1 ) et Q0 = ( y2 + 1 ).
On calcule les polynômes de l'identité de Bézout U = ( 1 − y ) et V = 1
avec d = 2, puis à l'ordre k = 1:
H = G − P0 Q0 = ( 2 y3 + 2 y2 + 3 y + 1 ) x + O ( 2 )
donc u = reste ( U H / d, Q0 ) = x y et v = reste ( V H / d,
P0 ) = − x.
Donc Q1 = x y + α Q0 avec α = ( x + 1 − 1 ) / lcoeff (
P0 ) = x et Q0 + Q1 = ( y2 + 1 ) ( x + 1 ) + x y. De
même, P1 = − x + β P0, avec β = ( x + 1 − 1 ) / lcoeff (
P0 ) = x donc P0 + P1 = ( y + 1 ) ( x + 1 ) − x. On remarque que P0 +
P1 et Q0 + Q1 sont bien à O ( 2 ) près les facteurs de F
lcoeff ( F ):
P = ( x + 1 ) y + x2 + 1 = P0 + P1 + O ( 2 ), Q = ( x +
1 ) ( y2 + x y + 1 ) = Q0 + Q1 + O ( 2 )
Une deuxième itération est nécessaire. On calcule
H = G − ( P0 + P1 ) ( Q0 + Q1 ) = ( 2 y2 + y + 1 ) x2 + O ( 3
)
puis reste ( U H / d, Q0 ) = y x2 et reste ( V H / d, P0 )
= x2. Ici les coefficients α et β sont nuls car lcoeff
( F ) n'a pas de partie homogène de degré 2. On trouve alors P = P0 + P1 +
P2 et Q = Q0 + Q1 + Q2. Pour calculer le pgcd, il suffit de calculer la
partie primitive de P vu comme polynôme en y, ici c'est encore P car le
contenu de P est 1 (remarque: pour Q le contenu est x + 1).
On trouve donc P comme pgcd.
4.4 Quel algorithme choisir?
Il est toujours judicieux de faire une évaluation en quelques n − 1 uplets
pour traquer les pgcd triviaux. (E)EZGCD sera efficace si (0,...,0) est un
point de bonne évaluation et si le nombre de remontées nécessaires pour le
lemme de Hensel est petit donc pour les pgcd de petit degré, GCDMOD est aussi
efficace si le degré du pgcd est petit. Le sous-résultant est efficace pour
les pgcd de grand degré car il y a alors peu de divisions euclidiennes à
effectuer et les coefficients n'ont pas trop le temps de croitre. SPMOD est
intéressant pour les polynômes creux de pgcd non trivial creux. GCDHEU est
intéressant pour les problèmes relativement petits.
Avec des machines multiprocesseurs, on a probablement intérêt à lancer en
parallèle plusieurs algorithmes et à s'arrêter dès que l'un deux recontre le
succès.
4.5 Pour en savoir plus.
Parmi les références citées dans le premier article, ce sont les livres de
Knuth, H. Cohen, et Davenport-Siret-Tournier qui traitent des algorithmes de
pgcd. On peut bien sûr consulter le source de son système de calcul formel
lorsqu'il est disponible :
-
pour MuPAD sur un système Unix, depuis le
répertoire d'installation de MuPAD (en général /usr/local/MuPAD)
après avoir désarchivé le fichier lib.tar du répertoire share/lib
par la commande
cd share/lib && tar xvf lib.tar
on trouve les algorithmes de calcul de PGCD dans le répertoire
share/lib/lib/POLYLIB/GCD
- Pour l'algorithme EZGCD, je me suis inspiré de l'implémentation de
Singular (logiciel libre disponible à www.singular.uni-kl.de)
Sur le web on trouve quelques articles en lignes sur le
sujet en cherchant les mots clefs GCDHEU, EZGCD, SPMOD sur un moteur de
recherche, il y a par exemple une description un peu différente du pgcd
heuristique sur:
www.inf.ethz.ch/personal/gonnet/CAII/HeuristicAlgorithms/node1.html
et un article de comparaison de ces algorithmes
par Fateman et Liao (dont la référence bibliographique est
Evaluation of the heuristic polynomial GCD.
in: ISSAC pages 240–247, 1995). Quelques autres références :
-
K.O.Geddes et al "Alg. for Computer Algebra", Kluwer 1992.
- pour GCDHEU Char, Geddes, Gonnet,
Gcdheu: Heuristic polynomial gcd algorithm based on integer gcd computation,
in: Journal of Symbolic Computation, 7:31–48, 1989.
- pour SPMOD "Probabilistic Algorithms for Sparse Polynomials",
in: Symbolic & Algebraic Comp. (Ed E.W.Ng), Springer 1979, pp216,
5 Le résultant
Il s'agit d'un point de vue d'algèbre linéaire sur le PGCD. Considérons
deux polynômes A et B de degrés p et q et de pgcd D et
l'identité de Bézout correspondante :
avec degré(U)<q et degré(V)<p.
Imaginons qu'on cherche U et V en oubliant qu'il s'agit d'une
identité de Bézout, en considérant simplement qu'il s'agit d'un
problème d'algèbre linéaire de p+q équations (obtenues en développant
et en identifiant chaque puissance de X de 0 à p+q−1)
à p+q inconnues (les p coefficients de V et les q coefficients de U)
On sait que A et B sont premiers entre eux si et seulement si ce problème
d'algèbre linéaire a une solution pour D=1. Donc si le déterminant
du système est non nul, alors A et B sont premiers entre eux.
Réciproquement si A et B sont premiers entre eux, le système a
une solution unique non seulement avec comme second membre 1 mais avec
n'importe quel polynôme de degré inférieur p+q, donc le
déterminant du système est non nul.
Définition:
On appelle résultant de A et B le déterminant de ce système
(7). Il s'annule si et seulement si A et B
ne sont pas premiers entre eux (ont au moins une racine commune).
On appelle matrice de Sylvester la transposée de la matrice du système
(les inconnues étant par ordre décroissant les coefficients de U
et V)
M(A,B)= |
⎛
⎜
⎜
⎜
⎜
⎜
⎜
⎜
⎝ |
aa |
aa−1 |
… |
… |
a0 |
0 |
… |
0 |
0 |
aa |
… |
… |
a1 |
a0 |
… |
0 |
⋮ |
|
|
|
|
|
|
⋮ |
0 |
0 |
… |
|
|
|
|
a0 |
bb |
bb−1 |
… |
b0 |
0 |
0 |
… |
0 |
⋮ |
|
|
|
|
|
|
⋮ |
0 |
0 |
… |
|
|
|
|
b0 |
|
|
⎞
⎟
⎟
⎟
⎟
⎟
⎟
⎟
⎠ |
(cette matrice contient b=degré(B) lignes de coefficients
du polynôme A et a=degré(A) lignes de coefficients du
polynôme B)
Lien avec l'algorithme du sous-résultant (calcul de PGCD)
On peut calculer le déterminant avec la suite des restes de divisions
euclidiennes de la manière suivante, on part de la pseudo-division
de A par B :
bba−b+1 A=BQ+R
on effectue alors sur chaque ligne contenant les coefficients de A
la manipulation de ligne correspondante, c'est-à-dire multiplier
la ligne par bba−b+1 et soustraire (q0 fois la ligne
de B terminant dans la même colonne+q1 fois la ligne
de B terminant une colonne avant+...). Toutes les lignes
contenant les coefficients de A ont été remplacées par des lignes
contenant les coefficients de R. Ces lignes contiennent k zéros initiaux
avec k ≥ 1, ce qui permet de réduire le déterminant à celui
de la matrice de Sylvester de R et B (à un coefficient multiplicatif
près qui vaut bbk par rapport au précédent donc
bbk−b(a−b+1) par rapport au déterminant de départ).
On échange ensuite R et B ce qui change
éventuellement le signe et on continue en faisant les
divisions euclidiennes de l'algorithme du sous-résultant (cf.
Knuth où on utilise la matrice de Sylvester pour prouver que
l'algorithme du sous-résultant est correct). Rappelons que
le sous-résultant définit les suites Ak (A0=A, A1=B),
dk le degré de Ak, δk=dk−dk+1,
gk (g0=1, si k≠ 0, gk coefficient dominant de Ak)
hk (h0=1, hk+1=hk1−δk gk+1δk) et
gkδk−1+1 Ak−1 = Ak Qk+1 +
gk−1 hk−1δk−1 Ak+1
Théorème 3
Le résultant est égal au signe près au coefficient hk où k
correspond au reste Ak constant (en supposant que le résultant
soit non nul).
Preuve
La transcription de l'égalité précédente sur les
résultants donne par la méthode ci-dessus :
gk(δk−1+1)dkRes(Ak−1,Ak) |
= |
gkdk−1−dk+1 Res(gk−1 hk−1δk−1 Ak+1,Ak) |
|
= |
gkdk−1−dk+1 (gk−1 hk−1δk−1)dk
Res(Ak+1,Ak) |
On en déduit que :
|
Res(Ak−1,Ak) |
|
gk−1dk hk−1dk−1−1 |
|
= gkdk−1−dk+1−(δk−1+1)dk
hk−1δk−1dk+1−dk−1 Res(Ak+1,Ak) |
On observe que :
hk−1δk−1dk+1−dk−1 =hk−1(δk−1−1)(dk−1)
= |
⎛
⎝ |
hk−1δk−1−1 |
⎞
⎠ |
dk−1
= |
⎛
⎜
⎜
⎝ |
|
|
⎞
⎟
⎟
⎠ |
|
donc :
Res(Ak−1,Ak) |
|
gk−1dk hk−1dk−1−1 |
|
= |
gkdk−1−dk+1−(δk−1+1)dk
|
⎛
⎜
⎜
⎝ |
|
|
⎞
⎟
⎟
⎠ |
|
Res(Ak+1,Ak) |
|
|
= |
gkdk−1−dk+1−dk−δk−1
|
⎛
⎜
⎜
⎝ |
|
|
⎞
⎟
⎟
⎠ |
|
Res(Ak+1,Ak) |
|
|
= |
Res(Ak+1,Ak) |
|
gkdk+1 hkdk−1 |
|
Donc en valeur absolue
| |
|
|
= | |
Res(Ak−1,Ak) |
|
gk−1dk hk−1dk−1−1 |
|
| |
En prenant le rang k tel que Ak est constant, on a dk=0
et le résultant est égal à gkdk−1, on obtient donc :
Comme ici δk−1=dk−1, le terme de droite est |hk|.
Remarque
On peut calculer au fur et à mesure le signe du résultant en tenant
compte des degrés de Ak pour inverser l'ordre de Ak−1 et
Ak dans le résultant.
Utilisation
La valeur du résultant est très utile pour savoir si 2 polynômes
dépendant de paramètres sont premiers entre eux en fonction
de la valeur des paramètres. En effet, la fonction gcd d'un
logiciel de calcul formel calculera le PGCD par rapport à toutes
les variables en incluant les paramètres. En cherchant quand le résultant
s'annule en fonction des paramètres on obtient un autre type
d'information.
Exemple :
Chercher quand le polynône P=x3+px+q possède
une racine multiple en fonction de p et q. On calcule le
résultant de P et P' et on trouve 4p3+27q2, donc P
a une racine multiple si et seulement si 4p3+27q2=0.
Remarque :
On peut montrer que le résultant de P et P' est divisible
par le coefficient dominant de P, on appelle le quotient discriminant.
6 Les suites de Sturm
L'algorithme du sous-résultant appliqué à un polynôme sans
racine multiple P et à sa dérivée
permet, à condition de changer les signes dans la suite des restes,
de connaitre le nombre de racines réelles d'un polynôme dans un
intervalle. Ceci est trè utile pour par exemple simplifier des valeurs
absolues de polynômes dans un intervalle.
On définit donc la suite de polynômes A0=P, A1=P', ..., Ak,0
par :
Ai =
Ai+1 Qi+2 −
Ai+2
(8)
avec Ak, le dernier reste non nul, un polynôme constant puisque
P n'a pas de racine multiple. On utilise plutot l'algorithme du
sous-résultant que l'algorithme d'Euclide, il faut alors
s'assurer que les signes de Ai et Ai+2 sont opposés lorsque
Ai+1 s'annule quitte à changer le signe de Ai+2 en fonction
du signe du coefficient dominant de Ai+1, de la parité de
la différence des degrés et du signe du coefficient gh1−δ.
On définit s(a) comme étant le nombre de changements de signes
de la suite Ai(a) en ignorant les 0.
Alors le nombre de racines réelles de A0=P sur l'intervalle
]a,b] est égal à s(a)−s(b).
Preuve
On considére la suite des signes en un point : elle ne peut contenir
deux 0 successifs (sinon toute la suite vaudrait 0 en ce point en appliquant
(8), or Ak est constant non nul). Elle ne peut pas
non plus contenir +,0,+ ni -,0,- à cause de la convention de signe
sur les restes de (8). Donc une racine b
de Ai pour 0<i<k, n'influe pas sur la valeur de s au voisinage
de b (il y a toujours un changement de signe entre les positions
i−1 et i+1). Comme Ak est constant, seules les racines de A0=P
sont susceptibles de faire varier s. Comme A1=P', le sens de
variations de A0 au voisinage d'une racine de A0 est déterminé
par le signe de A1, donc les possibilités sont -,+ vers +,+
ou +,- vers -,-, ce qui diminue s d'une unité.
7 Exercices (PGCD, résultant, ...)
7.1 Instructions
Les instructions arithmétiques sont en général dans
la librairie standard.
Elles sont dans les menus
Math->Integer et Alg->Polynomes/Arit.polynomiale de Xcas
.
Certaines de ces instructions
sont dans la librairie numtheory
(en maple) ou
numlib
(en MuPAD)
(utilisez ?numtheory
ou ?numlib
pour avoir la liste
des fonctions de ces librairies),
pour éviter de taper numlib::
ou numtheory::
à chaque fois, on peut lancer en maple la commande
with(numtheory);
ou en MuPAD
export(numlib);
.
-
chrem
(en MuPAD numlib::ichrem
) :
restes chinois (entier)
divisors
(en maple numtheory::divisors
, en MuPAD
numlib::divisors
) :
liste des diviseurs d'un entier
gcd, lcm
: PGCD et PPCM
igcdex
: Bézout pour des entiers
iquo
et irem
quotient et reste de la division
euclidienne de deux entiers
isprime
test de primalité. En maple et MuPAD, il
s'agit d'un test de pseudo-primalité. En Xcas, utiliser
is_pseudoprime
pour effectuer un test plus rapide
de pseudo-primalité.
mods
: reste euclidien symétrique
nextprime
et prevprime
(en MuPAD numlib::prevprime
): nombre premier suivant
ou précédent
powmod(a,b,n)
(Xcas), a &^ b mod n
(Maple),
powermod(a,b,n)
(Mupad): calcul de ab (mod n ) par
l'algorithme de la puissance rapide
On peut représenter les polynômes par leur écriture symbolique
(par exemple x^2+1
), ou par des listes (représentation dense
ou creuse, récursive ou distribuée). Xcas, Maple et MuPAD
acceptent la représentation symbolique. Xcas propose deux types
de représentation, dense à une variable (poly1[ ]
), ou
distribuée (%%%{ }%%%
) et des instructions de conversion
(poly2symb
et symb2poly
) entre représentations.
MuPAD propose également une représentation non symbolique, cf.
la documentation ?poly
. L'intérêt d'une représentation
non symbolique est l'efficacité des opérations polynomiales, (et la
possibilité de chronométrer des opérations comme le produit
de 2 polynômes).
Les instructions qui suivent
utilisent la représentation symbolique, certaines acceptent
les autres représentations.
-
coeff
coefficient(s) d'un polynôme,
coeffs
liste des coefficients d'un polynôme
(à développer auparavant, en mupad on utilise coeff
)
content
contenu (pgcd des coefficients)
degree
degré
divide
division euclidienne,
gcd, lcm
PGCD et PPCM
gcdex
Bézout,
genpoly
(en MuPAD numlib::genpoly
):
crée un polynôme à partir de la
représentation z-adique d'un entier (utile pour le PGCD heuristique)
icontent
: contenu entier pour un polynôme à plusieurs
variables
indets
:
liste des noms de variables d'une expression
lcoeff
: coefficient dominant d'un polynôme
ldegree
: valuation
- (MuPAD)
multcoeffs
multiplie les coefficients d'un polynôme
- (MuPAD)
pdivide
pseudo-division
- (MuPAD)
poly(expr,[var],coeff)
crée un polynôme à partir de
l'expression symbolique expr
par rapport une variable ou
à une liste de variables var
, on peut indiquer dans quel anneau
vivent les coefficients (par exemple dans Z/13Z avec comme 3ème argument
IntMod(13)
)
primpart
: partie primitive d'un polynôme
quo
, rem
(xcas et Maple) quotient et reste euclidien
(en MuPAD utiliser les options Quo et Rem de divide
)
tcoeff
: coefficient de plus bas degré d'un polynôme
interp
(MuPAD interpolate
) : interpolation de Lagrange
convert(.,sqrfree)
(MuPAD polylib::sqrfree
) :
décomposition en facteurs n'ayant pas de racine multiples
convert(.,parfrac)
(MuPAD polylib::partfrac
) : décomposition en éléments simples
resultant
(MuPAD polylib::resultant
) :
calcule le résultant de 2 polynômes par rapport à une variable.
Notez aussi que le menu Exemples->poly->pgcd.xws
de Xcas contient
des exemples de programmes de calcul de pgcd de type Euclide.
7.1.3 Calculs modulo n
Pour travailler dans Z/nZ[X] :
-
avec
Xcas
on utilise la notation % comme en C, par
exemple gcd(P % 3, Q % 3). On peut aussi utiliser la notation
Maple en mode “syntaxe Maple” (cf. ci-dessous)
- avec Maple,
on utilise les formes inertes des instructions (qui renvoient l'instruction
non évaluée), dont le nom est le même que le nom de commande
habituel mais précédé par une majuscule, puis on indique
mod n
, par exemple Gcd(P,Q) mod 11
.
- avec MuPAD, on désigne le type des coefficients par exemple par
IntMod(13)
puis on construit des objets ayant des coefficients
de ce type (par exemple des polynômes, cf. infra). Par exemple
poly(x^2+1,[x],IntMod(13))
.
7.2 Exercices PGCD
- Calculez le pgcd de x202+x101+1
et sa dérivée modulo 3 et modulo 5. Conclusion?
- P=51x3−35x2+39x−115 et Q=17x4−23x3+34x2+39x−115.
Calculez le pgcd de P et Q modulo 5, 7 et 11. En déduire
le pgcd de P et Q par le théorème des restes chinois. Pourquoi
ne doit-on pas essayer modulo 17?
- Écrire un programme qui détermine le degré probable
du pgcd de 2 polynômes en une variable en utilisant le pgcd modulaire
(on considère le degré probable déterminé lorsqu'on trouve
deux nombres premiers réalisant le minimum des degrés trouvés)
- Détaillez l'algorithme du PGCD heuristique pour les
polynômes P=(x+1)7−(x−1)6 et sa dérivée. Comparez avec l'algorithme
d'Euclide naïf.
- Écrire un programme mettant en oeuvre le pgcd heuristique
pour des polynômes à une variable.
- On veut comprendre comment un logiciel de calcul formel calcule
On se ramène d'abord à une fraction propre (numérateur N de degré
inférieur au dénominateur),
Soit P=X3+1, calculez le PGCD de P et P', puis
deux polynômes U et V tels que:
N=UP+VP'
On décompose alors l'intégrale en deux morceaux :
Faites une intégration par parties sur le deuxième terme
et en déduire la valeur de l'intégrale du départ.
- Écrire un programme mettant en oeuvre l'algorithme modulaire
de calcul du PGCD.
- Écrire un programme qui détermine le degré probable du PGCD
par rapport à toutes les
variables de 2 polynôme à plusieurs variables
en utilisant l'évaluation en toutes les variables
sauf une.
- Calculer le pgcd par une méthode modulaire de
(xy−x+1)(xy+x2+1) et (xy−x−y)(xy−x+1)
7.3 Exercices (résultant)
-
Pour quelles valeurs de p le polynôme X5+X3−pX+1 admet-il
une racine multiple?
- Résoudre le système en éliminant successivement les
variables grâce au résultant :
|
⎧
⎨
⎩ |
a3+b3+c3 |
= |
8 |
a2+b2+c2 |
= |
6 |
a+b+2c |
= |
4 |
|
- Donner le détail des calculs avec Bézout de la décomposition
en éléments simples de :
puis calculer le coefficient de xn du développement en séries
entières de cette fraction en 0.
- Calculer
en utilisant le résultant pour calculer les logarithmes.
- En utilisant uniquement l'instruction de calcul de PGCD
déterminer la multiplicité maximale d'un facteur irréductible
de
x14−x13−14x12+12x11+78x10−54x9−224x8+116x7+361x6−129x5−330x4+72x3+160x2−16x−32
7.4 Exercice (Bézout modulaire)
Soit A et B deux polynômes à coefficients entiers et premiers
entre eux. Soit c ∈ Z* le résultant de A et B,
on va calculer les polynômes U et V de l'identité de Bézout
A U +
B V =
c , deg(
U)<deg(
B), deg(
V)<deg(
A)
(9)
par une méthode modulaire.
-
Montrer, en utilisant les formules de Cramer,
que les coefficients de U et V sont des entiers de
valeur absolue inférieure ou égale à la borne de Hadamard h de
la matrice de Sylvester de A et B (dont le déterminant est c,
le résultant de A et B). Calculer h en fonction
de la norme euclidienne de A, B et de leurs degrés.
- On calcule c ∈ Z* puis on
résoud (9) dans Z/pi Z[X] pour
plusieurs nombres premiers pi (choisis si possible inférieurs
à √231 pour des raisons d'efficacité), puis on calcule par le
théorème des restes chinois (9)
dans Z/Πpi Z[X]. Donner une minoration de
Πi pi faisant intervenir h qui permette de garantir
que l'écriture en représentation symétrique de (9)
dans Z/Πpi Z[X] est identique à (9) dans Z[X].
- Application : résoudre de cette manière l'équation de
Bézout pour
A=(X+1)4(X−3), B=(X−1)4(X+2)
(vous pouvez utiliser
sans justifications l'instruction de calcul de résultant,
des coefficients de Bézout dans Z/piZ[X] et
de reste chinois de votre logiciel).
- Écrire une fonction mettant en oeuvre cet algorithme.
- Que pensez-vous de l'intérêt de cet algorithme par rapport à
l'algorithme d'Euclide étendu dans Z[X]?
7.5 Exercice (Géométrie et résultants).
On cherche une relation algébrique entre les coordonnées de 4 points
A,B,C,D qui traduise le fait que ces 4 points sont cocycliques. Cette
condition étant invariante par translation, on cherche une
relation entre les 6 coordonnées des 3 vecteurs v1=(x1,y1),
v2=(x2,y2) et v3=(x3,y3)
d'origine A et d'extrémité B, C et D.
On peut supposer quitte à translater que le centre du cercle est
l'origine, on a donc 5 paramètres : le rayon du cercle R et les
4 angles des points sur le cercle θ0, θ1, θ2 et
θ3. La relation cherchée va s'obtenir en éliminant les
5 paramètres des expressions des 6 coordonnées en fonction de
ces paramètres.
-
Exprimer les 6 coordonnées en fonction de
R et a=tan(θ0/2), b=tan(θ1/2), c=tan(θ2/2)
et d=tan(θ3/2). On obtient ainsi 6 équations, par exemple les
deux premières sont de la forme
x1− F(R,a,b)= 0, y1− G(R,a,b)= 0
où F et G sont deux fractions rationnelles.
- En réduisant au même dénominateur, calculer 6
polynômes, fonction de
x1,y1,x2,y2,x3,y3,R,a,b,c,d, qui doivent s'annuler
pour que les points soient cocycliques
(Vous pouvez utiliser l'instruction
numer
pour obtenir le
numérateur d'une fraction rationnelle).
- Éliminer b des polynômes
contenant x1 et y1 et factoriser
le polynôme obtenu, faire de même avec c, x2 et y2
et d, x3 et y3, en déduire (en supposant que les points sont
tous distincts) 3 polynômes en x1,y1,x2,y2,x3,y3,R,a qui
s'annulent.
- Éliminer R et a, en déduire la relation cherchée.
- Vérifier que cette relation est équivalente à la nullité
de la partie imaginaire du birapport des affixes α, β, γ,
δ des 4 points :
8 Factorisation
On présente ici quelques algorithmes utilisés pour factoriser un polynôme
à coefficients entiers.
Pour un polynôme en une variable,
cele se fait en plusieurs étapes : on commence
par se ramener à un polynôme P dont tous les facteurs sont de multiplicité
un, ensuite on factorise P dans Z/pZ (par la méthode de Berlekamp
ou Cantor-Zassenhauss), puis on remonte à Z/pk Z
pour k suffisamment grand (en fonction de la borne de Landau sur les
facteurs de P), et on recombine enfin les facteurs modulaires pour
trouver les facteurs de P. Lorsque P à plusieurs variables, on utilise
une méthode analogue à celle permettant de trouver le pgcd de polynômes
à plusieurs variables.
Rappel
Le pgcd des coefficients d'un polynôme est appelé contenu de ce polynôme.
Un polynôme est dit primitif si son contenu est égal à 1.
8.1 Les facteurs multiples
Étant donné un polynôme P à coefficients entiers, on cherche à
écrire :
P=Πk=1n Pkk
où les Pk n'ont pas de facteurs multiples et sont premiers entre
eux deux à deux. Comme on est en
caractéristique 0, cela revient à dire que pgcd(Pk,Pk')=1
et pgcd(Pk,Pj)=1. Bien entendu
on va utiliser la dérivée de P dans l'algorithme de recherche des Pk :
Soit G le pgcd de P et de P'. On a :
G=Πk=1n Pkk−1,
en effet G divise P et P' :
W1= |
|
=Πk=1n Pk,
Z1= |
|
= |
|
kPk'Πj≠ k Pj |
il s'agit de vérifier que W1 et Z1 sont premiers entre eux. Soit F un
facteur irréductible du pgcd de W1 et Z1, alors F divise l'un des
Pk,
appelons Pl ce facteur. Comme F divise Πj≠ k Pj si k≠ l,
on en déduit que F divise le dernier terme de la somme de Z1, c'est-à-dire
que F divise lPl'Πj≠ l Pj donc F divise Pl' puisque
les Pk sont premiers entre eux. Donc Pl et Pl' ont un facteur
en commun, ce qui est contraire aux hypothèses.
On pose alors :
Y1=Z1−W1'= |
|
(k−1)Pk' Πj≠ k Pj |
On définit alors par récurrence des suites de polynômes Wn, Yn et
Gm par :
-
Gm=pgcd(Wm,Ym)
- Wm+1=Wm/Gm et Ym+1=Ym/Gm−Wm'
On va montrer que Pm=Gm. Commençons au rang n=1, on voit que P1
divise Y1 (puisqu'il est commun à tous les Πj≠ k Pj car
k>1) et divise W1. Et c'est le seul facteur commun, car tout autre
facteur irréductible serait un diviseur d'un Pl pour l>1, donc diviserait
(l−1)Pl'Πj≠ l,j>1 Pj, donc diviserait Pl'.
Le raisonnement en un rang quelconque est identique, les polynômes sont
donnés par :
Gm=Pm, Wm=Πk>=m Pk,
Ym=Σk>m (k−m)Pk'Πj≥ m, j≠ k Pj
Lorsqu'on programme cet algorithme, le test d'arrêt est Gm=1.
Square-free factorisation (Algorithme de Yun)
Argument: un polynôme primitif P à coefficients entiers (ou dans Z[i]
ou dans un corps de caractéristique nulle).
Valeur renvoyée: une liste de polynômes Pm telle que
P=Πk=1n Pkk.
-
Initialiser la liste résultat à liste vide.
- Initialiser W à P et Y à P'. Calculer le pgcd G de W et Y
et simplifier W et Y par leur pgcd puis poser Y=Y−W'.
- Boucle infinie.
- Calculer le pgcd G de W et Y. Si G=1, on renvoie la liste
résultat sinon ajouter G à la liste résultat.
- Simplifier W et Y par G, puis poser Y=Y−W' et passer à
l'itération suivante.
Remarque : lorsqu'on veut factoriser un polynôme à coefficients modulaires,
il faut aussi se ramener à un polynôme sans facteurs multiples mais
on ne peut pas utiliser cet algorithme tel quel car la caractéristique
du corps n'est pas nulle.
Exemple :
Factorisation sans facteurs multiples de
P(X)=(X3−1)(X+2)2(X2+3)3.
En mode interactif avec un logiciel de calcul formel, effectuons l'étape
d'initialisation :
W:=normal((x^3-1)*(x+2)^2*(x^2+3)^3);
Y:=diff(W,x);
G:=gcd(W,Y);
x^5+2*x^4+6*x^3+12*x^2+9*x+18
W:=normal(W/G);
x^6+2*x^5+3*x^4+5*x^3+-2*x^2+-3*x-6
Y:=normal(Y/G);
Y:=normal(Y-diff(W,x));
5*x^5+8*x^4+3*x^3+-5*x^2+-8*x-3
On vérifie bien que W=(x+2)*(x3−1)*(x2+3) est le produit
des facteurs Pi. On entame maintenant la boucle :
G:=gcd(W,Y);
x^3-1 -> P1
Y:=normal(Y/G);
W:=normal(W/G);
Y:=normal(Y-diff(W,x));
2*x^2+4*x
G:=gcd(W,Y);
x+2 -> P2
Y:=normal(Y/G);
W:=normal(W/G);
Y:=normal(Y-diff(W,x));
0
G:=gcd(W,Y);
x^2+3 -> P3
puis W=1 et Y=0 et le prochain G vaut 1, on a bien trouvé tous
les facteurs Pi.
8.2 Factorisation en une variable
On suppose maintenant qu'on veut factoriser un polynôme P sans facteur
multiple (et primitif). En général on commence par simplifier P par
ses facteurs linéaires (détectés avec l'algorithme présenté dans le
premier article de cette série). On commence par chercher un nombre premier p
tel que P dans Z/pZ conserve le même degré et reste sans facteur
multiple (donc pgcd(P,P')=1 dans Z/pZ), ce qui est toujours
possible (il suffit de prendre p plus grand que le plus grand entier
apparaissant dans l'algorithme du sous-résultant pour calculer
le pgcd de P et P' dans Z).
Convention
Tous les polynômes ayant leurs coefficients dans un corps fini sont
supposés avoir comme coefficient dominant 1 lorsque le choix
existe (par exemple les facteurs d'un polynôme modulo p).
8.2.1 Factorisation dans Z/pZ[X]
On suppose qu'on a un polynôme P à coefficients dans Z/pZ sans
facteur multiple. Il s'agit de factoriser P dans Z/pZ[X].
Il existe essentiellement deux stratégies, l'une commence par factoriser par
groupes de facteurs de même degré puis casse les facteurs et l'autre
plus directe à base d'algèbre linéaire modulaire (méthode de Berlekamp).
Dans les deux cas, on utilise le fait que si F est un polynôme,
alors les polynômes à coefficients dans Z/pZ
modulo F forment un anneau A qui est aussi un espace vectoriel
sur Z/pZ de dimension le degré de F
(si F est irréductible, alors A est un corps).
On s'intéresse alors aux propriétés de l'application
φ: x ∈ A ↦ xp.
On observe d'abord que cette application est une application linéaire.
Cela découle du petit théorème de Fermat pour φ(λ x)=λ
φ(x) et de la formule de Newton et de la primalité de p pour
φ(x+y)=φ(x)+φ(y).
Calcul de φ
Pour mettre en oeuvre ces algorithmes, on commence par déterminer la matrice
de l'endomorphisme φ: x ↦ xp dans Z/pZ[X] (mod P(X) )
muni de sa base canonique { 1, X,...,Xdeg(P)−1 }.
8.2.2 Distinct degree factorization
Cette méthode consiste à détecter les groupes de facteurs
ayant un degré donné (distinct degree factorization). Si nécessaire,
on utilise ensuite un autre algorithme pour casser ces groupes.
On utilise ici les propriétés des itérées de l'application linéaire
φ sur des espaces vectoriels de corps de base Z/pZ.
On va déterminer le produit Pk de tous les facteurs de P de degré k
en calculant le pgcd de P et de X(pk)−X dans Z/pZ[X].
Pour k=1, Xp−X est le produit des X−k pour tout k∈ Z/pZ
par le petit théorème de Fermat (kp=k (mod p )), donc le pgcd
de P et de X(p1)−X dans Z/pZ[X] est le produit des facteurs
de P de degré 1.
Pour k>1, le raisonnement se généralise de la manière suivante : on
considère un facteur irréductible F(X) de P de degré k et le corps
K=(Z/pZ)[Y] (mod F(Y) ). Le corps K est un corps fini, c'est
aussi un espace vectoriel sur Z/pZ de dimension k, donc K possède
pk éléments et K* est un groupe multiplicatif à pk−1 éléments,
donc tout élément de K* vérifie l'équation xpk−1=1 donc
tout élément de K vérifie x(pk)=x. En particulier pour
x=Y (mod F(Y) )
on trouve que Y(pk)=Y (mod F(Y) ) donc F(X) divise X(pk)−X
dans Z/pZ.
Réciproquement, si on se donne un facteur irréductible F qui divise
Xpk−X, soit K le corps correspondant à F,
alors le noyau de l'application linéaire
x ∈ K ↦ xpk−x ∈ K
est K tout entier, car Y=Ypk (mod F )
entraine (Y2)(pk)=Y2 pk=(Ypk)2=Y2 (mod F ) et de même
pour les autres puissances de Y qui, avec Y0=1 également dans le
noyau, forment une base de l'espace vectoriel K sur Z/pZ. Donc le
nombre d'éléments de K est inférieur ou égal au degré du polynôme
Xpk−X (puisque X(pk)−X est divisible par
X−x pour tout x∈ K),
donc le degré de F est inférieur ou égal à k.
Donc Pk est égal au pgcd de P/Πj<k Pj avec Xpk−X.
Algorithme distinct degree factorization
Argument: un polynôme P à coefficients entiers
sans facteur multiple et primitif.
Valeur renvoyée: la liste L des produits des facteurs irréductibles et du
degré correspondant de P (ordonné par ordre croissant de degré).
On commence par initialiser L à vide et un polynôme auxiliaire Q à X
(il contiendra les valeurs de Xpk−X (mod P )), on fait une boucle
indéfinie sur k commençant à 1 et incrémenté de 1 à chaque itération
-
Si k est strictement plus grand que le degré de P divisé par 2,
on rajoute le couple (P,degre(P)) à L et on renvoie L
- On remplace Q par Qp (mod P ) en utilisant le calcul de φ
modulo P
- On calcule le pgcd G de Q−X et de P.
- Si G vaut 1, on passe à l'itération suivante
- On rajoute le couple (G,k) à la liste L et on remplace P
par le quotient de P par G.
Exemple :
Factorisation en degré distincts de (X3+X+1)(X4−X+1) dans
Z/5Z. On regarde d'abord si P reste sans facteur multiple après
réduction modulo 5.
P:=normal((x^3+x+1)*(x^4-x+1) mod 5);
gcd(P,diff(P,x));
1 mod 5 -> ok P est sans facteur multiple
P1:=gcd(P,(x^5-x)mod 5);
(1 mod 5)*x -2 mod 5 -> P1
P:=normal(P/P1);
P2:=gcd(P,(x^(5^2)-x)mod 5);
1 mod 5 -> pas de facteur de degre 2
P3:=gcd(P,(x^(5^3)-x)mod 5);
(x^6+2*x^5+x^2+x+2) mod 5
Donc P admet 3 facteurs dans Z/5Z: un de degré 1 (x−2) et
deux de degré 3 (dont le produit est x6+2x5+x2+x+2).
Le même calcul dans Z/7Z donne
P:=normal((x^3+x+1)*(x^4-x+1) mod 7);
gcd(P,diff(P,x));
1 mod 7 -> ok P est sans facteur multiple
P1:=gcd(P,(x^7-x)mod 7);
1 mod 7
P2:=gcd(P,(x^(7^2)-x)mod 7);
1 mod 7
P3:=gcd(P,(x^(7^3)-x)mod 7);
(x^3+x+1) mod 7
donc P possède un facteur de degré 3 modulo 7, donc le facteur restant
de degré 4 est forcément irréductible.
On remarque sur cet exemple que 7 est plus intéressant que 5, car
la factorisation modulo 7 donne moins de facteurs (à recombiner pour
trouver la factorisation dans Z) et la factorisation est
complète modulo 7 alors que modulo 5 il faut casser le facteur de
degré 6 en deux facteurs de degré 3. La plupart des algorithmes
de factorisation effectuent la factorisation en degré distinct
modulo plusieurs entiers (ce qui peut de plus être parallélisé)
et choisissent le meilleur.
8.2.3 La méthode de Cantor-Zassenhaus
Cet algorithme sert à casser des groupes de facteurs de même degré,
c'est une méthode probabiliste. On suppose donc qu'on a un produit P
d'au moins deux facteurs irréductibles de degré d à casser.
Soit D l'un des polynômes irréductibles de degré d à coefficients
dans Z/pZ, et soit K=Z/pZ[Y] (mod D(Y) ), on a :
Xpd−X=Πα ∈ K (X−α)
puisque le corps K possède pd éléments tous racines
de l'équation Xpd=X.
On considère un polynôme T non constant, et le polynôme
Tpd−T. En remplaçant X par T ci-dessus, on en déduit :
Tpd−T=Πα ∈ K (T−α)
Donc pour tout élément β ∈ K=Z/pZ[Y] (mod D(Y) ), on a
(Tpd−T)(β)=Πα ∈ K (T(β)−α)=0
Donc Tpd−T est divisible par Xpd−X (puisque toutes les racines
du second sont racines du premier), donc est divisible par tout polynôme
irréductible de degré inférieur ou égal à d à coefficients dans Z/pZ.
Comme
et que ces trois facteurs sont premiers entre eux, on en déduit que tout
polynôme irréductible de degré inférieur ou égal à d à coefficients dans
Z/pZ divise l'un des trois facteurs ci-dessus. Pour casser P, l'idée
consiste alors à calculer le pgcd de P et Tpd−1/2−1
pour un polynôme pris au hasard. On sait que P divise le produit des
3 termes de (10), et on espère que les facteurs irréductibles
de P ne diviseront pas tous le même terme.
On va montrer que si T est un polynôme de degré ≤ 2d−1 choisi au hasard,
la probabilité que deux facteurs irréductibles de P ne divisent pas
Tpd−T est proche de 0.5. Soient donc A et B deux facteurs
irréductibles de P de degré d. D'après l'identité de Bézout, tout
polynôme T de degré ≤ 2d−1 s'écrit de manière unique sous la forme :
avec degre(U ≤ d−1) et degre(V ≤ d−1) et réciproquement
une combinaison linéaire de cette forme est un polynôme de degré ≤ 2d−1.
Choisir T au hasard revient donc à choisir un couple (U,V) de polynômes
à coefficients dans Z/pZ au hasard et
de manière indépendante. D'autre part, A et B étant de degré d, on
sait que dans K=Z/pZ[Y] (mod D(Y) ) ces polynômes admettent d racines.
Soit donc α [respectivement β] une racine de A [resp. B]
dans K. Alors A divise Tpd−1/2−1
si et seulement si T(α )pd−1/2=1 (et de même pour
B et β) car Tpd−1/2−1 a ses coefficients dans
Z/pZ (et non dans K).
En appliquant (11), A divise Tpd−1/2−1
si et seulement si :
Le premier terme de cette égalité est une constante égale à 1 ou -1,
le second a une probabilité proche de 0.5 (égale à pd−1/2pd)
de valoir 1 ou -1 car, comme A est irréductible,
V(α) décrit K lorsque V décrit les
polynômes de degré ≤ d−1.
De même, B a une probabilité proche de 0.5 de diviser
Tpd−1/2−1, et ces 2 probabilités sont indépendantes
puisque U et V le sont, donc la probabilité que soit A soit B divise
divise Tpd−1/2−1 est proche de 0.5.
Algorithme de Cantor-Zassenhaus
Argument: Un polynôme P à coefficients dans Z/pZ de degré k
dont tous les facteurs irréductibles sont de degré d.
Valeur renvoyée: la liste des facteurs irréductibles de P.
-
Si k=d renvoyer une liste contenant P.
- Déterminer un polynôme T aléatoire de degré inférieur ou égal
à 2d−1 et de coefficient dominant 1. Calculer le pgcd D de P
et de T(pd−1)/2−1. Si le degré de T est égal à 0 ou à k
recommencer cette étape.
- Appeler récursivement cet algorithme avec T et P/T et
renvoyer la liste réunion des deux listes renvoyées.
Exemple :
Cassons le polynôme de degré 6 obtenu dans l'exemple précédent
(modulo 5). Donc P:=(x6+2*x5+x2+x+2) (mod 5 ) et d=3, 2d−1=5,
(pd−1)/2=62.
On choisit au hasard un polynôme de degré inférieur ou égal à 5, par exemple
T=x4−x3+x+1, puis on calcule T62 modulo P ce qui donne
(x5+x3+x2+1) (mod 5 ) puis le pgcd de T62−1 et de P
qui vaut x3+x+1 (mod 5 ), on a donc cassé P en deux.
En prenant T:=x4−x3+x+2, on trouve T62=1 (mod P ), donc
ce T n'aurait pas permis de casser P.
8.2.4 La méthode de Berlekamp
Cette méthode permet de factoriser un polynôme sans facteurs multiples,
elle peut aussi servir à casser des groupes de facteurs de même degré.
Ici on travaille dans l'anneau des polynômes à coefficients dans Z/pZ
modulo le polynôme P et on s'intéresse au noyau de φ−Id
(où φ: x ↦ xp). On
suppose que P=Πj=1n Fj où les Fj sont irréductibles et
premiers entre eux. On va montrer que le noyau de φ−Id est
composé des polynômes Q tels que Q (mod Fj ) est constant
(dans Z/pZ) pour tout j.
Si Q (mod Fj )=sj ∈ Z/pZ, alors Qp (mod Fj )=sjp=sj, donc
par le théorème des restes chinois, Q=Qp (mod P ).
Réciproquement, si
Qp−Q=0 (mod P ), en utilisant la factorisation :
Xp−X= Πj ∈ Z/pZ (X−j)
on en tire P divise Qp−Q=Πj ∈ Z/pZ (Q(X)−j),
donc Fj divise l'un des facteurs et Q(X) (mod Fj ) ∈ Z/pZ.
Le noyau de φ −Id
est donc un espace vectoriel de dimension n, le nombre
de facteurs irréductibles de P et possède donc pn éléments
(en effet pour tout n uplet de sj, on peut construire un polynôme
Q du noyau par le théorème des restes chinois en posant Q(mod Fj )=sj).
L'intérêt du noyau de φ−Id est qu'on peut le calculer sans connaitre
les Fj. Une fois ce calcul fait, voyons comment on peut remonter
aux Fj. On connait déjà la dimension du noyau donc le nombre de facteurs
irréductibles. De plus, on remarque que le polynome constant est un
élément du noyau qu'on appellera T1, on note alors T2,...,Tn les
autres polynômes du noyau. Ensuite, on calcule le pgcd de P avec T2−jT1
pour j∈ Z/pZ. On sait que T2=s2,j (mod Fj ), donc ce pgcd
est égal au produit des facteurs Fj tels que s2,j=jT1. L'un au moins
des pgcd calculés est non trivial car sinon T2=T1 (mod Fj ) pour
tout j donc T2=T1. Si on a de la chance tous les s2,j seront
distincts et les pgcd non triviaux de P avec T2−jT1 donneront les Fk.
Sinon il faudra continuer avec T3−jT1 etc.
Exemple :
Revenons sur la factorisation de P:=(x6+2x5+x2+x+2) (mod 5 ).
Commençons par calculer la matrice de φ dans la base
{ 1,x,x2,...,x5}. On a évidemment φ(1)=1 et
φ(x)=x5, puis φ(x2)=x10=x5+x4−2x3+x (mod P ),
puis en multipliant par x5 et en divisant par P,
φ(x3)=−x4+2x3, de la même manière on obtient
φ(x4)=−x5+2x4+x3−x2−2 et φ(x5)=x3+x2−x.
La matrice de φ est donc :
M= |
⎛
⎜
⎜
⎜
⎜
⎜
⎜
⎝ |
|
1 |
0 |
0 |
0 |
−2 |
0 |
0 |
0 |
1 |
0 |
0 |
−1 |
0 |
0 |
0 |
0 |
−1 |
1 |
0 |
0 |
−2 |
2 |
1 |
1 |
0 |
0 |
1 |
−1 |
2 |
0 |
0 |
1 |
1 |
0 |
−1 |
0 |
|
|
⎞
⎟
⎟
⎟
⎟
⎟
⎟
⎠ |
On calcule ensuite le noyau de φ−Id (comme matrice à coefficients
dans Z/5Z), on obtient une
base du noyau en prenant par exemple les vecteurs (−1,0,0,0,0,0)
et (0,0,−1,−1,0,−1). Donc le polynôme P possède 2 facteurs dans
Z/5Z[X]. Pour déterminer les facteurs, on calcule le pgcd de P
avec le polynôme T2−s où T2=−x5−x3−x2 correspond au 2ème
vecteur de la base du noyau. On obtient pour s=0 un pcgd non trivial
(x3+x+1), ce qui permet de calculer les 2 facteurs. Si on avait
essayé d'autres valeurs de s, pour s=1 on obtient comme pgcd 1, pour
s=2 on trouve le 2ème facteur x3+2x2−x+2.
8.2.5 Remontée (Hensel)
Il s'agit de passer d'une factorisation de P dans Z/pZ[X] à une
factorisation de P dans Z/pk Z[X], la méthode est analogue à celle
de l'algorithme EZGCD de calcul de pgcd de polynômes.
On suppose donc que
P=Πj=1n Pj (mod p )
où les Pj sont premiers entre eux deux à deux dans Z/pZ.
Il s'agit de trouver des polynômes Pj,k=Pj (mod p ) tels que
P=Πj=1n Pj,k (mod pk )
Commençons par le cas k=2. On pose
Pj,2=Pj+pQj=Pj (mod p )
On a alors :
P |
= |
Πj=1n Pj,2 (mod p2 ) =Πj=1n (Pj+pQj) (mod p2 ) |
|
= |
Πj=1n Pj + p |
|
Qj Πk≠ j Pk (mod p2 ) |
|
Donc :
On est ramené à résoudre une identité de Bézout généralisée.
On montrera dans l'appendice le :
Théorème 4 (Identité de Bézout généralisée)
Soit P1, ..., Pn (n≥ 2) des polynômes premiers entre eux deux
à deux modulo p. Alors pour tout polynôme Q, il existe des polynômes
Q1, ..., Qn tels que :
On a donc réussi à remonter l'égalité P=Π Pj (mod p ) à
P=Π Pj,2 (mod p2 ). Le passage de P=Π Pj,l (mod pl )
à P=Π Pj,l+1 (mod pl+1 ) est identique, on a :
Pj,l+1=Pj,l+plQj
où les Qj sont les solutions de l'identité de Bézout généralisée avec :
Lorsqu'on programme cet algorithme (cf. l'appendice),
on calcule une fois pour toutes les
solutions de l'identité de Bézout pour Q=1, et on multiplie par Q.
Algorithme de remontée de Hensel linéaire
Arguments: Un polynôme P à coefficients entiers, la liste L={ Pj }
de ses facteurs dans Z/pZ[X]
Valeur renvoyée: la liste des facteurs de P dans Z/pl Z[X]
On calcule la borne de Landau-Mignotte6
pour les facteurs de P, on multiplie
par le coefficient dominant de P et on calcule l tel que pl est
strictement plus grand que deux fois cette quantité. On calcule
aussi les polynômes Qj de l'identité de Bézout généralisée pour Q=1
Puis on fait une boucle pour k variant de 2 à l:
-
On détermine P−Πj Pj (mod pk ), on divise par pk−1
et on place le résultat dans Q
- On multiplie les polynômes Qj de l'identité de Bézout
généralisée (correspondants au polynôme 1) par Q
et on détermine le reste de la division euclidienne de Q Qj par Pj,
on multiplie par pk−1 et on ajoute le résultat à Pj.
Il existe une version quadratique de cette méthode. On passe alors de
P=Π Pj,l (mod pl ) à P=Π Pj,2l (mod p2l ). Pour
cela, il faut trouver les polynômes Qj solutions de l'équation :
|
|
Qj Πk≠ j Pk,l=Q (mod pl ) |
Pour l=1, c'est l'identité de Bézout généralisée, mais ce n'est plus le
cas pour l>1. En fait, on résout cette égalité en remontant l'identité
de Bézout quadratiquement, plus précisément pour trouver les Sj
solutions de
|
|
Sj Πk≠ j Pk,2l=Q (mod p2l ) |
on pose Sj=Qj+pl Rj, il s'agit donc de trouver les Rj solutions de
|
|
(Qj+pl Rj) Πk≠ j Pk,2l=Q (mod p2l ) |
soit :
|
|
Rj Πk≠ j Pk,l
= |
|
(mod pl ) |
on en déduit les Rj.
Algorithme de remontée de Hensel quadratique
Arguments et valeur renvoyée identiques à l'algorithme de remontée de Hensel
linéaire ci-dessus.
On commence comme dans le cas linéaire par calculer les coefficients
de l'identité de Bézout généralisée pour Q=1 et la valeur de l telle
que p2l soit supérieur à deux fois la borne de Landau des facteurs
de P fois le coefficient dominant de P.
On fait une boucle sur k variant de 1 à l:
-
On calcule P−Πj Pj (mod p2k ), on divise par p2k−1
et on place le résultat dans Q
- On multiplie par Q les polynômes Qj de l'identité de Bézout
généralisée (avec comme second membre le polynôme 1),
on calcule le reste euclidien du résultat par Pj (modulo p2k−1),
on multiplie par p2k−1 et on ajoute à Pj (avec les notations
précédentes, on passe ainsi des Pj,2k−1 aux Pj,2k)
- Si k=l on renvoie la liste des Pj
- On calcule 1−Σj Qj Πk≠ j Pk (mod p2k ), on
divise par p2k−1 et on place le résultat dans Q
- On multiplie par Q les polynômes Qj de l'identité de Bézout,
généralisée et on calcule le reste euclidien du résultat par
Pj (modulo p2k−1), on multiplie par p2k−1 et
on ajoute à Qj (ce qui ajuste les polynômes Qj qui vérifient
maintenant l'identité de Bézout modulo p2k)
Remarque
Pendant l'étape de remontée de Hensel, une optimisation classique
consiste à tester la divisibilité dans Z du polynôme P par le
facteur lifté Pj (7)
lorsqu'il n'a pas subi de modification pendant 2 étapes successives
(autrement dit lorsque Pj (mod pl )=Pj (mod pl+1 ) (ou
(mod p2l ) pour le lift quadratique). Si la division
est exacte, on obtient un facteur irréductible de P dans Z.
On recalcule alors la borne de Landau de P/Pj pour diminuer
le nombre d'itérations à effectuer dans cette étape.
Exemple :
Reprenons le polynôme P(X)=(X3+X+1)(X4−X+1)
et supposons qu'on ait choisi de le factoriser modulo 5 puis
de remonter. On a 3 facteurs
a=x−2, b=x3+x+1 et c=x3+2x2−x+2. Si on développe P, on trouve 6
coefficients non nuls de valeur absolue 1,
on peut calculer la borne de Landau-Mignotte correspondante
sur les coefficients d'un facteur entier : 25 (√(6)+1)
soit un peu plus de 110, il suffit donc d'effectuer 3 étapes de
remontée linéaire (54=625>111/2).
On commence par trouver 3 polynômes A, B, C tels que
A(x3+x+1)(x3+2x2−x+2)+B(x−2)(x3+2x2−x+2)+ |
|
|
+C(x−2)(x3+x+1) |
= |
1 (mod 5 ) |
On commence par résoudre D(x3+2x2−x+2)+C(x−2)(x3+x+1)=1(mod 5 ),
on trouve C=2x2−2 et D=−2x3−2x2+2x+1. Puis on calcule
A et B en résolvant E(x3+x+1)+F(x−2)=1 qui donne E=1 et
F=−x2−2x qu'on multiplie par D, donc A=D et B=2x5+x4+2x3−2x.
Ce qui donne l'identité de Bézout généralisée.
Passons aux calculs de remontée. On a abc=x7−4x5+5x4+−9x3−x2−4
et P=x7+x5+x3−x2+1, donc Q=(P−abc)/5=x5−x4+2x3+1. On pose
alors
a1 |
= |
a+5 (QA (mod a ))(mod 25 ), |
b1 |
= |
b+5 (QB (mod b )) (mod 25 ), |
c1 |
= |
c+5 (QC (mod c )) (mod 25 ) |
donc :
a1= a+5 × (−2), b1=b+5 × 0,
c1=c+5 × (2x2−x)
En principe, on continue encore 2 itérations de la même manière.
La 2ème itération donne :
Q=(P−a1 b1 c1)/25= 6x5−3x4+7x3+3x2−2x+1
a2 |
= |
a1+25 (QA (mod a )) (mod 125 ), |
b2 |
= |
b1+25 (QB (mod b )) (mod 125 ), |
c2 |
= |
c1+25 (QC (mod c )) (mod 125 ) |
donc :
a2=a1 +25(−1)=x−37, b2=b1=b, c2=c1+25(x2+1)
=x3+37x2−6x+27
On peut aussi observer que b1=b, ceci laisse à penser que b est
un facteur de P dans Z ce qu'on vérifie en effectuant la
division euclidienne de P par b=x3+x+1. Comme elle tombe
juste, on est ramené à factoriser x4−x+1 et donc à remonter
la factorisation de ac. La borne de Landau diminue à 8(√3+1)
puisque le degré est 4 et la norme euclidienne du polynôme est √3.
Il suffit alors de remonter dans Z/125 Z au lieu de Z/625 Z
(on gagne ainsi une itération).
8.2.6 Combinaison de facteurs
Lorsqu'on a les facteurs de P dans Z/pkZ[X] avec pk plus grand
que le produit du coefficient dominant de P multiplié par la borne
de Landau-Mignotte sur les coefficients de P, on commence par
tester la divisibilité dans Z[X] de P par chaque facteur trouvé
multiplié par le coefficient dominant de P. Si la division est
exacte, on a un facteur irréductible, mais si elle n'est pas exacte
il peut se produire qu'un facteur irréductible de P dans Z[X] soit un
produit de deux, voir plusieurs, facteurs modulaires. Il faut
donc tester la divisibilité de P dans Z[X] par toutes les combinaisons
possibles de produits de facteurs modulaires (toujours multiplié par
le coefficient dominant de P). Cette étape peut être exponentiellement
longue si le nombre de facteurs modulaires est grand et si par
exemple P est irréductible, bien que les cas soient très rares.
Algorithme de recombinaison
Arguments: un polynôme à coefficients entiers, primitif et sans facteur
multiple P de coefficient dominant pn,
la liste L des facteurs de P dans Z/pl Z[X] pour
l assez grand et pl
Valeur de retour: la liste F des facteurs de P dans Z.
Initialiser F à vide, initialiser le nombre de facteurs à combine c
à 1, entamer une boucle infinie :
-
Si c est strictement supérieur au cardinal de L divisé par 2,
ajouter le quotient de P par le produit des facteurs de F à F
et retourner F
- Initialiser un vecteur v=(v1,...,vc) à c composantes à
la valeur (1,...,c)
- Boucle indéfinie intérieure :
-
Faire le produit des facteurs de F d'indice v, multiplier
par pn dans Z/pl Z, écrire le facteur en représentation symétrique,
le rendre primitif et tester si c'est un facteur de P dans Z.
- Si on a trouvé un facteur, le rajouter à la liste F et supprimer les
indices de v de la liste L, terminer cette boucle intérieure.
- Sinon, incrémenter v de la manière suivante:
On fait une boucle sur un index m initialisé à la taille de v,
diminuant de 1 à chaque itération: on ajoute 1 à l'élement de v
d'indice m, si l'élément obtenu est inférieur ou égal
au cardinal de L+m−n, on arrête cette boucle, sinon on passe
à l'itération suivante. Si m=0 à la fin de la boucle, v
ne peut pas être incrémenté.
- Si v ne peut être incrémenté, on incrémente c et on termine
la boucle intérieure.
- Sinon on fait une boucle à nouveau
sur m en partant de la valeur actuelle incrémentée de 1, et tant
que m≤ n on pose vm=vm−1+1. Puis on passe à l'itération
suivante de la boucle intérieure.
Il existe différentes méthodes
qui améliorent la complexité de cette étape :
-
La recherche des degré possibles de facteurs fondée sur
la factorisation en degrés distincts pour différents nombres premiers
permet d'éviter des tests de division si une combinaison de facteurs
est d'un degré exclu par la factorisation pour d'autres nombres premiers.
- Le test de divisibilité du coefficient dominant ou du coefficient
constant permet aussi d'éviter des divisions complètes de polynômes.
Mais ces astuces n'évitent pas l'énumération de toutes les combinaisons
possibles de facteurs et donc la complexité exponentielle. Lorsque
les combinaisons d'un petit nombre de facteurs (par exemple 3)
échouent, les systèmes récents utilisent
l'algorithme knapsack de Van Hoeij basé sur l'algorithme LLL
(recherche de base d'un réseau ayant des vecteurs de petite norme)
qui permet d'eliminer complètement cette complexité exponentielle.
Exemple :
Toujours le même exemple, il nous restait deux
facteurs dans Z/125 Z, le facteur x3+x+1 ayant été
détecté comme un facteur de P=x7+x5+x3−x2+1 dans Z.
On teste chacun des facteurs a2=x−37 et c2=x3+37x2−6*x+27
séparément, sans succès. On les multiplie alors modulo 125,
ce qui donne x4−x+1 en représentation symétrique qui est bien
un facteur de P (donc un facteur irréductible).
8.3 Factorisation à plusieurs variables
Comme pour le PGCD en plusieurs variables, on se ramène d'abord en
une variable, en général on évalue toutes les variables sauf celle
correspondant au degré partiel le plus faible. On factorise ensuite
en une variable puis on remonte. A chaque étape de remontée, il peut
être à nouveau nécessaire de combiner plusieurs facteurs. Différentes
stratégies existent, comme pour le PGCD : factorisarion heuristique
(avec reconstruction z-adique), remontée variable par variable
ou toutes les variables en même temps comme dans EZGCD.
On va présenter ici plus en détails l'algorithme de factorisation heuristique.
Soit P un polynôme en X1,...,Xn à coefficients entiers avec n>1,
on choisit une des variables par exemple Xn, qu'on notera X dans la suite.
On considère P comme un polynôme en X1,...,Xn−1 à coefficients dans
Z[X]. On suppose que P est primitif (quitte à extraire
son contenu qui est dans Z[X]). On calcule ensuite
P(z) pour un entier z tel que8 |z| ≥ 2|P|+2. On factorise P(z)
dans Z[X1,...,Xn−1] :
P(
z)(
X1,...,
Xn−1)=
c(
z) Π
j=1k pj(
X1,...,
Xn−1)
(12)
où c est le contenu du polynôme P(z) (comme polynôme en n−1
variables à coefficients entiers). Il s'agit de reconstruire les facteurs
de P à partir des pj et de c. Deux problèmes se posent alors,
celui de la recombinaison possible de plusieurs facteurs pj pour
obtenir un facteur irréductible de P, et l'existence d'un facteur entier du
contenu c à combiner avec un ou plusieurs pj pour obtenir ce
facteur irréductible. Plus précisément, si Pk est un facteur
irréductible de P, on a :
Pk(
z)=
d(
z) Π
certains j pj, où
d(
z) divise
c(
z)
(13)
On a le :
Théorème 5
Soit P(X1,...,Xn−1,X) un polynôme à coefficients
entiers ayant au moins 2 variables. On suppose que P est primitif
vu comme polynôme en les variables X1,...,Xn−1
à coefficients dans Z[X].
Il existe une majoration C du contenu |c(z)| de P évalué en X=z
(plus précisément on peut trouver un entier C tel que c(z) divise
C).
Il existe un nombre fini de z tels que l'un des facteurs irréductibles
Pk de P évalué en X=z soit
réductible (c'est-à-dire tels que (13) admette
plusieurs facteurs pj distincts)
Preuve
Pour déterminer C, on remarque que les facteurs du contenu de P(z)
sont des facteurs communs des coefficients de P évalués en z
vu comme polynôme en X1,...,Xn−1 à coefficients dans Z[X].
Donc c(z) divise le générateur de l'idéal engendré par ces coefficients
(ce générateur est un polynôme de Z[X] qui est constant car on a supposé
P primitif), on peut aussi dire que deux au moins des coefficients
dans Z[X] de P sont premiers entre eux, alors c(z) divise le
coefficient de l'identité de Bézout de ces 2 coefficients vu
comme polynômes en X.
Considérons maintenant un facteur irréductible Pk de P de degré d
par rapport à X. Pour X1,...,Xn−1 fixés, on factorise Pk sur C :
Pk(X)=pk Πj=1d (X−zj)
On va maintenant se restreindre à un domaine des X1,...,Xn−1 sur
lequel les zj ont une dépendance analytique par rapport à X1,...,Xn−1.
Pour cela on veut appliquer le théorème des fonctions implicites pour
déterminer zj au voisinage d'une solution donnée. On calcule donc
la dérivée P'k de Pk par rapport à X. On sait que P n'a pas
de facteurs multiples, donc Pk et Pk' sont premiers entre
eux, donc d'après l'identité de Bézout, il existe un polynôme non nul D
dépendant de X1,...,Xn−1 et deux polynômes U et V dépendant
de X1,...,Xn−1,X tels que :
U Pk + V Pk' = D
Si D(X1,...,Xn−1) ne s'annule pas, on va pouvoir appliquer le théorème
des fonctions implicites. On se fixe x1,..,xn−1,
on calcule dans C les racines zj du polynôme P(x1,..,xn−1,X)
pour une solution zj telle que P(x1,..,xn−1,zj)=0,
comme D est non nul, on a P'(x1,...,xn−1,zj)≠ 0, donc on peut
écrire au voisinage de (x1,..,xn−1)
zj=zj(X1,...,Xn−1), P(X1,...,Xn−1,zj)=0
avec des fonctions zj analytiques.
Si D est constant, D ne s'annule pas,
sinon quitte à permuter les variables, on peut supposer que
le degré de D par rapport à X1 est non nul.
On peut alors se restreindre à une zone X1 >> X2 >> .. >> Xn−1 >> 1
où D sera non nul ce qui permet de suivre analytiquement les zj.
Supposons maintenant qu'il existe un nombre infini de z tels Pk(z)
soit réductible. Alors il existe un ensemble infini Z
de ces valeurs de z pour lesquels l'un des facteurs à coefficients
entiers fj de Pk(z) correspond à un même
sous-ensemble R des racines zj de Pk et à un même contenu
c (puisqu'il y a un nombre fini de combinaisons possibles des
racines en facteur et un nombre fini de diviseurs possibles
du contenu de Pk). Pour z ∈ Z, on a :
fj(X1,...,Xn,z)=c Πl ∈ R (z−zj),
fj ∈ Z[X1,...,Xn−1]
Soit L(X) le polynôme obtenu par interpolation de Lagrange
en cardinal(R)+1 points z de Z, égal à fj en X=z.
Pour des raisons de degré, on a :
L=c Πl ∈ R (X−zj)
donc L est un facteur de P.
De plus L est un polynôme en X1,...,Xn−1,X à coefficients
rationnels (par construction). Ceci vient en contradiction avec l'hypothèse
Pk irréductible, car on a construit un facteur de Pk à coefficients
rationnels L de degré strictement inférieur.
Corollaire
Pour z assez grand, la reconstruction z-adique de c(z) pj(z) est
un polynôme dont la partie primitive est un facteur irréductible de P.
Preuve du corollaire
On prend z assez grand pour que tous les facteurs irréductibles de P
évalués en z aient un seul facteur polynomial (i.e. soient de la forme
d(z)pj(z)). Quitte à augmenter z, on peut supposer que
|z|> 2 C L où C est la majoration de |c(z)| et L est la borne
de Landau sur les facteurs de P. Alors la reconstruction z-adique
de c(z)pj(z) est c(z)/d(z)Pj, donc sa partie primitive est un
facteur irréductible de P.
Algorithme de factorisation heuristique à plusieurs variables
Argument: un polynôme P primitif en au moins 2 variables.
Valeur renvoyée: les facteurs irréductibles de P
Choisir la variable X par rapport à laquelle P est de plus bas degré puis
factoriser le contenu de P vu comme polynôme à coefficients dans Z[X].
Initialiser un entier z à 2|P|+2 (où |P| est le plus grand coefficient
entier de P en valeur absolue) et une liste L à la factorisation de
du contenu de P.
Boucle indéfinie :
-
Si P=1 renvoyer la liste L des facteurs de P.
- Tant que pgcd(P(z),P'(z))=0 incrémenter z de 1.
- Factoriser P(z)=c(z)Π pj
- Pour tous les facteurs pj, déterminer le polynôme Pj tel que
c(z)pj=Pj(z) par remontée
z-adique (avec les coefficients de Pj écrit en représentation
symétrique, de valeur absolue plus petite que |z|/2). Tester si
la partie primitive de Pj divise P. Si oui, rajouter un facteur
irréductible à la liste L, et diviser P par ce facteur.
- Augmenter z, par exemple remplacer z par la partie entière de
√2z.
8.4 Preuve de l'identité de Bézout généralisée
Elle se fait par récurrence. Pour n=2, c'est l'identité de Bézout usuelle.
Pour passer
du rang n−1 au rang n, on isole Pn dans l'identité à résoudre :
|
⎛
⎜
⎜
⎝ |
|
|
Qj (Π1 ≤ k ≤ n−1,k≠ j Pk) |
⎞
⎟
⎟
⎠ |
Pn +
Qn Πk≤ n−1 Pk =Q (mod p ) |
Comme Pn est premier avec Πk≤ n−1 Pk, en appliquant Bézout,
on trouve deux polynômes Qn et Rn tels que :
Rn Pn +
Qn Π
k≤ n−1 Pk =
Q (mod
p )
(14)
Il reste à résoudre
|
|
Qj Π1 ≤ k ≤ n−1,k≠ j Pk=Rn (mod p ) |
ce que l'on peut faire par hypothèse de récurrence.
8.5 Algorithme de Bézout généralisé
Arguments: une liste P1,...,Pn de polynômes premiers entre eux 2 à 2
et un polynôme Q à coefficients dans Z/pZ
Valeur renvoyée: la liste de polynômes Q1,...,Qn tels que
On peut commencer par calculer le produit de tous les Pk puis faire une
boucle sur j pour calculer les produits des Pk pour k≠ j en divisant
le produit complet par Pj (on fait ainsi n−1 multiplications et
n divisions au lieu de n(n−1) multiplications).
Boucle indéfinie sur n décrémenté de 1 par itération :
-
Si n=2, on rajoute à la liste résultat les polynômes
Q1 et Q2 de l'algorithme de Bézout usuel et on renvoie la liste
- Sinon, on calcule les polynômes Rn et Qn vérifiant (14),
on rajoute Qn en début de liste, on remplace Q par Rn.
Remarquons que lorsque nous utiliserons cet algorithme, Q sera la différence
entre deux polynômes de même degré (le degré de P) et de même coefficient
dominant 1, on peut donc
remplacer les Qi par le reste euclidien de Qi par Pi sans
changer l'égalité.
8.6 Pour en savoir plus
Pour factoriser des polynômes ayant des coefficients dans des
extensions algébriques, il existe un algorithme assez simple,
l'algorithme de Trager, qui n'est pas forcément le plus performant
(la recherche est encore active dans ce domaine), cf. le livre de
Henri Cohen pp. 142-144.
Pour factoriser sur des corps finis, on peut consulter la thèse
de Bernardin disponible sur le web (http://www.bernardin.lu
).
On peut aussi consulter le code source de Mupad, les routines
de factorisation se trouvent dans le répertoire lib/POLYLIB/FACLIB
après avoir désarchivé la lib.tar
. Le point d'entrée pour factoriser
des polynômes à plusieurs variables sur Z est le fichier
mfactor.mu
, on observera que l'algorithme utilisé par Mupad est
assez différent de celui qu'on a détaillé dans la section précédente.
8.7 Exercices (factorisation des polynômes)
-
Déterminer le nombre de racines de −x7+x4+12x−5 comprises
entre 0 et 6 (en utilisant les suites de Sturm, on donnera les
détails des calculs).
- Écrire un programme calculant la suite de Sturm d'un polynôme
supposé squarefree (on peut tester avec
sqrfree
), en utilisant
l'algorithme d'Euclide.
- Trouver les facteurs de degré 1 s'ils existent de
3x5+25x4+67x3+77x2+55x+13 en remontant ses racines
dans Z/pZ[X] pour p premier bien choisi.
- Factoriser le polynôme x5+x+1 par la méthode
de Berlekamp.
- Calculer avec un logiciel les valeurs numériques des racines
complexes de P(x)=x5+x+1. Trouver les combinaisons de racines
dont la somme est entière (aux arrondis près). En déduire la factorisation
en facteurs irréductibles sur Z de P.
- Factorisation numérique sur C. Écrire un programme
qui calcule une racine d'un polynôme à coefficients complexes
en utilisant une méthode itérative de type méthode de Newton
(avec éventuellement un préfacteur lorsqu'on débute la recherche).
Les polynômes seront représentés par la liste de leurs coefficients
et l'évaluation faite par la méthode de Horner.
Trouver ensuite toutes les racines du polynôme en éliminant la
racine trouvée (toujours avec Horner). Trouver les combinaisons
de racines correspondant à un facteur à coefficients entiers.
- Même question pour les facteurs de degré 2 d'un polynôme à coefficients
réels sans racines réelles en utilisant la méthode de Bairstow décrite
ci-dessous.
On cherche un facteur F=x2+sx+p de P, on calcule le quotient et le reste
de la division P=FQ+R par une méthode de type Horner, il s'agit de
rendre R (vu comme un vecteur à 2 composantes) nul. On calcule
donc ∂s,p R (en cherchant le quotient et le reste
de xQ et Q par F, pourquoi?) et on pose :
(s,p)n+1=(s,p)n− λ (∂s,p R)−1 R (s,p)n
où λ est un préfacteur compris entre 0 et 1 et ajusté à 1
lorsqu'on est proche du facteur.
- Soit p un entier premier et P un polynôme à
coefficients dans Z/pZ. On a la relation
gcd(Xpk−X,P) = |
|
f,
f irréductible |
En utilisant cette relation,
déterminer les degrés des facteurs de
(x3+x+1)(x4+x+1)
modulo 5 et 7 (sans utiliser la commande factor).
Peut-on en déduire que x3+x+1 et
x4+x+1 sont irréductibles sur Z?
- Utiliser les options “verbose” de votre logiciel de calcul formel
pour factoriser x202+x101+1 et vérifiez que vous avez compris
la méthode utilisée.
- Montrer que 2x+x2y+x3+2x4+y3+x5 est irréductible sur Z
sans utiliser l'instruction factor à 2 variables (on pourra factoriser
pour quelques valeurs de x ou de y)
- Que se passe-t-il lorsqu'on exécute l'algorithme de Yun
dans Z/nZ?
- Déterminer les degrés des facteurs de (x3+x+1)(x4+x+1) modulo 5
et 7 (sans utiliser la commande factor). Peut-on en déduire que x3+x+1 et
x4+x+1 sont irréductibles sur Z?
- Utiliser les options “verbose” de votre logiciel de calcul formel
pour factoriser x202+x101+1 et vérifiez que vous avez compris
la méthode utilisée.
- Montrer que 2x+x2y+x3+2x4+y3+x5 est irréductible sur Z
sans utiliser directement l'instruction factor
(on pourra factoriser pour quelques
valeurs de x ou de y)
9 Intégration
9.1 Introduction
Que peut-on espérer d'un système de calcul formel lorsqu'il s'agit
de calculer une primitive? Tout d'abord, on peut espérer qu'il
sache résoudre ce que l'on donne en exercice à nos étudiants!
Ceci suppose donc de connaitre quelques méthodes classiques, par
exemple: intégration de polynômes (!), polynômes multipliés par exponentielle
ou/et fonctions trigonométriques, de polynômes trigonométriques par
linéarisation, de fractions rationnelles,
de fractions trigonométriques, de fractions de racines carrées de
polynômes du second ordre, de fonctions s'y ramenant par une ou plusieurs
intégrations par parties ou par
changement de fonction (par exemple reconnaissance de formes F(u)u' )
ou par changement de variables, etc.
Mais au-delà de ces méthodes (qui ont l'avantage de la rapidité mais
tiennent parfois plus de la
recette de cuisine que de l'algorithme...), on peut se demander
si la primitive d'une fonction donnée peut ou non s'exprimer en terme
des fonctions “élémentaires”. Par exemple, tout le monde “sait”
que la fonction ex2 n'admet pas de primitive “simple”, encore
faut-il donner un sens mathématique précis à cette affirmation.
Ceci nécessite de donner une définition rigoureuse du terme fonction
élémentaire. On peut alors appliquer un algorithme développé
par Risch (pour les extensions dites transcendantes, obtenue par ajout
des fonctions exponentielle et logarithme)
qui permet de répondre à la question :
il s'agit vu de très loin d'une extension de l'algorithme d'intégration
des fractions rationnelles.
Cet article se décompose en deux parties principales :
-
la section 9.2 présente les définitions de fonctions
élémentaires, de tour de variables, et donne deux théorèmes,
le théorème de structure de Risch qui permet d'écrire une fonction
contenant des exponentielles et des logarithmes comme une fonction
élémentaire par rapport à une tour de variable, et
le théorème de Liouville qui donne la forme que peut prendre
une primitive d'une fonction élémentaire lorsqu'elle est aussi élémentaire.
- la section 9.3 décrit l'algorithme d'intégration de Risch
permettant de décider si une fonction élémentaire donnée possède
ou non une primitive élémentaire et de la calculer dans le premier
cas. Nous ne présentons ici l'algorithme de Risch que pour les extensions
transcendantes pures (ln et exp).
Le lecteur intéressé par le cas des extensions algébriques
pourra consulter la thèse de Trager. Pour les extensions
plus générales (incluant en particulier les fonctions
tangente, arctangente), la référence est le livre de Bronstein
donnée en section 9.4.
9.2 Fonctions élémentaires
9.2.1 Extensions transcendantes, tour de variables
On se donne une expression f(x) dépendant de la variable x que l'on
souhaite intégrer par rapport à x. L'algorithme de Risch s'applique à
cette expression si on peut l'écrire comme une fraction rationnelle à
plusieurs variables algébriquement indépendantes
x, f1(x), f2(x,f1(x)), ...,
fn(x,f1(x),f2(x,f1(x)),...,fn−1(x,f1(x),...,fn−2(x)))
où les fi sont soit l'exponentielle soit le logarithme d'une fraction
rationnelle (le corps de base appelé aussi corps de
constantes ici est soit C, soit une extension algébrique de Q ou une
extension algébrique d'un corps de fractions rationnelles s'il
y a des paramètres).
On appelle tour de variables
la suite des x,f1,...,fn (chaque étage est donc une exponentielle
d'une fraction rationnelle ou le logarithme d'une fraction rationnelle
dépendant des étages précédents)
et on dira que f est une fonction élémentaire
par rapport à cette tour de variables.
L'intérêt de l'écriture d'une expression sous forme de tour est
qu'elle est stable par dérivation :
si on dérive par rapport à x
une fonction élémentaire dépendant d'une tour de variables, on obtient encore
une fonction élémentaire dépendant de la même tour de variables.
Autrement dit, l'ensemble des fonctions élémentaires pour une tour
fixée est un corps différentiel.
Exemples:
-
ex2 est bien dans ce cas, pour n=1, f1
est l'exponentielle de x2 qui est algébriquement indépendant
de x. Les fonctions (2x2−1)ex2
ou x/(ex2−1) sont aussi élémentaires par rapport à
la tour de variables {x,ex2 }.
- x ln(x) exp(x) est élémentaire par rapport à la tour
{ x, ln(x), exp(x)}, mais aussi par rapport à la tour
{ x, exp(x), ln(x)}.
- xex ln(x) est élémentaire, en prenant n=2, f1=ln(x)
et f2=ex f1.
- xn=enln(x), où n est un paramètre, convient avec
comme tour {x, ln(x), en ln(x)
- eln(x) ne convient pas car il n'est pas algébriquement
indépendant de x,ln(x) mais on peut le réécrire sous une forme
acceptable puisque eln(x)=x.
- eln(x)/2 ne convient pas non plus car son carré est égal à x.
Une réécriture ne suffit pas, cet exemple est bien sûr une extension
algébrique et non transcendante.
Dans la suite, on va s'intéresser aux tours de variables dans lesquelles
on a effectué des simplifications évidentes.
On élimine les ln∘ exp de la manière suivante :
si fk=ln(gk), on regarde si gk vu comme fraction
en f1,...,fk−1 possède un facteur fjm (avec m ∈ Z)
lorsque fj=exp(gj) est une exponentielle.
Si c'est le cas, on a fk= m gj + ln(gk/gjm). On change
alors de tour en remplaçant fk par fk=ln(gk/gjm)=fk−mgj.
On élimine aussi les exp∘ ln, si
fk=exp(gk), pour j<k si fj est un logarithme,
on regarde si cj=∂fjgk|fj=0 est un entier, si
c'est le cas on remplace fk par fk=fk/gkcj.
Exemples:
|
→ |
−x2 + ln(ex2+1) |
e3 ln(x)+ln(x)2+5 |
→ |
x3 eln(x)2+5 |
9.2.2 Théorème de structure de Risch
On voit donc qu'il est nécessaire de disposer d'un algorithme
pour décider si des exponentielles et logarithmes sont
algébriquement indépendants. Cet algorithme est basé sur
un théorème de structure dû à Risch :
Théorème 6
Soit f=ln(g(x)) le logarithme d'une fonction élémentaire
g par rapport à une tour de variables T, alors soit f
est algébriquement indépendant des variables de T, soit f est
élémentaire et plus précisément combinaison linéaire rationnelle
des logarithmes et des arguments des exponentielles de la tour T.
Soit f=exp(g) l'exponentielle d'une fonction élémentaire g
par rapport à une tour de variables T, alors soit f
est algébriquement indépendante des variables de T, soit
il existe n tel que fn soit élémentaire par rapport à T
(on peut alors appliquer le cas précédent à ng=ln(fn))
Démonstration :
Commençons par le cas de l'exponentielle. On considère le polynôme minimal
de f=exp(g) :
an fn+...+a0=0, an ≠ 0 , a0 ≠ 0
où les ai sont des fractions rationnelles en T. On dérive
et on applique f'=g'f :
(an'+n an g') fn + ... + ( ak' + kak g')fk +... =0
c'est un multiple du polynôme minimal donc il existe une fraction rationnelle
C (par rapport à la tour de variables) telle que :
∀ k, (ak'+k ak g') = C ak
Comme an≠ 0, cela entraine an'/an+ng'=C. Le coefficient
constant a0 est aussi non nul, donc a0'/a0=C et
n g' = a0'/a0 − an'/an ⇒ ng=ln( |
|
) + k |
où k est constant, donc fn=exp(ng)=ek a0/an est élémentaire.
Passons au cas du logarithme, supposons que f=ln(g) dépende
algébriquement de la tour T, on va commencer par montrer que
f est élémentaire. On écrit :
an fn+...+a0=0
où les ai sont des fractions rationnelles en T. On dérive en
appliquant f'=g'/g :
an' fn + (n an f' + an−1')fn−1 ... + a1 f'+a0 '
Comme f' est une fraction rationnelle en T, le polynôme
an' Xn + (n an f'+an−1') Xn−1+...+ a1 f'+a0' qui annule f
doit être un multiple du polynôme minimal de f, il existe donc
une fraction rationnelle C par rapport à T telle que :
an' = C an (n an f'+an−1') = C an−1 ...
On en déduit f' :
donc il existe une constante c telle que :
donc f est élémentaire par rapport à la même tour T que g.
Montrons maintenant qu'un logarithme f=ln(g) qui est élémentaire
par rapport à une tour de variable T est combinaison linéaire à
coefficients rationnelles des logarithmes et des arguments
des exponentielles de T9.
Soit X la dernière variable de la tour T.
On factorise maintenant le numérateur et le dénominateur de g en
Πj Pjj où les Pj sont sans facteurs multiples et
premiers entre eux 2 à 2 (par rapport à X), il existe
C indépendant de X tel que :
|
g=C |
|
Pjj ⇒
ln(g)=ln |
(C)+ |
|
j ln(Pj)
(15) |
Alors f'=ln(C)'+Σj j Pj'/Pj donc ΠPj f' est un
polynôme en X.
Soit N/D la fraction irréductible représentant f, on a :
on vient donc de montrer que :
|
⎛
⎜
⎜
⎝ |
|
Pj |
⎞
⎟
⎟
⎠ |
|
est un polynôme en X
(16) |
Soit P un facteur irréductible de D de multiplicité
k tel que D=Pk Q (donc P premier avec Q, mais P est aussi
premier avec N car f=N/D est irréductible). Alors en simplifiant
numérateur et dénominateur par Pk−1, on a :
|
⎛
⎜
⎜
⎝ |
|
Pj |
⎞
⎟
⎟
⎠ |
N' P Q − N (kP'Q+PQ') |
|
Pk+1 Q2 |
|
est un polynôme en X.
(17) |
On en déduit, après simplification d'au plus un facteur P au dénominateur
avec l'un des Pj, que Pk divise
N' P Q − N (kP'Q+PQ') donc P divise P'. Ceci n'est possible
que si P=1 (et donc le dénominateur de f est égal à 1)
ou si la variable X est une exponentielle et P=X.
Montrons que ce deuxième cas est en fait exclus:
en effet si P=X=exp(Y) est une exponentielle, on a alors
D=Xk et Q=1.
Comme P'=Y'X, (17) devient :
|
⎛
⎜
⎜
⎝ |
|
Pj |
⎞
⎟
⎟
⎠ |
|
est un polynôme en X |
Comme X ne divise pas N, N possède donc un coefficient constant
a0 non nul. Le coefficient constant de N'−kNY' est a0'−ka0 Y'.
Si ce terme était nul alors a0'=ka0 Y' donc a0=c exp(kY)=cXk
or a0 ne dépend pas de X donc c=0 donc a0=0, absurde.
Donc X ne divise pas N'−kNY'.
Comme Xk+1 divise ΠPj X (N' − k N Y' ), on en déduit que
Xk divise un des Pj. Donc k=1 et Pj=XQj.
Revenons maintenant à (15), on a :
f=ln(g) = ln(C)+j ln |
(XQj)+ |
|
l ln(Pl) |
on dérive :
on voit qu'il n'est plus nécessaire de multiplier f' par Pj
pour avoir un polynôme, multiplier par Qj suffit, plus précisément
|
⎛
⎜
⎜
⎝ |
|
Pl |
⎞
⎟
⎟
⎠ |
Qj |
|
est un polynôme en X.
|
donc Xk+1 divise
(Πl ≠ jPl ) Qj X (N' − k N Y' )
ce qui est impossible.
Donc D=1 dans tous les cas et on a f=N. Donc
f'=N'=ln |
(C)'+ |
|
j Pj'/Pj
est un polynôme par rapport à X |
On en déduit que les Pj ne dépendent pas de X sauf si
X est une exponentielle et Pj=X.
Dans les deux cas N' ne
dépend pas de X donc le polynôme N est de degré 0 ou 1 en X
(si X est une exponentielle, N est forcément de degré 0)
-
Si X=exp(Y) est une exponentielle (avec Y élémentaire
ne dépendant pas de X), alors f=N est indépendant de X.
On retire jY à f et on divise g par Xj
(en posant j=0 si aucun des Pj n'est égal à X),
qui devient indépendant de X, on conserve ainsi l'égalité f=ln(g)
mais avec une variable de moins dans la tour de variables par
rapport à laquelle f et g sont élémentaires.
- Si X n'est pas une exponentielle, N=cX+d avec c
dans le corps de constantes, et d indépendant de X.
Si X=x, on a g=exp(cx+d) qui n'est rationnel que si
c=0. On a alors d donc f et g constants.
Si X=ln(Y) est un logarithme (avec Y élémentaire
ne dépendant pas de X), alors ∀ j, Pj=1 donc g est élémentaire
indépendante de X.
On a alors :
f=N=cln(Y)+d = ln(g)
avec c dans le corps des constantes, d et g élémentaires
indépendants de X. On cherche maintenant la fonction
élémentaire d. Cette fonction n'est pas le logarithme d'une
fonction élémentaire en général car c n'est pas forcément entier,
mais d' a les mêmes propriétés que la dérivée du logarithme
d'une fonction élémentaire.
On peut donc reprendre le même raisonnement mais avec une variable de moins
dans la tour de variables. Si la tour qu'on a choisie est normalisée,
alors Y ne contient au numérateur et au dénominateur aucune puissance
d'une exponentielle d'une variable de la tour donc le polynôme Pj
du cas précédent ne peut provenir de Y ce qui entraine que j
est bien entier dans le cas précédent (bien que c ne le soit
pas forcément).
Après avoir fait une récurrence sur le nombre de variables de la tour,
on a donc f qui s'exprime comme combinaison linéaire à coefficients
entiers des arguments gk des variables exponentielles fk=exp(gk)
de la tour et à coefficients a priori quelconque des variables logarithmes
fl=ln(gl) de la tour :
f = |
|
jk gk + |
|
xl ln(gl) = ln(g) |
Comme g est élémentaire, h=g/Πk exp(gk)jk
est élémentaire de logarithme Σl xl ln(gl) .
Montrons que si les arguments des ln sont des polynômes
sans facteurs multiples, alors
les xl sont entiers. Rappelons
que les ln(gl) sont algébriquement indépendants, on peut donc
construire des polynômes irréductibles Il par rapport aux variables
de la tour tels que Il divise une fois gl mais ne divise pas les gk
précédents. Soit h=Πj ∈ Z Pjj la factorisation
sans facteurs multiples de h. On dérive alors ln(h) ce qui donne :
où Πj Pjj est la décomposition sans facteurs multiples
de h. Comme Il divise un et un seul des Pj on en déduit
que xl est égal au j correspondant et est donc entier.
(Remarque: si on n'impose pas aux arguments des logarithmes
d'être des polynômes sans facteurs carrés,
on obtiendrait ici des coefficients rationnels).
En pratique:
On peut effecter l'algorithme de la manière suivante :
Remarque
On n'est pas obligé de se limiter aux seules fonctions logarithmes
et exponentielles, l'essentiel est de pouvoir tester l'indépendance
algébrique des expressions créées. Pour éviter d'avoir à introduire
des exponentielles et logarithmes complexes dans une expression
réelle, on peut autoriser
par exemple des extensions en tangente ou en arctangente.
9.2.3 Théorème de Liouville
On a vu que la dérivée d'une fonction élémentaire dépendant
d'une tour de variables est une fonction élémentaire dépendant
de la même tour de variables.
Réciproquement, supposons qu'une fonction élémentaire admette
une primitive qui soit élémentaire, c'est-à-dire qu'elle doit
être une fraction rationelle par rapport à une tour de variables
mais pas forcément identique à celle de départ. Alors, si une telle
écriture existe, à des termes logarithmiques près, elle
ne peut dépendre que de la même tour de variables, plus précisément
on a le théorème de Liouville :
Théorème 7
Soit f une fonction élémentaire par rapport à une tour de variables T
et un corps de constantes K admettant une primitive élémentaire F. Alors
il existe un nombre fini de constantes c1,...,cn et de fonctions
élémentaires v1,...,vn par rapport à T avec comme corps de constantes
une extension algébrique K' de K tel que F − Σk ck ln(vk)
soit élémentaire par rapport à T et K.
Preuve:10
Soit f élémentaire de tour T1 (corps K) et
F sa primitive supposée élémentaire de tour T2 et de corps K'
une extension algébrique de K.
On commence par rajouter après les élements de T1 les
élements nécessaires de T2 pour obtenir une tour T par rapport
à laquelle f et F sont élémentaires (plus précisément F sera
élémentaire quitte à autoriser des puissances fractionnaires
des variables exponentielles de T1). Le théorème de structure
de Risch permet de faire cela, en effet on regarde pour chaque
élément de T2 s'il est algébriquement indépendant des éléments
de T1 ou non. S'il l'est, on le rajoute à la tour T, s'il
ne l'est pas alors dans le cas d'un logarithme il est élémentaire
et dans le cas d'une exponentielle, une de ses puissances est
élémentaire. Donc F est bien une fraction rationnelle par rapport
aux éléments logarithmiques de T1, aux racines n-ième
des éléments exponentiels de T1 et à des éléments de T2
dans cet ordre (le corps des constantes étant K').
Première étape:
Commençons par les éléments restant de T2. Soit Xk l'élément
au sommet de la tour T. La dérivée f de F par rapport à Xk
ne dépend pas de Xk. Donc soit F ne dépend pas de Xk et
on passe à la variable suivante, soit Xk=ln(vk) est un logarithme
et F=ck ln(vk)+dk avec ck ∈ K' et vk et dk
indépendants de Xk. S'il
n'y a pas d'autres éléments restants de T2, on passe à la 2ème étape.
Sinon soit Xk−1 la variable suivante
(juste en-dessous de Xk dans la tour).
En dérivant, on a :
Supposons que vk dépende de Xk−1, on fait alors un raisonnement
analogue à celui de la preuve du théorème de structure de Risch, en décomposant
vk en produit/quotient de facteurs sans multiplicités vk=ΠPjj
et en écrivant dk=N/D on a :
est un polynôme en Xk−1. On en déduit comme précédemment que
D=1, N'=dk' est indépendant de Xk−1. Comme on a supposé que
vk dépend de Xk−1, Xk−1=exp(Yk−1) est alors une
exponentielle, N=dk ne dépend pas de Xk−1 et l'un des Pj=Xk−1
(sinon tous les Pj seraient constants en Xk−1 donc vk aussi).
On élimine alors la variable Xk−1 en écrivant
ln(vk)=jYk−1+ln(wk), avec Yk−1 et wk élémentaires et
indépendants de Xk−1.
Si vk est indépendant de Xk−1, alors dk' aussi donc
soit dk est indépendant de Xk−1 et on passe à la variable
suivante, soit Xk−1 est un logarithme et
dk=ck−1ln(vk−1)+dk−1.
En continuant pour toutes les variables restantes de T2, on obtient
avec d et vk élémentaires pour T1 (avec exponentielles
modifiées en en prenant une racine n-ième) et K'.
Deuxième étape
Il s'agit de montrer que pour les exponentielles, il n'est en fait pas
nécessaire de prendre de racines n-ième. La compréhension
de cette étape demande
un peu de familiarité avec l'algorithme de Risch (cf. infra).
On va faire la preuve pour la variable au sommet de la tour T1 si
c'est une exponentielle. On verra dans le déroulement
de l'algorithme de Risch que pour les autres variables, il y a
appel récursif de l'algorithme d'intégration, donc traiter
la variable au sommet suffira.
Soit donc exp(Y) la variable au sommet de la tour T1, on note
X=exp(Y/n) la racine n-ième de cette variable qui est utilisée
pour exprimer F=Σck lnvk + N/D comme une fraction
rationnelle en X alors que f=F' est une fraction rationnelle en Xn.
On a donc :
Σck |
|
+ |
|
'
=f=fraction rationnelle en (Xn) |
Notons que le fait que X soit une exponentielle est essentiel,
car par exemple l'intégrale d'une fraction rationnelle dépendant de xn
comme x3 ou 1/(x3−1) ne s'exprime pas en fonction de x3.
On traite d'abord la partie polynomiale généralisée de f en Xn:
Son intégrale est un polynôme généralisé, éventuellement dépendant
de X, soit Σj∈ Z Aj Xj. On dérive, et on obtient
pour k non multiple de n, Ak Y/n+Ak'=0 dont Ak=0 est
solution. La partie polynôme généralisé ne dépend donc que de Xn.
On effectue aussi les intégrations par parties pour réduire le
dénominateur de f à un polynôme sans facteurs multiples (réduction
de Hermite), ce qui se fait en introduisant des fractions rationnelles
en Xn uniquement. Reste la partie logarithmique. On utilise le critère
du résultant, les coefficients des logarithmes sont les racines
ck du polynôme en t
ResX (D,N−tD')
où ces racines doivent être indépendantes de x (puisque F existe)
et les vk correspondants sont égaux à
gcd(D,N−ck D')
Or comme X est une exponentielle, D' est un polynôme en
Xn, de même que D et N, donc vk est un polynôme
en Xn.
Troisième étape
Il reste enfin à montrer que seuls les ck et vk nécessitent
une extension algébrique de K. Ceci est encore une conséquence
de l'algorithme de Risch, la construction
de la partie polynomiale (éventuellement généralisée) et de la
partie fractionnaire ne font en effet intervenir que des coefficients
dans le corps K.
9.3 L'algorithme de Risch
On suppose dans la suite qu'on s'est ramené à une fraction rationnelle
par rapport à une tour de variables (où on a effectué les simplifications
évidentes ln∘ exp, ainsi que exp∘ ln, dans le
premier cas en extrayant les facteurs évidents en les variables
précédentes exponentielles, dans le deuxième cas en extrayant la
partie linéaire à coefficient entier en les variables logarithmes
précédentes).
On note X la variable au sommet de la tour et N0/D0 l'écriture
de la fonction élémentaire comme fraction irréductible avec
N0 et D0 polynômes en X.
Exemples
∫(2x2+1) ex2 |
X=ex2 |
N0=(2x2+1) X, D0=1 |
|
X=ln(x) |
N0=xX, D0=x+X |
La première étape va consister à se ramener à un dénominateur sans facteurs
multiples. Elle est analogue au cas des fractions
rationnelles de x et est basée sur l'identité de Bézout entre
P et P' vu comme polynômes en la variable du haut de la tour.
Il apparait toutefois une difficulté pour les
extensions exponentielles, à savoir que X=ef et X'=f' X
ne sont pas premiers entre eux comme polynômes en X, on devra
traiter le pôle 0 d'une fraction rationnelle en une exponentielle X comme
on traite l'intégration d'un polynôme en x.
Si P est sans facteurs multiples et premier avec X, alors
P(X) et P(X)'=f' X P'(X) vu comme
polynômes en X n'ont pas de facteurs en commun.
On commence donc, si X est une exponentielle et D0 un
multiple de X, par appliquer Bézout pour décomposer la fraction N0/D0
en :
|
|
= |
|
+ |
|
, gcd(X,D1)=1, D0=Xk D1 |
On isole aussi la partie polynômiale en effectuant
la division euclidienne de N0 par D0 (ou de N1 par D1 si X
est une exponentielle),
on obtient alors une écriture sous la forme :
où la somme sur j est finie et porte sur des entiers positifs ou nul
si X n'est pas une exponentielle, ou sur des entiers relatifs si X
est une exponentielle.
On effectue la même écriture sur la partie fractionnaire de F,
et en identifiant les parties polynomiales et éventuellement la partie
polaire en 0 si X est une exponentielle, on peut séparer l'intégration
en 2 parties: intégration de la partie polynomiale (généralisée)
et intégration de la partie fractionnaire propre.
Exemples
-
(2x2+1) ex2 = 0+(2x2+1)X est un polynôme,
-
la partie polynomiale est x (de degré 0 en X), la partie fractionnaire
est −x2/(x+X)
-
la partie polynôme généralisé est xX−1
9.3.1 Intégration d'une fraction propre
9.3.2 Réduction sans facteurs multiples
On factorise D en Πi Pii avec Pi sans facteurs multiples
(et les Pi premiers entre eux 2 à 2) et on décompose
en éléments simples relativement à cette factorisation (en appliquant
Bézout) :
Pour chaque polynome Pi, on applique Bézout à Pi et P'i :
on intègre par parties le second terme
on rassemble les deux intégrales ayant Pii−1 au dénominateur
et on recommence jusqu'à avoir une puissance 1 au dénominateur. Il reste
alors à intégrer une somme de fractions du type N/D avec
D et D' premiers entre eux.
Exemple
On reprend le dernier exemple de la section précédente pour
éliminer la puissance 2 au dénominateur:
N2=2x et P2=(X+1) avec X=ex. On a P2'=X, donc A2=2x et
B2=−2x :
il reste donc à intégrer (2x−2)/(ex+1).
9.3.3 La partie logarithmique
Comme on l'a vu lors de la preuve du théorème de structure de Risch,
si on dérive une fraction en X, le dénominateur de la dérivée ne
peut se décomposer qu'en produit de facteurs de multiplicité supérieure
ou égale à 2. Il en résulte que la fraction à intégrer résiduelle (encore
notée f=N/D) après l'étape de réduction ci-dessus ne peut provenir que de la
dérivation de F=Σk ck ln(vk) :
f= |
|
=F'= ( |
|
ck ln |
(vk))'= |
|
ck |
|
En identifiant les décompositions
en éléments simples de F' et f, on montre également que
les vk divisent D, plus précisément on peut imposer aux vk
d'être premiers entre eux 2 à 2 et dans ce cas D=Πvk.
Donc :
et :
Soit t un paramètre, formons le polynôme N−tD' :
N−tD' = |
|
|
⎛
⎜
⎜
⎝ |
(ck −t) vk' |
|
vj |
⎞
⎟
⎟
⎠ |
donc le pgcd en X des polynômes N−tD' et D est :
-
si t n'est égal à aucun des ck, N−tD' est premier
avec vk pour tout k car vk divise
Σl ≠ k (cl −t) vl' Πj≠ l vj
et vk'Πj≠ k vj est premier avec vk. Donc
le pgcd est 1.
- si t est égal à l'un des ck, alors le pgcd est le produit
des vk tels que ck=t (notons que dans ce cas on peut
rassembler ces vk à l'intérieur d'un même logarithme)
Considérons le polynôme R de la variable t égal au résultant par rapport
à X des polynômes D et N−tD' (rappelons qu'il s'agit du
déterminant du système linéaire AD+B(N−tD')=1
où les inconnues sont les coefficients des polynômes A et B,
ce déterminant est nul si et seulement si le système n'a pas
de solution donc si et seulement si D et N−tD' ne sont pas
premiers entre eux), alors ce polynôme en t
s'annule si et seulement si t=ck.
On cherche les racines ck en t de ce polynôme,
elles doivent être indépendantes de x si F est élémentaire,
et dans ce cas la primitive F de f=N/D vaut
Exemples
Remarque importante
Pour les extensions exponentielles ou logarithmiques,
la dérivée de la partie logarithmique
calculée comme ci-dessus contiendra en général
une partie entière constante par rapport à X, il faut
donc retirer cette partie entière à la partie polynomiale.
9.3.4 La partie polynomiale (généralisée)
On doit résoudre :
avec une somme sur j ∈Z si X est une exponentielle et
j∈ N sinon.
Si X=x, j≥ 0 et la résolution est immédiate: on prend A0=0 et
Aj+1=aj/(j+1).
9.3.5 Extension logarithmique
Si X=ln(Y) est un logarithme, j ≥ 0 et on doit résoudre :
|
|
(Aj'+(j+1)Aj+1 |
|
) Xj = |
|
aj Xj |
Soit k la plus grande puissance non nulle de f (aj=0
si j>k et ak≠ 0). Pour j>k, on a :
On résout pour des valeurs de j décroissante, pour j suffisamment
grand, on a Aj+1=0 car la somme sur j est finie, donc Aj
est constant. Si Aj ≠ 0, alors au rang j−1, on a
Aj−1 ' = −j Aj Y'/Y qui n'admet pas de solutions car
Aj−1 ne peut pas dépendre de X=ln(Y). On en déduit que pour
j>k+1, on a Aj=0 et Ak+1 est constant. En fait la
valeur constante de Ak+1 sera déterminée par une condition
de compatibilité en résolvant l'équation au rang du dessous.
On continue la résolution de
Aj'+(j+1)Aj+1 ln(Y)' = aj
par valeur décroissante de j, à chaque
rang on va déterminer Aj à une constante près en résolvant
un problème d'intégration (par appel récursif de l'algorithme
de Risch, mais si j ≠ 0 sans autoriser l'ajout de nouveaux
logarithmes sauf ln(Y))
et la valeur de la constante de Aj+1 (on fait varier Aj+1
de la constante nécessaire pour absorber le terme en ln(Y)
qui apparait lors de l'appel récursif de Risch).
Au rang 0, on est ramené à un problème d'intégration avec
une variable de moins (la constante
indéterminée dans A1 peut par exemple être choisie comme
le coefficient constant de ln(Y) s'il en apparait un en intégrant).
Exemple
X=ln(x2+1) et on cherche l'intégrale de X2. On a donc A3
est constant,
A2' + 3 A3 ln(x2+1)' = 1
La primitive de 1 est élémentaire et ne fait pas intervenir de ln
donc A3=0 et A2=x+C2. Au rang 1, on a :
A1' + 3 x |
|
+ C2 ln(x2+1)' = 0 |
On calcule la primitive de 6x2/(x2+1) qui doit être une fraction
rationnelle à un Cln(x2+1) près, on voit que ce n'est pas le cas
donc X2 n'admet pas de primitive élémentaire.
Remarque: si on avait voulu intégrer X au lieu de X2, la même
méthode montre que la primitive existe, car au rang 0 il n'y
a plus de contraintes sur les ln qu'on peut rajouter.
9.3.6 Extension exponentielle
Si X=exp(Y) est une exponentielle, on doit résoudre :
Ceci va se faire degré par degré :
Exemple
Pour calculer ∫a(x) exp(x2), on a j=1, et on doit résoudre
l'équation différentielle :
A1'+2xA1= a(x)
Pour j=0, il suffit de faire un appel récursif à l'algorithme de Risch,
mais pour j≠ 0, la situation se complique!
Notons Z la variable située juste en-dessous de X dans la tour
de variables (dans l'exemple ci-dessus Z=x), il s'agit de résoudre :
avec f, g élémentaires par rapport à une tour dont le
variable au sommet est Z, on cherche y élémentaire par rapport
à cette tour (ici f=jY' est une dérivée mais dans certains
cas nous devrons résoudre par appel récursif des équations
du type ci-dessus où f ne sera pas une dérivée).
Élimination des dénominateurs
Soit P un facteur irréductible du dénominateur de y, notons
α<0 la valuation de y par rapport à P,
β celle de f, γ celle de g.
Si P n'est pas une exponentielle,
la valuation de y' est α−1, celle de f y est α +β .
Si β ≠ −1,
il n'y a pas de simplification possible dans le membre de gauche
donc α + min(β,−1) =γ. Autrement dit, si
β ≥ 0 alors α=γ+1 et si β<−1
alors α=γ−β.
On observe que γ<0 donc
P est un facteur du dénominateur gd de g. De plus, on va montrer
que la valuation α de P dans y est l'opposé de celle
de P dans :
D= |
gcd(gd,∂Z gd) |
|
gcd(c,∂Z c) |
|
,
c=gcd(fd,gd)
(20) |
En effet, si β ≥ 0, P ne divise pas fd donc ne divise
pas c, donc la valuation de P dans D est −γ−1. Si β < −1,
alors α=γ − β <0 entraine −γ > −β donc la
valuation de P dans c est −β et la valuation de P dans D
est −γ−1 − (−β−1).
Si β=−1, s'il n'y a pas de simplifications dans le membre
de gauche pour les termes de plus petite puissance en P, alors
α=γ+1. S'il y a simplification,
on décompose en éléments
simples (avec Bézout) puis on ordonne par puissances croissantes
de P :
y= N1 Pα+..., f= N2 P−1+...,
avec N1,N2 de degré plus petit que P, puis on remplace dans
(19). On cherche les termes de valuation α−1
en P qui doivent se simplifier :
α N1 P' Pα−1 + N2 P−1 N1 Pα=0
donc :
N2 = −α P'
ce qui détermine α.
Récapitulons
Si f est une dérivée, alors β=−1 est exclus et on peut
appliquer (20) pour déterminer D. Si f n'est
pas une dérivée, on calcule les facteurs de degré 1 de fd :
on décompose f par Bézout en isolant la partie N/f1
les α possibles sont alors les racines entières (en t)
du résultant en Z de N−tf1' et f1, ils correspondent aux
facteurs gcd(N−α f1',f1) que l'on retire de fd pour
appliquer (20).
Exemple
Reprenons y'+2xy=a(x). Si a(x)=1 (résolution de ∫exp(x2)),
ou plus généralement si a(x) est un polynôme,
alors D=1. Si a(x)=1/x2, on trouve D=x et on pose y=xz,
donc x2(xz'+z)+2x4z=1 soit x3z'+(2x4+1)z=1.
Reste le cas où Z est une exponentielle et P=exp(z). On reprend
le même raisonnement, y' a pour valuation −α<0, fy a pour
valuation −β−α, donc si β > 0,
α=γ et si β<0, α=γ−β.
Si β=0, s'il n'y a pas de simplifications du terme de plus bas
degré, on est ramené au cas précédent.
Si β=0 et s'il y a simplification des termes de plus
bas degré en Z, notons f0 le coefficient constant de f
par rapport à Z et yα le coefficient de Zα
dans y, on a
yα' + (α z' + f0) yα=0
donc :
Comme yα est élémentaire et indépendant de Z
on en déduit par le théorème de structure de Risch
que −α z −∫f0 est combinaison linéaire à coefficients
rationnels des logarithmes et des arguments des exponentielles de la tour,
de plus le coefficient de z doit être nul pour que yα soit
indépendant de Z, ce qui impose la valeur de α (après avoir
résolu récursivement le problème d'intégration pour f0)
Majoration du degré du numérateur de y
En multipliant y par D Z−α, puis en réduisant au
même dénominateur,
on se ramène alors à une équation différentielle à coefficients
polynomiaux par rapport à la variable Z dont l'inconnue est un polynôme
N :
On va chercher une majoration sur le degré possible de N puis
utiliser l'identité de Bézout pour simplifier
cette équation.
On écrit maintenant N=Σk=0n Nk Zk et on remplace,
il y a à nouveau trois cas selon le type de Z.
Si Z=x: cas exponentielle rationnelle
Donc Z'=1, le degré de RN' est r+n−1 (si N est non constant
c'est-à-dire si T n'est pas un multiple de S), le degré de
SN est s+n. Si r−1≠ s, on en déduit que :
n=t−max(r−1,s)
Si r−1=s, on peut avoir
une simplification du terme de plus haut degré s+n (sinon
on est dans le cas précédent) si n Rr =Ss
d'où on déduit le degré n de N.
Par exemple, pour y'+2xy=T ou pour x3z'+(2x4+1)z=1 on a r=s−1 donc
n+s=t, donc pas de solution dans le deuxième cas, dans le premier cas
il ne peut y avoir de solutions que si t ≥ s, en particulier
il n'y a pas de solution pour t=1, on a donc démontré que ∫exp(x2)
n'admet pas de primitive élémentaire.
Si Z=exp(z): cas exponentielle d'exponentielle
Ici les Nk peuvent ne pas être constants, on a :
Comme on l'a déjà observé, Nn'+n Nn z'≠ 0, donc le
degré de N' est égal au degré de N. On a donc trois cas :
-
si r≠ s, alors n=t−max(r,s)
- si r=s et les termes de plus haut degré du membre de gauche ne
se simplifient pas, alors, n=t−r=t−s.
- si r=s et s'il y a simplification, alors :
Rr(Nn'+nNnz')+SsNn=0
donc :
et :
On appelle alors l'algorithme de Risch avec une variable de moins (Ss
et Rr ne dépendent plus de Z) pour calculer I=∫Ss/Rr.
Il s'agit alors de trouver n tel que l'exponentielle précédente
soit élémentaire et indépendante de la variable Z. Le théorème
de structure de Risch implique que −nz−∫Ss/Rr est combinaison
linéaire à coefficients rationnels des logarithmes et des arguments
des exponentielles de autres variables de la tour (jusqu'à z non compris).
Ceci permet de déterminer n de manière unique (c'est le coefficient
rationnel de ∫Ss/Rr en z).
Si Z=ln(z): exponentielle de logarithme
Ici aussi, les Nk peuvent ne pas être constants, on a :
Si Nn n'est pas constant, le terme de plus haut degré de
RN' est Nn' Rr Zn+r, si Nn est constant,
le terme de plus haut degré de RN' est Rr(nNnz'/z+Nn−1') Zr−1
qui est non nul (sinon z'/z=CNn−1' et z=exp(CNn−1) serait
une exponentielle).
Le terme de plus haut degré de SN est Nn Ss Zn+s.
Réduction (algorithme SPDE de Rothstein)
On observe d'abord que si R et S ont un facteur
en commun, alors ce facteur divise T car N' et N sont des polynômes
en Z. On peut donc quitte à simplifier par gcd(R,S) se ramener
au cas où R et S sont premiers entre eux, il existe donc deux
polynômes U et V tels que :
RU+
SV=
T, deg(
V)< deg(
R)
(22)
En soustrayant (22) de (21),
on montre que R divise N−V. Soit H=(N−V)/R. Alors N=RH+V donc
R (RH'+R'H+V')+SRH+SV= T=RU+SV
donc après simplification par SV et division par R,
H vérifie l'équation :
R H' + (S+R') H = U − V'
C'est une équation du même type mais avec deg(H)=deg(N)-deg(R)
ou H=0 (si N=V).
Donc si deg(R)>0, au bout d'un nombre fini d'étapes on doit
tomber sur un second membre nul ou des simplifications de R avec S+R'
telles que R simplifié soit constant en Z.
Résolution
Si R est constant par rapport à Z,
on simplifie par R et on doit résoudre
N'+SN=T
Si S=0, c'est un problème d'intégration. Supposons donc que
S≠ 0. Si S est non constant par rapport à Z ou si
Z=x, le degré de N' est strictement inférieur
au degré de SN, on peut donc facilement résoudre.
Reste le cas où S=b est constant non nul par rapport à Z et Z est
une exponentielle ou un logarithme.
Si Z=exp(z)
On a alors doit alors résoudre
Nk'+ k Nk z' + b Nk=Tk
c'est une équation différentielle de Risch mais avec une variable de
moins.
Si Z=ln(z)
On doit alors résoudre
Nk'+ (k+1) Nk+1 |
|
+ b Nk =Tk |
c'est aussi une équation différentielle de Risch avec une
variable de moins.
Exemple
Voyons comment on intègre xn avec n un paramètre par l'algorithme
de Risch (cela illustre les possibilités couvertes par l'algorithme
mais aussi l'efficacité des méthodes traditionnelles d'intégration
lorsqu'elles s'appliquent).
On écrit d'abord xn=en ln(x), donc la tour de variables
est { x, Z=ln(x), X=en ln(x)}, il s'agit donc d'intégrer
X qui est un polynôme généralisé. On cherche donc A1 solution
de l'équation différentielle de Risch
A1'+ n /x A1=1
Par rapport à Z=ln(x) la fonction f=n/x est un polynôme, donc on
applique le dernier cas ci-dessus, A1 est aussi indépendant de ln(x)
et on se ramène à résoudre la même équation mais avec comme variable
principale x et non Z. Cette fois, il y a un dénominateur x en f.
Si A1 possède un dénominateur, il faut qu'il y ait annulation
du terme de plus bas degré en x car le second membre n'a pas de
dénominateur, on obtient n+α=0 qui n'a pas de solution, donc
A1 est un polynôme en x et l'équation se réécrit en :
xA1'+nA1=x
On majore alors le degré en x de A1 par 1, car il ne peut pas y avoir
d'annulation de terme de plus grand degré. Ensuite, on peut appliquer
l'algorithme SPDE de Rothstein pour réduire le degré, ou ici conclure
à la main, x divise nA1 donc A1=Cx qu'on remplace et C=1/(n+1).
Finalement, A1=x/(n+1) et ∫xn=x/(n+1) xn.
9.4 Quelques références
-
M. Bronstein:
Symbolic Integration I, Transcendental functions, Springer
- M. Bronstein:
Integration tutorial,
http://www-sop.inria.fr/cafe/Manuel.Bronstein/publications/mb_papers.html
- J.H. Davenport, Y. Siret, E. Tournier:
Calcul formel: Systèmes et algorithmes
de manipulations algébriques
- R. Risch:
les références des articles originaux de Risch sont dans
le “Integration tutorial” de Bronstein.
- B. Trager:
PHD thesis MIT, 1984
- On peut lire en clair le code source de l'implémentation en MuPAD
(sous Unix, désarchiver le fichier lib.tar du répertoire
/usr/local/MuPAD/share/lib et regarder dans le sous-répertoire
lib/INTLIB)
10 Algèbre linéaire
On présente ici des algorithmes autour de la résolution exacte
de systèmes (réduction des matrices sous forme échelonnée)
et la recherche de valeurs propres et de vecteurs propres
(diagonalisation et jordanisation des matrices).
10.1 Résolution de systèmes, calcul de déterminant.
10.1.1 La méthode du pivot de Gauß.
-
Le pivot : on détermine à partir d'une ligne i
la ligne j où apparait le premier coefficient non nul p dans
la colonne à réduire. On échange les lignes
i et j. Puis pour j>i (réduction sous-diagonale)
ou j≠ i (réduction complète), on effectue l'opération
Lj ← Lj − pj/pLi.
Inconvénient : avec des données exactes de taille non bornée,
la complexité des coefficients augmente plus vite qu'en choisissant
le pivot le plus simple possible, (remarque, lorsque les données
sont approchées, on n'utilise pas non plus cette méthode
pour des raisons de stabilité numérique).
Le domaine d'utilisation naturel concerne donc les coefficients
dans un corps fini (par exemple Z/nZ).
- Le pivot partiel. On choisit le meilleur coefficient non nul de la
colonne, où meilleur dépend du type de coefficient : avec des données
exactes, on choisirait le coefficient de taille la plus petite possible,
avec des données approximatives, on choisit
le coefficient de plus grande norme dans la colonne.
Le domaine d'utilisation naturel concerne les coefficients
approchés. Pour les coefficients exacts, on remplacerait la
réduction par Lj ← pLj −pj Li pour ne pas effectuer
de division. Mais avec cette méthode, la taille des coefficients
augmente de manière exponentielle. On peut améliorer
la taille des coefficients intermédiaires en divisant chaque
ligne par le PGCD de ses coefficients, mais comme pour le
calcul du PGCD par l'algorithme du sous-résultant, il existe
une méthode plus efficace présentée ci-dessous.
- La méthode de Bareiss : on initialise un coefficient b à 1.
On remplace l'étape de réduction ci-dessus
par Lj ← (pLj −pj Li)/b.
À la fin de l'étape de réduction, on met le coefficient b
à la valeur du pivot p. L'intérêt de la méthode est que la division
se fait sans introduire de fraction (la preuve pour les deux premières
étapes se fait facilement à la main ou avec
un système de calcul formel (cf. infra), pour le cas général, on vérifie
que le déterminant de la matrice de départ
est égal au dernier coefficient sur la diagonale obtenu par
cette méthode de réduction, ce dernier est donc entier, le
même raisonnement fait sur des sous-matrices dont on prend les
k premières lignes et colonnes et une autre ligne et une autre
colonne montre que tous les coefficients des matrices intermédiaires
sont entiers).
On peut utiliser cette méthode aussi bien pour la réduction
sous-diagonale que pour la réduction complète (les lignes
intervenant dans la combinaison linéaire subissent des
modifications identiques dans les deux cas).
Montrons avec MuPAD ou xcas en mode mupad (commande maple_mode(2)
)
qu'en effet, on n'introduit pas de dénominateur dans la méthode
de Bareiss. Sans
restreindre la généralité, il suffit de le montrer avec une
matrice 3x3 à coefficients symboliques génériques.
pivot:=proc (M,n,m,r) // n ligne du pivot, m colonne, r ligne a modifier
local col,i,a,b;
begin
col:=ncols(M);
a:=M[n,m];
b:=M[r,m];
for i from 1 to col do
// print(i,a,b,n,m,r);
M[r,i]:=a*M[r,i]-b*M[n,i];
end_for;
return(M);
end_proc; /* End of pivot */
A:=matrix(3,3,[[a,b,c],[d,e,f],[g,h,j]]);
A:=pivot(A,1,1,2); A:=pivot(A,1,1,3); /* reduction 1ere colonne */
A:=pivot(A,2,2,3); A:=pivot(A,2,2,1); /* reduction 2eme colonne */
factor(A[3,3]);
Ce qui met bien en évidence le facteur a dans A3,3.
10.1.2 Le déterminant.
On peut bien sûr appliquer les méthodes ci-dessus en tenant compte
des pivots utilisés et du produit des coefficients diagonaux. Dans le cas de
la méthode de Bareiss, si on effectue la réduction sous-diagonale
uniquement, il n'est pas nécessaire de garder une trace des pivots
et de calculer le produit des coefficients diagonaux,
montrons que la valeur du déterminant est égal au
dernier coefficient diagonal : en effet si R désigne la matrice réduite et
que l'on pose R0,0=1, alors la réduction par la méthode de
Bareiss de la colonne i a pour effet de multiplier le déterminant
de la matrice initiale M par (Ri,i/(Ri−1,i−1)n−i. Donc :
det(R) |
= |
det |
(M) |
|
(Ri,i/(Ri−1,i−1)n−i |
|
|
= |
|
Rn,n |
= |
det(M) |
Pour les matrices à coefficients entiers, on peut aussi utiliser une
méthode modulaire : on calcule une borne à priori sur le déterminant
et on calcule le déterminant modulo suffisamment de petits nombres
premiers pour le reconstruire par les restes chinois. L'avantage
de cet algorithme est qu'il est facile à paralléliser.
On utilise souvent la borne d'Hadamard sur le déterminant :
Preuve de la borne : on majore le déterminant par le produit des
normes des vecteurs colonnes de M.
Remarque :
Si on veut juste prouver l'inversibilité d'une matrice à coefficients
entiers, il suffit
de trouver un nombre premier p tel que le déterminant de cette matrice modulo
p soit non nul.
Développement par rapport à une ligne ou une colonne
On a tendance à oublier ce type de méthode car le développement
complet du déterminant (faisant intervenir une somme sur toutes les
permutations du groupe symétrique)
nécessite d'effectuer n! produits
de n coefficients et n! additions ce qui est gigantesque. Or on peut
"factoriser" une partie des calculs et se ramener à n.2n opérations
élémentaires au lieu de n.n!. Remarquons aussi que le nombre
d'opérations élémentaires n'a guère de sens si on ne tient pas
compte de la complexité des expressions, l'avantage principal
de la méthode de développement étant d'éviter d'effectuer
des divisions.
Calcul du déterminant par développement de Laplace
On calcule d'abord tous les mineurs 2x2 des colonnes 1 et 2
que l'on place dans une table de mineurs,
puis on calcule les mineurs 3x3 des colonnes 1 à 3 en développant
par rapport à la colonne 3 et en utilisant les mineurs précédents,
puis les mineurs 4x4 avec les mineurs 3x3, etc..
On évite ainsi de recalculer plusieurs fois les mêmes mineurs.
Cf. par exemple l'implémentation en C++ dans giac/xcas
(www-fourier.ujf-grenoble.fr/~parisse/giac.html
)
qui utilise le type générique map<>
de la librairie standard C++ (STL)
pour stocker les tables de mineurs (fonction
det_minor
du fichier vecteur.cc).
Nombre d'opérations élémentaires : il y a (2n) mineurs d'ordre 2
à calculer nécessitant chacun 2 multiplications (et 1 addition),
puis (3n) mineurs d'ordre 3 nécessitant 3 multiplications et
2 additions, etc. donc le nombre de multiplications est de
2(2n)+3(3n)+...+n(nn), celui d'additions est
(2n)+2(3n)+...+(n−1)(nn) soit un nombre d'opérations
élémentaires majoré par n.2n.
On observe "expérimentalement" que cet algorithme est intéressant
lorsque le nombre de
paramètres dans le déterminant est grand et que la matrice est
plutôt creuse (majorité de coefficients nuls). Il existe des
heuristiques de permutation des lignes ou des colonnes visant
à optimiser la position des zéros (par exemple, les auteurs de GiNaC
(www.ginac.de
) suite à des expérimentations
privilégient la simplification des petits mineurs en mettant les colonnes
contenant le maximum de zéros à gauche selon la description faite
ici).
Pour se convaincre de l'intérêt de cet algorithme, on peut effectuer
le test O1 de Lewis-Wester
http://www.bway.net/~lewis/calatex.html
il s'agit de calculer un déterminant de taille 15 avec 18 paramètres.
10.1.3 Systèmes linéaires
On peut appliquer la méthode du pivot de Gauß ou les règles
de Cramer. Pour les systèmes à coefficients entiers non singuliers,
on peut aussi utiliser une méthode p-adique asymptotiquement
plus efficace. On calcule d'abord une borne sur les
coefficients des fractions solutions de l'équation Ax=b
en utilisant les règles de Cramer et la borne d'Hadamard.
On calcule ensuite l'inverse de A modulo p (en changeant de p si
A n'est pas inversible modulo p), puis, si
x= |
|
xi pi, A( |
|
xi pi)=b (mod pk ) |
on ajoute xk pk et on obtient l'équation :
qui détermine xk.
On s'arrête lorsque k est suffisamment grand pour pouvoir reconstruire
les fractions à l'aide de l'identité de Bézout (cf. l'appendice).
10.1.4 Base du noyau
On commence bien sûr par réduire la matrice (réduction complète
en-dehors de la diagonale), et on divise chaque ligne par son
premier coefficient non nul (appelé pivot). On insère alors
des lignes de 0 pour que les pivots (non nuls) se trouvent
sur la diagonale. Puis en fin de matrice, on ajoute ou on supprime des
lignes de 0 pour avoir une matrice carrée de dimension le nombre de colonnes
de la matrice de départ.
On parcourt alors la matrice en diagonale. Si
le i-ième coefficient est non nul, on passe au suivant.
S'il est nul, alors tous
les coefficients d'indice supérieur ou égal à i du i-ième
vecteur colonne vi sont nuls (mais pas forcément pour les indices
inférieurs à i). Si on remplace le i-ième coefficient de vi
par -1, il est facile de se convaincre que c'est un vecteur du noyau,
on le rajoute donc à la base du noyau. On voit facilement
que tous les vecteurs de ce type forment une famille libre de
la bonne taille, c'est donc bien une base du noyau.
10.2 Réduction des endomorphismes
10.2.1 Le polynôme minimal
On prend un vecteur v au hasard et on calcule la relation linéaire
de degré minimal entre v, Av, ..., Anv en cherchant
le premier vecteur w du noyau de la matrice obtenue en écrivant
les vecteurs v, Av, etc. en colonne dans cet ordre. Les
coordonnées de w donnent alors par ordre de degré croissant
un polynôme P de degré minimal tel que P(A)v=0 donc
P divise le polynôme minimal M. Donc si P est de
degré n, P=M. Sinon, il faut vérifier que le polynôme obtenu
annule la matrice A. On peut aussi calculer en parallèle le polynôme P
précédent pour quelques vecteurs aléatoires et prendre le PPCM des
polynômes obtenus.
Exemple 1
Polynôme minimal de () . On prend v=(1,0), la matrice à réduire est
alors :
Le noyau est engendré par (−6,5,−1) donc P=−x2+5x−6.
Exemple 2
en prenant v=(1,0,0) on obtient la matrice :
A= |
⎛
⎜
⎜
⎝ |
1 |
3 |
5 |
7 |
0 |
−1 |
−2 |
−3 |
0 |
1 |
2 |
3 |
|
⎞
⎟
⎟
⎠ |
→
|
⎛
⎜
⎜
⎝ |
1 |
0 |
−1 |
−2 |
0 |
1 |
2 |
3 |
0 |
0 |
0 |
0 |
|
⎞
⎟
⎟
⎠ |
le permier vecteur du noyau est (−1,2,−1) d'où un polynôme divisant
le polynôme minimal −x2+2x−1.
10.2.2 Le polynôme caractéristique
Pour une matrice générique, le polynôme caractéristique est égal
au polynôme minimal, il est donc intéressant de chercher si le polynôme
annulateur de A sur un vecteur aléatoire est de degré n,
car le temps de calcul du polynôme caractéristique est alors en O(n3).
Si cette méthode probabiliste échoue, on se
rabat sur une des méthode déterministe ci-dessous:
-
on utilise la formule det(λ I −A) déterminé par
une des méthodes de calcul de déterminant ci-dessus. Cela
nécessite O(n3) opérations mais avec des coefficients
polynômes en λ.
- on fait une interpolation de Lagrange en donnant n+1 valeurs
distinctes à λ. Ce qui nécessite O(n4) opérations mais avec
des coefficients indépendants de λ, de plus cette méthode
est facile à programmer de manière parallèle.
- si la matrice est à coefficients entiers
on peut utiliser la méthode de Hessenberg (voir ci-dessous), on calcule
une borne à priori sur les coefficients du polynôme caractéristique
(cf. Cohen p.58-59) :
|Pk| ≤ |
⎛
⎝ |
|
⎞
⎠ |
(n−k)(n−k)/2 |M|n−k , |
on calcule le polynôme caractéristique modulo suffisamment
de petits entiers puis on remonte par les restes chinois.
10.2.3 La méthode de Hessenberg
Pour les matrices à coefficients de taille bornée (modulaires par exemple)
on préfère la méthode de Hessenberg qui est plus
efficace, car elle nécessite de l'ordre de n3 opérations sur
les coefficients.
On se raméne d'abord à une matrice triangulaire supérieure à
une diagonale près qui est semblable à la
matrice de départ puis on
applique une formule de récurrence pour calculer les coefficients
du polynôme caractéristique.
Algorithme de réduction de Hessenberg:
Dans une colonne m donnée de la matrice H,
on cherche à partir de la ligne
m+1 un coefficient non nul. S'il n'y en a pas on passe à la colonne
suivante. S'il y en a un en ligne i, on échange les lignes m+1
et i et les colonnes m+1 et i. Ensuite pour tout i≥ m+2,
soit u=Hi,m/Hm+1,m, on remplace alors la ligne Li de H
par Li−uLm+1 et la colonne Cm+1 par Cm+1+uCi
ce qui revient “à remplacer le vecteur em+1 de la base
par le vecteur em+1+uei” ou plus précisément
à multiplier à gauche par () et à droite par la matrice inverse
() (en utilisant les lignes et colonnes
m+1 et i au lieu de 1 et 2 pour ces matrices).
Ceci a pour effet d'annuler le coefficient Hi,m
dans la nouvelle matrice.
On obtient ainsi en O(n3) opérations
une matrice H' semblable à H de la forme :
|
⎛
⎜
⎜
⎜
⎜
⎜
⎜
⎝ |
H'1,1 |
H'1,2 |
... |
H'1,n−2 |
H'1,n−1 |
H'1,n |
H'2,1 |
H'2,2 |
... |
H'2,n−2 |
H'2,n−1 |
H'2,n |
0 |
H'3,2 |
... |
H'3,n−2 |
H'3,n−1 |
H'3,n |
0 |
0 |
... |
H'4,n−2 |
H'4,n−1 |
H'4,n |
⋮ |
⋮ |
... |
⋮ |
⋮ |
⋮ |
0 |
0 |
... |
0 |
H'n,n−1 |
H'n,n |
|
|
⎞
⎟
⎟
⎟
⎟
⎟
⎟
⎠ |
On calcule alors le polynôme caractéristique de H' par une récurrence
qui s'obtient en développant le déterminant par rapport à la dernière
colonne :
hn(λ) = det(λ In−H) |
= |
(λ−H'n,n) hn−1(λ) −(−H'n−1,n) (−H'n,n−1)
hn−2(λ) + |
|
|
+ (−H'n−2,n) (−H'n,n−1) (−H'n−1,n−2) hn−3(λ) − ... |
où les hi s'entendent en gardant les i premières lignes/colonnes de H'.
On peut écrire cette formule pour m≤ n :
hm(λ)= (λ − H'm,m) hm−1(λ)
− |
|
H'm−i,m |
|
H'm−j+1,m−j hi−1(λ) |
Pour effectuer cette récurrence de manière efficace, on conserve
les hm(λ) dans un tableau de polynômes et on utilise une
variable produit contenant successivement les ΠH'm−j+1,m−j.
10.2.4 La méthode de Leverrier-Faddeev-Souriau
Cette méthode permet le calcul simultané des coefficients
pi (i=0..n) du polynôme caractéristique
P(λ)=det(λ I−A) et des coefficients matriciels
Bi (i=0..n−1) du polynôme en λ donnant la matrice adjointe
(ou comatrice) B(λ) de λ I −A :
|
(λ I −A)B(λ)=(λ I −A) |
|
Bk λk
= ( |
|
pk λk)I =P(λ)I
(23) |
Remarquons que cette équation donne une démonstration assez simple
de Cayley-Hamilton puisque le reste de la division euclidienne
du polynôme P(λ)I par λ I −A est P(A).
Pour déterminer simultanément les pk et Bk,
on a les relations de récurrence :
Bn−1=
pn I=
I,
Bk−
ABk+1=
pk+1 I
(24)
Il nous manque une relation entre les pk et Bk pour pouvoir
faire le calcul par valeurs décroissantes de k, on va montrer le :
Théorème 8
La dérivée du polynôme caractéristique P'(λ),
est égale à la trace de la matrice adjointe
de λ I−A
tr(B)=P'(λ)
Le théorème nous donne tr(Bk) = (k+1)pk+1 .
Si on prend la trace de (24), on a :
tr(Bn−1)=n pn, (k+1)pk+1 −tr(ABk+1)
=npk+1
donc on calcule pk+1 en fonction de Bk+1 puis Bk :
Démonstration du théorème:
Soient V1(λ),...Vn(λ) les vecteurs colonnes
de λ I−A et bi,j(λ) les coefficients de B, on a :
P'(λ0) |
= |
det(V1(λ),V2(λ),...,Vn(λ) )'
|λ=λ0 |
|
= |
det(V'1(λ0),V2(λ0),...,Vn(λ0) )+
det(V1(λ0),V'2(λ0),...,Vn(λ0) )+ |
|
|
+...+det(V1(λ0),V2(λ0),...,V'n(λ0) ) |
Il suffit alors de remarquer que
V'i(λ0) est le i-ième vecteur de la base canonique donc :
det(V1(λ0),V2(λ0),...,V'i(λ0),...,Vn(λ0) )
=bi,i(λ0)
Finalement :
P'(λ0)= |
|
bi,i(λ0)=tr (B(λ0)) |
Remarque :
En réindexant les coefficients de P et B de la manière suivante :
P(λ) |
= |
λn+p1λn−1+p2λn−2...+pn |
B(λ) |
= |
λn−1I+λn−2B1+...+Bn−1 |
on a montré que :
|
⎧
⎪
⎪
⎪
⎪
⎨
⎪
⎪
⎪
⎪
⎩ |
A1=A, |
p1=−tr(A), |
B1=A1+p1I |
A2=AB1, |
|
B2=A2+p2I |
⋮ |
⋮ |
⋮ |
Ak=ABk−1, |
|
Bk=Ak+pkI |
|
|
On peut alors vérifier que Bn=An+pnI=0.
D'où ce petit programme à utiliser avec xcas en mode mupad
(maple_mode(2);
), ou avec MuPAD, ou à adapter
avec un autre système :
iequalj:=(j,k)->if j=k then return(1); else return(0); end_if;
faddeev:=proc(A) // renvoie la liste des matrices B et le polynome P
local Aj,AAj,Id,coef,n,pcara,lmat;
begin
n:=ncols(A);
Id:=matrix(n,n,iequalj); // matrice identite
Aj:=Id;
lmat:=[]; // B initialise a liste vide
pcara:=[1]; // coefficient de plus grand degre de P
for j from 1 to n do
lmat:=append(lmat,Aj); // rajoute Aj a la liste de matrices
AAj:=Aj*A;
coef:=-trace(AAj)/j; // mupad linalg::tr
pcara:=append(pcara,coef); // rajoute coef au polynome caracteristique
Aj:=AAj+coef*Id;
end_for;
lmat,pcara; // resultat
end_proc;
10.2.5 Les vecteurs propres simples.
On suppose ici qu'on peut factoriser le polynôme caractéristique
(ou calculer dans une extension algébrique d'un corps).
Lorsqu'on a une valeur propre simple λ0, en écrivant
la relation (A−λ0 I)B(λ0)=P(λ0)I=0,
on voit que les vecteurs colonnes de la matrice B(λ0)
sont vecteurs propres.
Remarquer que B(λ0) ≠ 0 sinon on pourrait factoriser
λ−λ0 dans B(λ) et apres simplifications on aurait :
or le 2ème membre est inversible en λ0 ce qui n'est pas le
cas du premier.
Pour avoir une base des vecteurs propres associés à λ0, on
calcule B(λ0) par la méthode de Horner appliquée au
polynôme B(λ) en λ=λ0, et on réduit en
colonnes la matrice obtenue.
10.2.6 La forme normale de Jordan
Pour les valeurs propres de multiplicité plus grande que 1, on souhaiterait
généraliser la méthode ci-dessus pour obtenir une base
de l'espace caractéristique, sous forme de cycles de Jordan.
Soit λ i, ni les valeurs propres comptées avec leur
multiplicité. On fait un développement de Taylor en
λ i:
−P(λ )I |
= |
(A−λ I) |
⎛
⎜
⎜
⎝ |
B(λi )+ B'(λ i)(λ −λ i)
+ ... + |
|
(λ −λ i)n−1 |
⎞
⎟
⎟
⎠ |
|
|
= |
|
Comme A−λ I=A−λ i I − (λ −λ i)I, on obtient
pour les ni premières puissances de λ −λ i:
|
(A−λ i I) B(λ i) |
= |
0 |
(25) |
(A−λ i I) B'(λ i) |
= |
B(λi ) |
(26) |
|
... |
|
(27) |
|
= |
|
(28) |
|
= |
|
(29) |
|
Le calcul des matrices B(n)(λ i)/n! pour n<ni se fait en
appliquant ni fois l'algorithme de Horner (avec reste).
Théorème 9
L'espace caractéristique de λ i est égal à
l'image de B(ni−1)(λ i)/(ni−1)!.
Preuve :
On montre d'abord que ImB(ni−1)(λ i)/(ni−1)! est inclus
dans l'espace caractéristique correspondant à λi en
appliquant l'équation (28) et les équations précédentes.
Réciproquement on veut prouver que tout vecteur caractéristique v est dans
l'image de B(ni−1)(λ i)/(ni−1)!. Prouvons le par récurrence
sur le plus petit entier m tel que
(A−λ i)mv=0. Le cas m=0 est clair puisque v=0.
Supposons le cas m vrai, prouvons le cas m+1. On applique l'équation
(29) à v, il suffit alors de prouver que
appartient à l'image de
B(ni−1)(λ i)/(ni−1)!.
Comme B(ni)(λi)
commute avec A (car c'est un polynôme en A ou en appliquant
le fait que B(λ) inverse de A−λ I):
(A−λ i)m w= |
|
(A−λ i)m+1v=0 |
et on applique l'hypothèse de récurrence à w.
Pour calculer les cycles de Jordan, nous allons effectuer une
réduction par le pivot de Gauß simultanément sur les colonnes
des matrices B(k)(λ i)/k! où k<ni.
La simultanéité a pour but de conserver les
relations (25) à (28) pour les matrices
réduites. Pour visualiser l'algorithme, on se représente les
matrices les unes au-dessus des autres, colonnes alignées.
On commence par réduire la matrice B(λ i) jusqu'à ce
que l'on obtienne une matrice réduite en recopiant les opérations
élémentaires de colonnes faites sur B(λ i) sur toutes les matrices
B(k)(λ i)/k!. On va continuer avec la liste des matrices
réduites issues de B'(λ i), ...,
B(ni−1)(λ i)/(ni−1)!,
mais en déplacant les colonnes non nulles de B(λ i)
d'une matrice vers le bas
(pour une colonne non nulle de la matrice réduite B(λ )
les colonnes correspondantes de B(k)(λ i) réduite
sont remplacées par les colonnes correspondantes de B(k−1)(λ i)
réduite pour k décroissant de ni−1 vers 1).
À chaque étape, on obtient une famille (éventuellement vide)
de cycles de Jordan, ce sont les vecteurs colonnes correspondants
aux colonnes non nulles de la matrice réduite du haut de la colonne.
On élimine bien sûr les colonnes correspondant aux fins de cycles
déjà trouvés.
Par exemple, si B(λ i)≠ 0, son rang est 1 et on a
une colonne non nulle, et un cycle de Jordan de longueur
ni fait des ni vecteurs colonnes des matrices
B(k)(λ i)/k! réduites.
Plus généralement, on obtiendra plus qu'un cycle de Jordan
(et dans ce cas B(λ i)= 0).
λ =2 est valeur propre de multiplicité 2, on obtient :
B(λ )= λ 2 I + λ |
⎛
⎜
⎜
⎝ |
|
⎞
⎟
⎟
⎠ |
+ |
⎛
⎜
⎜
⎝ |
|
⎞
⎟
⎟
⎠ |
on applique l'algorithme de Horner :
Comme B(2)≠ 0, on pourrait arrêter les calculs en utilisant
une colonne non nulle et le cycle de Jordan associé
(2,2,1)→ (1,1,0) → (0,0,0) . Expliquons tout
de même l'algorithme général sur cet exemple. La réduction
de B(2) s'obtient en effectuant les manipulations de colonnes
C2+C1 → C2 et C3−C1 → C3.
On effectue les mêmes opérations sur B'(2)
et on obtient :
L'étape suivante consiste à déplacer vers le bas d'une matrice les
colonnes non nulles de la matrice du haut, on obtient :
qui se réduit en :
on chercherait alors dans les colonnes 2 et 3 de nouveaux cycles (puisque
la colonne 1 a déja été utilisée pour fournir un cycle).
λ =1 est valeur propre de multiplicité 3.
On trouve :
Le processus de réduction commence avec B'(1) en haut de la liste
de matrices, on effectue les opérations élémentaires de
colonne C2−C1→ C2
et C3+C1 → C3 et on obtient:
La première colonne donne le premier cycle de Jordan
(1,0,0) → (2,−1,1).
On déplace les premières colonnes d'une matrice vers le bas :
qu'on réduit par les opérations 2C2 +C1 → C2 et
2C3−C1→ C3 en :
Puis on effectue C3−C2 → C3 et la deuxième colonne
nous donne le deuxième cycle de Jordan, réduit ici à un
seul vecteur propre (0,1,1).
10.2.9 Le polynôme minimal par Faddeev
On vérifie aisément que le degré du facteur
(λ−λi) dans le polynôme minimal de A est égal
à ni−k où k est le plus grand entier tel que :
∀ j<k, B(j)(λi)=0
10.2.10 Formes normales rationnelles
On se place ici dans une problématique différente : trouver une matrice
semblable la plus simple possible sans avoir à introduire d'extension
algébrique pour factoriser le polynôme caractéristique.
Quitte à “compléter” plus tard la factorisation et la jordanisation à
partir de la forme simplifiée. Il existe diverses formes associées
à une matrice et plusieurs algorithmes permettant de les relier entre elles,
forme de Smith, de Frobenius, forme normale de Jordan rationnelle.
On va présenter une méthode directe de calcul d'une forme normale
contenant le maximum de zéros (dont la forme dite normale de Jordan
rationnelle peut se déduire) en utilisant le même algorithme que pour
la forme
normale de Jordan. Soit Q(λ)=q0+...+qd λd
un facteur irréductible
de degré d et de multiplicité q
du polynôme caractéristique P. Il
s'agit de construire un sous-espace de dimension dq formé de “cycles
de Jordan rationnels”.
On part toujours de la relation
(λ I −A) Σk≤ n−1 Bk λk=P(λ)I.
On observe que Q(λ)I−Q(A) est divisible par (λ I −A)
donc il existe une matrice M(λ) telle que :
(Q(λ) I −Q(A)) ( |
|
Bk λk)
=Q(λ)q M(λ) |
On observe aussi que Q a pour coefficient dominant 1 puisqu'il divise
P, on peut donc effectuer des divisions euclidiennes de polynômes
donc de polynômes à coefficients matriciels par Q sans avoir
à diviser des coefficients. Ce qui nous
permet de décomposer B(λ)=Σk≤ n−1 Bk λk en
puissances croissantes de Q :
B(λ)= |
|
Ck(λ) Q(λ)k, deg(Ck)<q |
On remplace et on écrit que les coefficients des puissances inférieures
à q de Q sont nulles (la k-ième étant non nulle
car M(λ) n'est pas divisible par Q pour les mêmes raisons
que pour la forme normale de Jordan). On a donc les relations :
Q(A)C0 = 0, Ck = Q(A) Ck+1
ce qui donne une colonne de matrice
Cq−1 → Cq−2 ... → C0 → 0
qui sont images l'une de l'autre en appliquant Q(A). On peut alors
faire l'algorithme de réduction simultanée sur les colonnes des Cj.
On observe
ensuite que le nombre de cycles de Jordan de Q(A) de longueur donnée
est un multiple de d, en effet il suffit de multiplier
un cycle par A, ..., Ad−1 pour créer un autre cycle, de plus ces
cycles forment des familles libres car on a supposé Q irréductible.
On peut donc choisir pour un cycle de longueur k des bases de la forme
(vk−1,Avk−1...,Ad−1vk−1) → ...
→ (v0,Av0...,Ad−1v0) → (0,...,0)
où la flèche → désigne l'image par Q(A).
Si on écrit la matrice de A dans la base
v0,Av0...,Ad−1v0,...,vk−1,Avk−1...,Ad−1vk−1
on obtient un “quasi-bloc de Jordan rationnel” de taille kd
multiple de d :
|
⎛
⎜
⎜
⎜
⎜
⎜
⎜
⎜
⎜
⎜
⎜
⎝ |
0 |
0 |
... |
−q0 |
|
0 |
0 |
... |
1 |
... |
1 |
0 |
... |
−q1 |
|
0 |
0 |
... |
0 |
... |
0 |
1 |
... |
−q2 |
|
0 |
0 |
... |
0 |
... |
⋮ |
⋮ |
... |
⋮ |
|
⋮ |
⋮ |
... |
⋮ |
... |
0 |
0 |
... |
−qd−1 |
|
0 |
0 |
... |
0 |
... |
|
0 |
0 |
... |
0 |
|
0 |
0 |
... |
−q0 |
... |
0 |
0 |
... |
0 |
|
1 |
0 |
... |
−q1 |
... |
⋮ |
⋮ |
... |
⋮ |
|
⋮ |
⋮ |
... |
⋮ |
... |
|
|
⎞
⎟
⎟
⎟
⎟
⎟
⎟
⎟
⎟
⎟
⎟
⎠ |
Exemple
Soit la matrice
A= |
⎛
⎜
⎜
⎜
⎜
⎜
⎜
⎜
⎜
⎜
⎜
⎜
⎜
⎜
⎜
⎜
⎜
⎜
⎜
⎝ |
1 |
−2 |
4 |
−2 |
5 |
−4 |
0 |
1 |
|
|
2 |
|
1 |
|
2 |
|
|
−3 |
0 |
−1 |
|
|
3 |
|
0 |
0 |
2 |
−2 |
3 |
−1 |
1 |
|
|
1 |
|
|
|
⎞
⎟
⎟
⎟
⎟
⎟
⎟
⎟
⎟
⎟
⎟
⎟
⎟
⎟
⎟
⎟
⎟
⎟
⎟
⎠ |
Son polynôme caractéristique est (x−2)2(x2−2)2 et on va déterminer
la partie bloc de Jordan rationnel correspondant au facteur irréductible
sur les entiers Q(x)=(x2−2) de multiplicité q=2.
On calcule B(x) et l'écriture de B comme
somme de puissances de Q (ici avec xcas
en mode xcas
) :
A:=[[1,-2,4,-2,5,-4],[0,1,5/2,(-7)/2,2,(-5)/2],[1,(-5)/2,2,1/(-2),5/2,-3],
[0,-1,9/2,(-7)/2,3,(-7)/2],[0,0,2,-2,3,-1],[1,(-3)/2,1/(-2),1,3/2,1/2]];
P:=det(A-x*idn(6));
B:=normal(P*inv(A-x*idn(6))); // preferer un appel a faddeev bien sur!
ecriture(B,Q,q):={
local j,k,l,n,C,D,E;
C:=B;
D:=B;
E:=NULL;
n:=coldim(B);
for (j:=0;j<q;j++){
for (k:=0;k<n;k++){
for (l:=0;l<n;l++){
D[k,l]:=rem(C[k,l],Q,x);
C[k,l]:=quo(C[k,l],Q,x);
}
}
E:=E,D;
}
return E;
};
E:=ecriture(B,x^2-2,2);
QA:=A*A-2*idn(6);
On vérifie bien que normal(QA*E(0))
et
normal(QA*E(1))-E(0))
sont nuls. On sait qu'on a un bloc de
taille 2 de cycles de Jordan de longueur 2, donc il n'est pas nécessaire
de faire des réductions ici, il suffit de prendre une colonne non nulle
de E(0), par exemple la première colonne en x=0
et la colonne correspondante de E(1) et leurs images par A, ici
cela donne (4,24,12,32,8,−4) correspondant à (0,4,−4,8,4,−4),
on calcule les images par A, la matrice de l'endomorphisme
restreint à ce sous-espace est alors le bloc de taille 4 :
|
⎛
⎜
⎜
⎜
⎝ |
0 |
2 |
0 |
1 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
2 |
0 |
0 |
1 |
0 |
|
|
⎞
⎟
⎟
⎟
⎠ |
Cette forme normale minimise le nombre de coefficients non nuls,
mais présente un inconvénient, la partie nilpotente ne commute pas
avec la partie bloc-diagonale, contrairement à la forme normale
rationnelle de Jordan qui contient des blocs identités au-dessus
de la diagonale de blocs.
Pour créer la forme normale rationnelle de Jordan, on doit donc remplacer
les blocs ( )
par des matrices identités. Supposons constitués les j premiers blocs de
taille d numérotés de 0 à j−1 avec comme base de vecteurs
(v0,0,...,v0,d−1,...,vj−1,d−1).
Il s'agit de trouver un vecteur vj,0 pour commencer le bloc
suivant. On définit alors vj,l en fonction de vj,l−1
en appliquant la relation Avj,l−1=vj,l+vj−1,l−1.
Il faut donc chercher vj,0 tel que
Avj,d−1=−
q0 vj,0−...−
qd−1 vj,d−1+
vj−1,d−1
(30)
En utilisant les relations de récurrence précédentes, on voit que
cela revient à fixer Q(A)vj,0 en fonction des vj',l avec
j'<j (l quelconque). Ce qui est toujours possible en utilisant
la colonne de matrices Cj' qui s'obtiennent en
fonction des Cj'+1 en appliquant Q(A).
Plus précisément, calculons les vj,l en fonction de vj,0
et des vj',l' (j'<j). On utilise les coefficients binomiaux
( ml) calculés par la règle du triangle de Pascal et
on montre par récurrence que :
|
vj,l = Al vj,0 − |
|
|
⎛
⎝ |
|
⎞
⎠ |
vj−m,l−m
(31) |
On remplace dans (30) d'où :
Ad vj,0 − |
|
|
⎛
⎝ |
|
⎞
⎠ |
vj−m,l−m
+ |
|
ql (Al vj,0 − |
|
|
⎛
⎝ |
|
⎞
⎠ |
vj−m,l−m )=0
|
finalement :
|
Q(A) vj,0= |
|
ql |
|
|
⎛
⎝ |
|
⎞
⎠ |
vj−m,l−m
(32) |
Application à l'exemple :
Ici v0,0=(4,24,12,32,8,−4) et v0,1=Avj,0 dont une préimage
par Q(A) est w1,0=(0,4,−4,8,4,−4) et w1,1=Aw1,0.
On applique (32), comme q1=0 et q2=1
on doit avoir :
Q(A) v1,0 = |
|
ql |
|
|
⎛
⎝ |
|
⎞
⎠ |
v1−m,l−m
=2v0,1 |
donc :
v1,0 |
= |
2A(0,4,−4,8,4,−4) |
= |
(−8,−32,0,−48,−16,16) |
v1,1 |
= |
Av1,0−v0,0 |
= |
(4,40,−4,64,24,−20) |
On vérifie bien que Av1,1=2v1,0+v0,1.
10.2.11 Fonctions analytiques
Soit f une fonction analytique et M une matrice. Pour calculer
f(M), on calcule la forme normale de Jordan de
M=P(D+N)P−1 où D=diag(d1,...,dm) est diagonale et N nilpotente
d'ordre n. On calcule
aussi le développement de Taylor formel de f en x à l'ordre
n−1, on a alors :
f(N)=P |
⎛
⎜
⎜
⎝ |
|
|
diag(f(j)(d1),...,
f(j)(dm)) |
|
j! |
|
Nj |
⎞
⎟
⎟
⎠ |
P−1 |
10.3 Quelques autres algorithmes utiles
Pour calculer le produit de matrices, on peut utiliser
l'algorithme de Strassen, on présente ici la variante
de Winograd. Soit à calculer :
|
⎛
⎝ |
|
⎞
⎠ |
|
⎛
⎝ |
|
⎞
⎠ |
= |
⎛
⎝ |
|
⎞
⎠ |
On calcule :
s1=a2,1+a2,2, s2=s1−a1,1,
s3=a1,1− a2,1, s4=a1,2−s2 |
t1=b1,2−b1,1, t2=b2,2−t1,
t3=b2,2−b1,2, t4=b2,1−t2 |
puis :
p1=a1,1 b1,1,
p2=a1,2b2,1,
p3=s1 t1, p4=s2 t2 |
p5=s3 t3, p6=s4 b2,2,
p7=a2,2 t4 |
u1= p1+p2 u2=p1+p4,
u3=u2+p5, u4=u3+p7 |
u5=u3+p3,
u6=u2+p3, u7=u6+p6 |
Alors c1,1=u1, c1,2=u7, c2,1=u4, c2,2=u5.
Cet algorithme utilise 7 multiplications et 15 additions
ce qui économise 1 multiplication et permet en appliquant
récursivement cet algorithme pour des matrices blocs
de réduire la complexité d'un produit de grandes matrices
normalement en O(n3) à O(nln(7)) (la preuve
est analogue à celle de la multiplication des polynômes
par l'algorithme de Karatsuba).
La plupart des algorithmes d'algèbre linéaire “numérique”
ont une utilité en calcul exact : par exemple la factorisation
LU (avec les variations décrites dans la section réduction
de Gauß), la factorisation QR (et donc la méthode de Gram-Schmidt,
ici pour des raisons d'efficacité on orthogonalise d'abord la
base de départ et on la normalise à la fin seulement),
Cholesky,.... On peut aussi facilement programmer la recherche de la
décomposition tP D P d'une matrice symétrique et en
déduire la signature d'une forme quadratique.
Citons enfin l'algorithme LLL (cf. Cohen) qui est utile
dans de nombreux domaines (il permet de trouver des vecteurs assez
courts dans un réseau, ce ne sont pas les plus courts, mais
en contrepartie on les trouve très vite).
10.4 Quelques références
-
Comme toujours on renvoie à l'excellent livre de Henri Cohen:
A Course in Computational Algebraic Number Theory
- Gantmacher: Théorie des matrices
- Pour une implémentation des algorithmes de forme normale
de Smith ou de Frobenius, cf. le source de MuPAD ou
http://www.mapleapps.com/maplelinks/share/normform.html
- Ferrard, Lemberg: Mathématiques Concrètes, Illustrées par la TI 92
et la TI 89
Présente aussi des algorithmes plus numériques, et le lien avec
la diagonalisation numérique de matrices.
- Press et al.: Numerical recipies in Fortran/C/Pascal.
Pour des algorithmes numériques (sur les matrices et autres).
10.5 Bézout et les p-adiques.
Soit n et a/b une fraction irréductible d'entiers tels que
b est premier avec n et |a| < √n/2 et 0 ≤ b ≤ √n/2.
Il s'agit de reconstruire a et b connaissant
x=a × (b−1) (mod n ) avec x∈ [0,n[.
Unicité
S'il existe une solution (a,b) vérifiant |a| < √n/2 et
0 ≤ b ≤ √n/2, soit (a',b') une solution
de x=a × (b−1) (mod n ) et
vérifiant |a'| < √n et 0 ≤ b' ≤ √n, alors :
a b'=a' b (mod n )
Comme |ab'| < n/2, |a'b| <n/2,
on en déduit que ab'=a'b. Donc a/b=a'/b'
donc a=a' et b=b' car a/b et a'/b' sont supposées irréductibles.
Reconstruction lorsqu'on sait qu'il y a une solution
On suit l'algorithme de calcul des coefficients de Bézout
pour les entiers n et x. On pose :
αk n + βk x= rk
où les rk sont les restes successifs de l'algorithme d'Euclide,
avec la condition initiale :
α0=1, β0=0, α1=0, β1=1, r0=n, r1=x
et la relation de récurrence :
βk+2=βk − qk+2 βk+1,
qk+2= |
|
On a βk x= rk (mod n ) pour tout rang mais il faut vérifier
les conditions de taille sur βk et rk pour trouver le couple
(a,b).
Montrons par récurrence que :
β
k+1 rk −
rk+1 β
k = (−1)
k n
(33)
Au rang k=0, on vérifie l'égalité, on l'admet au rang k,
alors au rang k+1, on a :
βk+2 rk+1 − rk+2 βk+1 |
= |
βk rk+1 − qk+2 rk+1 βk+1 − rk+2 βk+1 |
|
= |
βk rk+1 − (rk−rk+2) βk+1 − rk+2 βk+1 |
|
= |
βk rk+1 − rk βk+1 |
|
= |
− (−1)k n |
On vérifie aussi que le signe de βk est positif si k est impair
et négatif si k est pair, on déduit donc de (33) :
|βk+1| rk < n
(avec égalité si rk+1=0)
Considérons la taille des restes successifs, il existe un rang k
tel que rk ≥ √n et rk+1<√n. On a alors
|βk+1| < n/rk ≤ √n.
Donc l'algorithme de Bézout permet de reconstruire l'unique couple
solution s'il existe.
Exemple
On prend n=101, a=2, b=3, a/b=68 (mod 101 ).
Puis on effectue Bézout pour 68 et 101 en affichant les étapes
intermédiaires (par exemple avec IEGCD
sur une HP49 ou exercice
avec votre système de calcul formel) :
= alpha*101+beta*68
101 1 0
68 0 1 L1 - 1*L2
33 1 -1 L2 - 2*L3
2 -2 3 ...
On s'arrête à la première ligne telle que le coefficient de la 1ère colonne
est inférieur à √101, on retrouve bien 2 et 3.
Quand on programme l'algorithme de
reconstruction, on ne calcule bien sûr pas la colonne des α,
ce qui donne par exemple le programme xcas ou mupad suivant :
// Renvoie a/b tel que a/b=x mod n et |a|,|b|<sqrt(n)
padictofrac:=proc (n,x)
local r0,beta0,r1,beta1,r2,q2,beta2;
begin
r0:=n;
beta0:=0;
r1:=x;
beta1:=1;
sqrtn:=float(sqrt(n));
while r1>sqrtn do
r2:= irem(r0,r1);
q2:=(r0-r2)/r1;
beta2:=beta0-q2*beta1;
beta0:=beta1; r0:=r1; beta1:=beta2; r1:=r2;
end_while;
return(r1/beta1);
end_proc;
10.6 Exercices (algèbre linéaire)
10.6.1 Instructions
-
Les commandes d'algèbre linéaire de Xcas sont
regroupées dans le menu Math->Alglin.
En maple et mupad, la commande ?linalg affiche
la liste des commandes d'algèbre linéaire.
- En maple il est conseillé d'exécuter with(linalg);,
en mupad export(linalg);, sinon il faut précéder
chaque commande de linalg::.
- En maple, attention
il faut utiliser le caractère & avant la multiplication
et il faut souvent utiliser evalm dans les programmes
utilisant des matrices et vecteurs.
- Pour travailler avec des
coefficients modulaires, en Xcas
on fait suivre les coefficients ou matrices de % n,
en maple on utilise les noms de commandes
avec une majuscule (forme inerte) suivi de mod n, en mupad
on définit les coefficients dans l'anneau, par exemple
Z19:=Dom::IntegerMod(19): MatZ19 := Dom::Matrix(Z19):
A:=MatZ19([[1, 2], [2]]); Z19(5)*A;
-
En utilisant un logiciel de calcul formel,
comparez le temps de calcul d'un déterminant de matrice
aléatoire à coefficients entiers de tailles 50 et 100,
d'une matrice de taille 6 et 12 avec comme coefficients symboliques
ligne j colonne k, xj+k lorsque j+k est pair
et 0 sinon. Peut-on en déduire une indication sur l'algorithme
utilisé?
- Écrire un programme calculant la borne de Hadamard d'un
déterminant à coefficients réels (rappel : c'est la borne obtenue en faisant
le produit des normes euclidiennes des vecteurs colonnes).
- Créez une matrice 4x4 aléatoire avec des coefficients entiers
compris entre -100 et 100, calculer la borne de Hadamard de son déterminant
avec le programme précédent, calculer ce déterminant modulo
quelques nombres premiers choisis en fonction de la borne de Hadamard
et vérifiez le résultat de la reconstruction modulaire du déterminant.
- Créez une matrice 100x100 aléatoire à coefficients entiers
et calculez son déterminant
modulo quelques nombres premiers. Dans quels cas peut-on
conclure que la matrice est inversible dans R? dans Z?
- Écrire un programme calculant par interpolation de Lagrange
le polynôme caractéristique d'une matrice (en donnant à λ
de det(λ I −A), n+1 valeurs distinctes).
- (Long) Écrire un programme qui calcule un déterminant de matrice
en calculant les mineurs 2x2 puis 3x3 etc. (méthode de Laplace)
- Recherche du polynôme minimal. On prend un vecteur aléatoire
à coefficients entiers et on calcule v, Av, ..., Anv puis
on cherche une relation linéaire minimale entre ces vecteurs, en
calculant le noyau de la matrice ayant ces vecteurs colonnes. Si le
noyau est de dimension 1, alors le polynôme minimal est égal au
polynome caractéristique et correspond à un vecteur de la base du noyau.
Sinon, il faut choisir un vecteur du noyau correspondant au degré
le plus petit possible puis faire le PPCM avec les polynomes obtenurs
avec d'autres vecteurs pour obtenir le polynôme minimal avec une grande
probabilité.
Essayez avec la matrice A de taille 3 ayant des 0 sur la diagonale et
des 1 ailleurs.
Écrire un programme mettant en oeuvre cette recherche, testez-le avec
une matrice aléatoire de taille 30.
- Testez l'algorithme méthode de Fadeev pour la matrice A ci-dessus.
Même question pour
A= |
⎛
⎜
⎜
⎝ |
|
⎞
⎟
⎟
⎠ |
,
A= |
⎛
⎜
⎜
⎝ |
|
⎞
⎟
⎟
⎠ |
- Écrire un programme calculant par une méthode itérative
la valeur propre de module maximal d'une matrice à coefficients
complexes. Dans le cas réel, modifier le programme pour pouvoir
traiter le cas d'un couple de complexes conjugués de module maximal.
Dans le cas hermitien ou réel symétrique, éliminer le couple valeur
propre/vecteur propre et continuer la diagonalisation numérique.
- Soient |a|,|b|<√n/2
Écrire une fonction ayant comme arguments a/b (mod n )
qui calcule a et b.
Utiliser ce programme pour résoudre un système 4,4 à coefficients entiers
par une méthode p-adique.
10.7 L'algorithme du simplexe
11 Interpolation
Étant donné la facilité de manipulation qu'apportent les
polynomes, on peut chercher à approcher une fonction par un
polynôme. De plus l'interpolation est un outil très utilisé
pour calculer des polynômes en calcul formel.
11.1 Lagrange
La méthode la plus naturelle consiste à chercher
un polynôme de degré le plus petit possible
égal à la fonction en certains points x0,...,xn
et à trouver une majoration de la différence entre la fonction
et le polynôme.
Le polynome interpolateur de Lagrange répond à cette question.
Soit donc x0,...,xn des réels distincts et y0,...,yn
les valeurs de la fonction à approcher en ces points (on posera
yj=f(xj) pour approcher la fonction f). On cherche
donc P tel que P(xj)=yi pour j ∈ [0,n].
Commencons par voir s'il y a beaucoup de solutions. Soit P et Q
deux solutions distinctes du problème, alors P−Q est non nul
et va s'annuler en x0, ...,xn donc possède n+1 racines donc
est de degré n+1 au moins. Réciproquement, si on ajoute
à P un multiple du polynome A=Πj=0n (X−xj), on obtient
une autre solution. Toutes les solutions se déduisent donc
d'une solution particulière en y ajoutant un polynome de degré
au moins n+1 multiple de A.
Nous allons maintenant construire
une solution particulière de degré au plus n.
Si n=0, on prend P=x0 constant. On procède ensuite par
récurrence. Pour construire le polynôme correspondant
à x0,...,xn+1 on part du polynoôme Pn correspondant à
x0,...,xn et on lui ajoute un multiple réel de A
Ainsi on a toujours Pn+1(xj)=yj pour j=0,..n, on calcule
maintenant a pour que Pn+1(xn+1)=yn+1.
En remplacant avec l'expression de Pn+1 ci-dessus, on obtient
Pn(xn+1)+a |
|
(xn+1−xj) = yn+1 |
Comme tous les xj sont distincts, il existe une solution unique a :
On a donc prouvé le :
Théorème 10
Soit n+1 réels distincts x0,...,xn et n+1
réels quelconques y0,...,yn.
Il existe un unique polynôme P de degré inférieur ou égal à
n, appelé polynome de Lagrange, tel que :
P(xi)=yi
Exemple : déterminons le polynome de degré inférieur ou égal
à 2 tel que P(0)=1, P(1)=2, P(2)=1. On commence par P0=1.
Puis on pose P1=P0+aX=1+aX. Comme P(1)=2=1+a on en tire a=1
donc P1=1+X. Puis on pose P2=P1+aX(X−1), on a P2(2)=3+2a=1
donc a=−1, finalement P2=1+X−X(X−1).
On peut calculer le polynome de Lagrange comme indiqué ci-dessus,
la méthode dite des différences divisées permettant de le faire
de la manière la plus efficace possible (cf. par exemple Demailly).
Reste à estimer l'écart entre une fonction et son polynome
interpolateur, on a le :
Théorème 11
Soit f une fonction n+1 fois dérivable sur un intervalle I=[a,b]
de R, x0,...,xn des réels distincts de I.
Soit P le polynome de Lagrange donné par les xj et yj=f(xj).
Pour tout réel x ∈ I,
il existe un réel ξx ∈ [a,b] (qui dépend de x) tel
que :
Ainsi l'erreur commise dépend d'une majoration de la taille
de la dérivée n+1-ième sur l'intervalle, mais aussi
de la disposition des points xj par rapport à x. Par exemple
si les points xj sont équidistribués, le terme
|Πj=0n(x−xj)| sera plus grand près du bord de I qu'au
centre de I.
Preuve du théorème : Si x est l'un des xj l'égalité est vraie. Soit
on considère maintenant la fonction :
g(t)=f(t)−P(t) − C |
|
(t−xj) |
elle s'annule en xj pour j variant de 0 à n ainsi qu'en x
suite au choix de la constante C, donc g s'annule au moins n+2 fois
sur l'intervalle contenant les xj et x, donc g' s'annule au moins
n+1 fois sur ce même intervalle, donc g'' s'annule au moins
n fois, etc. et finalement g[n+1] s'annule une fois
au moins sur cet intervalle. Or
g[n+1] = f[n+1] − C (n+1)!
car P est de degré inférieur ou égal à n
et Πj=0n(x−xj) − xn+1 est de degré
inférieur ou égal à n. Donc il existe bien un réel ξx dans
l'intervalle contenant les xj et x tel que
11.2 Différences divisées
Le calcul pratique du polynôme de Lagrange se fait efficacement
dans la base { 1,x−x0,...,(x−x0)...(x−xn−1)} par
la méthode des différences divisées.
On définit de manière récursive les coefficients
[Y]= Y,
[Y0,...,Yn]= |
[Y1,...,Yn]−[Y0,...,Yn−1] |
|
Yn−Y0 |
|
Le polynome d'interpolation est alors donné par :
P(x)=[y0]+[y0,y1](x−x0)+[y0,y1,y2](x−x0)(x−x1)
+ ... + [y0,...,yn](x−x0)..(x−xn−1)
Pour la preuve, cf. par exemple Demailly.
11.3 Les splines
Il s'agit de fonctions définies par des polynomes de degré borné
sur des intervalles, dont on fixe la valeur
aux extrémités des intervalles (comme pour le polynome de Lagrange)
ce qui rend la fonction continue, de plus on exige un
degré de régularité plus grand, par exemple etre de classe C2.
Enfin, on fixe des conditions aux bornes de la réunion des
intervalles, par exemple avoir certaines dérivées nulles.
Par exemple supposons qu'on se donne n intervalles, donc n+1
points x0,...,xn, on se fixe une régularité Cd−1. Ceci
entraine (n−1)d conditions de recollement, on y ajoute n+1
conditions de valeur en x0,...,xn, on a donc nd+1 conditions,
la borne sur le degré des polynomes doit donc etre d (ou plus,
mais d suffit) ce qui donne n(d+1) degrés de liberté, on
peut donc ajouter d−1 conditions, par exemple pour les splines
naturelles, on impose que les dérivées d'ordre d/2 à d−1
soient nulles en x0 et xn (si d est pair, on commence à
la dérivée d/2+1-ième nulle en xn).
Pour trouver les polynomes, on doit donc résoudre un grand système
linéaire. Une méthode permettant de diminuer la taille du système
linéaire à résoudre dans le cas des splines naturelles
consiste à se fixer n inconnues z0,..,zn−1
représentant les dérivées d-ième de la spline f en
x0 sur [x0,x1] à xn−1 sur [xn−1,xn],
et (d−1)/2 inconnues fj, représentant
la valeur de la dérivée de f en x0 pour j variant
de 1 à (d−1)/2. On peut alors écrire le polynome sur l'intervalle
[x0,x1] car on connait son développement de Taylor en x0.
On effectue un changement d'origine (par application répétée
de Horner) en x1. On obtient alors le polynome sur [x1,x2]
en remplaçant uniquement la dérivée d-ième par z1.
On continue ainsi jusqu'en xn−1. Le système s'obtient en
calculant la valeur du polynome en x0,...,xn et la nullité
des dérivées d'ordre (d−1)/2 à d/2 en xn. On résoud
le système et on remplace pour avoir les valeurs numériques
des coefficients du polynome.
- 1
- Les
systèmes de calcul formel embarqués (calculatrices) ou devant
gérer des calculs intensifs utilisent d'ailleurs des
méthodes spécifiques pour gérer le problème de la fragmentation de
la mémoire, appelés “garbage collector”. Ce type de méthode
est intégré dans des langages comme Lisp ou Java, en C/C++ on trouve
des libraries pour cela, par exemple GC de Boehm.
- 2
- un quartet=un demi octet
- 3
- Plus précisément deux
piles, la pile de donnée et la pile gérant le flux d'exécution. Cette
dernière n'est pas visible par l'utilisateur
- 4
- Sauf si
on utilise comme dernier argument le nombre d'arguments de la fonction ou
si on utilise (cf. infra) un tag de début de liste d'arguments
- 5
- Toutefois une adaptation du logiciel utilisant comme
quantum de base par exemple 32 bits porterait cette limite
à 6553665535−1
- 6
- Rappelons qu'il s'agit d'une
majoration sur la valeur absolue des coefficients des facteurs de P
- 7
- Plus exactement, on multiplie Pj par le
coefficient dominant de P modulo pl
- 8
- Ici |P| désigne le plus grand
coefficient de P en valeur absolue
- 9
- cette preuve peut être sautée en première
lecture
- 10
- Peut être omise en première lecture
Retour à la page principale de Giac/Xcas.
Ce document a été traduit de LATEX par HEVEA