ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-4/src/math/jama_cholesky.hpp
Revision: 3495
Committed: Tue Apr 7 20:16:26 2009 UTC (15 years, 2 months ago) by gezelter
File size: 5232 byte(s)
Log Message:
adding jama and tnt libraries for various linear algebra routines

File Contents

# Content
1 #ifndef JAMA_CHOLESKY_H
2 #define JAMA_CHOLESKY_H
3
4 #include <cmath>
5 /* needed for sqrt() below. */
6
7
8 namespace JAMA
9 {
10
11 using namespace TNT;
12
13 /**
14 <P>
15 For a symmetric, positive definite matrix A, this function
16 computes the Cholesky factorization, i.e. it computes a lower
17 triangular matrix L such that A = L*L'.
18 If the matrix is not symmetric or positive definite, the function
19 computes only a partial decomposition. This can be tested with
20 the is_spd() flag.
21
22 <p>Typical usage looks like:
23 <pre>
24 Array2D<double> A(n,n);
25 Array2D<double> L;
26
27 ...
28
29 Cholesky<double> chol(A);
30
31 if (chol.is_spd())
32 L = chol.getL();
33
34 else
35 cout << "factorization was not complete.\n";
36
37 </pre>
38
39
40 <p>
41 (Adapted from JAMA, a Java Matrix Library, developed by jointly
42 by the Mathworks and NIST; see http://math.nist.gov/javanumerics/jama).
43
44 */
45
46 template <class Real>
47 class Cholesky
48 {
49 Array2D<Real> L_; // lower triangular factor
50 int isspd; // 1 if matrix to be factored was SPD
51
52 public:
53
54 Cholesky();
55 Cholesky(const Array2D<Real> &A);
56 Array2D<Real> getL() const;
57 Array1D<Real> solve(const Array1D<Real> &B);
58 Array2D<Real> solve(const Array2D<Real> &B);
59 int is_spd() const;
60
61 };
62
63 template <class Real>
64 Cholesky<Real>::Cholesky() : L_(0,0), isspd(0) {}
65
66 /**
67 @return 1, if original matrix to be factored was symmetric
68 positive-definite (SPD).
69 */
70 template <class Real>
71 int Cholesky<Real>::is_spd() const
72 {
73 return isspd;
74 }
75
76 /**
77 @return the lower triangular factor, L, such that L*L'=A.
78 */
79 template <class Real>
80 Array2D<Real> Cholesky<Real>::getL() const
81 {
82 return L_;
83 }
84
85 /**
86 Constructs a lower triangular matrix L, such that L*L'= A.
87 If A is not symmetric positive-definite (SPD), only a
88 partial factorization is performed. If is_spd()
89 evalutate true (1) then the factorizaiton was successful.
90 */
91 template <class Real>
92 Cholesky<Real>::Cholesky(const Array2D<Real> &A)
93 {
94
95
96 int m = A.dim1();
97 int n = A.dim2();
98
99 isspd = (m == n);
100
101 if (m != n)
102 {
103 L_ = Array2D<Real>(0,0);
104 return;
105 }
106
107 L_ = Array2D<Real>(n,n);
108
109
110 // Main loop.
111 for (int j = 0; j < n; j++)
112 {
113 Real d(0.0);
114 for (int k = 0; k < j; k++)
115 {
116 Real s(0.0);
117 for (int i = 0; i < k; i++)
118 {
119 s += L_[k][i]*L_[j][i];
120 }
121 L_[j][k] = s = (A[j][k] - s)/L_[k][k];
122 d = d + s*s;
123 isspd = isspd && (A[k][j] == A[j][k]);
124 }
125 d = A[j][j] - d;
126 isspd = isspd && (d > 0.0);
127 L_[j][j] = sqrt(d > 0.0 ? d : 0.0);
128 for (int k = j+1; k < n; k++)
129 {
130 L_[j][k] = 0.0;
131 }
132 }
133 }
134
135 /**
136
137 Solve a linear system A*x = b, using the previously computed
138 cholesky factorization of A: L*L'.
139
140 @param B A Matrix with as many rows as A and any number of columns.
141 @return x so that L*L'*x = b. If b is nonconformat, or if A
142 was not symmetric posidtive definite, a null (0x0)
143 array is returned.
144 */
145 template <class Real>
146 Array1D<Real> Cholesky<Real>::solve(const Array1D<Real> &b)
147 {
148 int n = L_.dim1();
149 if (b.dim1() != n)
150 return Array1D<Real>();
151
152
153 Array1D<Real> x = b.copy();
154
155
156 // Solve L*y = b;
157 for (int k = 0; k < n; k++)
158 {
159 for (int i = 0; i < k; i++)
160 x[k] -= x[i]*L_[k][i];
161 x[k] /= L_[k][k];
162
163 }
164
165 // Solve L'*X = Y;
166 for (int k = n-1; k >= 0; k--)
167 {
168 for (int i = k+1; i < n; i++)
169 x[k] -= x[i]*L_[i][k];
170 x[k] /= L_[k][k];
171 }
172
173 return x;
174 }
175
176
177 /**
178
179 Solve a linear system A*X = B, using the previously computed
180 cholesky factorization of A: L*L'.
181
182 @param B A Matrix with as many rows as A and any number of columns.
183 @return X so that L*L'*X = B. If B is nonconformat, or if A
184 was not symmetric posidtive definite, a null (0x0)
185 array is returned.
186 */
187 template <class Real>
188 Array2D<Real> Cholesky<Real>::solve(const Array2D<Real> &B)
189 {
190 int n = L_.dim1();
191 if (B.dim1() != n)
192 return Array2D<Real>();
193
194
195 Array2D<Real> X = B.copy();
196 int nx = B.dim2();
197
198 // Cleve's original code
199 #if 0
200 // Solve L*Y = B;
201 for (int k = 0; k < n; k++) {
202 for (int i = k+1; i < n; i++) {
203 for (int j = 0; j < nx; j++) {
204 X[i][j] -= X[k][j]*L_[k][i];
205 }
206 }
207 for (int j = 0; j < nx; j++) {
208 X[k][j] /= L_[k][k];
209 }
210 }
211
212 // Solve L'*X = Y;
213 for (int k = n-1; k >= 0; k--) {
214 for (int j = 0; j < nx; j++) {
215 X[k][j] /= L_[k][k];
216 }
217 for (int i = 0; i < k; i++) {
218 for (int j = 0; j < nx; j++) {
219 X[i][j] -= X[k][j]*L_[k][i];
220 }
221 }
222 }
223 #endif
224
225
226 // Solve L*y = b;
227 for (int j=0; j< nx; j++)
228 {
229 for (int k = 0; k < n; k++)
230 {
231 for (int i = 0; i < k; i++)
232 X[k][j] -= X[i][j]*L_[k][i];
233 X[k][j] /= L_[k][k];
234 }
235 }
236
237 // Solve L'*X = Y;
238 for (int j=0; j<nx; j++)
239 {
240 for (int k = n-1; k >= 0; k--)
241 {
242 for (int i = k+1; i < n; i++)
243 X[k][j] -= X[i][j]*L_[i][k];
244 X[k][j] /= L_[k][k];
245 }
246 }
247
248
249
250 return X;
251 }
252
253
254 }
255 // namespace JAMA
256
257 #endif
258 // JAMA_CHOLESKY_H