Codice R.Spettrale

Home Su

 

/*
   Calcola la matrice di iterazione del metodo
   di Gauss Seidel e di Jacobi, e ne calcola
   il raggio spettrale col metodo delle potenze.
Parametro sulla linea di comando:
nomefile     -> legge la matrice dal file ('-' per tastiera)
n            ->  matrice di Hilbert n per n
n a b c      ->  matrice tridiagonale n per n con elementi [a b c]
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "matutils.h"
#define PREC (5e-16f)
/*
   Matrice J
   La diagonale e' nulla, per il resto
   basta dividere ogni riga di A per l'elemento
   diagonale e cambiare segno.
*/
void MatriceJacobi(int n,const matrice a, matrice m)
{
  int i, j;
  for (i=0; i<n; i++)
    for (j=0; j<n; j++)
      if (i==j) m[i][j]=0.;
      else m[i][j] = -a[i][j]/a[i][i];
}
/*
   Matrice G
   Calcolata con una "forward substitution" dove la matrice
   da invertire e' la parte triangolare inferiore di A
   e il "termine noto" e' la parte strettamente superiore.
   Nota: prima riga di G == prima riga di J, inoltre
   la prima colonna di G e' nulla.
*/
void MatriceGaussSeidel(int n,const matrice a, matrice g)
{
  int i, j, k;
  double sum;
  for (i=0; i<n; i++)
    for (k=0; k<n; k++) {
      if (i<k) sum=a[i][k]; else sum=0.;
      for (j=0; j<i; j++) sum += a[i][j]*g[j][k];
      g[i][k] = -sum/a[i][i];
    }
}
#define MAXITER 200
#define LOOSEPREC (PREC*8192)
/*
   Metodo delle potenze.
   Spesso non converge (ad es. perche' ci sono piu' autovalori
   con lo stesso modulo) e restituisce -1.
   ATTENZIONE: -1 non puņ essere confuso con un vero raggio
   spettrale, essendo un numero negativo!
*/
double RaggioSpettrale(int n,const matrice a)
{
  int i, j, niter=0;
  double sum, norma, *x, *newx, beta=0, oldbeta=1;
  x = calloc(n,sizeof *x);
  newx = calloc(n,sizeof *newx);
  for (i=0; i<n; i++) x[i]=1;
  while ( ++niter<MAXITER && fabs(beta-oldbeta)>LOOSEPREC ) {
    oldbeta=beta;
    norma = -1;
    for (i=0; i<n; i++) {
      sum = 0.;
      for (j=0; j<n; j++) sum += a[i][j]*x[j];
      newx[i] = sum;
      if ( fabs(sum)>norma ) norma=fabs(sum);
    }
    beta = newx[0]/x[0];
    for (i=0; i<n; i++) x[i]=newx[i]/norma;
  }
  if (niter==MAXITER) return -1;
  return fabs(beta);
}


int main(int argc, char *argv[])
{
  int n=0;
  matrice a, l;
	/* 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);
  MatriceJacobi(n,a,l);
  printf("Matrice J (raggio spettrale %f):\n",RaggioSpettrale(n,l));
  Stampa(n,l);
  MatriceGaussSeidel(n,a,l);
  printf("Matrice G (raggio spettrale %f):\n",RaggioSpettrale(n,l));
  Stampa(n,l);
        /* Libera memoria utilizzata */
  libera_matrice(n,a);
  libera_matrice(n,l);
  return 0;
}