예제 #1
0
        /**
         * Transforms the matrix to Schur form and calculates the eigenvalues.
         *
         * @param matrix Matrix to transform.
         * @return the {@link SchurTransformer Shur transform} for this matrix
         */
        private SchurTransformer transformToSchur(RealMatrix matrix)
        {
            SchurTransformer schurTransform = new SchurTransformer(matrix);

            double[][] matT = schurTransform.getT().getData();

            realEigenvalues = new double[matT.Length];
            imagEigenvalues = new double[matT.Length];

            for (int i = 0; i < realEigenvalues.Length; i++)
            {
                if (i == (realEigenvalues.Length - 1) ||
                    Precision.equals(matT[i + 1][i], 0.0, EPSILON))
                {
                    realEigenvalues[i] = matT[i][i];
                }
                else
                {
                    double x = matT[i + 1][i + 1];
                    double p = 0.5 * (matT[i][i] - x);
                    double z = Math.Sqrt(Math.Abs(p * p + matT[i + 1][i] * matT[i][i + 1]));
                    realEigenvalues[i]     = x + p;
                    imagEigenvalues[i]     = z;
                    realEigenvalues[i + 1] = x + p;
                    imagEigenvalues[i + 1] = -z;
                    i++;
                }
            }
            return(schurTransform);
        }
예제 #2
0
        /**
         * Calculates the eigen decomposition of the given real matrix.
         * <p>
         * Supports decomposition of a general matrix since 3.1.
         *
         * @param matrix Matrix to decompose.
         * @throws MaxCountExceededException if the algorithm fails to converge.
         * @throws MathArithmeticException if the decomposition of a general matrix
         * results in a matrix with zero norm
         * @since 3.1
         */
        public EigenDecomposition(RealMatrix matrix)
        {
            double symTol = 10 * matrix.getRowDimension() * matrix.getColumnDimension() * Precision.EPSILON;

            isSymmetric = MatrixUtils.IsSymmetric(matrix, symTol);
            if (isSymmetric)
            {
                transformToTridiagonal(matrix);
                findEigenVectors(transformer.getQ().getData());
                findEigenVectors(transformer.getQ().getData());
            }
            else
            {
                SchurTransformer t = transformToSchur(matrix);
                findEigenVectorsFromSchur(t);
            }
        }
