~ubuntu-branches/ubuntu/quantal/commons-math/quantal

« back to all changes in this revision

Viewing changes to src/java/org/apache/commons/math/linear/QRDecompositionImpl.java

  • Committer: Bazaar Package Importer
  • Author(s): Damien Raude-Morvan
  • Date: 2009-03-15 20:20:21 UTC
  • Revision ID: james.westby@ubuntu.com-20090315202021-zto3nmvqgcf3ami4
Tags: upstream-1.2
ImportĀ upstreamĀ versionĀ 1.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
 
3
 * contributor license agreements.  See the NOTICE file distributed with
 
4
 * this work for additional information regarding copyright ownership.
 
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
 
6
 * (the "License"); you may not use this file except in compliance with
 
7
 * the License.  You may obtain a copy of the License at
 
8
 *
 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
 
10
 *
 
11
 * Unless required by applicable law or agreed to in writing, software
 
12
 * distributed under the License is distributed on an "AS IS" BASIS,
 
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
14
 * See the License for the specific language governing permissions and
 
15
 * limitations under the License.
 
16
 */
 
17
 
 
18
package org.apache.commons.math.linear;
 
19
 
 
20
/**
 
21
 * Calculates the QR-decomposition of a matrix. In the QR-decomposition of
 
22
 * a matrix A consists of two matrices Q and R that satisfy: A = QR, Q is
 
23
 * orthogonal (Q<sup>T</sup>Q = I), and R is upper triangular. If A is
 
24
 * m&times;n, Q is m&times;m and R m&times;n. 
 
25
 * <p>
 
26
 * Implemented using Householder reflectors.</p>
 
27
 *
 
28
 * @see <a href="http://mathworld.wolfram.com/QRDecomposition.html">MathWorld</a>
 
29
 * @see <a href="http://en.wikipedia.org/wiki/QR_decomposition">Wikipedia</a>
 
30
 * 
 
31
 * @version $Revision: 620312 $ $Date: 2008-02-10 12:28:59 -0700 (Sun, 10 Feb 2008) $
 
32
 * @since 1.2
 
33
 */
 
