Objectifs du chapitre
À la fin de ce chapitre, vous serez capable de:
- expliquer pourquoi la règle de Cramer, mathématiquement irréprochable, n'est pas un algorithme, et chiffrer son coût;
- résoudre un système triangulaire par descente ou par remontée, et justifier le coût de chacune;
- conduire l'élimination de Gauss sur une matrice, reconnaître qu'elle produit une factorisation , et énoncer la condition sur les mineurs principaux dominants qui en garantit l'existence et l'unicité;
- établir le coût de la factorisation et dire pourquoi on factorise une fois pour résoudre ensuite autant de seconds membres qu'on veut;
- appliquer le pivotage partiel, écrire la factorisation sous la forme , et distinguer un problème mal conditionné d'un algorithme instable sur un exemple à petit pivot;
Le problème, et une fausse solution
Tout le chapitre porte sur une seule question: étant donné inversible et , calculer le vecteur tel que
C'est sans doute le calcul le plus exécuté de toute l'informatique scientifique. Une simulation de structure, un circuit électrique, un écoulement, une régression, une reconstruction d'image, un pas de méthode implicite pour une équation différentielle: tous finissent par (3.1), et souvent des milliers de fois. Il vaut donc la peine de savoir exactement ce qu'il en coûte.
L'algèbre linéaire, elle, a répondu depuis longtemps: , et la règle de Cramer donne même chaque composante en fermé,
où est la matrice dont la -ième colonne a été remplacée par . Cette formule est exacte, élégante, et elle a une valeur théorique considérable — elle montre que la solution dépend de façon rationnelle des données, ce qui servira au chapitre 4. Comme algorithme, c'est une catastrophe.
Ce que veut dire
Évaluons (3.2) honnêtement. Il faut déterminants d'ordre . Si l'on calcule chacun par la définition de Leibniz,
la somme porte sur les permutations et chaque terme demande multiplications. Un seul déterminant coûte donc multiplications et additions.
Prenons , une taille dérisoire — un modèle de poutre à cinq nœuds en dépasse déjà largement. On a
donc un déterminant coûte environ opérations, et les vingt et un déterminants de Cramer en réclament
Supposons — c'est une hypothèse de calcul, pas une mesure — une machine effectuant un milliard d'opérations flottantes par seconde. Il lui faudrait secondes, soit environ 32 000 ans, pour résoudre un système de vingt équations. La méthode que nous allons construire dans ce chapitre en demande : le rapport est de .
Pour résoudre avec inversible d'ordre , laquelle de ces approches est raisonnable?
Les systèmes triangulaires
La stratégie de tout le chapitre tient en une phrase: on ne sait résoudre facilement qu'un système triangulaire, donc on ramène tout système à des systèmes triangulaires.
Descente et remontée
Soit avec triangulaire inférieure inversible. La première ligne s'écrit et donne immédiatement. La deuxième, , ne contient plus qu'une inconnue une fois connue. De proche en proche:
C'est la substitution avant, ou descente. Symétriquement, pour avec triangulaire supérieure inversible, on part de la dernière ligne:
C'est la substitution arrière, ou remontée. En Python, la remontée tient en six lignes:
def remontee(U, y):
"""Resout U x = y, U triangulaire superieure inversible."""
n = len(y)
x = [0.0] * n
for i in range(n - 1, -1, -1):
s = y[i]
for j in range(i + 1, n):
s -= U[i][j] *
Comptons. Pour l'indice , la somme de (3.5) contient produits, donc multiplications et soustractions, suivies d'une division. Le total est
Une substitution coûte exactement opérations flottantes, et la descente aussi, par le même compte. Retenez ce : il est la raison de tout ce qui suit, car il est négligeable devant le de la factorisation.
La remontée ci-dessous parcourt les lignes dans le mauvais sens et renvoie un vecteur faux sans la moindre erreur. Réparez-la. Le programme doit afficher la solution du système triangulaire du cours, soit la liste des composantes 2, 3 et -1.
L'élimination de Gauss
Trois opérations qui ne changent rien
Le système (3.1) est invariant par trois opérations élémentaires sur les lignes: échanger deux lignes, multiplier une ligne par un scalaire non nul, ajouter à une ligne un multiple d'une autre. Chacune correspond à la multiplication à gauche par une matrice inversible, donc ne change ni l'ensemble des solutions, ni le rang, ni l'inversibilité. L'élimination de Gauss n'utilise que la troisième — et, à partir de la section sur le pivotage, la première.
Sur le système témoin du cours, les trois états successifs de la matrice augmentée sont ceux de la figure 3.1.
Remettez dans l'ordre les opérations d'une résolution de par élimination de Gauss et remontée.
Glissez les éléments pour les mettre dans le bon ordre
- Résoudre le système triangulaire par remontée, de la dernière ligne vers la première
- Contrôler le résultat par le résidu
- Choisir le pivot de la colonne 1 et former les multiplicateurs
- Recommencer sur le bloc restant: pivot de la colonne 2, multiplicateurs , soustractions
- Constater que la matrice est devenue triangulaire supérieure et lire le dernier pivot
- Soustraire fois la ligne 1 à chaque ligne , second membre compris
L'élimination est une factorisation déguisée
Voici l'observation qui organise tout le reste du chapitre. Pendant l'élimination, on calcule et on jette les multiplicateurs . Ne les jetons pas. Rangeons-les à la place des zéros qu'ils viennent de créer, dans le triangle inférieur, et considérons la matrice
Multiplions-la par la matrice de l'exemple 3.1. Le produit vaut
Ce n'est pas une coïncidence. L'opération est la multiplication à gauche par , dont l'inverse est — on défait la soustraction en la rajoutant. En composant toutes les étapes, on obtient avec triangulaire inférieure à diagonale unité, donc , et le miracle de bookkeeping est que est exactement la matrice (3.8): les multiplicateurs y figurent tels quels, sans changement de signe et sans mélange. C'est une propriété particulière de l'ordre dans lequel l'élimination procède, et elle rend la factorisation gratuite.
Une fois obtenue, résoudre (3.1) revient à résoudre deux systèmes triangulaires:
Existence et unicité
La factorisation n'existe pas toujours. Le contre-exemple tient en quatre coefficients:
qui est inversible — c'est une matrice de permutation — et dont le premier pivot est nul: l'élimination s'arrête à la première division. Si , la première colonne donne avec , donc , puis , ce qui est impossible. La bonne condition porte sur les sous-matrices du coin supérieur gauche.
Démonstration. Par récurrence sur , en construisant la factorisation bloc par bloc; l'existence et l'unicité s'obtiennent du même mouvement.
Initialisation. Pour , avec . La seule écriture avec à diagonale unité est , , et (3.10) se lit .
Hérédité. Supposons le résultat acquis pour l'ordre , et écrivons par blocs:
Par hypothèse de récurrence, de façon unique, et , donc est inversible; l'est aussi, sa diagonale valant . Cherchons et sous la forme
Cette forme est imposée: toute matrice triangulaire inférieure à diagonale unité d'ordre a pour bloc supérieur gauche une matrice triangulaire inférieure à diagonale unité d'ordre , et de même pour . En multipliant,
L'identification avec donne trois équations, que l'on résout dans l'ordre:
Chacune a une solution et une seule, puisque et sont inversibles. Le bloc est quant à lui déjà déterminé de façon unique par l'hypothèse de récurrence. La factorisation d'ordre existe donc et est unique.
Il reste (3.10). En prenant les déterminants,
d'où , qui est non nul par hypothèse. Le cas donne .
L'algorithme de Doolittle
Le théorème 3.1 fournit aussi une manière de calculer et directement, en identifiant les coefficients de un par un plutôt qu'en simulant l'élimination. Comme pour et pour ,
et en isolant le dernier terme on obtient les formules de Doolittle: pour (partie de ), donne
et pour (partie de ),
Il suffit de balayer dans un ordre où tout ce dont on a besoin est déjà calculé: ligne de , puis colonne de , et on recommence. En Python, avec la matrice écrasée sur place — sous la diagonale, sur et au-dessus, exactement comme le fait LAPACK:
def factorise_lu(A):
"""Factorisation LU sans pivotage. Renvoie (L, U) avec L a diagonale unite."""
n = len(A)
U = [ligne[:] for ligne in A]
L = [[1.0 if i == j else 0.0 for j in range(n)] for i in range(n)]
for k in range(n - 1):
for
Ces deux boucles imbriquées sur et , à l'intérieur de la boucle sur , sont la raison du que nous allons maintenant compter exactement.
La factorisation ci-dessous calcule bien , mais elle jette les multiplicateurs et renvoie une matrice égale à l'identité. Conservez-les. Le programme affiche les trois lignes de , puis les trois lignes de , pour le système témoin du cours.
Le coût de la factorisation
Démonstration. Comptons le travail de l'étape , pour . À cette étape, le bloc encore actif est la sous-matrice d'indices , de taille . Pour chacune des lignes :
- une division pour former le multiplicateur , soit opération;
(Le coefficient d'indice lui-même n'est pas calculé: on sait qu'il vaut zéro, et on y range .) L'étape coûte donc
En posant , qui décrit quand décrit , le total vaut
Les deux sommes sont classiques:
D'où
et en réduisant au même dénominateur,
Les deux termes correctifs sont d'ordre et , donc négligeables: .
La formule (3.14) a été vérifiée en exécutant le compte brut de l'algorithme pour allant de à : les deux valeurs coïncident à l'entier près. Quelques repères, avec le rapport à l'équivalent :
| exact | rapport | (une substitution) | ||
|---|---|---|---|---|
| 10 | 615 | 667 | 0,92 | 100 |
| 100 | 661 650 |
Notez la dernière colonne: pour , une substitution coûte opérations contre pour la factorisation, soit 666 fois moins. C'est de ce rapport que vient toute la stratégie.
Combien d'opérations flottantes exactement demande la factorisation d'une matrice pleine d'ordre , d'après la formule (3.14)?
Une factorisation, beaucoup de seconds membres
Voici la raison d'être de , et elle n'est pas le coût brut: l'élimination de Gauss et la factorisation coûtent exactement la même chose, à quelques près. La différence est ailleurs.
L'élimination de Gauss agit sur la matrice augmentée: elle transforme et ensemble. Si un deuxième second membre arrive plus tard — et il arrive presque toujours plus tard —, il faut tout recommencer, à chaque fois. La factorisation, elle, ne touche pas à : elle produit et , qui ne dépendent que de , et chaque nouveau second membre ne coûte plus que les deux substitutions de (3.9), soit opérations.
Le gain se chiffre. Pour et seconds membres:
| + résolutions | éliminations complètes | rapport | |
|---|---|---|---|
| 1 |
Pour un seul second membre, les deux approches se valent — l'écart de est le prix des substitutions. À partir de dix, la factorisation gagne presque un facteur , et à cent elle est soixante-dix-sept fois plus rapide. Or les situations à seconds membres multiples sont la règle: un pas de temps implicite résout le même système à chaque instant, une méthode de Newton pour un système non linéaire réutilise la même jacobienne plusieurs itérations de suite, une analyse de sensibilité rejoue le même modèle sous vingt chargements.
Deux sous-produits gratuits
Le déterminant. D'après (3.10), — au signe près s'il y a eu des échanges de lignes, ce que la section suivante précisera. C'est le seul moyen raisonnable de calculer un déterminant d'ordre élevé, et il coûte et non .
L'inverse. La -ième colonne de est la solution de . On l'obtient donc par une factorisation et couples de substitutions, soit opérations: Ce qui donne la règle d'hygiène la plus importante de ce chapitre.
Vous devez résoudre pour 50 seconds membres connus les uns après les autres, avec fixe d'ordre 400. Quelle stratégie choisissez-vous?
Le pivotage partiel
Un exemple minuscule qui détruit tout
Le théorème 3.1 dit que l'élimination échoue quand un pivot s'annule. En virgule flottante, elle échoue bien avant: il suffit qu'un pivot soit petit devant les coefficients qu'il va servir à diviser. Voici le système, en deux inconnues:
Sa solution exacte est
c'est-à-dire à près. Et le problème est excellemment conditionné: la matrice vaut , son inverse , d'où
Un conditionnement de 4 signifie qu'une perturbation relative de sur les données ne peut produire qu'une perturbation relative de sur la solution: il n'y a aucune excuse à perdre le moindre chiffre.
Éliminons quand même sans échanger les lignes. Le multiplicateur vaut , puis
En double précision, dépasse : l'espacement local des nombres machine y vaut 16, et comme s'arrondissent tous deux au nombre, . Le et le ont été purement et simplement absorbés — c'est l'annulation du chapitre 1, dans l'autre sens: une petite quantité disparaît devant une grande. La remontée donne alors
On obtient au lieu de : une erreur relative de 100 % sur la première composante. Pas 10 %, pas trois chiffres perdus: la totalité.
Échangeons maintenant les deux lignes avant d'éliminer:
Le multiplicateur vaut cette fois , et
deux quantités qui s'arrondissent à — mais l'erreur commise est ici de en valeur absolue sur un nombre d'ordre , c'est-à-dire au niveau du bruit d'arrondi, et non sur un nombre d'ordre . On obtient puis : la solution correcte, à la précision machine.
La stratégie du pivot partiel
La recherche du maximum coûte comparaisons à l'étape , soit comparaisons en tout: un terme en , donc gratuit devant le de la factorisation. C'est le meilleur rapport qualité-prix de tout le chapitre: pour un coût d'ordre inférieur, on borne tous les multiplicateurs par 1 et on rend l'échec impossible.
Il existe aussi un pivotage total, qui cherche le maximum dans toute la sous-matrice active et échange lignes et colonnes. Il donne une meilleure borne théorique sur le facteur de croissance, mais il coûte comparaisons, ce qui n'est plus négligeable, et il n'est presque jamais utilisé: en pratique, le pivotage partiel suffit. On connaît des matrices pour lesquelles il donne un facteur de croissance de — elles existent, elles sont construites exprès, et elles n'apparaissent pas dans les applications. C'est un des rares endroits de ce cours où la pratique est nettement meilleure que la théorie, et il faut le dire ainsi plutôt que de prétendre que la borne est bonne.
Démonstration. Par récurrence sur . Pour , prendre , , , qui est inversible.
Supposons le résultat vrai à l'ordre et soit inversible d'ordre . Sa première colonne n'est pas nulle (sinon serait singulière), donc il existe avec
Soit la permutation qui échange les lignes et . La matrice a pour premier coefficient , et les multiplicateurs
vérifient par le choix de . Posons et , matrice de l'élimination de la première colonne. Alors
où est d'ordre . Comme et que ce déterminant vaut , la matrice est inversible. Par hypothèse de récurrence, il existe , , d'ordre avec et .
Posons . Le point technique est le suivant: ne touche pas la première ligne, donc , et par conséquent
où est la même matrice d'élimination, avec ses multiplicateurs simplement permutés: permuter des lignes après coup revient à permuter les multiplicateurs et à permuter avant. Leurs modules restent . En multipliant l'égalité précédente par à gauche:
Le membre de droite se factorise:
Posons enfin et notons . Comme , on obtient avec
La matrice est triangulaire inférieure à diagonale unité, ses coefficients hors diagonale sont les et ceux de , tous de module ; et est triangulaire supérieure inversible puisque et inversible.
En pratique, ne se stocke pas comme une matrice: on garde un vecteur de entiers disant quelle ligne a été choisie à chaque étape, ce qui coûte mots au lieu de . La résolution devient alors: permuter , descendre, remonter.
def resoudre(A, b):
"""Resout A x = b par elimination de Gauss avec pivot partiel."""
n = len(b)
M = [ligne[:] for ligne in A]
c = list(b)
for k in range(n - 1):
p = max(range(k, n), key=lambda i: abs(M[i][k]))
M[k], M[p] = M[p], M[k]
c[k], c[p]
Le surcoût de la recherche du pivot est de comparaisons, à comparer aux opérations flottantes de la factorisation: pour , environ contre , soit un millième.
Ajoutez le pivotage partiel à cette résolution. Sur le système à petit pivot de la première ligne, elle doit maintenant afficher la solution (1; 1), et continuer de donner (2; 3; -1) sur le système témoin du cours.
Le lecteur règle le système lui-même
Le système est x + y = 2 et a₂₁x + a₂₂y = 3. Faites tourner la deuxième droite jusqu'à la rendre presque parallèle à la première, puis perturbez son second membre: le déplacement de l'intersection n'a rien à voir avec la taille de la perturbation. Le facteur d'amplification observé reste toujours en dessous du conditionnement κ∞(A), qui est la borne du chapitre 4.
Dans le plan, une équation linéaire à deux inconnues est une droite, et résoudre un système , c'est intersecter deux droites. Cette lecture géométrique donne tout de suite l'intuition dont le chapitre 4 fera une inégalité: quand les deux droites sont franchement obliques l'une par rapport à l'autre, leur intersection est un point net, et déplacer légèrement l'une des deux le déplace légèrement. Quand elles deviennent presque parallèles, le point d'intersection glisse le long des droites à la moindre perturbation — sans que la perturbation soit grande, et sans que le déterminant soit nul.
Faites tourner la deuxième droite jusqu'à et , avec : la solution saute de plusieurs unités pour une perturbation de sur un second membre d'ordre 3. Le readout «amplification observée» donne le rapport des deux erreurs relatives, et il reste toujours inférieur au conditionnement affiché à côté. C'est l'invariant de cette figure, et c'est exactement l'inégalité du chapitre 4. Remarquez enfin que le déterminant, lui, n'est pas un bon indicateur: on peut le rendre aussi petit qu'on veut en multipliant une ligne par , sans rien changer aux droites ni à la solution.
Sur le système , avec , l'élimination sans échange de lignes renvoie au lieu de . Comment qualifiez-vous cette situation?
Cholesky: quand la matrice est symétrique définie positive
Une classe de matrices revient si souvent — matrices de rigidité en mécanique, matrices de covariance en statistique, matrices de Gram des moindres carrés du chapitre 7, discrétisations d'opérateurs elliptiques — qu'elle mérite son propre algorithme, deux fois plus rapide et sans pivotage.
Démonstration. Condition suffisante. Supposons avec triangulaire inférieure de diagonale strictement positive. Alors , et pour ,
avec égalité seulement si ; or , donc est inversible et . D'où .
Condition nécessaire. Supposons SDP. Chaque sous-matrice principale dominante est elle-même SDP: pour non nul, le vecteur est non nul et
Le déterminant d'une matrice SDP est le produit de ses valeurs propres, toutes strictement positives; donc pour tout . Le théorème 3.1 s'applique: de façon unique, avec des pivots .
Posons et , qui est triangulaire supérieure . Alors . En transposant et en utilisant :
Or est triangulaire inférieure à diagonale unité et est triangulaire supérieure: le membre de droite est donc, lui aussi, une factorisation de . L'unicité du théorème 3.1 force
Comme tous les sont strictement positifs, est bien définie, et
avec triangulaire inférieure de diagonale . L'unicité de découle de celle de et de : si , en factorisant chaque diagonale on retrouve deux décompositions de , donc deux factorisations , qui coïncident; les racines carrées positives étant uniques, .
L'algorithme et son coût
Les formules s'obtiennent comme celles de Doolittle, en identifiant pour . Le terme diagonal donne
et les termes sous-diagonaux, pour ,
from math import sqrt
def cholesky(A):
"""Facteur de Cholesky B de A symetrique definie positive: A = B B^T."""
n = len(A)
B = [[0.0] * n for _ in range(n)]
for j in range(n):
s = A[j][j] - sum(B[j][k] * B[j][k] for k in range(j))
B[j][j]
Le compte est le même exercice qu'au théorème 3.2. La colonne demande opérations et une racine pour le terme diagonal, puis, pour chacune des lignes en dessous, opérations et une division. En sommant sur , on trouve
soit asymptotiquement: deux fois moins que . Pour , le compte exact donne opérations contre , soit un rapport de . On gagne aussi la mémoire: tient dans le triangle inférieur de , et la symétrie évite d'en stocker la moitié.
Pourquoi Cholesky n'a pas besoin de pivoter
C'est la propriété la plus agréable de cette factorisation, et elle se démontre en une ligne. De on tire, pour tout ,
Aucun coefficient du facteur ne peut dépasser la racine du plus grand terme diagonal de : le facteur de croissance est borné a priori, indépendamment de la matrice, donc il n'y a rien à surveiller pendant l'élimination et aucun échange de lignes à faire. De plus, les pivots sont strictement positifs et la racine carrée de (3.22) est toujours définie — en arithmétique exacte.
Ce facteur de Cholesky oublie de retrancher les termes déjà calculés: il prend la racine du coefficient diagonal tel quel. Complétez les deux sommes de (3.22) et (3.23). Le programme affiche les trois lignes du facteur de la matrice de l'exemple 3.3.
Matrices bandes et matrices creuses
La bande, et ce qu'elle fait gagner
Ces matrices sont omniprésentes: discrétiser une équation différentielle par différences finies donne une matrice tridiagonale (chapitre 9), un problème bidimensionnel sur une grille donne une matrice de largeur , une spline cubique du chapitre 7 conduit à un système tridiagonal.
La propriété décisive est que l'élimination de Gauss sans pivotage préserve la bande. Le raisonnement est immédiat sur (3.7): à l'étape , seules les lignes ont un coefficient non nul en colonne , donc seules celles-là sont modifiées; et la ligne n'a de coefficients non nuls que jusqu'à la colonne , donc la modification ne s'étend pas au-delà. Aucun zéro situé hors de la bande n'est jamais touché. Le facteur hérite de la largeur inférieure et de la largeur supérieure .
Le coût suit. À l'étape , le bloc actif n'est plus mais au plus , d'où
Pour et , le compte exact de l'algorithme donne opérations, contre pour la même matrice traitée comme pleine: . Le cas tridiagonal est encore plus favorable: la factorisation et les deux substitutions se fondent en un algorithme unique, dit de , dont le coût exact est opérations — pour , contre en plein. On est passé de à .
Une matrice tridiagonale d'ordre est factorisée par l'algorithme de Thomas, dont le coût exact est opérations. Combien d'opérations cela fait-il?
Le creux, et le remplissage
Une matrice creuse est une matrice dont la grande majorité des coefficients sont nuls, sans que ces zéros forment nécessairement une bande. On ne stocke alors que les coefficients non nuls, avec leurs indices, et l'on espère que la factorisation restera creuse elle aussi.
Cet espoir est souvent déçu, et c'est le phénomène central de l'algèbre linéaire creuse.
Le mécanisme est donc purement combinatoire: c'est le motif des zéros, et lui seul, qui décide du remplissage. Et il dépend violemment de l'ordre dans lequel on numérote les inconnues — qui est pourtant arbitraire, puisque renuméroter les inconnues et les équations ne change ni le système ni sa solution.
L'exemple de la figure 3.3 est extrême, et c'est pour cela qu'il est instructif. La matrice flèche
a coefficients non nuls, soit 28 pour . La première étape de l'élimination utilise la ligne 1, qui est pleine, pour modifier toutes les lignes suivantes, qui ont toutes un coefficient en colonne 1: chaque couple avec reçoit une contribution, et la sous-matrice restante devient pleine d'un coup. Les facteurs ont coefficients non nuls, soit 72 de remplissage, et la factorisation coûte le prix plein.
Renumérotons maintenant les inconnues dans l'ordre inverse. La flèche pointe vers le bas à droite: chaque ligne n'a que deux coefficients, en et . À l'étape , la seule ligne à modifier est la ligne , et le seul coefficient touché est en colonne — où il est déjà non nul. Le remplissage est nul, les facteurs ont exactement les 28 coefficients de départ, et le coût est linéaire en .
Même matrice, mêmes équations, même solution: seul l'ordre de numérotation a changé, et le coût est passé de à . C'est pourquoi tout solveur creux sérieux commence par une phase d'analyse symbolique, qui ne regarde que le motif des zéros et cherche une permutation minimisant le remplissage de , avant toute arithmétique. Trouver la permutation optimale est un problème NP-difficile, et l'on utilise donc des heuristiques, qui forment une petite bibliothèque classique: Cuthill–McKee inverse, qui regroupe les coefficients près de la diagonale pour fabriquer une bande étroite; le degré minimum, qui élimine à chaque étape l'inconnue créant le moins de remplissage; la dissection emboîtée, qui coupe récursivement le graphe de la matrice en deux moitiés séparées par un petit ensemble de sommets. Ces trois familles portent le nom de leur idée et non d'un gain chiffré, parce que ce gain dépend entièrement de la structure du problème: il peut être nul, ou valoir plusieurs ordres de grandeur comme dans la figure 3.3.
Ce qu'une bibliothèque appelle vraiment
Il vaut la peine de savoir ce qui se passe derrière un appel comme numpy.linalg.solve(A, b) — d'autant que ce cours vous demande d'écrire les boucles vous-même précisément pour que cet appel cesse d'être une boîte noire.
Sous presque toutes les bibliothèques d'algèbre linéaire dense se trouve LAPACK, écrite en Fortran depuis 1992, et sous LAPACK les BLAS, trois niveaux de briques élémentaires: niveau 1 pour les opérations vecteur-vecteur, niveau 2 pour matrice-vecteur, niveau 3 pour matrice-matrice. Les routines pertinentes ici portent des noms de six lettres dont la première, d, indique la double précision:
| Routine | Ce qu'elle fait |
|---|---|
dgetrf | factorisation avec pivotage partiel, matrice pleine |
dgetrs | descente et remontée à partir des facteurs de dgetrf |
dgesv | les deux d'affilée: c'est ce qu'appelle solve |
dpotrf | factorisation de Cholesky d'une matrice SDP |
dgbtrf | factorisation d'une matrice bande stockée par diagonales |
L'algorithme de dgetrf est exactement celui de ce chapitre, à une transformation près: il est par blocs. Au lieu de traiter une colonne à la fois, il factorise un panneau de colonnes (typiquement ), puis met à jour le reste de la matrice par un seul produit matriciel, qui est une opération de niveau 3. Le nombre d'opérations flottantes est inchangé, : ce qui change est le nombre d'accès à la mémoire, car un produit matriciel réutilise chaque donnée chargée fois au lieu d'une. C'est une leçon générale de calcul scientifique, et elle ne contredit pas le comptage d'opérations de ce chapitre — elle le complète: à nombre d'opérations égal, l'organisation des données décide de la vitesse réelle.
Du côté creux, les solveurs directs de référence (SuperLU, UMFPACK, MUMPS, CHOLMOD pour le cas SDP) enchaînent toujours les mêmes trois phases: analyse symbolique — la renumérotation de la section précédente, qui ne fait aucune arithmétique —, factorisation numérique, puis résolution pour chaque second membre. La séparation en trois phases est la traduction logicielle de la règle de ce chapitre: ce qui ne dépend que de se calcule une fois.
Quelques réflexes, pour finir:
- appeler
solve, jamaisinv— quatre fois moins cher et plus précis; - si plusieurs seconds membres, conserver la factorisation (
scipy.linalg.lu_factorpuislu_solve); - si la matrice est SDP, le dire à la bibliothèque (
cho_factor,assume_a="pos"): on gagne le facteur 2 du théorème 3.4 et la garantie de stabilité sans pivotage; - si elle est creuse, la stocker creuse, et non comme un tableau plein de zéros: une matrice pleine demanderait 80 gigaoctets;
- et toujours, à la fin, regarder le résidu.
Synthèse
- La règle de Cramer et l'inverse explicite sont des outils de démonstration, pas des algorithmes: à , Cramer avec la formule de Leibniz demande opérations, contre pour la factorisation — un rapport de . Calculer pour résoudre un système coûte quatre fois trop cher et donne un résultat moins précis.
Quel est le coût, en nombre d'opérations flottantes, d'une seule substitution arrière sur un système triangulaire d'ordre ?
Exercices
Vous pouvez afficher le corrigé directement sous chaque énoncé après avoir cherché la solution.
Soit
- Montrer que n'admet aucune factorisation avec à diagonale unité, alors qu'elle est inversible.
On résout
- Montrer que la matrice est SDP et calculer son facteur de Cholesky.
- Montrer que si est SDP et inversible, alors est SDP. En déduire que est SDP pour toute matrice de permutation — autrement dit, qu'on peut renuméroter les inconnues sans perdre la définie positivité.
On note le nombre d'opérations flottantes (hors racines carrées) de la factorisation de Cholesky d'une matrice pleine SDP d'ordre , avec les formules (3.22) et (3.23).
- Compter le travail de la colonne : terme diagonal, puis les termes sous-diagonaux.
- En déduire sous forme close, et vérifier que .
Références
- Quarteroni, A., Sacco, R. et Saleri, F., Méthodes numériques — algorithmes, analyse et applications, Springer, Milan, chap. 3 (méthodes directes pour les systèmes linéaires, factorisations et de Cholesky, matrices bandes).
- Rappaz, J. et Picasso, M., Introduction à l'analyse numérique, Presses polytechniques et universitaires romandes, Lausanne, chap. 2.
- Trefethen, L. N. et Bau, D., Numerical Linear Algebra, SIAM, Philadelphie, leçons 20 à 23 (élimination de Gauss, pivotage, stabilité et facteur de croissance).
- Golub, G. H. et Van Loan, C. F., Matrix Computations, Johns Hopkins University Press, Baltimore, chap. 3 et 4 (algorithmes par blocs, matrices bandes, Cholesky).
- Higham, N. J., Accuracy and Stability of Numerical Algorithms, 2e éd., SIAM, Philadelphie, chap. 9 (analyse d'erreur de l'élimination de Gauss et du pivotage).
- Davis, T. A., Direct Methods for Sparse Linear Systems, SIAM, Philadelphie (renumérotation, remplissage et solveurs creux).