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

File Contents

# User Rev Content
1 gezelter 1336 #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