/*
* 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�ly.
* -Ken
*
* The views represented here are mine and are not necessarily shared by
* my employer.
Ken Turkowski [email protected]
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 <stdlib.h>
#include <neato.h>
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];
}
}
|