All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xmlobjects.gml.util.jama.QRDecomposition Maven / Gradle / Ivy

There is a newer version: 1.1.2
Show newest version
/*
 * gml-objects - A Java mapping for the OGC Geography Markup Language (GML)
 * https://github.com/xmlobjects/gml-objects
 *
 * Copyright 2019-2024 Claus Nagel 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.xmlobjects.gml.util.jama;

/**
 * QR Decomposition.
 * 

* For an m-by-n matrix A with m >= n, the QR decomposition is an m-by-n * orthogonal matrix Q and an n-by-n upper triangular matrix R so that * A = Q*R. *

* The QR decompostion always exists, even if the matrix does not have * full rank, so the constructor will never fail. The primary use of the * QR decomposition is in the least squares solution of nonsquare systems * of simultaneous linear equations. This will fail if isFullRank() * returns false. */ public class QRDecomposition implements java.io.Serializable { /* ------------------------ Class variables * ------------------------ */ /** * Array for internal storage of decomposition. * * @serial internal array storage. */ private double[][] QR; /** * Row and column dimensions. * * @serial column dimension. * @serial row dimension. */ private int m, n; /** * Array for internal storage of diagonal of R. * * @serial diagonal of R. */ private double[] Rdiag; /* ------------------------ Constructor * ------------------------ */ /** * QR Decomposition, computed by Householder reflections. * Structure to access R and the Householder vectors and compute Q. * * @param A Rectangular matrix */ public QRDecomposition(Matrix A) { // Initialize. QR = A.getArrayCopy(); m = A.getRowDimension(); n = A.getColumnDimension(); Rdiag = new double[n]; // Main loop. for (int k = 0; k < n; k++) { // Compute 2-norm of k-th column without under/overflow. double nrm = 0; for (int i = k; i < m; i++) { nrm = Maths.hypot(nrm, QR[i][k]); } if (nrm != 0.0) { // Form k-th Householder vector. if (QR[k][k] < 0) { nrm = -nrm; } for (int i = k; i < m; i++) { QR[i][k] /= nrm; } QR[k][k] += 1.0; // Apply transformation to remaining columns. for (int j = k + 1; j < n; j++) { double s = 0.0; for (int i = k; i < m; i++) { s += QR[i][k] * QR[i][j]; } s = -s / QR[k][k]; for (int i = k; i < m; i++) { QR[i][j] += s * QR[i][k]; } } } Rdiag[k] = -nrm; } } /* ------------------------ Public Methods * ------------------------ */ /** * Is the matrix full rank? * * @return true if R, and hence A, has full rank. */ public boolean isFullRank() { for (int j = 0; j < n; j++) { if (Rdiag[j] == 0) return false; } return true; } /** * Return the Householder vectors * * @return Lower trapezoidal matrix whose columns define the reflections */ public Matrix getH() { Matrix X = new Matrix(m, n); double[][] H = X.getArray(); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (i >= j) { H[i][j] = QR[i][j]; } else { H[i][j] = 0.0; } } } return X; } /** * Return the upper triangular factor * * @return R */ public Matrix getR() { Matrix X = new Matrix(n, n); double[][] R = X.getArray(); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (i < j) { R[i][j] = QR[i][j]; } else if (i == j) { R[i][j] = Rdiag[i]; } else { R[i][j] = 0.0; } } } return X; } /** * Generate and return the (economy-sized) orthogonal factor * * @return Q */ public Matrix getQ() { Matrix X = new Matrix(m, n); double[][] Q = X.getArray(); for (int k = n - 1; k >= 0; k--) { for (int i = 0; i < m; i++) { Q[i][k] = 0.0; } Q[k][k] = 1.0; for (int j = k; j < n; j++) { if (QR[k][k] != 0) { double s = 0.0; for (int i = k; i < m; i++) { s += QR[i][k] * Q[i][j]; } s = -s / QR[k][k]; for (int i = k; i < m; i++) { Q[i][j] += s * QR[i][k]; } } } } return X; } /** * Least squares solution of A*X = B * * @param B A Matrix with as many rows as A and any number of columns. * @return X that minimizes the two norm of Q*R*X-B. * @throws IllegalArgumentException Matrix row dimensions must agree. * @throws RuntimeException Matrix is rank deficient. */ public Matrix solve(Matrix B) { if (B.getRowDimension() != m) { throw new IllegalArgumentException("Matrix row dimensions must agree."); } if (!this.isFullRank()) { throw new RuntimeException("Matrix is rank deficient."); } // Copy right hand side int nx = B.getColumnDimension(); double[][] X = B.getArrayCopy(); // Compute Y = transpose(Q)*B for (int k = 0; k < n; k++) { for (int j = 0; j < nx; j++) { double s = 0.0; for (int i = k; i < m; i++) { s += QR[i][k] * X[i][j]; } s = -s / QR[k][k]; for (int i = k; i < m; i++) { X[i][j] += s * QR[i][k]; } } } // Solve R*X = Y; for (int k = n - 1; k >= 0; k--) { for (int j = 0; j < nx; j++) { X[k][j] /= Rdiag[k]; } for (int i = 0; i < k; i++) { for (int j = 0; j < nx; j++) { X[i][j] -= X[k][j] * QR[i][k]; } } } return (new Matrix(X, n, nx).getMatrix(0, n - 1, 0, nx - 1)); } private static final long serialVersionUID = 1; }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy