/* * This code was (mostly) written by Ken Turkowski, who said: * * Oh, that. I wrote it in college the first time. It's open source - I think I * posted it after seeing so many people solve equations by inverting matrices * by computing minors naïvely. * -Ken * * The views represented here are mine and are not necessarily shared by * my employer. Ken Turkowski turk@apple.com Immersive Media Technologist http://www.worldserver.com/turk/ Apple Computer, Inc. 1 Infinite Loop, MS 302-3VR Cupertino, CA 95014 */ /* This module solves linear equations in several variables (Ax = b) using * LU decomposition with partial pivoting and row equilibration. Although * slightly more work than Gaussian elimination, it is faster for solving * several equations using the same coefficient matrix. It is * particularly useful for matrix inversion, by sequentially solving the * equations with the columns of the unit matrix. * * lu_decompose() decomposes the coefficient matrix into the LU matrix, * and lu_solve() solves the series of matrix equations using the * previous LU decomposition. * * Ken Turkowski (apple!turk) * written 3/2/79, revised and enhanced 8/9/83. */ #include #include static double *scales; static double **lu; static int *ps; /* lu_decompose() decomposes the coefficient matrix A into upper and lower * triangular matrices, the composite being the LU matrix. * * The arguments are: * * a - the (n x n) coefficient matrix * n - the order of the matrix * * 1 is returned if the decomposition was successful, * and 0 is returned if the coefficient matrix is singular. */ int lu_decompose(double **a, int n) { register int i, j, k; int pivotindex = 0; double pivot, biggest, mult, tempf; double fabs(); if (lu) free_array(lu); lu = new_array(n,n,0.0); if (ps) free(ps); ps = N_NEW(n,int); if (scales) free(scales); scales = N_NEW(n,double); for (i = 0; i < n; i++) { /* For each row */ /* Find the largest element in each row for row equilibration */ biggest = 0.0; for (j = 0; j < n; j++) if (biggest < (tempf = fabs(lu[i][j] = a[i][j]))) biggest = tempf; if (biggest != 0.0) scales[i] = 1.0 / biggest; else { scales[i] = 0.0; return(0); /* Zero row: singular matrix */ } ps[i] = i; /* Initialize pivot sequence */ } for (k = 0; k < n-1; k++) { /* For each column */ /* Find the largest element in each column to pivot around */ biggest = 0.0; for (i = k; i < n; i++) { if (biggest < (tempf = fabs(lu[ps[i]][k]) * scales[ps[i]])) { biggest = tempf; pivotindex = i; } } if (biggest == 0.0) return(0); /* Zero column: singular matrix */ if (pivotindex != k) { /* Update pivot sequence */ j = ps[k]; ps[k] = ps[pivotindex]; ps[pivotindex] = j; } /* Pivot, eliminating an extra variable each time */ pivot = lu[ps[k]][k]; for (i = k+1; i < n; i++) { lu[ps[i]][k] = mult = lu[ps[i]][k] / pivot; if (mult != 0.0) { for (j = k+1; j < n; j++) lu[ps[i]][j] -= mult * lu[ps[k]][j]; } } } if (lu[ps[n-1]][n-1] == 0.0) return(0); /* Singular matrix */ return(1); } /* lu_solve() solves the linear equation (Ax = b) after the matrix A has * been decomposed with lu_decompose() into the lower and upper triangular * matrices L and U. * * The arguments are: * * x - the solution vector * b - the constant vector * n - the order of the equation */ void lu_solve(double *x, double *b, int n) { register int i, j; double dot; /* Vector reduction using U triangular matrix */ for (i = 0; i < n; i++) { dot = 0.0; for (j = 0; j < i; j++) dot += lu[ps[i]][j] * x[j]; x[i] = b[ps[i]] - dot; } /* Back substitution, in L triangular matrix */ for (i = n-1; i >= 0; i--) { dot = 0.0; for (j = i+1; j < n; j++) dot += lu[ps[i]][j] * x[j]; x[i] = (x[i] - dot) / lu[ps[i]][i]; } }