source: GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/mixmops.cxx @ 1097

Revision 1097, 6.2 KB checked in by mattausch, 18 years ago (diff)
Line 
1/************************************************************************
2
3  NxN Matrix class
4
5  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
6 
7  $Id: mixmops.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
8
9 ************************************************************************/
10
11#include "stdmix.h"
12#include "MxMatrix.h"
13
14// This section originally from Paul's matrix library.
15
16#define SWAP(a, b, t)   {t = a; a = b; b = t;}
17#define A(i,j) mxm_ref(_a, i, j, N)
18#define B(i,j) mxm_ref(_b, i, j, N)
19
20// Solve nxn system Ax=b.
21// Leaves solution x in b, and destroys original A and b vectors.
22// Return value is determinant of A.
23// If system is singular, returns 0 and leaves trash in b
24//
25// Uses Gaussian elimination with partial pivoting.
26//
27static
28double internal_solve(double *_a, double *b, const int N)
29{
30    int i, j, k;
31    double max, t, det, sum, pivot;
32
33    /*---------- forward elimination ----------*/
34
35    det = 1.0;
36    for (i=0; i<N; i++) {               /* eliminate in column i */
37        max = -1.0;
38        for (k=i; k<N; k++)             /* find pivot for column i */
39            if (fabs(A(k, i)) > max) {
40                max = fabs(A(k, i));
41                j = k;
42            }
43        if (max<=0.) return 0.0;        /* if no nonzero pivot, PUNT */
44        if (j!=i) {                     /* swap rows i and j */
45            for (k=i; k<N; k++)
46                SWAP(A(i, k), A(j, k), t);
47            det = -det;
48            SWAP(b[i], b[j], t);        /* swap elements of column vector */
49        }
50        pivot = A(i, i);
51        det *= pivot;
52        for (k=i+1; k<N; k++)           /* only do elems to right of pivot */
53            A(i, k) /= pivot;
54
55        /* we know that A(i, i) will be set to 1, so don't bother to do it */
56        b[i] /= pivot;
57        for (j=i+1; j<N; j++) {         /* eliminate in rows below i */
58            t = A(j, i);                /* we're gonna zero this guy */
59            for (k=i+1; k<N; k++)       /* subtract scaled row i from row j */
60                A(j, k) -= A(i, k)*t;   /* (ignore k<=i, we know they're 0) */
61            b[j] -= b[i]*t;
62        }
63    }
64
65    /*---------- back substitution ----------*/
66
67    for (i=N-1; i>=0; i--) {            /* solve for x[i] (put it in b[i]) */
68        sum = b[i];
69        for (k=i+1; k<N; k++)           /* really A(i, k)*x[k] */
70            sum -= A(i, k)*b[k];
71        b[i] = sum;
72    }
73
74    return det;
75}
76
77// Returns determinant of a, and b=a inverse.
78// If matrix is singular, returns 0 and leaves trash in b.
79//
80// Uses Gaussian elimination with partial pivoting.
81//
82static
83double internal_invert(double *_a, double *_b, const int N)
84{
85    uint i, j, k;
86    double max, t, det, pivot;
87
88    /*---------- forward elimination ----------*/
89
90    for (i=0; i<N; i++)                 /* put identity matrix in B */
91        for (j=0; j<N; j++)
92            B(i, j) = (double)(i==j);
93
94    det = 1.0;
95    for (i=0; i<N; i++) {               /* eliminate in column i, below diag */
96        max = -1.;
97        for (k=i; k<N; k++)             /* find pivot for column i */
98            if (fabs(A(k, i)) > max) {
99                max = fabs(A(k, i));
100                j = k;
101            }
102        if (max<=0.) return 0.;         /* if no nonzero pivot, PUNT */
103        if (j!=i) {                     /* swap rows i and j */
104            for (k=i; k<N; k++)
105                SWAP(A(i, k), A(j, k), t);
106            for (k=0; k<N; k++)
107                SWAP(B(i, k), B(j, k), t);
108            det = -det;
109        }
110        pivot = A(i, i);
111        det *= pivot;
112        for (k=i+1; k<N; k++)           /* only do elems to right of pivot */
113            A(i, k) /= pivot;
114        for (k=0; k<N; k++)
115            B(i, k) /= pivot;
116        /* we know that A(i, i) will be set to 1, so don't bother to do it */
117
118        for (j=i+1; j<N; j++) {         /* eliminate in rows below i */
119            t = A(j, i);                /* we're gonna zero this guy */
120            for (k=i+1; k<N; k++)       /* subtract scaled row i from row j */
121                A(j, k) -= A(i, k)*t;   /* (ignore k<=i, we know they're 0) */
122            for (k=0; k<N; k++)
123                B(j, k) -= B(i, k)*t;
124        }
125    }
126
127    /*---------- backward elimination ----------*/
128
129    for (i=N-1; i>0; i--) {             /* eliminate in column i, above diag */
130        for (j=0; j<i; j++) {           /* eliminate in rows above i */
131            t = A(j, i);                /* we're gonna zero this guy */
132            for (k=0; k<N; k++)         /* subtract scaled row i from row j */
133                B(j, k) -= B(i, k)*t;
134        }
135    }
136
137    return det;
138}
139
140#undef A
141#undef B
142#undef SWAP
143
144float mxm_invert(float *r, const float *a, const int N)
145{
146    mxm_local_block(a2, double, N);
147    mxm_local_block(r2, double, N);
148
149    uint i;
150    for(i=0; i<N*N; i++) a2[i] = a[i];
151    float det = internal_invert(a2, r2, N);
152    for(i=0; i<N*N; i++) r[i] = r2[i];
153
154    mxm_free_local(a2);
155    mxm_free_local(r2);
156    return det;
157}
158
159double mxm_invert(double *r, const double *a, const int N)
160{
161    mxm_local_block(a2, double, N);
162    mxm_set(a2, a, N);
163    double det = internal_invert(a2, r, N);
164    mxm_free_local(a2);
165    return det;
166}
167
168double mxm_solve(double *x, const double *A, const double *b, const int N)
169{
170    mxm_local_block(a2, double, N);
171    mxm_set(a2, A, N);
172    mxv_set(x, b, N);
173    double det = internal_solve(a2, x, N);
174    mxm_free_local(a2);
175    return det;
176}
177
178// Originally based on public domain code by <Ajay_Shah@rand.org>
179// which can be found at http://lib.stat.cmu.edu/general/ajay
180//
181// The factorization is valid as long as the returned nullity == 0
182// U contains the upper triangular factor itself.
183//
184int mxm_cholesky(double *U, const double *A, const int N)
185{
186    double sum;
187
188    int nullity = 0;
189    mxm_set(U, 0.0, N);
190
191    for(int i=0; i<N; i++)
192    {
193        /* First compute U[i][i] */
194        sum = mxm_ref(A, i, i, N);
195
196        for(int j=0; j<=(i-1); j++)
197            sum -= mxm_ref(U, j, i, N) * mxm_ref(U, j, i, N);
198
199        if( sum > 0 )
200        {
201            mxm_ref(U, i, i, N) = sqrt(sum);
202
203            /* Now find elements U[i][k], k > i. */
204            for(int k=(i+1); k<N; k++)
205            {
206                sum = mxm_ref(A, i, k, N);
207
208                for(int j=0; j<=(i-1); j++)
209                    sum -= mxm_ref(U, j, i, N)*mxm_ref(U, j, k, N);
210               
211                mxm_ref(U, i, k, N) = sum / mxm_ref(U, i, i, N);
212            }
213        }
214        else
215        {
216            for(int k=i; k<N; k++) mxm_ref(U, i, k, N) = 0.0;
217            nullity++;
218        }
219    }
220
221    return nullity;
222}
Note: See TracBrowser for help on using the repository browser.