|
| /* Iterativi.c Jacobi + GaussSeidel Risolve sistemi lineari con i metodi iterativi classici. Sono possibili ancora ottimizzazioni nei calcoli. Riga di comando: - "solve 10" crea una matrice di Hilbert 10x10 - "solve 10 1 2 3" crea una tridiagonale 10x10 con elementi 1, 2, 3 (quello centrale è l'elemento diagonale) - "solve nomefile" legge la matrice dal file `nomefile' (prima la dimensione, poi tutti gli elementi per riga) Usare nomefile='-' per leggere da stdin */ #include <stdio.h> #include <stdlib.h> #include <math.h> #include "matutils.h" #define EPS (5e-13f) #define MAXITER 50 /* Metodo iterativo di Jacobi per risolvere Ax=b Restituisce 0 se non c'e' convergenza, altrimenti il numero di iterazioni effettuate. Controllo di convergenza in norma infinito: |x - xold|<EPS */ int JacobiSolve(int n, const matrice a, const double *b, double *x) { int i,j, niter=0; double sum, *oldx, diff=1.0; oldx = calloc(n,sizeof *oldx); for (i=0; i<n; i++) { oldx[i]=x[i]=1.0; } while (diff>EPS && ++niter<MAXITER) { diff = 0.0; for (i=0; i<n; i++) { sum = b[i]; for (j=0; j<n; j++) if (j!=i) sum -= a[i][j]*oldx[j]; x[i] = sum / a[i][i]; diff += fabs(x[i]-oldx[i]); } for (i=0; i<n; i++) oldx[i] = x[i]; /* printf("%d %g ",niter,diff); StampaVet(n,x); */ } free(oldx); if (niter==MAXITER) return 0; return niter; } /* Metodo iterativo di Gauss Seidel per risolvere Ax=b Restituisce 0 se non c'e' convergenza, altrimenti il numero di iterazioni effettuate. Nota: gia' per n=4 e A=matrice di Hilbert e' rho(G)=0.999 e praticamente non c'e' convergenza (anche se teoricamente si') * Inserire peso "w" per ottenere il metodo SOR */ int GaussSeidelSolve(int n, const matrice a, const double *b, double *x) { int i,j, niter=0; double sum, oldxi, diff=1.; for (i=0; i<n; i++) x[i]=1.; while (diff>EPS && ++niter<MAXITER) { diff = 0.0; for (i=0; i<n; i++) { sum = b[i]; for (j=0; j<n; j++) if (j!=i) sum -= a[i][j]*x[j]; oldxi = x[i]; x[i] = sum / a[i][i]; /* <- Inserire peso "w" */ diff += fabs(x[i]-oldxi); } /* printf("%d %g ",niter,diff); StampaVet(n,x); */ } if (niter==MAXITER) return 0; return niter; } int main(int argc, char *argv[]) { int i, n; matrice a, l; double *x1, *x2; /* Inizializzazione della matrice */ if (argc!=2 && argc!=5) { fprintf(stderr,"Uso:\n" "\t%s <nomefile> Legge matrice dal file (usare '-' per stdin)\n" "\t%s <N> Matrice di Hilbert NxN\n" "\t%s <N> <A> <B> <C> Matrice tridiagonare NxN con elementi [A B C]\n", argv[0],argv[0],argv[0]); return 1; } n = atoi(argv[1]); if (argc==2) { if (n==0) a = LeggiFile(argv[1],&n); else { a = alloca_matrice(n); hilbert(n,a); } } else { a = alloca_matrice(n); tridiagonale(n, atof(argv[2]), atof(argv[3]), atof(argv[4]), a); } l=alloca_matrice(n); printf("Matrice iniziale:\n"); Stampa(n,a); x1 = calloc(n, sizeof *x1); for (i=0; i<n; i++) x1[i]=1.; x2 = calloc(n, sizeof *x2); /* Sistema lineare risolto con Jacobi */ printf("Sol. di A.x = "); StampaVet(n,x1); i = JacobiSolve(n,a,x1,x2); if ( !i ) printf("Jacobi non converge\n"); else { printf("Jacobi (%d it): ",i); StampaVet(n,x2); } /* Sistema lineare risolto con GaussSeidel */ printf("Sol. di A.x = "); StampaVet(n,x1); i = GaussSeidelSolve(n,a,x1,x2); if ( !i ) printf("GaussSeidel non converge\n"); else { printf("GaussSeidel (%d it): ",i); StampaVet(n,x2); } /* Libera memoria utilizzata */ free(x2); free(x1); libera_matrice(n,a); libera_matrice(n,l); return 0; } |