예제 #3
0
        /**
         * Find eigenvectors from a matrix transformed to Schur form.
         *
         * @param schur the schur transformation of the matrix
         * @throws MathArithmeticException if the Schur form has a norm of zero
         */
        private void findEigenVectorsFromSchur(SchurTransformer schur)
        {
            double[][] matrixT = schur.getT().getData();
            double[][] matrixP = schur.getP().getData();

            int n = matrixT.Length;

            // compute matrix norm
            double norm = 0.0;

            for (int i = 0; i < n; i++)
            {
                for (int j = Math.Max(i - 1, 0); j < n; j++)
                {
                    norm += Math.Abs(matrixT[i][j]);
                }
            }

            // we can not handle a matrix with zero norm
            if (Precision.equals(norm, 0.0, EPSILON))
            {
                throw new Exception("MathArithmeticException");
            }

            // Backsubstitute to find vectors of upper triangular form

            double r = 0.0;
            double s = 0.0;
            double z = 0.0;

            for (int idx = n - 1; idx >= 0; idx--)
            {
                double p = realEigenvalues[idx];
                double q = imagEigenvalues[idx];

                if (Precision.equals(q, 0.0))
                {
                    // Real vector
                    int l = idx;
                    matrixT[idx][idx] = 1.0;
                    for (int i = idx - 1; i >= 0; i--)
                    {
                        double w = matrixT[i][i] - p;
                        r = 0.0;
                        for (int j = l; j <= idx; j++)
                        {
                            r += matrixT[i][j] * matrixT[j][idx];
                        }
                        if (Precision.compareTo(imagEigenvalues[i], 0.0, EPSILON) < 0)
                        {
                            z = w;
                            s = r;
                        }
                        else
                        {
                            l = i;
                            if (Precision.equals(imagEigenvalues[i], 0.0))
                            {
                                if (w != 0.0)
                                {
                                    matrixT[i][idx] = -r / w;
                                }
                                else
                                {
                                    matrixT[i][idx] = -r / (Precision.EPSILON * norm);
                                }
                            }
                            else
                            {
                                // Solve real equations
                                double x = matrixT[i][i + 1];
                                double y = matrixT[i + 1][i];
                                q = (realEigenvalues[i] - p) * (realEigenvalues[i] - p) +
                                    imagEigenvalues[i] * imagEigenvalues[i];
                                double t = (x * s - z * r) / q;
                                matrixT[i][idx] = t;
                                if (Math.Abs(x) > Math.Abs(z))
                                {
                                    matrixT[i + 1][idx] = (-r - w * t) / x;
                                }
                                else
                                {
                                    matrixT[i + 1][idx] = (-s - y * t) / z;
                                }
                            }

                            // Overflow control
                            double tx = Math.Abs(matrixT[i][idx]);
                            if ((Precision.EPSILON * tx) * tx > 1)
                            {
                                for (int j = i; j <= idx; j++)
                                {
                                    matrixT[j][idx] /= tx;
                                }
                            }
                        }
                    }
                }
                else if (q < 0.0)
                {
                    // Complex vector
                    int l = idx - 1;

                    // Last vector component imaginary so matrix is triangular
                    if (Math.Abs(matrixT[idx][idx - 1]) > Math.Abs(matrixT[idx - 1][idx]))
                    {
                        matrixT[idx - 1][idx - 1] = q / matrixT[idx][idx - 1];
                        matrixT[idx - 1][idx]     = -(matrixT[idx][idx] - p) / matrixT[idx][idx - 1];
                    }
                    else
                    {
                        Complex result = cdiv(0.0, -matrixT[idx - 1][idx],
                                              matrixT[idx - 1][idx - 1] - p, q);
                        matrixT[idx - 1][idx - 1] = result.getReal();
                        matrixT[idx - 1][idx]     = result.getImaginary();
                    }

                    matrixT[idx][idx - 1] = 0.0;
                    matrixT[idx][idx]     = 1.0;

                    for (int i = idx - 2; i >= 0; i--)
                    {
                        double ra = 0.0;
                        double sa = 0.0;
                        for (int j = l; j <= idx; j++)
                        {
                            ra += matrixT[i][j] * matrixT[j][idx - 1];
                            sa += matrixT[i][j] * matrixT[j][idx];
                        }
                        double w = matrixT[i][i] - p;

                        if (Precision.compareTo(imagEigenvalues[i], 0.0, EPSILON) < 0)
                        {
                            z = w;
                            r = ra;
                            s = sa;
                        }
                        else
                        {
                            l = i;
                            if (Precision.equals(imagEigenvalues[i], 0.0))
                            {
                                Complex c = cdiv(-ra, -sa, w, q);
                                matrixT[i][idx - 1] = c.getReal();
                                matrixT[i][idx]     = c.getImaginary();
                            }
                            else
                            {
                                // Solve complex equations
                                double x  = matrixT[i][i + 1];
                                double y  = matrixT[i + 1][i];
                                double vr = (realEigenvalues[i] - p) * (realEigenvalues[i] - p) +
                                            imagEigenvalues[i] * imagEigenvalues[i] - q * q;
                                double vi = (realEigenvalues[i] - p) * 2.0 * q;
                                if (Precision.equals(vr, 0.0) && Precision.equals(vi, 0.0))
                                {
                                    vr = Precision.EPSILON * norm *
                                         (Math.Abs(w) + Math.Abs(q) + Math.Abs(x) +
                                          Math.Abs(y) + Math.Abs(z));
                                }
                                Complex c = cdiv(x * r - z * ra + q * sa,
                                                 x * s - z * sa - q * ra, vr, vi);
                                matrixT[i][idx - 1] = c.getReal();
                                matrixT[i][idx]     = c.getImaginary();

                                if (Math.Abs(x) > (Math.Abs(z) + Math.Abs(q)))
                                {
                                    matrixT[i + 1][idx - 1] = (-ra - w * matrixT[i][idx - 1] +
                                                               q * matrixT[i][idx]) / x;
                                    matrixT[i + 1][idx] = (-sa - w * matrixT[i][idx] -
                                                           q * matrixT[i][idx - 1]) / x;
                                }
                                else
                                {
                                    Complex c2 = cdiv(-r - y * matrixT[i][idx - 1],
                                                      -s - y * matrixT[i][idx], z, q);
                                    matrixT[i + 1][idx - 1] = c2.getReal();
                                    matrixT[i + 1][idx]     = c2.getImaginary();
                                }
                            }

                            // Overflow control
                            double t = Math.Max(Math.Abs(matrixT[i][idx - 1]),
                                                Math.Abs(matrixT[i][idx]));
                            if ((Precision.EPSILON * t) * t > 1)
                            {
                                for (int j = i; j <= idx; j++)
                                {
                                    matrixT[j][idx - 1] /= t;
                                    matrixT[j][idx]     /= t;
                                }
                            }
                        }
                    }
                }
            }

            // Back transformation to get eigenvectors of original matrix
            for (int j = n - 1; j >= 0; j--)
            {
                for (int i = 0; i <= n - 1; i++)
                {
                    z = 0.0;
                    for (int k = 0; k <= Math.Min(j, n - 1); k++)
                    {
                        z += matrixP[i][k] * matrixT[k][j];
                    }
                    matrixP[i][j] = z;
                }
            }

            eigenvectors = new ArrayRealVector[n];
            double[] tmp = new double[n];
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    tmp[j] = matrixP[j][i];
                }
                eigenvectors[i] = new ArrayRealVector(tmp);
            }
        }