Determines the Generalized eigenvalues and eigenvectors of two real square matrices.

A generalized eigenvalue problem is the problem of finding a vector v that obeys A * v = λ * B * v where A and B are matrices. If v obeys this equation, with some λ, then we call v the generalized eigenvector of A and B, and λ is called the generalized eigenvalue of A and B which corresponds to the generalized eigenvector v. The possible values of λ, must obey the identity det(A - λ*B) = 0.

Part of this code has been adapted from the original EISPACK routines in Fortran.

References: http://en.wikipedia.org/wiki/Generalized_eigenvalue_problem#Generalized_eigenvalue_problem http://www.netlib.org/eispack/

Inheritance: ICloneable
        public void GeneralizedEigenvalueDecompositionConstructorTest()
        {
            // Suppose we have the following 
            // matrices A and B shown below:

            double[,] A = 
            {
                { 1, 2, 3},
                { 8, 1, 4},
                { 3, 2, 3}
            };

            double[,] B = 
            {
                { 5, 1, 1},
                { 1, 5, 1},
                { 1, 1, 5}
            };

            // Now, suppose we would like to find values for λ 
            // that are solutions for the equation det(A - λB) = 0

            // For this, we can use a Generalized Eigendecomposition
            var gevd = new GeneralizedEigenvalueDecomposition(A, B);

            // Now, if A and B are Hermitian and B is positive
            // -definite, then the eigenvalues λ will be real:
            double[] lambda = gevd.RealEigenvalues;

            // Check if they are indeed a solution:
            for (int i = 0; i < lambda.Length; i++)
            {
                // Compute the determinant equation show above
                double det = Matrix.Determinant(A.Subtract(lambda[i].Multiply(B))); // almost zero

                Assert.IsTrue(det < 1e-6);
            }


            double[,] expectedVectors =
            {               
                { 0.427490473174445, -0.459244062074000, -0.206685960405416 },
                { 1,	1,	-1},
                { 0.615202547759401,	-0.152331764458173, 0.779372135871111}
            };

            double[,] expectedValues =
            {
              {1.13868666711946,	0,	0 },
              {0, -0.748168231839396,	0},
              {0,	0,	-0.104804149565775}
            };


            Assert.IsTrue(Matrix.IsEqual(gevd.Eigenvectors, expectedVectors, 0.00000000001));
            Assert.IsTrue(Matrix.IsEqual(gevd.DiagonalMatrix, expectedValues, 0.00000000001));
        }
