/// <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>An alternative way of expressing the same relationship is to say that the eigenvalues of a matrix are its /// diagonal elements when the matrix is expressed in a basis that diagonalizes it. That is, given Z such that Z<sup>-1</sup>MZ = D, /// where D is diagonal, the columns of Z are the eigenvectors of M and the diagonal elements of D are the eigenvalues.</para> /// <para>Note that the eigenvectors of a matrix are not entirely unique. Given an eigenvector z, any scaled vector αz /// is an eigenvector with the same eigenvalue, so eigenvectors are at most unique up to a rescaling. If an eigenvalue /// is degenerate, i.e. there are two or more linearly independent eigenvectors with the same eigenvalue, then any linear /// combination of the eigenvectors is also an eigenvector with that eigenvalue, and in fact any set of vectors that span the /// same subspace could be taken as the eigenvector set corresponding to that eigenvalue.</para> /// <para>The eigenvectors of a symmetric matrix are always orthogonal and the eigenvalues are always real. The transformation /// matrix Z is thus orthogonal (Z<sup>-1</sup> = Z<sup>T</sup>).</para> /// <para>Finding the eigenvalues and eigenvectors of a symmetric matrix is an O(N<sup>3</sup>) operation.</para> /// <para>If you require only the eigenvalues, not the eigenvectors, of the matrix, the <see cref="Eigenvalues"/> method /// will produce them faster than this method.</para> /// </remarks> public RealEigensystem Eigensystem() { double[][] A = SymmetricMatrixAlgorithms.Copy(values, dimension); double[] V = SquareMatrixAlgorithms.CreateUnitMatrix(dimension); SymmetricMatrixAlgorithms.JacobiEigensystem(A, V, dimension); return(new RealEigensystem(dimension, SymmetricMatrixAlgorithms.GetDiagonal(A, dimension), V)); }
/// <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> /// 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)); }
public static double[] AccumulateBidiagonalV(double[] store, int rows, int cols) { // Q_1 * ... (Q_{n-1} * (Q_n * 1)) double[] result = SquareMatrixAlgorithms.CreateUnitMatrix(cols); for (int k = cols - 2; k >= 0; k--) { // apply Householder reflection to each column from the left for (int j = k + 1; j < cols; j++) { VectorAlgorithms.ApplyHouseholderReflection(store, (k + 1) * rows + k, rows, result, j * cols + (k + 1), 1, cols - k - 1); } } return(result); }
// 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)); }
public static double[] AccumulateBidiagonalU(double[] store, int rows, int cols) { // ((1 * Q_n) * Q_{n-1}) ... * Q_1 double[] result = SquareMatrixAlgorithms.CreateUnitMatrix(rows); // iterate over Householder reflections for (int k = cols - 1; k >= 0; k--) { // apply Householder reflection to each row from the right for (int j = k; j < rows; j++) { VectorAlgorithms.ApplyHouseholderReflection(store, k * rows + k, 1, result, k * rows + j, rows, rows - k); } } return(result); }
/// <summary> /// Solve the system of equations Ax=b, where A is the original matrix. /// </summary> /// <param name="rhs">The right-hand-side vector b.</param> /// <returns>The solution vector x.</returns> /// <remarks> /// <para>The components of <paramref name="rhs"/> are not modified.</para> /// </remarks> public ColumnVector Solve(IList <double> rhs) { if (rhs == null) { throw new ArgumentNullException(nameof(rhs)); } if (rhs.Count != dimension) { throw new DimensionMismatchException(); } double[] y = new double[rhs.Count]; rhs.CopyTo(y, 0); y = MatrixAlgorithms.Multiply(qtStore, dimension, dimension, y, dimension, 1); SquareMatrixAlgorithms.SolveUpperRightTriangular(rStore, y, 0, dimension); return(new ColumnVector(y, dimension)); }
/// <summary> /// Computes the matrix raised to the given power. /// </summary> /// <param name="n">The power to which to raise the matrix, which must be positive.</param> /// <returns>The matrix A<sup>n</sup>.</returns> /// <remarks> /// <para>This method uses exponentiation-by-squaring, so typically only of order log(n) matrix multiplications are required. /// This improves not only the speed with which the matrix power is computed, but also the accuracy.</para> /// </remarks> /// <exception cref="ArgumentOutOfRangeException"><paramref name="n"/> is negative.</exception> /// <seealso href="https://en.wikipedia.org/wiki/Exponentiation_by_squaring"/> public SquareMatrix Power(int n) { if (n < 0) { throw new ArgumentOutOfRangeException(nameof(n)); } else if (n == 0) { return(new SquareMatrix(SquareMatrixAlgorithms.CreateUnitMatrix(dimension), dimension)); } else if (n == 1) { return(this.Copy()); } else { double[] pStore = SquareMatrixAlgorithms.Power(store, dimension, n); return(new SquareMatrix(pStore, dimension)); } }
/* * /// <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> /// Computes the the inverse of the original matrix. /// </summary> /// <returns>The independent inverse of the original matrix.</returns> public SquareMatrix Inverse() { // set up permuted unit matrix double[] aiStore = new double[dimension * dimension]; for (int i = 0; i < dimension; i++) { aiStore[dimension * permutation[i] + i] = 1.0; } // solve each column for (int c = 0; c < dimension; c++) { int i0 = dimension * c; SquareMatrixAlgorithms.SolveLowerLeftTriangular(luStore, aiStore, i0, dimension); SquareMatrixAlgorithms.SolveUpperRightTriangular(luStore, aiStore, i0, dimension); } return(new SquareMatrix(aiStore, dimension)); /* * // this is basically just inserting unit vectors into Solve, * // but we reproduce that logic so as to take some advantage * // of the fact that most of the components are zero * * int n = Dimension; * * SquareMatrix MI = new SquareMatrix(n); * * // iterate over the columns * for (int c = 0; c < n; c++) { * * // we are dealing with the k'th unit vector * // the c'th unit vector gets mapped to the k'th unit vector, where perm[k] = c * * // solve L y = e_k * // components below the k'th are zero; this loop determines k as it zeros lower components * int k = 0; * while (perm[k] != c) { * MI.SetEntry(k, c, 0.0); * k++; * } * // the k'th component is one * MI[k, c] = 1.0; * // higher components are non-zero... * for (int i = k + 1; i < n; i++) { * double t = 0.0; * // ...but loop to compute them need only go over j for which MI[j, c] != 0, i.e. j >= k * for (int j = k; j < i; j++) { * t -= lu.GetEntry(i, j) * MI.GetEntry(j, c); * } * MI.SetEntry(i, c, t); * } * * // solve U x = y * // at this stage, the first few components of y are zero and component k is one * // but this doesn't let us limit the loop any further, since we already only loop over j > i * for (int i = n - 1; i >= 0; i--) { * double t = MI.GetEntry(i, c); * for (int j = n - 1; j > i; j--) { * t -= lu.GetEntry(i, j) * MI.GetEntry(j, c); * } * MI.SetEntry(i, c, t / lu.GetEntry(i, i)); * } * * } * * return (MI); */ }
/// <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> /// Returns a square matrix with unit matrix entries. /// </summary> /// <returns>An independent, write-able copy of the unit matrix.</returns> public SquareMatrix ToSquareMatrix() { double[] storage = SquareMatrixAlgorithms.CreateUnitMatrix(n); return(new SquareMatrix(storage, n)); }