예제 #1
0
 /// <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 = &#x3BB;z, i.e. multiplying an eigenvector by a
 /// matrix reproduces the same vector, up to a prortionality constant &#x3BB; called the eigenvalue.</para>
 /// <para>For v to be an eigenvector of M with eigenvalue &#x3BB;, (M - &#x3BB;I)z = 0. But for a matrix to
 /// anihilate any non-zero vector, that matrix must have determinant, so det(M - &#x3BB;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 &#x3B1;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));
 }
예제 #2
0
 /// <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));
 }
예제 #3
0
 /// <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);
 }
예제 #4
0
        /// <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 = &#x3BB;z, i.e. multiplying an eigenvector by a
        /// matrix reproduces the same vector, up to a prortionality constant &#x3BB; called the eigenvalue.</para>
        /// <para>For v to be an eigenvector of M with eigenvalue &#x3BB;, (M - &#x3BB;I)z = 0. But for a matrix to
        /// anihilate any non-zero vector, that matrix must have determinant, so det(M - &#x3BB;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);
        }
예제 #5
0
 /// <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));
 }
예제 #6
0
 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);
 }
예제 #7
0
        // 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));
        }
예제 #8
0
        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);
        }
예제 #9
0
        /// <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));
        }
예제 #10
0
 /// <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));
     }
 }
예제 #11
0
        /*
         * /// <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);
        }
예제 #12
0
        /// <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);
             */
        }
예제 #13
0
 /// <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));
 }
예제 #14
0
 /// <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));
 }