/// <summary> /// Computes the singular value decomposition of the square matrix. /// </summary> /// <returns>The singular value decomposition of the matrix.</returns> /// <remarks> /// <para>Singular value decomposition is an advanced matrix decomposition technique that can be applied /// to all matrices, including non-square and singular square matrices.</para> /// </remarks> public SingularValueDecomposition SingularValueDecomposition() { double[] copy = MatrixAlgorithms.Copy(store, offset, rowStride, colStride, dimension, dimension); RectangularMatrix r = new RectangularMatrix(copy, dimension, dimension); return(r.SingularValueDecomposition()); }
/// <summary> /// Computes a QR decomposition of the matrix. /// </summary> /// <returns>A QR decomposition of the matrix.</returns> /// <seealso cref="Matrices.QRDecomposition"/> public SquareQRDecomposition QRDecomposition() { double[] rStore = MatrixAlgorithms.Copy(store, offset, rowStride, colStride, dimension, dimension); double[] qtStore = SquareMatrixAlgorithms.CreateUnitMatrix(dimension); MatrixAlgorithms.QRDecompose(rStore, qtStore, dimension, dimension); return(new SquareQRDecomposition(qtStore, rStore, dimension)); }
/// <summary> /// Computes the eigenvalues of the matrix. /// </summary> /// <returns>The eigenvalues of the matrix.</returns> /// <seealso cref="Eigendecomposition"/> public Complex[] Eigenvalues() { double[] aStore = MatrixAlgorithms.Copy(store, offset, rowStride, colStride, dimension, dimension); SquareMatrixAlgorithms.IsolateCheapEigenvalues(aStore, null, dimension); SquareMatrixAlgorithms.ReduceToHessenberg(aStore, null, dimension); Complex[] eigenvalues = SquareMatrixAlgorithms.ReduceToRealSchurForm(aStore, null, dimension); return(eigenvalues); }
/// <summary> /// Computes the eigenvalues and eigenvectors of the matrix. /// </summary> /// <returns>A representation of the eigenvalues and eigenvectors of the matrix.</returns> /// <remarks> /// <para>For a generic vector v and matrix M, Mv = u will point in some direction with no particular relationship to v. /// The eigenvectors of a matrix M are vectors z that satisfy Mz = λz, i.e. multiplying an eigenvector by a /// matrix reproduces the same vector, up to a prortionality constant λ called the eigenvalue.</para> /// <para>For v to be an eigenvector of M with eigenvalue λ, (M - λI)z = 0. But for a matrix to /// anihilate any non-zero vector, that matrix must have determinant, so det(M - λI)=0. For a matrix of /// order N, this is an equation for the roots of a polynomial of order N. Since an order-N polynomial always has exactly /// N roots, an order-N matrix always has exactly N eigenvalues.</para> /// <para>Since a polynomial with real coefficients can still have complex roots, a real square matrix can nonetheless /// have complex eigenvalues (and correspondly complex eigenvectors). However, again like the complex roots of a real /// polynomial, such eigenvalues will always occurs in complex-conjugate pairs.</para> /// <para>Although the eigenvalue polynomial ensures that an order-N matrix has N eigenvalues, it can occur that there /// are not N corresponding independent eigenvectors. A matrix with fewer eigenvectors than eigenvalues is called /// defective. Like singularity, defectiveness represents a delecate balance between the elements of a matrix that can /// typically be disturbed by just an infinitesimal perturbation of elements. Because of round-off-error, then, floating-point /// algorithms cannot reliably identify defective matrices. Instead, this method will return a full set of eigenvectors, /// but some eigenvectors, corresponding to very nearly equal eigenvalues, will be very nearly parallel.</para> /// <para>While a generic square matrix can be defective, many subspecies of square matrices are guaranteed not to be. /// This includes Markov matrices, orthogonal matrices, and symmetric matrices.</para> /// <para>Determining the eigenvalues and eigenvectors of a matrix is an O(N<sup>3</sup>) operation. If you need only the /// eigenvalues of a matrix, the <see cref="Eigenvalues"/> method is more efficient.</para> /// </remarks> public ComplexEigensystem Eigensystem() { double[] aStore = MatrixAlgorithms.Copy(store, dimension, dimension); int[] perm = new int[dimension]; for (int i = 0; i < perm.Length; i++) { perm[i] = i; } SquareMatrixAlgorithms.IsolateCheapEigenvalues(aStore, perm, dimension); double[] qStore = MatrixAlgorithms.AllocateStorage(dimension, dimension); for (int i = 0; i < perm.Length; i++) { MatrixAlgorithms.SetEntry(qStore, dimension, dimension, perm[i], i, 1.0); } //double[] qStore = SquareMatrixAlgorithms.CreateUnitMatrix(dimension); // Reduce the original matrix to Hessenberg form SquareMatrixAlgorithms.ReduceToHessenberg(aStore, qStore, dimension); // Reduce the Hessenberg matrix to real Schur form SquareMatrixAlgorithms.ReduceToRealSchurForm(aStore, qStore, dimension); //MatrixAlgorithms.PrintMatrix(aStore, dimension, dimension); //SquareMatrix A = new SquareMatrix(aStore, dimension); SquareMatrix Q = new SquareMatrix(qStore, dimension); Complex[] eigenvalues; Complex[][] eigenvectors; // Extract the eigenvalues and eigenvectors of the Schur form matrix SquareMatrixAlgorithms.SchurEigensystem(aStore, dimension, out eigenvalues, out eigenvectors); // transform eigenvectors of schur form into eigenvectors of original matrix // while we are at it, normalize so largest component has value 1 for (int i = 0; i < dimension; i++) { Complex[] v = new Complex[dimension]; double norm = 0.0; for (int j = 0; j < dimension; j++) { for (int k = 0; k < dimension; k++) { v[j] += Q[j, k] * eigenvectors[i][k]; } norm = Math.Max(norm, Math.Max(Math.Abs(v[j].Re), Math.Abs(v[j].Im))); } for (int j = 0; j < dimension; j++) { v[j] = v[j] / norm; } eigenvectors[i] = v; } ComplexEigensystem eigensystem = new ComplexEigensystem(dimension, eigenvalues, eigenvectors); return(eigensystem); }
/// <summary> /// Creates a transpose of the matrix. /// </summary> /// <returns>The matrix transpose M<sup>T</sup>.</returns> public SquareMatrix Transpose() { // To transpose, just copy with double[] transpose = MatrixAlgorithms.Copy(store, offset, colStride, rowStride, dimension, dimension); return(new SquareMatrix(transpose, dimension)); //return (new SquareMatrix(store, 0, colStride, rowStride, dimension, false)); //double[] tStore = MatrixAlgorithms.Transpose(store, dimension, dimension); //return (new SquareMatrix(tStore, dimension)); }
/// <summary> /// Computes the inverse of the original matrix. /// </summary> /// <returns>A<sup>-1</sup></returns> public SquareMatrix Inverse() { // solve R Q^T column-by-column double[] iStore = MatrixAlgorithms.Copy(qtStore); for (int c = 0; c < dimension; c++) { SquareMatrixAlgorithms.SolveUpperRightTriangular(rStore, iStore, dimension * c, dimension); } return(new SquareMatrix(iStore, dimension)); }
// complicated specific operations /// <summary> /// Computes the QR decomposition of the matrix. /// </summary> /// <returns>The QR decomposition of the matrix.</returns> /// <remarks> /// <para>Only matrices with a number of rows greater than or equal to the number of columns can be QR decomposed. If your /// matrix has more columns than rows, you can QR decompose its transpose.</para> /// </remarks> /// <seealso cref="QRDecomposition"/> public QRDecomposition QRDecomposition() { if (rows < cols) { throw new InvalidOperationException(); } double[] rStore = MatrixAlgorithms.Copy(store, offset, rowStride, colStride, rows, cols); double[] qtStore = SquareMatrixAlgorithms.CreateUnitMatrix(rows); MatrixAlgorithms.QRDecompose(rStore, qtStore, rows, cols); return(new QRDecomposition(qtStore, rStore, rows, cols)); }
/// <summary> /// Computes the singular value decomposition of the matrix. /// </summary> /// <returns>The SVD of the matrix.</returns> public SingularValueDecomposition SingularValueDecomposition() { if (rows >= cols) { // copy the matrix so as not to distrub the original double[] copy = MatrixAlgorithms.Copy(store, offset, rowStride, colStride, rows, cols); // bidiagonalize it double[] a, b; MatrixAlgorithms.Bidiagonalize(copy, rows, cols, out a, out b); // form the U and V matrices double[] left = MatrixAlgorithms.AccumulateBidiagonalU(copy, rows, cols); double[] right = MatrixAlgorithms.AccumulateBidiagonalV(copy, rows, cols); // find the singular values of the bidiagonal matrix MatrixAlgorithms.ExtractSingularValues(a, b, left, right, rows, cols); // sort them MatrixAlgorithms.SortValues(a, left, right, rows, cols); // package it all up return(new SingularValueDecomposition(left, a, right, rows, cols)); } else { double[] scratch = MatrixAlgorithms.Transpose(store, rows, cols); double[] a, b; MatrixAlgorithms.Bidiagonalize(scratch, cols, rows, out a, out b); double[] left = MatrixAlgorithms.AccumulateBidiagonalU(scratch, cols, rows); double[] right = MatrixAlgorithms.AccumulateBidiagonalV(scratch, cols, rows); MatrixAlgorithms.ExtractSingularValues(a, b, left, right, cols, rows); MatrixAlgorithms.SortValues(a, left, right, cols, rows); left = MatrixAlgorithms.Transpose(left, cols, cols); right = MatrixAlgorithms.Transpose(right, rows, rows); return(new SingularValueDecomposition(right, a, left, rows, cols)); } }
/* * /// <summary> * /// Inverts the matrix, in place. * /// </summary> * /// <remarks> * /// <para>This method replaces the elements of M with the elements of M<sup>-1</sup>.</para> * /// <para>In place matrix inversion saves memory, since separate storage of M and M<sup>-1</sup> is not required.</para></remarks> * private void InvertInPlace () { * } */ /// <summary> /// Computes the LU decomposition of the matrix. /// </summary> /// <returns>The LU decomposition of the matrix.</returns> /// <remarks> /// <para>The LU decomposition of a matrix M is a set of matrices L, U, and P such that LU = PM, where L /// is lower-left triangular, U is upper-right triangular, and P is a permutation matrix (so that PM is /// a row-wise permutation of M).</para> /// <para>The LU decomposition of a square matrix is an O(N<sup>3</sup>) operation.</para> /// </remarks> public LUDecomposition LUDecomposition() { // Copy the matrix content double[] luStore = MatrixAlgorithms.Copy(store, offset, rowStride, colStride, dimension, dimension); // Prepare an initial permutation and parity int[] permutation = new int[dimension]; for (int i = 0; i < permutation.Length; i++) { permutation[i] = i; } int parity = 1; // Do the LU decomposition SquareMatrixAlgorithms.LUDecompose(luStore, permutation, ref parity, dimension); // Package it up and return it LUDecomposition LU = new LUDecomposition(luStore, permutation, parity, dimension); return(LU); }
/// <summary> /// Returns the transpose of the matrix. /// </summary> /// <returns>M<sup>T</sup></returns> public RectangularMatrix Transpose() { // Just copy with rows <-> columns to get transpose double[] transpose = MatrixAlgorithms.Copy(store, offset, colStride, rowStride, cols, rows); return(new RectangularMatrix(transpose, cols, rows)); }
// simple specific operations /// <summary> /// Copies the matrix. /// </summary> /// <returns>An indpendent copy of the matrix.</returns> public RectangularMatrix Copy() { double[] cStore = MatrixAlgorithms.Copy(store, offset, rowStride, colStride, rows, cols); return(new RectangularMatrix(cStore, rows, cols)); }
/// <summary> /// Computes the inverse of the matrix. /// </summary> /// <returns>The matrix inverse M<sup>-1</sup>.</returns> /// <remarks> /// <para>The inverse of a matrix M is a matrix M<sup>-1</sup> such that M<sup>-1</sup>M = I, where I is the identity matrix.</para> /// <para>If the matrix is singular, inversion is not possible. In that case, this method will fail with a <see cref="DivideByZeroException"/>.</para> /// <para>The inversion of a matrix is an O(N<sup>3</sup>) operation.</para> /// </remarks> /// <exception cref="DivideByZeroException">The matrix is singular.</exception> public SquareMatrix Inverse() { double[] iStore = MatrixAlgorithms.Copy(store, offset, rowStride, colStride, dimension, dimension); SquareMatrixAlgorithms.GaussJordanInvert(iStore, dimension); return(new SquareMatrix(iStore, dimension)); }
/// <summary> /// Copies the matrix. /// </summary> /// <returns>An independent copy of the matrix.</returns> public SquareMatrix Copy() { double[] copyStore = MatrixAlgorithms.Copy(store, offset, rowStride, colStride, dimension, dimension); return(new SquareMatrix(copyStore, dimension)); }
/// <summary> /// Copies the matrix. /// </summary> /// <returns>An independent copy of the matrix.</returns> public SquareMatrix Copy() { double[] cStore = MatrixAlgorithms.Copy(store, dimension, dimension); return(new SquareMatrix(cStore, dimension)); }