1 package tim.prune.function.estimate.jama;
\r
6 * For an m-by-n matrix A with m >= n, the QR decomposition is an m-by-n
\r
7 * orthogonal matrix Q and an n-by-n upper triangular matrix R so that A = Q*R.
\r
9 * The QR decomposition always exists, even if the matrix does not have full
\r
10 * rank, so the constructor will never fail. The primary use of the QR
\r
11 * decomposition is in the least squares solution of nonsquare systems of
\r
12 * simultaneous linear equations. This will fail if isFullRank() returns false.
\r
14 * Original authors The MathWorks, Inc. and the National Institute of Standards and Technology
\r
15 * The original public domain code has now been modified and reduced,
\r
16 * and is placed under GPL2 with the rest of the GpsPrune code.
\r
18 public class QRDecomposition
\r
21 /** Array for internal storage of decomposition */
\r
22 private double[][] _QR;
\r
24 /** Row and column dimensions */
\r
27 /** Array for internal storage of diagonal of R */
\r
28 private double[] _Rdiag;
\r
32 * QR Decomposition, computed by Householder reflections.
\r
34 * @param inA Rectangular matrix
\r
35 * @return Structure to access R and the Householder vectors and compute Q.
\r
37 public QRDecomposition(Matrix inA)
\r
40 _QR = inA.getArrayCopy();
\r
41 _m = inA.getNumRows();
\r
42 _n = inA.getNumColumns();
\r
43 _Rdiag = new double[_n];
\r
46 for (int k = 0; k < _n; k++)
\r
48 // Compute 2-norm of k-th column without under/overflow.
\r
50 for (int i = k; i < _m; i++) {
\r
51 nrm = Maths.pythag(nrm, _QR[i][k]);
\r
56 // Form k-th Householder vector.
\r
57 if (_QR[k][k] < 0) {
\r
60 for (int i = k; i < _m; i++) {
\r
65 // Apply transformation to remaining columns.
\r
66 for (int j = k + 1; j < _n; j++)
\r
69 for (int i = k; i < _m; i++) {
\r
70 s += _QR[i][k] * _QR[i][j];
\r
73 for (int i = k; i < _m; i++) {
\r
74 _QR[i][j] += s * _QR[i][k];
\r
83 * ------------------------ Public Methods ------------------------
\r
87 * Is the matrix full rank?
\r
88 * @return true if R, and hence A, has full rank.
\r
90 public boolean isFullRank()
\r
92 for (int j = 0; j < _n; j++) {
\r
100 * Return the Householder vectors
\r
102 * @return Lower trapezoidal matrix whose columns define the reflections
\r
104 private Matrix getH()
\r
106 Matrix X = new Matrix(_m, _n);
\r
107 double[][] H = X.getArray();
\r
108 for (int i = 0; i < _m; i++) {
\r
109 for (int j = 0; j < _n; j++) {
\r
111 H[i][j] = _QR[i][j];
\r
121 * Return the upper triangular factor
\r
125 private Matrix getR()
\r
127 Matrix X = new Matrix(_n, _n);
\r
128 double[][] R = X.getArray();
\r
129 for (int i = 0; i < _n; i++) {
\r
130 for (int j = 0; j < _n; j++) {
\r
132 R[i][j] = _QR[i][j];
\r
133 } else if (i == j) {
\r
134 R[i][j] = _Rdiag[i];
\r
144 * Generate and return the (economy-sized) orthogonal factor
\r
148 private Matrix getQ()
\r
150 Matrix X = new Matrix(_m, _n);
\r
151 double[][] Q = X.getArray();
\r
152 for (int k = _n - 1; k >= 0; k--) {
\r
153 for (int i = 0; i < _m; i++) {
\r
157 for (int j = k; j < _n; j++) {
\r
158 if (_QR[k][k] != 0) {
\r
160 for (int i = k; i < _m; i++) {
\r
161 s += _QR[i][k] * Q[i][j];
\r
163 s = -s / _QR[k][k];
\r
164 for (int i = k; i < _m; i++) {
\r
165 Q[i][j] += s * _QR[i][k];
\r
174 * Least squares solution of A*X = B
\r
175 * @param B A Matrix with as many rows as A and any number of columns
\r
176 * @return X that minimizes the two norm of Q*R*X-B
\r
177 * @exception IllegalArgumentException if matrix dimensions don't agree
\r
178 * @exception RuntimeException if Matrix is rank deficient.
\r
180 public Matrix solve(Matrix B)
\r
182 if (B.getNumRows() != _m) {
\r
183 throw new IllegalArgumentException("Matrix row dimensions must agree.");
\r
185 if (!isFullRank()) {
\r
186 throw new RuntimeException("Matrix is rank deficient.");
\r
189 // Copy right hand side
\r
190 int nx = B.getNumColumns();
\r
191 double[][] X = B.getArrayCopy();
\r
193 // Compute Y = transpose(Q)*B
\r
194 for (int k = 0; k < _n; k++) {
\r
195 for (int j = 0; j < nx; j++) {
\r
197 for (int i = k; i < _m; i++) {
\r
198 s += _QR[i][k] * X[i][j];
\r
200 s = -s / _QR[k][k];
\r
201 for (int i = k; i < _m; i++) {
\r
202 X[i][j] += s * _QR[i][k];
\r
207 for (int k = _n - 1; k >= 0; k--) {
\r
208 for (int j = 0; j < nx; j++) {
\r
209 X[k][j] /= _Rdiag[k];
\r
211 for (int i = 0; i < k; i++) {
\r
212 for (int j = 0; j < nx; j++) {
\r
213 X[i][j] -= X[k][j] * _QR[i][k];
\r
217 return (new Matrix(X, _n, nx).getMatrix(0, _n - 1, 0, nx - 1));
\r