34
public class QRDecompositionImpl implements QRDecomposition {
 
35
 
 
36
    /**
 
37
     * A packed representation of the QR decomposition. The elements above the 
 
38
     * diagonal are the elements of R, and the columns of the lower triangle 
 
39
     * are the Householder reflector vectors of which an explicit form of Q can
 
40
     * be calculated. 
 
41
     */
 
42
    private double[][] qr;
 
43
 
 
44
    /**
 
45
     * The diagonal elements of R.
 
46
     */
 
47
    private double[] rDiag;
 
48
 
 
49
    /**
 
50
     * The row dimension of the given matrix. The size of Q will be m x m, the 
 
51
     * size of R will be m x n. 
 
52
     */
 
53
    private int m;
 
54
 
 
55
    /**
 
56
     * The column dimension of the given matrix. The size of R will be m x n. 
 
57
     */
 
58
    private int n;
 
59
 
 
60
    /**
 
61
     * Calculates the QR decomposition of the given matrix. 
 
62
     * 
 
63
     * @param matrix The matrix to decompose.
 
64
     */
 
65
    public QRDecompositionImpl(RealMatrix matrix) {
 
66
        m = matrix.getRowDimension();
 
67
        n = matrix.getColumnDimension();
 
68
        qr = matrix.getData();
 
69
        rDiag = new double[n];
 
70
 
 
71
        /*
 
72
         * The QR decomposition of a matrix A is calculated using Householder
 
73
         * reflectors by repeating the following operations to each minor
 
74
         * A(minor,minor) of A:
 
75
         */
 
76
        for (int minor = 0; minor < Math.min(m, n); minor++) {
 
77
            /*
 
78
             * Let x be the first column of the minor, and a^2 = |x|^2.
 
79
             * x will be in the positions qr[minor][minor] through qr[m][minor].
 
80
             * The first column of the transformed minor will be (a,0,0,..)'
 
81
             * The sign of a is chosen to be opposite to the sign of the first
 
82
             * component of x. Let's find a:
 
83
             */
 
84
            double xNormSqr = 0;
 
85
            for (int row = minor; row < m; row++) {
 
86
                xNormSqr += qr[row][minor]*qr[row][minor];
 
87
            }
 
88
            double a = Math.sqrt(xNormSqr);
 
89
            if (qr[minor][minor] > 0) a = -a;
 
90
            rDiag[minor] = a;
 
91
 
 
92
            if (a != 0.0) {
 
93
 
 
94
                /*
 
95
                 * Calculate the normalized reflection vector v and transform
 
96
                 * the first column. We know the norm of v beforehand: v = x-ae
 
97
                 * so |v|^2 = <x-ae,x-ae> = <x,x>-2a<x,e>+a^2<e,e> =
 
98
                 * a^2+a^2-2a<x,e> = 2a*(a - <x,e>).
 
99
                 * Here <x, e> is now qr[minor][minor].
 
100
                 * v = x-ae is stored in the column at qr:
 
101
                 */
 
102
                qr[minor][minor] -= a; // now |v|^2 = -2a*(qr[minor][minor])
 
103
 
 
104
                /*
 
105
                 * Transform the rest of the columns of the minor:
 
106
                 * They will be transformed by the matrix H = I-2vv'/|v|^2.
 
107
                 * If x is a column vector of the minor, then
 
108
                 * Hx = (I-2vv'/|v|^2)x = x-2vv'x/|v|^2 = x - 2<x,v>/|v|^2 v.
 
109
                 * Therefore the transformation is easily calculated by
 
110
                 * subtracting the column vector (2<x,v>/|v|^2)v from x.
 
111
                 * 
 
112
                 * Let 2<x,v>/|v|^2 = alpha. From above we have
 
113
                 * |v|^2 = -2a*(qr[minor][minor]), so
 
114
                 * alpha = -<x,v>/(a*qr[minor][minor])
 
115
                 */
 
116
                for (int col = minor+1; col < n; col++) {
 
117
                    double alpha = 0;
 
118
                    for (int row = minor; row < m; row++) {
 
119
                        alpha -= qr[row][col]*qr[row][minor];
 
120
                    }
 
121
                    alpha /= a*qr[minor][minor];
 
122
 
 
123
                    // Subtract the column vector alpha*v from x.
 
124
                    for (int row = minor; row < m; row++) {
 
125
                        qr[row][col] -= alpha*qr[row][minor];
 
126
                    }
 
127
                }
 
128
            }
 
129
        }
 
130
    }
 
131
 
 
132
    /**
 
133
     * Returns the matrix R of the QR-decomposition. 
 
134
     * 
 
135
     * @return the R matrix
 
136
     */
 
137
    public RealMatrix getR()
 
138
    {
 
139
        // R is supposed to be m x n
 
140
        RealMatrixImpl ret = new RealMatrixImpl(m,n);
 
141
        double[][] r = ret.getDataRef();
 
142
 
 
143
        // copy the diagonal from rDiag and the upper triangle of qr
 
144
        for (int row = Math.min(m,n)-1; row >= 0; row--) {
 
145
            r[row][row] = rDiag[row];
 
146
            for (int col = row+1; col < n; col++) {
 
147
                r[row][col] = qr[row][col];
 
148
            }
 
149
        }
 
150
        return ret;
 
151
    }
 
152
 
 
153
    /**
 
154
     * Returns the matrix Q of the QR-decomposition.
 
155
     * 
 
156
     * @return the Q matrix
 
157
     */
 
158
    public RealMatrix getQ()
 
159
    {
 
160
        // Q is supposed to be m x m
 
161
        RealMatrixImpl ret = new RealMatrixImpl(m,m);
 
162
        double[][] Q = ret.getDataRef();
 
163
 
 
164
        /* 
 
165
         * Q = Q1 Q2 ... Q_m, so Q is formed by first constructing Q_m and then 
 
166
         * applying the Householder transformations Q_(m-1),Q_(m-2),...,Q1 in 
 
167
         * succession to the result 
 
168
         */ 
 
169
        for (int minor = m-1; minor >= Math.min(m,n); minor--) {
 
170
            Q[minor][minor]=1;
 
171
        }
 
172
 
 
173
        for (int minor = Math.min(m,n)-1; minor >= 0; minor--){
 
174
            Q[minor][minor] = 1;
 
175
            if (qr[minor][minor] != 0.0) {
 
176
                for (int col = minor; col < m; col++) {
 
177
                    double alpha = 0;
 
178
                    for (int row = minor; row < m; row++) {
 
179
                        alpha -= Q[row][col] * qr[row][minor];
 
180
                    }
 
181
                    alpha /= rDiag[minor]*qr[minor][minor];
 
182
 
 
183
                    for (int row = minor; row < m; row++) {
 
184
                        Q[row][col] -= alpha*qr[row][minor];
 
185
                    }
 
186
                }
 
187
            }
 
188
        }
 
189
 
 
190
        return ret;
 
191
    }
 
192
}