Exemple #2
0
        /// <summary>
        ///   Creates a new object that is a copy of the current instance.
        /// </summary>
        /// <returns>
        ///   A new object that is a copy of this instance.
        /// </returns>
        public object Clone()
        {
            var clone = new GeneralizedEigenvalueDecomposition();

            clone.ai   = (double[])ai.Clone();
            clone.ar   = (double[])ar.Clone();
            clone.beta = (double[])beta.Clone();
            clone.n    = n;
            clone.Z    = (double[, ])Z.Clone();
            return(clone);
        }
        public void GeneralizedEigenvalueDecompositionConstructorTest()
        {
            double[,] A = 
            {
                { 1, 2, 3},
                { 8, 1, 4},
                { 3, 2, 3}
            };

            double[,] B = 
            {
                { 5, 1, 1},
                { 1, 5, 1},
                { 1, 1, 5}
            };

            GeneralizedEigenvalueDecomposition gevd = new GeneralizedEigenvalueDecomposition(A, B);

            double[,] expectedVectors =
            {               
                { 0.427490473174445, -0.459244062074000, -0.206685960405416 },
                { 1,	1,	-1},
                { 0.615202547759401,	-0.152331764458173, 0.779372135871111}
            };

            double[,] expectedValues =
            {
              {1.13868666711946,	0,	0 },
              {0, -0.748168231839396,	0},
              {0,	0,	-0.104804149565775}
            };


            Assert.IsTrue(Matrix.IsEqual(gevd.Eigenvectors, expectedVectors, 0.00000000001));
            Assert.IsTrue(Matrix.IsEqual(gevd.DiagonalMatrix, expectedValues, 0.00000000001));
        }
 /// <summary>
 ///   Creates a new object that is a copy of the current instance.
 /// </summary>
 /// <returns>
 ///   A new object that is a copy of this instance.
 /// </returns>
 public object Clone()
 {
     var clone = new GeneralizedEigenvalueDecomposition();
     clone.ai = (double[])ai.Clone();
     clone.ar = (double[])ar.Clone();
     clone.beta = (double[])beta.Clone();
     clone.n = n;
     clone.Z = (double[,])Z.Clone();
     return clone;
 }
        public void GeneralizedEigenvalueDecompositionConstructorTest2()
        {
            double[,] A = Matrix.Identity(100);
            double[,] B = Matrix.Identity(100);

            GeneralizedEigenvalueDecomposition gevd = new GeneralizedEigenvalueDecomposition(A, B);

            double[,] expectedVectors = Matrix.Identity(100);
            double[,] expectedValues = Matrix.Identity(100);

            Assert.IsTrue(Matrix.IsEqual(gevd.Eigenvectors, expectedVectors));
            Assert.IsTrue(Matrix.IsEqual(gevd.DiagonalMatrix, expectedValues));
        }
        public void GeneralizedEigenvalueDecompositionConstructorTest4()
        {
            var A = new double[3, 3];
            A[0, 0] = 2.6969840958234776;
            A[0, 1] = 3.0761868753825254;
            A[0, 2] = -1.9236284084262458;
            A[1, 0] = -0.09975623250927601;
            A[1, 1] = 3.1520214626342158;
            A[1, 2] = 2.3928828222643972;
            A[2, 0] = 5.2090689722490815;
            A[2, 1] = 2.32098631016956;
            A[2, 2] = 5.522974475996091;


            var B = new double[3, 3];
            B[0, 0] = -16.753710484948808;
            B[0, 1] = -14.715495544818925;
            B[0, 2] = -41.589502695291074;
            B[1, 0] = -31.78618974973736;
            B[1, 1] = -14.30788463834109;
            B[1, 2] = -18.388254830328865;
            B[2, 0] = -3.2512542741611838;
            B[2, 1] = -18.774698582838617;
            B[2, 2] = -1.5640121915210088;


            var gevd = new GeneralizedEigenvalueDecomposition(A, B);

            var V = gevd.Eigenvectors;
            var D = gevd.DiagonalMatrix;

            // A*V = B*V*D
            var AV = A.Multiply(V);
            var BVD = B.Multiply(V).Multiply(D);
            Assert.IsTrue(Matrix.IsEqual(AV, BVD, 0.000001));

            double[,] expectedVectors =
            {
                {1,	-0.120763598920560,	-0.636412048994645},
            {-0.942794724207834,	-1,	-0.363587951005355},
                {   -0.0572052757921662,	-0.0606762790704327,	1},
            };

            double[,] expectedValues = 
            {
                {0.186046511627907,	0,	0},
                {0,	-0.170549605858232,	0},
                {   0,	0,	0.186046511627907}
            };

            //Assert.IsTrue(Matrix.IsEqual(V, expectedVectors,0.001));
            Assert.IsTrue(Matrix.IsEqual(D, expectedValues, 0.00001));

        }
        public void GeneralizedEigenvalueDecompositionConstructorTest3()
        {
            for (int i = 0; i < 10000; i++)
            {
                for (int j = 1; j < 6; j++)
                {
                    var A = Matrix.Random(j, j, -1, 1);
                    var B = Matrix.Random(j, j, -1, 1);

                    var gevd = new GeneralizedEigenvalueDecomposition(A, B);

                    var V = gevd.Eigenvectors;
                    var D = gevd.DiagonalMatrix;

                    // A*V = B*V*D
                    var AV = A.Multiply(V);
                    var BVD = B.Multiply(V).Multiply(D);

                    Assert.IsTrue(Matrix.IsEqual(AV, BVD, 0.0000001));
                }
            }

            for (int i = 0; i < 100; i++)
            {
                int j = 50;
                var A = Matrix.Random(j, j, -1, 1);
                var B = Matrix.Random(j, j, -1, 1);

                var gevd = new GeneralizedEigenvalueDecomposition(A, B);

                var V = gevd.Eigenvectors;
                var D = gevd.DiagonalMatrix;

                // A*V = B*V*D
                var AV = A.Multiply(V);
                var BVD = B.Multiply(V).Multiply(D);

                Assert.IsTrue(Matrix.IsEqual(AV, BVD, 0.0000001));
            }
        }
 /// <summary>Eigenvalue decomposition.</summary>
 protected static double[] eig(double[,] a, double[,] b, out double[,] V, out double[] im, out double[] alphar, out double[] alphai, out double[] beta)
 {
     var eig = new GeneralizedEigenvalueDecomposition(a, b);
     V = eig.Eigenvectors;
     im = eig.ImaginaryEigenvalues;
     beta = eig.Betas;
     alphar = eig.RealAlphas;
     alphai = eig.ImaginaryAlphas;
     return eig.RealEigenvalues;
 }
 /// <summary>Eigenvalue decomposition.</summary>
 protected static double[] eig(double[,] a, double[,] b, out double[,] V, out double[] im)
 {
     var eig = new GeneralizedEigenvalueDecomposition(a, b);
     V = eig.Eigenvectors;
     im = eig.ImaginaryEigenvalues;
     return eig.RealEigenvalues;
 }
        //---------------------------------------------


        #region Public Methods
        /// <summary>
        ///   Computes the Multi-Class Kernel Discriminant Analysis algorithm.
        /// </summary>
        /// 
        public override void Compute()
        {
            // Get some initial information
            int dimension = Source.GetLength(0);
            double[,] source = Source;
            double total = dimension;


            // Create the Gram (Kernel) Matrix
            double[,] K = new double[dimension, dimension];
            for (int i = 0; i < dimension; i++)
            {
                double[] row = source.GetRow(i);
                for (int j = i; j < dimension; j++)
                {
                    double s = kernel.Function(row, source.GetRow(j));
                    K[i, j] = s; // Assume K will be symmetric
                    K[j, i] = s;
                }
            }


            // Compute entire data set measures
            base.Means = Statistics.Tools.Mean(K);
            base.StandardDeviations = Statistics.Tools.StandardDeviation(K, Means);


            // Initialize the kernel analogous scatter matrices
            double[,] Sb = new double[dimension, dimension];
            double[,] Sw = new double[dimension, dimension];


            // For each class
            for (int c = 0; c < Classes.Count; c++)
            {
                // Get the Kernel matrix class subset
                double[,] Kc = K.Submatrix(Classes[c].Indices);
                int count = Kc.GetLength(0);

                // Get the Kernel matrix class mean
                double[] mean = Statistics.Tools.Mean(Kc);


                // Construct the Kernel equivalent of the Within-Class Scatter matrix
                double[,] Swi = Statistics.Tools.Scatter(Kc, mean, (double)count);

                // Sw = Sw + Swi
                for (int i = 0; i < dimension; i++)
                    for (int j = 0; j < dimension; j++)
                        Sw[i, j] += Swi[i, j];


                // Construct the Kernel equivalent of the Between-Class Scatter matrix
                double[] d = mean.Subtract(base.Means);
                double[,] Sbi = Matrix.OuterProduct(d, d).Multiply(total);

                // Sb = Sb + Sbi
                for (int i = 0; i < dimension; i++)
                    for (int j = 0; j < dimension; j++)
                        Sb[i, j] += Sbi[i, j];


                // Store additional information
                base.ClassScatter[c] = Swi;
                base.ClassCount[c] = count;
                base.ClassMeans[c] = mean;
                base.ClassStandardDeviations[c] = Statistics.Tools.StandardDeviation(Kc, mean);
            }


            // Add regularization to avoid singularity
            for (int i = 0; i < dimension; i++)
                Sw[i, i] += regularization;


            // Compute the generalized eigenvalue decomposition
            GeneralizedEigenvalueDecomposition gevd = new GeneralizedEigenvalueDecomposition(Sb, Sw);

            if (gevd.IsSingular) // check validity of the results
            {
                throw new SingularMatrixException("One of the matrices is singular. Please retry " +
                    "the method with a higher regularization constant.");
            }


            // Get the eigenvalues and corresponding eigenvectors
            double[] evals = gevd.RealEigenvalues;
            double[,] eigs = gevd.Eigenvectors;

            // Sort eigenvalues and vectors in descending order
            eigs = Matrix.Sort(evals, eigs, new GeneralComparer(ComparerDirection.Descending, true));


            if (threshold > 0)
            {
                // We will be discarding less important
                // eigenvectors to conserve memory.

                // Calculate component proportions
                double sum = 0.0; // total variance
                for (int i = 0; i < dimension; i++)
                    sum += Math.Abs(evals[i]);

                if (sum > 0)
                {
                    int keep = 0;

                    // Now we will detect how many components we have
                    //  have to keep in order to achieve the level of
                    //  explained variance specified by the threshold.

                    while (keep < dimension)
                    {
                        // Get the variance explained by the component
                        double explainedVariance = Math.Abs(evals[keep]);

                        // Check its proportion
                        double proportion = explainedVariance / sum;

                        // Now, if the component explains an
                        // enough proportion of the variance,
                        if (proportion > threshold)
                            keep++; // We can keep it.
                        else
                            break;  // Otherwise we can stop, since the
                        // components are ordered by variance.
                    }

                    if (keep > 0)
                    {
                        // Resize the vectors keeping only needed components
                        eigs = eigs.Submatrix(0, dimension - 1, 0, keep - 1);
                        evals = evals.Submatrix(0, keep - 1);
                    }
                    else
                    {
                        // No component will be kept.
                        eigs = new double[dimension, 0];
                        evals = new double[0];
                    }
                }
            }


            // Store information
            base.Eigenvalues = evals;
            base.DiscriminantMatrix = eigs;
            base.ScatterBetweenClass = Sb;
            base.ScatterWithinClass = Sw;


            // Project into the kernel discriminant space
            this.Result = K.Multiply(eigs);


            // Compute feature space means for later classification
            for (int c = 0; c < Classes.Count; c++)
            {
                ProjectionMeans[c] = ClassMeans[c].Multiply(eigs);
            }


            // Computes additional information about the analysis and creates the
            //  object-oriented structure to hold the discriminants found.
            CreateDiscriminants();
        }