source: branches/MetisMQI/src/main/java/weka/core/matrix/QRDecomposition.java

Last change on this file was 29, checked in by gnappo, 15 years ago

Taggata versione per la demo e aggiunto branch.

File size: 6.1 KB
Line 
1/*
2 * This software is a cooperative product of The MathWorks and the National
3 * Institute of Standards and Technology (NIST) which has been released to the
4 * public domain. Neither The MathWorks nor NIST assumes any responsibility
5 * whatsoever for its use by other parties, and makes no guarantees, expressed
6 * or implied, about its quality, reliability, or any other characteristic.
7 */
8
9/*
10 * QRDecomposition.java
11 * Copyright (C) 1999 The Mathworks and NIST
12 *
13 */
14
15package weka.core.matrix;
16
17import weka.core.RevisionHandler;
18import weka.core.RevisionUtils;
19
20import java.io.Serializable;
21
22/**
23 * QR Decomposition.
24 * <P>
25 * For an m-by-n matrix A with m &gt;= n, the QR decomposition is an m-by-n
26 * orthogonal matrix Q and an n-by-n upper triangular matrix R so that A = Q*R.
27 * <P>
28 * The QR decompostion always exists, even if the matrix does not have full
29 * rank, so the constructor will never fail.  The primary use of the QR
30 * decomposition is in the least squares solution of nonsquare systems of
31 * simultaneous linear equations.  This will fail if isFullRank() returns false.
32 * <p/>
33 * Adapted from the <a href="http://math.nist.gov/javanumerics/jama/" target="_blank">JAMA</a> package.
34 *
35 * @author The Mathworks and NIST
36 * @author Fracpete (fracpete at waikato dot ac dot nz)
37 * @version $Revision: 5953 $
38 */
39public class QRDecomposition 
40  implements Serializable, RevisionHandler {
41
42  /** for serialization */
43  private static final long serialVersionUID = -5013090736132211418L;
44
45  /**
46   * Array for internal storage of decomposition.
47   *    @serial internal array storage.
48   */
49  private double[][] QR;
50
51  /**
52   * Row and column dimensions.
53   *    @serial column dimension.
54   *    @serial row dimension.
55   */
56  private int m, n;
57
58  /**
59   * Array for internal storage of diagonal of R.
60   *    @serial diagonal of R.
61   */
62  private double[] Rdiag;
63
64  /**
65   * QR Decomposition, computed by Householder reflections.
66   * @param A    Rectangular matrix
67   */
68  public QRDecomposition(Matrix A) {
69    // Initialize.
70    QR = A.getArrayCopy();
71    m = A.getRowDimension();
72    n = A.getColumnDimension();
73    Rdiag = new double[n];
74
75    // Main loop.
76    for (int k = 0; k < n; k++) {
77      // Compute 2-norm of k-th column without under/overflow.
78      double nrm = 0;
79      for (int i = k; i < m; i++) {
80        nrm = Maths.hypot(nrm,QR[i][k]);
81      }
82
83      if (nrm != 0.0) {
84        // Form k-th Householder vector.
85        if (QR[k][k] < 0) {
86          nrm = -nrm;
87        }
88        for (int i = k; i < m; i++) {
89          QR[i][k] /= nrm;
90        }
91        QR[k][k] += 1.0;
92
93        // Apply transformation to remaining columns.
94        for (int j = k+1; j < n; j++) {
95          double s = 0.0; 
96          for (int i = k; i < m; i++) {
97            s += QR[i][k]*QR[i][j];
98          }
99          s = -s/QR[k][k];
100          for (int i = k; i < m; i++) {
101            QR[i][j] += s*QR[i][k];
102          }
103        }
104      }
105      Rdiag[k] = -nrm;
106    }
107  }
108
109  /**
110   * Is the matrix full rank?
111   * @return     true if R, and hence A, has full rank.
112   */
113  public boolean isFullRank() {
114    for (int j = 0; j < n; j++) {
115      if (Rdiag[j] == 0)
116        return false;
117    }
118    return true;
119  }
120
121  /**
122   * Return the Householder vectors
123   * @return     Lower trapezoidal matrix whose columns define the reflections
124   */
125  public Matrix getH() {
126    Matrix X = new Matrix(m,n);
127    double[][] H = X.getArray();
128    for (int i = 0; i < m; i++) {
129      for (int j = 0; j < n; j++) {
130        if (i >= j) {
131          H[i][j] = QR[i][j];
132        } else {
133          H[i][j] = 0.0;
134        }
135      }
136    }
137    return X;
138  }
139
140  /**
141   * Return the upper triangular factor
142   * @return     R
143   */
144  public Matrix getR() {
145    Matrix X = new Matrix(n,n);
146    double[][] R = X.getArray();
147    for (int i = 0; i < n; i++) {
148      for (int j = 0; j < n; j++) {
149        if (i < j) {
150          R[i][j] = QR[i][j];
151        } else if (i == j) {
152          R[i][j] = Rdiag[i];
153        } else {
154          R[i][j] = 0.0;
155        }
156      }
157    }
158    return X;
159  }
160
161  /**
162   * Generate and return the (economy-sized) orthogonal factor
163   * @return     Q
164   */
165  public Matrix getQ() {
166    Matrix X = new Matrix(m,n);
167    double[][] Q = X.getArray();
168    for (int k = n-1; k >= 0; k--) {
169      for (int i = 0; i < m; i++) {
170        Q[i][k] = 0.0;
171      }
172      Q[k][k] = 1.0;
173      for (int j = k; j < n; j++) {
174        if (QR[k][k] != 0) {
175          double s = 0.0;
176          for (int i = k; i < m; i++) {
177            s += QR[i][k]*Q[i][j];
178          }
179          s = -s/QR[k][k];
180          for (int i = k; i < m; i++) {
181            Q[i][j] += s*QR[i][k];
182          }
183        }
184      }
185    }
186    return X;
187  }
188
189  /**
190   * Least squares solution of A*X = B
191   * @param B    A Matrix with as many rows as A and any number of columns.
192   * @return     X that minimizes the two norm of Q*R*X-B.
193   * @exception  IllegalArgumentException  Matrix row dimensions must agree.
194   * @exception  RuntimeException  Matrix is rank deficient.
195   */
196  public Matrix solve(Matrix B) {
197    if (B.getRowDimension() != m) {
198      throw new IllegalArgumentException("Matrix row dimensions must agree.");
199    }
200    if (!this.isFullRank()) {
201      throw new RuntimeException("Matrix is rank deficient.");
202    }
203
204    // Copy right hand side
205    int nx = B.getColumnDimension();
206    double[][] X = B.getArrayCopy();
207
208    // Compute Y = transpose(Q)*B
209    for (int k = 0; k < n; k++) {
210      for (int j = 0; j < nx; j++) {
211        double s = 0.0; 
212        for (int i = k; i < m; i++) {
213          s += QR[i][k]*X[i][j];
214        }
215        s = -s/QR[k][k];
216        for (int i = k; i < m; i++) {
217          X[i][j] += s*QR[i][k];
218        }
219      }
220    }
221    // Solve R*X = Y;
222    for (int k = n-1; k >= 0; k--) {
223      for (int j = 0; j < nx; j++) {
224        X[k][j] /= Rdiag[k];
225      }
226      for (int i = 0; i < k; i++) {
227        for (int j = 0; j < nx; j++) {
228          X[i][j] -= X[k][j]*QR[i][k];
229        }
230      }
231    }
232    return (new Matrix(X,n,nx).getMatrix(0,n-1,0,nx-1));
233  }
234 
235  /**
236   * Returns the revision string.
237   *
238   * @return            the revision
239   */
240  public String getRevision() {
241    return RevisionUtils.extract("$Revision: 5953 $");
242  }
243}
Note: See TracBrowser for help on using the repository browser.