TP2 : instabilités numériques Pensez à structurer l implémentation, à mettre des commentaires et à passer les arguments par référence en les protégeant (const) si besoin. On se propose de tester la méthode d élimination de Gauss pour résoudre un système linéaire AX = b. De façon formelle, l algorithme a la forme suivante : for ( int k=1;k<n; k++) for ( int i=k+1; i<=n; i ++) {for ( int j=k+1;j<=n; j++) {A( i, j) =A( i, k) A(k, j )/A(k, k ); B( i) =A( i, k) B(k)/A(k, k ) ; Structures On commencera par écrire une strucure vecteur possédant un entier pour la dimension et un pointeur de double pour stocker les valeurs et une structure matrice possédant des données similaires : struct vecteur double val ; ; struct matrice double lignes ; On adoptera un stockage de la matrice ligne par ligne. A ces structures seront associées les fonctionnalités suivantes : init(int d, double v=0) : intialisation du vecteur ou de la matrice à partir de la dimension et d une valeur init(const vecteur &) et init(const matrice &) : initialisation à partir d un vecteur et d une matrice clear() : libération de la mémoire print() : impression Fonctions Outre ces fonctionnalités, on écrira également les fonction suivantes : matrice hilbert(int d) : génération de la matrice de Hilbert H ij = 1/(i + j 1). vecteur produit(const matrice &A,const vecteur &X) : produit matrice x vecteur (utile pour fabriquer un second membre b = Ax) 1
double ps(const vecteur &X,const vecteur &Y) : produit scalaire double norme(const vecteur &X) : norme euclidienne d un vecteur double normesup(const vecteur &X) : norme sup d un vecteur vecteur cl(const vecteur &X,double a, const vecteur &Y, double b) : combinaison linéaire de 2 vecteurs (utile pour calculer l erreur) print() : impression vecteur gauss(const matrice &A,const vecteur &B, double eps) : méthode de Gauss, eps valeur minimale du pivot Pour finir, on écrira un programme principal réalisant une boucle sur la dimension (dim=2 à 50), calculant les erreurs euclidienne et sup commises par la méthode de Gauss appliquée à la matrice de Hilbert et au second membre b = Ax avec x i = 1 i. Ces erreurs pourront être stockées sur un fichier, chaque ligne contenant la dimension, l erreur euclidienne, l erreur sup, qui pourra être relu en Matlab (load fichier;) afin de tracer les courbes d erreur (dim,log10(erreur)). Pour écrire dans un fichier, il faut inclure l entête <fstream> et écrire les instructions suivantes : ofstream out ( nom fichier ) ;... out<<dim<< <<er2<< <<ersup<<end ;... out. close ( ) ; 2
Correction // Résolution d un système linéaire AX=B par la méthode de Gauss // inclusion entêtes système #include <iostream> #include <fstream> #include <cmath> using namespace std ; // strucure vecteur struct vecteur double val ; void i n i t ( int d, double v ) ; void i n i t (const vecteur & U) ; void clear ( ) ; void print ( ostream &); ; // i n i t i a l i s a t i o n du vecteur // i n i t i a l i s a t i o n avec un vecteur // effacement de la matrice //impression de la matrice // strucure matrice, stockage ligne par ligne struct matrice double lignes ; void i n i t ( int d, double v ) ; // i n i t i a l i s a t i o n de la matrice void i n i t (const matrice & A) ; // recopie d une matrice void clear ( ) ; // effacement de la matrice void print ( ostream &); //impression de la matrice vecteur ligne ( int i ) const ; // conversion d une ligne en vecteur ; //méthodes attachées à la structure matrice void matrice : : i n i t ( int d, double v=0.) {// allocation dim=d ; lignes=new double [d ] ; for ( int i =0; i<dim ; i++) { lignes [ i ]=new double [ dim ] ; for ( int j =0;j<dim ; j++) lignes [ i ] [ j ]=v ; void matrice : : i n i t (const matrice & A) // recopie d une matrice {dim=a. dim ; lignes=new double [ dim ] ; for ( int i =0; i<dim ; i++) { lignes [ i ]=new double [ dim ] ; for ( int j =0;j<dim ; j++) lignes [ i ] [ j ]=A. lignes [ i ] [ j ] ; void matrice : : clear () {for ( int i =0; i<dim ; i++) delete [ ] lignes [ i ] ; delete [ ] lignes ; void matrice : : print ( ostream & out=cout ) {for ( int i =0; i<dim ; i++) {out<< ligne <<i<< : ; for ( int j =0;j<dim ; j++) out<<lignes [ i ] [ j]<< ; out<<endl ; vecteur matrice : : ligne ( int i ) const // attention pas de recopie de la ligne 3
{ vecteur V; V. dim=dim ; V. val=lignes [ i ] ; return V; // construction de la matrice de Hilbert matrice hilbert ( int d) {matrice H; ; H. i n i t (d ) ; for ( int i =0; i<h. dim ; i++) for ( int j =0;j<H. dim ; j++) H. lignes [ i ] [ j ]=1./( i+j +1.); return H; //méthodes attachées à la structure vecteur void vecteur : : i n i t ( int d, double v=0.) {// allocation dim=d ; val=new double [ d ] ; for ( int i =0; i<dim ; i++) val [ i ]=v ; void vecteur : : i n i t (const vecteur & U) {// allocation dim=u. dim ; val=new double [ dim ] ; for ( int i =0; i<dim ; i++) val [ i ]=U. val [ i ] ; void vecteur : : clear () {delete [ ] val ; void vecteur : : print ( ostream & out=cout ) {for ( int i =0; i<dim ; i++) out<<val [ i]<< ; // produit scalaire de vecteurs double ps (const vecteur & U, const vecteur & V) {double u=u. val ; double v=v. val ; double r =0.; for ( int i =0; i<u. dim ; i++,++u,++v) r+=( u) ( v ) ; return r ; //norme euclidienne d un vecteur double norme(const vecteur & U) {return sqrt ( ps (U,U) ) ; //norme sup d un vecteur double normesup (const vecteur & U) {double s=0; for ( int i =0; i<u. dim ; i++) s=max( s, abs (U. val [ i ] ) ) ; return s ; //combinaison linéaire de 2 vecteurs vecteur cl (const vecteur & U, double a, const vecteur & V, double b) { vecteur R; R. i n i t (U. dim ) ; for ( int i =0; i<r. dim ; i++) R. val [ i ]=a U. val [ i ]+b V. val [ i ] ; 4
return R; // produit matrice x vecteur ( tableau ) vecteur produit (const matrice & M, const vecteur & X) { vecteur R; R. i n i t (M. dim ) ; for ( int i =0; i<r. dim ; i++) R. val [ i ]=ps (M. ligne ( i ),X) ; return R; // résolution du système par Gauss ligne sans pivot // la matrice A et B ne sont pas modifiés en sortie vecteur gauss (const matrice & A, const vecteur & B, double eps=1.e 20) {matrice M; // recopie des arguments M. i n i t (A) ; vecteur X; X. i n i t (B) ; int d=m. dim ; for ( int k=0;k<d 1;k++) // boucle de Gauss {double piv=m. lignes [ k ] [ k ] ; // test pivot if ( abs ( piv)<eps ) {cout<< ligne <<k+1<< pivot < <<eps ; exit ( 1); for ( int i=k+1; i<d ; i++) // élimination {double c=m. lignes [ i ] [ k ]/ piv ; for ( int j=k+1;j<d ; j++) M. lignes [ i ] [ j] =c M. lignes [ k ] [ j ] ; M. lignes [ i ] [ k ]=0.; X. val [ i] =c X. val [ k ] ; for ( int i=d 1; i >=0;i ) // résolution du système triangulaire {for ( int j=d 1;j>i ; j ) X. val [ i] =M. lignes [ i ] [ j ] X. val [ j ] ; X. val [ i ]/=M. lignes [ i ] [ i ] ; M. clear ( ) ; return X; //programme principal int main () { // résolution HX=B (H matrice de Hilbert ) int nb=51; ofstream out ( erreurs ) ; // fichier de résultat // boucle sur la dimension for ( int dim=2; dim<nb ; dim++) {out<<dim ; matrice H=hilbert (dim ) ; //matrice de Hilbert vecteur X;X. i n i t (dim, 1 ) ; vecteur HX=produit (H,X) ; vecteur Y=gauss (H,HX) ; //Gauss vecteur d=cl (X,1,Y, 1); out<< <<norme(d)<< <<normesup (d ) ; vecteur Yp=gauss pivot (H,HX) ; //Gauss avec pivot partiel vecteur dp=cl (X,1,Yp, 1); out<< <<norme( dp)<< <<normesup ( dp)<<e n d l ; // libération mémoire H. clear ( ) ;X. clear ( ) ;HX. clear ( ) ; Y. clear ( ) ;Yp. clear ( ) ; d. clear ( ) ; dp. clear ( ) ; 5
//impression des erreurs out. close ( ) ; return 0; On obtient les résultats suivants : 25 Méthode de Gauss (matrice de Hilbert) 20 15 10 conditionnement log10(erreur) 5 0 5 err. sup err. L2 10 15 20 0 5 10 15 20 25 30 35 40 45 50 dim L utilisation de la méthode de Gauss avec pivot n apporte aucune amélioration car l instabilité est due au très mauvais conditionnement de la matrice. // résolution du système par Gauss ligne avec pivot partiel // la matrice A et B ne sont pas modifiés en sortie vecteur gauss pivot (const matrice & A, const vecteur & B, double eps=1.e 20) {matrice M; M. i n i t (A) ; vecteur X; X. i n i t (B) ; int d=m. dim ; int ind [ d ] ; // tableau de permutation des lignes for ( int i =0; i<d ; i++) ind [ i ]= i ; // boucle Gauss for ( int k=0;k<d 1;k++) {// recherche du pivot maximal int K=ind [ k ] ; int imax=k ; double piv=m. lignes [K] [ k ] ; for ( int i=k+1; i<d ; i++) {int I=ind [ i ] ; float c=abs (M. lignes [ I ] [ k ] ) ; if ( abs ( c)>abs ( piv )){ piv=c ; imax=i ; if ( abs ( piv)<eps ) {cout<< i t é r a t i o n <<k<< pivot < <<eps ; exit ( 1); //permutation des lignes if (imax!=k) {int K=ind [ k ] ; 6
ind [ k]=ind [ imax ] ; ind [ imax]=k; // élimination for ( int i=k+1; i<d ; i++) {int I=ind [ i ] ; int K=ind [ k ] ; double c=m. lignes [ I ] [ k ]/ piv ; for ( int j=k+1;j<d ; j++) M. lignes [ I ] [ j] =c M. lignes [K] [ j ] ; M. lignes [ I ] [ k ]=0.; X. val [ I] =c X. val [K] ; // résolution du système triangulaire for ( int i=d 1; i >=0;i ) {int I=ind [ i ] ; for ( int j=d 1;j>i ; j ) {int J=ind [ j ] ; X. val [ I] =M. lignes [ I ] [ j ] X. val [ J ] ; X. val [ I ]/=M. lignes [ I ] [ i ] ; return X; 7