using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace VisualMath.Accord.Math.Decompositions { using System; using VisualMath.Accord.Math; /// /// QR decomposition for a rectangular matrix. /// /// /// /// 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 decomposition 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 returns . /// /// public sealed class QrDecomposition { private double[,] qr; private double[] Rdiag; /// Constructs a QR decomposition. /// The matrix A to be decomposed. public QrDecomposition(double[,] value) : this(value, false) { } /// Constructs a QR decomposition. /// The matrix A to be decomposed. /// True if the decomposition should be performed on /// the transpose of A rather than A itself, false otherwise. Default is false. public QrDecomposition(double[,] value, bool transpose) { if (value == null) { throw new ArgumentNullException("value", "Matrix cannot be null."); } if ((!transpose && value.GetLength(0) < value.GetLength(1)) || (transpose && value.GetLength(1) < value.GetLength(0))) { throw new ArgumentException("Matrix has more columns than rows.", "value"); } this.qr = transpose ? value.Transpose() : (double[,])value.Clone(); int rows = qr.GetLength(0); int cols = qr.GetLength(1); this.Rdiag = new double[cols]; for (int k = 0; k < cols; k++) { // Compute 2-norm of k-th column without under/overflow. double nrm = 0; for (int i = k; i < rows; i++) { nrm = Tools.Hypotenuse(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 < rows; i++) { qr[i, k] /= nrm; } qr[k, k] += 1.0; // Apply transformation to remaining columns. for (int j = k + 1; j < cols; j++) { double s = 0.0; for (int i = k; i < rows; i++) { s += qr[i, k] * qr[i, j]; } s = -s / qr[k, k]; for (int i = k; i < rows; i++) { qr[i, j] += s * qr[i, k]; } } } this.Rdiag[k] = -nrm; } } /// Least squares solution of A * X = B /// Right-hand-side matrix with as many rows as A and any number of columns. /// A matrix that minimized the two norm of Q * R * X - B. /// Matrix row dimensions must be the same. /// Matrix is rank deficient. public double[,] Solve(double[,] value) { if (value == null) throw new ArgumentNullException("value", "Matrix cannot be null."); if (value.GetLength(0) != qr.GetLength(0)) throw new ArgumentException("Matrix row dimensions must agree."); if (!this.FullRank) throw new InvalidOperationException("Matrix is rank deficient."); // Copy right hand side int count = value.GetLength(1); double[,] X = (double[,])value.Clone(); int m = qr.GetLength(0); int n = qr.GetLength(1); // Compute Y = transpose(Q)*B for (int k = 0; k < n; k++) { for (int j = 0; j < count; 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 < count; j++) X[k, j] /= Rdiag[k]; for (int i = 0; i < k; i++) for (int j = 0; j < count; j++) X[i, j] -= X[k, j] * qr[i, k]; } double[,] r = new double[n, count]; for (int i = 0; i < n; i++) for (int j = 0; j < count; j++) r[i, j] = X[i, j]; return r; } /// Least squares solution of X * A = B /// Right-hand-side matrix with as many columns as A and any number of rows. /// A matrix that minimized the two norm of X * Q * R - B. /// Matrix column dimensions must be the same. /// Matrix is rank deficient. public double[,] SolveTranspose(double[,] value) { if (value == null) throw new ArgumentNullException("value", "Matrix cannot be null."); if (value.GetLength(1) != qr.GetLength(0)) throw new ArgumentException("Matrix row dimensions must agree."); if (!this.FullRank) throw new InvalidOperationException("Matrix is rank deficient."); // Copy right hand side int count = value.GetLength(0); double[,] X = value.Transpose(); int m = qr.GetLength(0); int n = qr.GetLength(1); // Compute Y = transpose(Q)*B for (int k = 0; k < n; k++) { for (int j = 0; j < count; 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 < count; j++) X[k, j] /= Rdiag[k]; for (int i = 0; i < k; i++) for (int j = 0; j < count; j++) X[i, j] -= X[k, j] * qr[i, k]; } double[,] r = new double[count, n]; for (int i = 0; i < n; i++) for (int j = 0; j < count; j++) r[j, i] = X[i, j]; return r; } /// Least squares solution of A * X = B /// Right-hand-side matrix with as many rows as A and any number of columns. /// A matrix that minimized the two norm of Q * R * X - B. /// Matrix row dimensions must be the same. /// Matrix is rank deficient. public double[] Solve(double[] value) { if (value == null) throw new ArgumentNullException("value"); if (value.GetLength(0) != qr.GetLength(0)) throw new ArgumentException("Matrix row dimensions must agree."); if (!this.FullRank) throw new InvalidOperationException("Matrix is rank deficient."); // Copy right hand side double[] X = (double[])value.Clone(); int m = qr.GetLength(0); int n = qr.GetLength(1); // Compute Y = transpose(Q)*B for (int k = 0; k < n; k++) { double s = 0.0; for (int i = k; i < m; i++) s += qr[i, k] * X[i]; s = -s / qr[k, k]; for (int i = k; i < m; i++) X[i] += s * qr[i, k]; } // Solve R*X = Y; for (int k = n - 1; k >= 0; k--) { X[k] /= Rdiag[k]; for (int i = 0; i < k; i++) X[i] -= X[k] * qr[i, k]; } return X; } /// Shows if the matrix A is of full rank. /// The value is if R, and hence A, has full rank. public bool FullRank { get { int columns = qr.GetLength(1); for (int i = 0; i < columns; i++) { if (this.Rdiag[i] == 0) { return false; } } return true; } } /// Returns the upper triangular factor R. public double[,] UpperTriangularFactor { get { int n = this.qr.GetLength(1); double[,] x = new double[n, n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (i < j) { x[i, j] = qr[i, j]; } else if (i == j) { x[i, j] = Rdiag[i]; } else { x[i, j] = 0.0; } } } return x; } } /// Returns the orthogonal factor Q. public double[,] OrthogonalFactor { get { int rows = qr.GetLength(0); int cols = qr.GetLength(1); double[,] x = new double[rows, cols]; for (int k = cols - 1; k >= 0; k--) { for (int i = 0; i < rows; i++) { x[i, k] = 0.0; } x[k, k] = 1.0; for (int j = k; j < cols; j++) { if (qr[k, k] != 0) { double s = 0.0; for (int i = k; i < rows; i++) { s += qr[i, k] * x[i, j]; } s = -s / qr[k, k]; for (int i = k; i < rows; i++) { x[i, j] += s * qr[i, k]; } } } } return x; } } /// Returns the diagonal of R. public double[] Diagonal { get { return Rdiag; } } /// Least squares solution of A * X = I public double[,] Inverse() { if (!this.FullRank) throw new InvalidOperationException("Matrix is rank deficient."); // Copy right hand side int m = qr.GetLength(0); int n = qr.GetLength(1); double[,] X = new double[m, m]; // Compute Y = transpose(Q) for (int k = n - 1; k >= 0; k--) { for (int i = 0; i < m; i++) X[k, i] = 0.0; X[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] * X[j, i]; s = -s / qr[k, k]; for (int i = k; i < m; i++) X[j, i] += s * qr[i, k]; } } } // Solve R*X = Y; for (int k = n - 1; k >= 0; k--) { for (int j = 0; j < m; j++) X[k, j] /= Rdiag[k]; for (int i = 0; i < k; i++) for (int j = 0; j < m; j++) X[i, j] -= X[k, j] * qr[i, k]; } return X; } } }