home *** CD-ROM | disk | FTP | other *** search
- /*
- The LU approach to numerical linear algebra.
- Mostly off Numerical Recipes.
- */
-
- #include <stdio.h>
- #include <math.h>
- #include "utils.h"
- #include "matrix.h"
-
- void lubksb (float **a, int n, int *indx, float b[]);
- void d_lubksb (double **a, int n, int *indx, double b[]);
- int ludcmp (float **a, int n, int *indx, float *d);
- int d_ludcmp (double **a, int n, int *indx, double *d);
- int dnear (double x, double y);
- int fnear (float x, float y);
-
- int d_LinSys (double **A, double *b, double *x, int K);
-
- #ifdef TESTING
- int TestInversion ();
- int TestLinSys ();
-
- int
- main ()
- {
- int returncode;
-
- returncode = 0;
- if (1 == TestInversion ())
- {
- returncode = 1;
- printf ("INVERSION TEST FAILED.\n");
- }
- if (1 == TestLinSys ())
- {
- returncode = 1;
- printf ("LINEAR SYSTEMS TEST FAILED.\n");
- }
- return returncode;
- }
-
- int
- TestInversion ()
- {
- double biggesterror, error, **A, **Acopy, **B, **product;
- int trial, i, j, K, returncode, seed;
-
- seed = 0;
- K = 20; /* going to be playing with K x K matrices. */
- A = dmatrix (1, K, 1, K);
- Acopy = dmatrix (1, K, 1, K);
- B = dmatrix (1, K, 1, K);
- product = dmatrix (1, K, 1, K);
- printf ("TESTING MATRIX INVERSION.\n");
- printf ("Today, we're going to play with %d x %d matrices.\n\n", K, K);
-
- for (trial = 1; trial <= 5; trial++)
- {
- printf ("Trial #%d:\n generating matrix,\n", trial);
- RandomSym (A, K, &seed);
- CopyMatrix (A, Acopy, K, K); /* because inversion clobbers A */
- printf (" inverting it,\n");
- returncode = d_Inverse (A, B, K);
- if (returncode != 0)
- {
- printf ("d_Inverse returned %d.\n", returncode);
- return 1;
- }
- printf (" post-multiplying,\n");
- d_MMult (Acopy, B, product, K, K, K);
- printf (" finding biggest error = ");
- biggesterror = -1.0e10;
- for (i = 1; i <= K; i++)
- for (j = 1; j <= K; j++)
- {
- if (i == j)
- error = fabs (product[i][i] - 1.0);
- else
- error = fabs (product[i][j]);
- if (error > biggesterror)
- biggesterror = error;
- }
- printf ("%e.\n\n", biggesterror);
- }
- free_dmatrix (A, 1, K, 1, K);
- free_dmatrix (B, 1, K, 1, K);
- free_dmatrix (Acopy, 1, K, 1, K);
- free_dmatrix (product, 1, K, 1, K);
- return 0;
- }
-
- int
- TestLinSys ()
- {
- double sum, biggesterror, error, **A, **Acopy;
- double *x, *b, *test;
- int row, trial, i, K, returncode, seed;
-
- seed = 0;
- K = 20; /* going to be playing with K x K matrices. */
- A = dmatrix (1, K, 1, K);
- Acopy = dmatrix (1, K, 1, K);
- x = dvector (1, K);
- b = dvector (1, K);
- test = dvector (1, K);
- printf ("TESTING SOLUTION OF LINEAR SYSTEMS.\n");
- printf ("Today, we're going to play with %d x %d systems.\n\n", K, K);
-
- for (trial = 1; trial <= 5; trial++)
- {
- printf ("Trial #%d:\n generating system,\n", trial);
- RandomSym (A, K, &seed);
- CopyMatrix (A, Acopy, K, K); /* because LinSys clobbers A. */
- for (i = 1; i <= K; i++)
- b[i] = ran1 (&seed);
- printf (" solving system,\n");
- returncode = d_LinSys (A, b, x, K);
- if (returncode != 0)
- {
- printf ("d_LinSys returned %d.\n", returncode);
- return 1;
- }
- printf (" post-multiplying,\n");
- for (row = 1; row <= K; row++)
- {
- sum = 0.0;
- for (i = 1; i <= K; i++)
- {
- sum += Acopy[row][i] * x[i];
- test[row] = sum;
- }
- }
- printf (" finding biggest error = ");
- biggesterror = -1.0e10;
- for (i = 1; i <= K; i++)
- {
- error = fabs (test[i] - b[i]);
- if (error > biggesterror)
- biggesterror = error;
- }
- printf ("%e.\n\n", biggesterror);
- }
- free_dmatrix (Acopy, 1, K, 1, K);
- free_dmatrix (A, 1, K, 1, K);
- free_dvector (x, 1, K);
- free_dvector (b, 1, K);
- free_dvector (test, 1, K);
- return 0;
- }
-
- #endif
-
- /* all routines are in matrix.h except low-level lu routines. */
-
- #define TINY 1.0e-10;
- #define DTINY 1.0e-20;
-
- int
- fnear (float x, float y)
- {
- return (fabs (x - y) < 1.0e-10) ? 1 : 0;
- }
-
- int
- dnear (double x, double y)
- {
- return (fabs (x - y) < 1.0e-20) ? 1 : 0;
- }
-
- void
- lubksb (float **a, int n, int *indx, float b[])
- {
- int i, ii = 0, ip, j;
- float sum;
-
- for (i = 1; i <= n; i++)
- {
- ip = indx[i];
- sum = b[ip];
- b[ip] = b[i];
- if (ii)
- for (j = ii; j <= i - 1; j++)
- sum -= a[i][j] * b[j];
- else if (sum)
- ii = i;
- b[i] = sum;
- }
- for (i = n; i >= 1; i--)
- {
- sum = b[i];
- for (j = i + 1; j <= n; j++)
- sum -= a[i][j] * b[j];
- b[i] = sum / a[i][i];
- }
- }
-
- void
- d_lubksb (double **a, int n, int *indx, double b[])
- {
- int i, ii = 0, ip, j;
- double sum;
-
- for (i = 1; i <= n; i++)
- {
- ip = indx[i];
- sum = b[ip];
- b[ip] = b[i];
- if (ii)
- for (j = ii; j <= i - 1; j++)
- sum -= a[i][j] * b[j];
- else if (sum)
- ii = i;
- b[i] = sum;
- }
- for (i = n; i >= 1; i--)
- {
- sum = b[i];
- for (j = i + 1; j <= n; j++)
- sum -= a[i][j] * b[j];
- b[i] = sum / a[i][i];
- }
- }
-
- int
- ludcmp (float **a, int n, int *indx, float *d)
- {
- int i, imax, j, k;
- float big, dum, sum, temp;
- float *vv;
-
- vv = vector (1, n);
- *d = 1.0;
- for (i = 1; i <= n; i++)
- {
- big = 0.0;
- for (j = 1; j <= n; j++)
- if ((temp = fabs (a[i][j])) > big)
- big = temp;
- if (fnear (big, 0.0))
- return 1;
- vv[i] = 1.0 / big;
- }
- for (j = 1; j <= n; j++)
- {
- for (i = 1; i < j; i++)
- {
- sum = a[i][j];
- for (k = 1; k < i; k++)
- sum -= a[i][k] * a[k][j];
- a[i][j] = sum;
- }
- big = 0.0;
- for (i = j; i <= n; i++)
- {
- sum = a[i][j];
- for (k = 1; k < j; k++)
- sum -= a[i][k] * a[k][j];
- a[i][j] = sum;
- if ((dum = vv[i] * fabs (sum)) >= big)
- {
- big = dum;
- imax = i;
- }
- }
- if (j != imax)
- {
- for (k = 1; k <= n; k++)
- {
- dum = a[imax][k];
- a[imax][k] = a[j][k];
- a[j][k] = dum;
- }
- *d = -(*d);
- vv[imax] = vv[j];
- }
- indx[j] = imax;
- if (a[j][j] == 0.0)
- a[j][j] = TINY;
- if (j != n)
- {
- dum = 1.0 / (a[j][j]);
- for (i = j + 1; i <= n; i++)
- a[i][j] *= dum;
- }
- }
- free_vector (vv, 1, n);
- return 0;
- }
-
- int
- d_ludcmp (double **a, int n, int *indx, double *d)
- {
- int i, imax, j, k;
- double big, dum, sum, temp;
- double *vv;
-
- vv = dvector (1, n);
- *d = 1.0;
- for (i = 1; i <= n; i++)
- {
- big = 0.0;
- for (j = 1; j <= n; j++)
- if ((temp = fabs (a[i][j])) > big)
- big = temp;
- if (dnear (big, 0.0))
- return 1;
- vv[i] = 1.0 / big;
- }
- for (j = 1; j <= n; j++)
- {
- for (i = 1; i < j; i++)
- {
- sum = a[i][j];
- for (k = 1; k < i; k++)
- sum -= a[i][k] * a[k][j];
- a[i][j] = sum;
- }
- big = 0.0;
- for (i = j; i <= n; i++)
- {
- sum = a[i][j];
- for (k = 1; k < j; k++)
- sum -= a[i][k] * a[k][j];
- a[i][j] = sum;
- if ((dum = vv[i] * fabs (sum)) >= big)
- {
- big = dum;
- imax = i;
- }
- }
- if (j != imax)
- {
- for (k = 1; k <= n; k++)
- {
- dum = a[imax][k];
- a[imax][k] = a[j][k];
- a[j][k] = dum;
- }
- *d = -(*d);
- vv[imax] = vv[j];
- }
- indx[j] = imax;
- if (a[j][j] == 0.0)
- a[j][j] = DTINY;
- if (j != n)
- {
- dum = 1.0 / (a[j][j]);
- for (i = j + 1; i <= n; i++)
- a[i][j] *= dum;
- }
- }
- free_dvector (vv, 1, n);
- return 0;
- }
-
- int
- Inverse (float **A, float **Y, int n)
- {
- int *indexes;
- int i, j;
- float d;
- float *onecolumn;
-
- indexes = ivector (1, n);
- if (ludcmp (A, n, indexes, &d) == 1)
- return 1;
- onecolumn = vector (1, n);
-
- for (i = 1; i <= n; i++)
- {
- for (j = 1; j <= n; j++)
- onecolumn[j] = 0.0;
- onecolumn[i] = 1.0;
- lubksb (A, n, indexes, onecolumn);
- for (j = 1; j <= n; j++)
- Y[j][i] = onecolumn[j];
- }
- free_ivector (indexes, 1, n);
- free_vector (onecolumn, 1, n);
- return 0;
- }
-
- int
- d_Inverse (double **A, double **Y, int n)
- {
- int *indexes;
- int i, j;
- double d;
- double *onecolumn;
-
- indexes = ivector (1, n);
- if (d_ludcmp (A, n, indexes, &d) == 1)
- {
- free_ivector (indexes, 1, n);
- return 1;
- }
- onecolumn = dvector (1, n);
-
- for (i = 1; i <= n; i++)
- {
- for (j = 1; j <= n; j++)
- onecolumn[j] = 0.0;
- onecolumn[i] = 1.0;
- d_lubksb (A, n, indexes, onecolumn);
- for (j = 1; j <= n; j++)
- Y[j][i] = onecolumn[j];
- }
- free_ivector (indexes, 1, n);
- free_dvector (onecolumn, 1, n);
- return 0;
- }
-
- int
- d_LinSys (double **A, double *b, double *x, int K)
- {
- int *indexes;
- double d;
-
- indexes = ivector (1, K);
- if (1 == d_ludcmp (A, K, indexes, &d))
- {
- free_ivector (indexes, 1, K);
- return 1;
- }
- CopyVector (b, x, K); /* copy b into x */
- d_lubksb (A, K, indexes, x);
- free_ivector (indexes, 1, K);
- return 0;
- }
-
- #undef TINY
- #undef DTINY
-