View Javadoc

1   package Jama;
2   
3      /** Cholesky Decomposition.
4      <P>
5      For a symmetric, positive definite matrix A, the Cholesky decomposition
6      is an lower triangular matrix L so that A = L*L'.
7      <P>
8      If the matrix is not symmetric or positive definite, the constructor
9      returns a partial decomposition and sets an internal flag that may
10     be queried by the isSPD() method.
11     @version $Id: CholeskyDecomposition.java,v 1.1.1.1 2010/11/30 21:31:59 jeremy Exp $
12     */
13  
14  public class CholeskyDecomposition implements java.io.Serializable {
15  
16  /* ------------------------
17     Class variables
18   * ------------------------ */
19  
20     /** Array for internal storage of decomposition.
21     @serial internal array storage.
22     */
23     private double[][] L;
24  
25     /** Row and column dimension (square matrix).
26     @serial matrix dimension.
27     */
28     private int n;
29  
30     /** Symmetric and positive definite flag.
31     @serial is symmetric and positive definite flag.
32     */
33     private boolean isspd;
34  
35  /* ------------------------
36     Constructor
37   * ------------------------ */
38  
39     /** Cholesky algorithm for symmetric and positive definite matrix.
40     @param  Arg   Square, symmetric matrix.
41     //     Structure to access L and isspd flag.
42     */
43  
44     public CholeskyDecomposition (Matrix Arg) {
45        // Initialize.
46        double[][] A = Arg.getArray();
47        n = Arg.getRowDimension();
48        L = new double[n][n];
49        isspd = (Arg.getColumnDimension() == n);
50        // Main loop.
51        for (int j = 0; j < n; j++) {
52           double[] Lrowj = L[j];
53           double d = 0.0;
54           for (int k = 0; k < j; k++) {
55              double[] Lrowk = L[k];
56              double s = 0.0;
57              for (int i = 0; i < k; i++) {
58                 s += Lrowk[i]*Lrowj[i];
59              }
60              Lrowj[k] = s = (A[j][k] - s)/L[k][k];
61              d = d + s*s;
62              isspd = isspd & (A[k][j] == A[j][k]); 
63           }
64           d = A[j][j] - d;
65           isspd = isspd & (d > 0.0);
66           L[j][j] = Math.sqrt(Math.max(d,0.0));
67           for (int k = j+1; k < n; k++) {
68              L[j][k] = 0.0;
69           }
70        }
71     }
72  
73  /* ------------------------
74     Temporary, experimental code.
75   * ------------------------ *\
76  
77     \** Right Triangular Cholesky Decomposition.
78     <P>
79     For a symmetric, positive definite matrix A, the Right Cholesky
80     decomposition is an upper triangular matrix R so that A = R'*R.
81     This constructor computes R with the Fortran inspired column oriented
82     algorithm used in LINPACK and MATLAB.  In Java, we suspect a row oriented,
83     lower triangular decomposition is faster.  We have temporarily included
84     this constructor here until timing experiments confirm this suspicion.
85     *\
86  
87     \** Array for internal storage of right triangular decomposition. **\
88     private transient double[][] R;
89  
90     \** Cholesky algorithm for symmetric and positive definite matrix.
91     @param  A           Square, symmetric matrix.
92     @param  rightflag   Actual value ignored.
93     @return             Structure to access R and isspd flag.
94     *\
95  
96     public CholeskyDecomposition (Matrix Arg, int rightflag) {
97        // Initialize.
98        double[][] A = Arg.getArray();
99        n = Arg.getColumnDimension();
100       R = new double[n][n];
101       isspd = (Arg.getColumnDimension() == n);
102       // Main loop.
103       for (int j = 0; j < n; j++) {
104          double d = 0.0;
105          for (int k = 0; k < j; k++) {
106             double s = A[k][j];
107             for (int i = 0; i < k; i++) {
108                s = s - R[i][k]*R[i][j];
109             }
110             R[k][j] = s = s/R[k][k];
111             d = d + s*s;
112             isspd = isspd & (A[k][j] == A[j][k]); 
113          }
114          d = A[j][j] - d;
115          isspd = isspd & (d > 0.0);
116          R[j][j] = Math.sqrt(Math.max(d,0.0));
117          for (int k = j+1; k < n; k++) {
118             R[k][j] = 0.0;
119          }
120       }
121    }
122 
123    \** Return upper triangular factor.
124    @return     R
125    *\
126 
127    public Matrix getR () {
128       return new Matrix(R,n,n);
129    }
130 
131 \* ------------------------
132    End of temporary code.
133  * ------------------------ */
134 
135 /* ------------------------
136    Public Methods
137  * ------------------------ */
138 
139    /** Is the matrix symmetric and positive definite?
140    @return     true if A is symmetric and positive definite.
141    */
142 
143    public boolean isSPD () {
144       return isspd;
145    }
146 
147    /** Return triangular factor.
148    @return     L
149    */
150 
151    public Matrix getL () {
152       return new Matrix(L,n,n);
153    }
154 
155    /** Solve A*X = B
156    @param  B   A Matrix with as many rows as A and any number of columns.
157    @return     X so that L*L'*X = B
158    @exception  IllegalArgumentException  Matrix row dimensions must agree.
159    @exception  RuntimeException  Matrix is not symmetric positive definite.
160    */
161 
162    public Matrix solve (Matrix B) {
163       if (B.getRowDimension() != n) {
164          throw new IllegalArgumentException("Matrix row dimensions must agree.");
165       }
166       if (!isspd) {
167          throw new RuntimeException("Matrix is not symmetric positive definite.");
168       }
169 
170       // Copy right hand side.
171       double[][] X = B.getArrayCopy();
172       int nx = B.getColumnDimension();
173 
174       // Solve L*Y = B;
175       for (int k = 0; k < n; k++) {
176          for (int i = k+1; i < n; i++) {
177             for (int j = 0; j < nx; j++) {
178                X[i][j] -= X[k][j]*L[i][k];
179             }
180          }
181          for (int j = 0; j < nx; j++) {
182             X[k][j] /= L[k][k];
183          }
184       }
185 
186       // Solve L'*X = Y;
187       for (int k = n-1; k >= 0; k--) {
188          for (int j = 0; j < nx; j++) {
189             X[k][j] /= L[k][k];
190          }
191          for (int i = 0; i < k; i++) {
192             for (int j = 0; j < nx; j++) {
193                X[i][j] -= X[k][j]*L[k][i];
194             }
195          }
196       }
197       return new Matrix(X,n,nx);
198    }
199 }