Statistiques
| Révision :

root / tmp / org.txm.analec.rcp / src / JamaPlus / QRDecomposition.java @ 2099

Historique | Voir | Annoter | Télécharger (5,92 ko)

1
package JamaPlus;
2
import JamaPlus.util.*;
3

    
4
/** QR Decomposition.
5
<P>
6
   For an m-by-n matrix A with m >= n, the QR decomposition is an m-by-n
7
   orthogonal matrix Q and an n-by-n upper triangular matrix R so that
8
   A = Q*R.
9
<P>
10
   The QR decompostion always exists, even if the matrix does not have
11
   full rank, so the constructor will never fail.  The primary use of the
12
   QR decomposition is in the least squares solution of nonsquare systems
13
   of simultaneous linear equations.  This will fail if isFullRank()
14
   returns false.
15
*/
16

    
17
public class QRDecomposition implements java.io.Serializable {
18

    
19
/* ------------------------
20
   Class variables
21
 * ------------------------ */
22

    
23
   /** Array for internal storage of decomposition.
24
   @serial internal array storage.
25
   */
26
   private double[][] QR;
27

    
28
   /** Row and column dimensions.
29
   @serial column dimension.
30
   @serial row dimension.
31
   */
32
   private int m, n;
33

    
34
   /** Array for internal storage of diagonal of R.
35
   @serial diagonal of R.
36
   */
37
   private double[] Rdiag;
38

    
39
/* ------------------------
40
   Constructor
41
 * ------------------------ */
42

    
43
   /** QR Decomposition, computed by Householder reflections.
44
   @param A    Rectangular matrix
45
   @return     Structure to access R and the Householder vectors and compute Q.
46
   */
47

    
48
   public QRDecomposition (Matrix A) {
49
      // Initialize.
50
      QR = A.getArrayCopy();
51
      m = A.getRowDimension();
52
      n = A.getColumnDimension();
53
      Rdiag = new double[n];
54

    
55
      // Main loop.
56
      for (int k = 0; k < n; k++) {
57
         // Compute 2-norm of k-th column without under/overflow.
58
         double nrm = 0;
59
         for (int i = k; i < m; i++) {
60
            nrm = Math.hypot(nrm,QR[i][k]);
61
         }
62

    
63
         if (nrm != 0.0) {
64
            // Form k-th Householder vector.
65
            if (QR[k][k] < 0) {
66
               nrm = -nrm;
67
            }
68
            for (int i = k; i < m; i++) {
69
               QR[i][k] /= nrm;
70
            }
71
            QR[k][k] += 1.0;
72

    
73
            // Apply transformation to remaining columns.
74
            for (int j = k+1; j < n; j++) {
75
               double s = 0.0; 
76
               for (int i = k; i < m; i++) {
77
                  s += QR[i][k]*QR[i][j];
78
               }
79
               s = -s/QR[k][k];
80
               for (int i = k; i < m; i++) {
81
                  QR[i][j] += s*QR[i][k];
82
               }
83
            }
84
         }
85
         Rdiag[k] = -nrm;
86
      }
87
   }
88

    
89
/* ------------------------
90
   Public Methods
91
 * ------------------------ */
92

    
93
   /** Is the matrix full rank?
94
   @return     true if R, and hence A, has full rank.
95
   */
96

    
97
   public boolean isFullRank () {
98
      for (int j = 0; j < n; j++) {
99
         if (Rdiag[j] == 0)
100
            return false;
101
      }
102
      return true;
103
   }
104

    
105
   /** Return the Householder vectors
106
   @return     Lower trapezoidal matrix whose columns define the reflections
107
   */
108

    
109
   public Matrix getH () {
110
      Matrix X = new Matrix(m,n);
111
      double[][] H = X.getArray();
112
      for (int i = 0; i < m; i++) {
113
         for (int j = 0; j < n; j++) {
114
            if (i >= j) {
115
               H[i][j] = QR[i][j];
116
            } else {
117
               H[i][j] = 0.0;
118
            }
119
         }
120
      }
121
      return X;
122
   }
123

    
124
   /** Return the upper triangular factor
125
   @return     R
126
   */
127

    
128
   public Matrix getR () {
129
      Matrix X = new Matrix(n,n);
130
      double[][] R = X.getArray();
131
      for (int i = 0; i < n; i++) {
132
         for (int j = 0; j < n; j++) {
133
            if (i < j) {
134
               R[i][j] = QR[i][j];
135
            } else if (i == j) {
136
               R[i][j] = Rdiag[i];
137
            } else {
138
               R[i][j] = 0.0;
139
            }
140
         }
141
      }
142
      return X;
143
   }
144

    
145
   /** Generate and return the (economy-sized) orthogonal factor
146
   @return     Q
147
   */
148

    
149
   public Matrix getQ () {
150
      Matrix X = new Matrix(m,n);
151
      double[][] Q = X.getArray();
152
      for (int k = n-1; k >= 0; k--) {
153
         for (int i = 0; i < m; i++) {
154
            Q[i][k] = 0.0;
155
         }
156
         Q[k][k] = 1.0;
157
         for (int j = k; j < n; j++) {
158
            if (QR[k][k] != 0) {
159
               double s = 0.0;
160
               for (int i = k; i < m; i++) {
161
                  s += QR[i][k]*Q[i][j];
162
               }
163
               s = -s/QR[k][k];
164
               for (int i = k; i < m; i++) {
165
                  Q[i][j] += s*QR[i][k];
166
               }
167
            }
168
         }
169
      }
170
      return X;
171
   }
172

    
173
   /** Least squares solution of A*X = B
174
   @param B    A Matrix with as many rows as A and any number of columns.
175
   @return     X that minimizes the two norm of Q*R*X-B.
176
   @exception  IllegalArgumentException  Matrix row dimensions must agree.
177
   @exception  RuntimeException  Matrix is rank deficient.
178
   */
179

    
180
   public Matrix solve (Matrix B) {
181
      if (B.getRowDimension() != m) {
182
         throw new IllegalArgumentException("Matrix row dimensions must agree.");
183
      }
184
      if (!this.isFullRank()) {
185
         throw new RuntimeException("Matrix is rank deficient.");
186
      }
187
      
188
      // Copy right hand side
189
      int nx = B.getColumnDimension();
190
      double[][] X = B.getArrayCopy();
191

    
192
      // Compute Y = transpose(Q)*B
193
      for (int k = 0; k < n; k++) {
194
         for (int j = 0; j < nx; j++) {
195
            double s = 0.0; 
196
            for (int i = k; i < m; i++) {
197
               s += QR[i][k]*X[i][j];
198
            }
199
            s = -s/QR[k][k];
200
            for (int i = k; i < m; i++) {
201
               X[i][j] += s*QR[i][k];
202
            }
203
         }
204
      }
205
      // Solve R*X = Y;
206
      for (int k = n-1; k >= 0; k--) {
207
         for (int j = 0; j < nx; j++) {
208
            X[k][j] /= Rdiag[k];
209
         }
210
         for (int i = 0; i < k; i++) {
211
            for (int j = 0; j < nx; j++) {
212
               X[i][j] -= X[k][j]*QR[i][k];
213
            }
214
         }
215
      }
216
      return (new Matrix(X,n,nx).getMatrix(0,n-1,0,nx-1));
217
   }
218
}