1 /* $Id: matrix.c,v 1.8 2003/04/07 16:27:10 ukai Exp $ */
3 * matrix.h, matrix.c: Liner equation solver using LU decomposition.
7 * LUfactor, LUsolve, Usolve and Lsolve, are based on the functions in
8 * Meschach Library Version 1.2b.
11 /**************************************************************************
13 ** Copyright (C) 1993 David E. Steward & Zbigniew Leyk, all rights reserved.
17 ** This Meschach Library is provided "as is" without any express
18 ** or implied warranty of any kind with respect to this software.
19 ** In particular the authors shall not be liable for any direct,
20 ** indirect, special, incidental or consequential damages arising
21 ** in any way from use of the software.
23 ** Everyone is granted permission to copy, modify and redistribute this
24 ** Meschach Library, provided:
25 ** 1. All copies contain this copyright notice.
26 ** 2. All modified copies shall carry a notice stating who
27 ** made the last modification and the date of such modification.
28 ** 3. No charge is made for this software or works derived from it.
29 ** This clause shall not be construed as constraining other software
30 ** distributed on the same medium as this software, nor is a
31 ** distribution fee considered a charge.
33 ***************************************************************************/
43 #define New(type) ((type*)GC_MALLOC(sizeof(type)))
44 #define NewAtom(type) ((type*)GC_MALLOC_ATOMIC(sizeof(type)))
45 #define New_N(type,n) ((type*)GC_MALLOC((n)*sizeof(type)))
46 #define NewAtom_N(type,n) ((type*)GC_MALLOC_ATOMIC((n)*sizeof(type)))
47 #define Renew_N(type,ptr,n) ((type*)GC_REALLOC((ptr),(n)*sizeof(type)))
49 #define SWAPD(a,b) { double tmp = a; a = b; b = tmp; }
50 #define SWAPI(a,b) { int tmp = a; a = b; b = tmp; }
54 #endif /* not HAVE_FLOAT_H */
56 static double Tiny = 10.0 / DBL_MAX;
57 #elif defined(FLT_MAX)
58 static double Tiny = 10.0 / FLT_MAX;
59 #else /* not defined(FLT_MAX) */
60 static double Tiny = 1.0e-30;
61 #endif /* not defined(FLT_MAX */
64 * LUfactor -- gaussian elimination with scaled partial pivoting
65 * -- Note: returns LU matrix which is A.
69 LUfactor(Matrix A, int *indexarray)
71 int dim = A->dim, i, j, k, i_max, k_max;
75 scale = new_vector(dim);
77 for (i = 0; i < dim; i++)
80 for (i = 0; i < dim; i++) {
82 for (j = 0; j < dim; j++) {
83 tmp = fabs(M_VAL(A, i, j));
91 for (k = 0; k < k_max; k++) {
94 for (i = k; i < dim; i++) {
95 if (fabs(scale->ve[i]) >= Tiny * fabs(M_VAL(A, i, k))) {
96 tmp = fabs(M_VAL(A, i, k)) / scale->ve[i];
109 SWAPI(indexarray[i_max], indexarray[k]);
110 for (j = 0; j < dim; j++)
111 SWAPD(M_VAL(A, i_max, j), M_VAL(A, k, j));
114 for (i = k + 1; i < dim; i++) {
115 tmp = M_VAL(A, i, k) = M_VAL(A, i, k) / M_VAL(A, k, k);
116 for (j = k + 1; j < dim; j++)
117 M_VAL(A, i, j) -= tmp * M_VAL(A, k, j);
124 * LUsolve -- given an LU factorisation in A, solve Ax=b.
128 LUsolve(Matrix A, int *indexarray, Vector b, Vector x)
132 for (i = 0; i < dim; i++)
133 x->ve[i] = b->ve[indexarray[i]];
135 if (Lsolve(A, x, x, 1.) == -1 || Usolve(A, x, x, 0.) == -1)
140 /* m_inverse -- returns inverse of A, provided A is not too rank deficient
141 * -- uses LU factorisation */
144 m_inverse(Matrix A, Matrix out)
146 int *indexarray = NewAtom_N(int, A->dim);
147 Matrix A1 = new_matrix(A->dim);
149 LUfactor(A1, indexarray);
150 return LUinverse(A1, indexarray, out);
155 LUinverse(Matrix A, int *indexarray, Matrix out)
157 int i, j, dim = A->dim;
161 out = new_matrix(dim);
162 tmp = new_vector(dim);
163 tmp2 = new_vector(dim);
164 for (i = 0; i < dim; i++) {
165 for (j = 0; j < dim; j++)
168 if (LUsolve(A, indexarray, tmp, tmp2) == -1)
170 for (j = 0; j < dim; j++)
171 M_VAL(out, j, i) = tmp2->ve[j];
177 * Usolve -- back substitution with optional over-riding diagonal
178 * -- can be in-situ but doesn't need to be.
182 Usolve(Matrix mat, Vector b, Vector out, double diag)
184 int i, j, i_lim, dim = mat->dim;
187 for (i = dim - 1; i >= 0; i--) {
195 for (; i >= 0; i--) {
197 for (j = i + 1; j <= i_lim; j++)
198 sum -= M_VAL(mat, i, j) * out->ve[j];
200 if (fabs(M_VAL(mat, i, i)) <= Tiny * fabs(sum))
203 out->ve[i] = sum / M_VAL(mat, i, i);
206 out->ve[i] = sum / diag;
213 * Lsolve -- forward elimination with (optional) default diagonal value.
217 Lsolve(Matrix mat, Vector b, Vector out, double diag)
219 int i, j, i_lim, dim = mat->dim;
222 for (i = 0; i < dim; i++) {
230 for (; i < dim; i++) {
232 for (j = i_lim; j < i; j++)
233 sum -= M_VAL(mat, i, j) * out->ve[j];
235 if (fabs(M_VAL(mat, i, i)) <= Tiny * fabs(sum))
238 out->ve[i] = sum / M_VAL(mat, i, i);
241 out->ve[i] = sum / diag;
248 * new_matrix -- generate a nxn matrix.
256 mat = New(struct matrix);
258 mat->me = NewAtom_N(double, n * n);
263 * new_matrix -- generate a n-dimension vector.
271 vec = New(struct vector);
273 vec->ve = NewAtom_N(double, n);