示例#1
0
 /// <summary>
 /// Gets or sets an entry of the matrix.
 /// </summary>
 /// <param name="r">The (zero-based) row number.</param>
 /// <param name="c">The (zero-based) column number.</param>
 /// <returns>The value of the specified matrix entry M<sub>r c</sub>.</returns>
 public override double this[int r, int c] {
     get {
         if ((r < 0) || (r >= dimension))
         {
             throw new ArgumentOutOfRangeException("r");
         }
         if ((c < 0) || (c >= dimension))
         {
             throw new ArgumentOutOfRangeException("c");
         }
         return(MatrixAlgorithms.GetEntry(store, dimension, dimension, r, c));
     }
     set {
         if ((r < 0) || (r >= dimension))
         {
             throw new ArgumentOutOfRangeException("r");
         }
         if ((c < 0) || (c >= dimension))
         {
             throw new ArgumentOutOfRangeException("c");
         }
         if (IsReadOnly)
         {
             throw new InvalidOperationException();
         }
         MatrixAlgorithms.SetEntry(store, dimension, dimension, r, c, value);
     }
 }
示例#2
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);
        }
        public static Complex[] ExtractEigenvalues(double[] aStore, double[] qStore, int dimension)
        {
            int count = 0;

            // keep track of extracted eigenvalues
            Complex[] lambdas = new Complex[dimension];

            double sum_old = Double.PositiveInfinity;

            int n = dimension - 1;

            while (n >= 0)
            {
                //Write(aStore, dimension, dimension);

                // find the lowest decoupled, unreduced block
                int    a   = n;
                double sum = 0.0;
                while (a > 0)
                {
                    double f = Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a, a)) +
                               Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a - 1, a - 1));
                    double e = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a, a - 1);
                    if ((f + e) == f)
                    {
                        MatrixAlgorithms.SetEntry(aStore, dimension, dimension, a, a - 1, 0.0);
                        break;
                    }
                    sum += Math.Abs(e);
                    a--;
                }

                /*
                 * Console.WriteLine("count = {0}", count);
                 * double[] qt = MatrixAlgorithms.Transpose(qStore, dimension, dimension);
                 * double[] qa = MatrixAlgorithms.Multiply(qStore, dimension, dimension, aStore, dimension, dimension);
                 * double[] qaqt = MatrixAlgorithms.Multiply(qa, dimension, dimension, qt, dimension, dimension);
                 * MatrixAlgorithms.PrintMatrix(qaqt, dimension, dimension);
                 */

                // check for maximum numbers of iterations without finding an eigenvalue
                if (count > 32)
                {
                    throw new NonconvergenceException();
                }

                // we are working between a and n, and our block is at least 3 wide

                // reduce if possible, otherwise do a iteration step

                if (a == n)
                {
                    // 1 X 1 block isolated
                    lambdas[a] = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a, a);
                    n         -= 1;
                    count      = 0;
                    sum_old    = Double.PositiveInfinity;
                }
                else if (a == (n - 1))
                {
                    // 2 X 2 block isolated
                    double Aaa = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a, a);
                    double Aba = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a + 1, a);
                    double Aab = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a, a + 1);
                    double Abb = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, a + 1, a + 1);
                    // eigenvalues are given by the quadratic formula
                    //   e = \frac{a_11 + a22}{2} \pm q
                    // descriminant q^2 = ( \frac{a_11 - a_22}{2} )^2 + a_21 a_1
                    double c  = (Aaa + Abb) / 2.0;
                    double d  = Aaa * Abb - Aba * Aab;
                    double q2 = c * c - d;
                    if (q2 >= 0.0)
                    {
                        // eigenvalues are real

                        double q = Math.Sqrt(q2);
                        if (c >= 0.0)
                        {
                            lambdas[a] = c + q;
                        }
                        else
                        {
                            lambdas[a] = c - q;
                        }
                        // i tried to do this as c + Math.Sign(c) * q, but when c = 0, Math.Sign(c) = 0, not 1
                        lambdas[a + 1] = d / lambdas[a];

                        /*
                         * double sn, cn;
                         * TwoByTwoSchur(ref Aaa, ref Aab, ref Aba, ref Abb, out sn, out cn);
                         * MatrixAlgorithms.SetEntry(aStore, dimension, dimension, a, a, Aaa);
                         * MatrixAlgorithms.SetEntry(aStore, dimension, dimension, a, a + 1, Aab);
                         * MatrixAlgorithms.SetEntry(aStore, dimension, dimension, a + 1, a, Aba);
                         * MatrixAlgorithms.SetEntry(aStore, dimension, dimension, a + 1, a + 1, Abb);
                         *
                         * // Multiply A from left by the rotation matrix R
                         * for (int cc = a + 2; cc < dimension; cc++) {
                         *  int i = MatrixAlgorithms.GetIndex(dimension, dimension, a, cc);
                         *  int j = MatrixAlgorithms.GetIndex(dimension, dimension, a + 1, cc);
                         *  double t = aStore[i];
                         *  aStore[i] = cn * t + sn * aStore[j];
                         *  aStore[j] = cn * aStore[j] - sn * t;
                         * }
                         * // Multiply A from the right by R^T
                         * for (int rr = 0; rr < a; rr++) {
                         *  int i = MatrixAlgorithms.GetIndex(dimension, dimension, rr, a);
                         *  int j = MatrixAlgorithms.GetIndex(dimension, dimension, rr, a + 1);
                         *  double t = aStore[i];
                         *  aStore[i] = cn * t + sn * aStore[j];
                         *  aStore[j] = cn * aStore[j] - sn * t;
                         * }
                         * // Multiply Q^T from the left by R
                         * if (qStore != null) {
                         *  for (int cc = 0; cc < dimension; cc++) {
                         *      int i = MatrixAlgorithms.GetIndex(dimension, dimension, a, cc);
                         *      int j = MatrixAlgorithms.GetIndex(dimension, dimension, a + 1, cc);
                         *      double t = qStore[i];
                         *      qStore[i] = cn * t + sn * qStore[j];
                         *      qStore[j] = cn * qStore[j] - sn * t;
                         *  }
                         * }
                         *
                         * lambdas[a] = Aaa;
                         * lambdas[a + 1] = Abb;
                         */
                    }
                    else
                    {
                        double q = Math.Sqrt(-q2);
                        lambdas[a]     = new Complex(c, q);
                        lambdas[a + 1] = new Complex(c, -q);
                    }

                    n      -= 2;
                    count   = 0;
                    sum_old = Double.PositiveInfinity;
                }
                else
                {
                    // use the lower-left 2 X 2 matrix to generate an approximate eigenvalue pair

                    int    m   = n - 1;
                    double Amm = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, m, m);
                    double Amn = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, m, n);
                    double Anm = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, n, m);
                    double Ann = MatrixAlgorithms.GetEntry(aStore, dimension, dimension, n, n);

                    // the trace of this 2 X 2 matrix is the sum of its eigenvalues, and its determinate is their product

                    double tr  = Amm + Ann;
                    double det = Amm * Ann - Amn * Anm;

                    // ad hoc shift
                    if ((count == 8) || (count == 16) || (count == 24))
                    {
                        double w = Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, n, n - 1)) +
                                   Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, m, m - 1));
                        tr  = 2.0 * w;
                        det = w * w;
                    }

                    FrancisTwoStep(aStore, qStore, dimension, a, n, tr, det);
                    sum_old = sum;
                    count++;
                }
            }

            return(lambdas);
        }
        // inverts the matrix in place
        // the in-place-ness makes this a bit confusing

        public static void GaussJordanInvert(double[] store, int dimension)
        {
            // keep track of row exchanges
            int[] ps = new int[dimension];

            // iterate over dimensions
            for (int k = 0; k < dimension; k++)
            {
                // look for a pivot in the kth column on any lower row
                int    p = k;
                double q = MatrixAlgorithms.GetEntry(store, dimension, dimension, k, k);

                for (int r = k + 1; r < dimension; r++)
                {
                    double s = MatrixAlgorithms.GetEntry(store, dimension, dimension, r, k);
                    if (Math.Abs(s) > Math.Abs(q))
                    {
                        p = r;
                        q = s;
                    }
                }
                ps[k] = p;

                // if no non-zero pivot is found, the matrix is singular and cannot be inverted
                if (q == 0.0)
                {
                    throw new DivideByZeroException();
                }

                // if the best pivot was on a lower row, swap it into the kth row
                if (p != k)
                {
                    Blas1.dSwap(store, k, dimension, store, p, dimension, dimension);
                }

                // divide the pivot row by the pivot element, so the diagonal element becomes unity
                MatrixAlgorithms.SetEntry(store, dimension, dimension, k, k, 1.0);
                Blas1.dScal(1.0 / q, store, k, dimension, dimension);

                // add factors to the pivot row to zero all off-diagonal elements in the kth column
                for (int r = 0; r < dimension; r++)
                {
                    if (r == k)
                    {
                        continue;
                    }
                    double a = MatrixAlgorithms.GetEntry(store, dimension, dimension, r, k);
                    MatrixAlgorithms.SetEntry(store, dimension, dimension, r, k, 0.0);
                    Blas1.dAxpy(-a, store, k, dimension, store, r, dimension, dimension);
                }
            }

            // unscramble exchanges
            for (int k = dimension - 1; k >= 0; k--)
            {
                int p = ps[k];
                if (p != k)
                {
                    Blas1.dSwap(store, dimension * p, 1, store, dimension * k, 1, dimension);
                }
            }
        }
        // EIGENVALUE ALGORITHMS

        //

        public static Complex[] ReduceToRealSchurForm(double[] aStore, double[] qStore, int dimension)
        {
            // keep track of eigenvalues
            Complex[] eigenvalues = new Complex[dimension];

            // keep track of interations
            int count = 0;

            // isolate the upper and lower boundaries of the curent subproblem
            // p is the upper index, n the lower index

            int n = dimension - 1;

            while (n >= 0)
            {
                // move up the matrix from endpoint n, looking for subdiagonal elements negligible compared to the neighboring diagonal elements
                // if we find one, that reduces the problem to the submatrix between p and n
                int p = n;
                while (p > 0)
                {
                    double d = Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, p, p)) + Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, p - 1, p - 1));
                    double e = Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, p, p - 1));

                    if (d + e == d)
                    {
                        //  double f = d * Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, p, p) - MatrixAlgorithms.GetEntry(aStore, dimension, dimension, p - 1, p - 1));
                        //  double g = e * Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, p - 1, p));

                        //  if (f + g == f) {
                        MatrixAlgorithms.SetEntry(aStore, dimension, dimension, p, p - 1, 0.0);
                        break;
                        //  }
                    }

                    p--;
                }

                /*
                 * if (p == n) {
                 *  // one eigenvalue
                 *  // reduce n and re-set count
                 * } else {
                 *  // compute m, matrix elements
                 *  // reduce n and re-set count
                 *  if (p == m) {
                 *      // two eigenvalues
                 *  } else {
                 *      // do step
                 *  }
                 * }
                 */

                //Print(a, dimension, p, n);

                // get the (indexes for) the entries in the trailing 2x2 matrix
                int m    = n - 1;
                int ammi = MatrixAlgorithms.GetIndex(dimension, dimension, m, m);
                int amni = MatrixAlgorithms.GetIndex(dimension, dimension, m, n);
                int anmi = MatrixAlgorithms.GetIndex(dimension, dimension, n, m);
                int anni = MatrixAlgorithms.GetIndex(dimension, dimension, n, n);

                if (n - p > 1)
                {
                    count++;
                    if (count > 32)
                    {
                        throw new NonconvergenceException();
                    }

                    double tr  = aStore[ammi] + aStore[anni];
                    double det = aStore[ammi] * aStore[anni] - aStore[amni] * aStore[anmi];

                    // ad hoc shift
                    if ((count == 8) || (count == 16) || (count == 24))
                    {
                        double w = Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, n, n - 1)) +
                                   Math.Abs(MatrixAlgorithms.GetEntry(aStore, dimension, dimension, n - 1, n - 2));
                        tr  = 2.0 * w;
                        det = w * w;
                    }

                    FrancisTwoStep(aStore, qStore, dimension, p, n, tr, det);
                }
                else
                {
                    if (p == n)
                    {
                        eigenvalues[n] = aStore[anni];
                    }
                    else if (p == m)
                    {
                        double sn, cn;
                        TwoByTwoRealSchur(ref aStore[ammi], ref aStore[amni], ref aStore[anmi], ref aStore[anni], out sn, out cn, out eigenvalues[m], out eigenvalues[n]);

                        // Multiply A from left by the rotation matrix R
                        for (int cc = p + 2; cc < dimension; cc++)
                        {
                            int    i = MatrixAlgorithms.GetIndex(dimension, dimension, p, cc);
                            int    j = MatrixAlgorithms.GetIndex(dimension, dimension, p + 1, cc);
                            double t = aStore[i];
                            aStore[i] = cn * t + sn * aStore[j];
                            aStore[j] = cn * aStore[j] - sn * t;
                        }
                        // Multiply A from the right by R^T
                        for (int rr = 0; rr < p; rr++)
                        {
                            int    i = MatrixAlgorithms.GetIndex(dimension, dimension, rr, p);
                            int    j = MatrixAlgorithms.GetIndex(dimension, dimension, rr, p + 1);
                            double t = aStore[i];
                            aStore[i] = cn * t + sn * aStore[j];
                            aStore[j] = cn * aStore[j] - sn * t;
                        }
                        // Multiply Q^T from the left by R
                        if (qStore != null)
                        {
                            for (int rr = 0; rr < dimension; rr++)
                            {
                                int    i = MatrixAlgorithms.GetIndex(dimension, dimension, rr, p);
                                int    j = MatrixAlgorithms.GetIndex(dimension, dimension, rr, p + 1);
                                double t = qStore[i];
                                qStore[i] = cn * t + sn * qStore[j];
                                qStore[j] = cn * qStore[j] - sn * t;
                            }
                        }
                    }

                    n     = p - 1;
                    count = 0;
                }
            }

            return(eigenvalues);
        }