Beispiel #1
0
        // Take a matrix and make all the eigenvalues non-negative
        private static Matrix projectToPositiveSemidefiniteMatrix(Matrix M)
        {
            int size = M.rows();

            Utils.QL_REQUIRE(size == M.columns(), () => "matrix not square");

            Matrix diagonal = new Matrix(size, size);
            SymmetricSchurDecomposition jd = new SymmetricSchurDecomposition(M);

            for (int i = 0; i < size; ++i)
            {
                diagonal[i, i] = Math.Max(jd.eigenvalues()[i], 0.0);
            }

            Matrix result = jd.eigenvectors() * diagonal * Matrix.transpose(jd.eigenvectors());

            return(result);
        }
Beispiel #2
0
        public void testEigenvectors()
        {
            //("Testing eigenvalues and eigenvectors calculation...");

            setup();

            Matrix[] testMatrices = { M1, M2 };

            for (int k=0; k<testMatrices.Length; k++) {

                Matrix M = testMatrices[k];
                SymmetricSchurDecomposition dec = new SymmetricSchurDecomposition(M);
                Vector eigenValues = dec.eigenvalues();
                Matrix eigenVectors = dec.eigenvectors();
                double minHolder = double.MaxValue;

                for (int i=0; i<N; i++) {
                    Vector v = new Vector(N);
                    for (int j = 0; j < N; j++)
                        v[j] = eigenVectors[j,i];
                    // check definition
                    Vector a = M * v;
                    Vector b = eigenValues[i] * v;
                    if (norm(a-b) > 1.0e-15)
                        Assert.Fail("Eigenvector definition not satisfied");
                    // check decreasing ordering
                    if (eigenValues[i] >= minHolder) {
                        Assert.Fail("Eigenvalues not ordered: " + eigenValues);
                    } else
                        minHolder = eigenValues[i];
                }

                // check normalization
                Matrix m = eigenVectors * Matrix.transpose(eigenVectors);
                if (norm(m-I) > 1.0e-15)
                    Assert.Fail("Eigenvector not normalized");
            }
        }
Beispiel #3
0
        public static Matrix rankReducedSqrt(Matrix matrix,
                                             int maxRank,
                                             double componentRetainedPercentage,
                                             SalvagingAlgorithm sa)
        {
            int size = matrix.rows();

            #if QL_EXTRA_SAFETY_CHECKS
            checkSymmetry(matrix);
            #else
            if (size != matrix.columns())
            {
                throw new Exception("non square matrix: " + size + " rows, " + matrix.columns() + " columns");
            }
            #endif

            if (!(componentRetainedPercentage > 0.0))
            {
                throw new Exception("no eigenvalues retained");
            }

            if (!(componentRetainedPercentage <= 1.0))
            {
                throw new Exception("percentage to be retained > 100%");
            }

            if (!(maxRank >= 1))
            {
                throw new Exception("max rank required < 1");
            }

            // spectral (a.k.a Principal Component) analysis
            SymmetricSchurDecomposition jd = new SymmetricSchurDecomposition(matrix);
            Vector eigenValues             = jd.eigenvalues();

            // salvaging algorithm
            switch (sa)
            {
            case SalvagingAlgorithm.None:
                // eigenvalues are sorted in decreasing order
                if (!(eigenValues[size - 1] >= -1e-16))
                {
                    throw new Exception("negative eigenvalue(s) (" + eigenValues[size - 1] + ")");
                }
                break;

            case SalvagingAlgorithm.Spectral:
                // negative eigenvalues set to zero
                for (int i = 0; i < size; ++i)
                {
                    eigenValues[i] = Math.Max(eigenValues[i], 0.0);
                }
                break;

            case SalvagingAlgorithm.Higham:
            {
                int    maxIterations  = 40;
                double tolerance      = 1e-6;
                Matrix adjustedMatrix = highamImplementation(matrix, maxIterations, tolerance);
                jd          = new SymmetricSchurDecomposition(adjustedMatrix);
                eigenValues = jd.eigenvalues();
            }
            break;

            default:
                throw new Exception("unknown or invalid salvaging algorithm");
            }

            // factor reduction

            /*std::accumulate(eigenValues.begin(),
             *                eigenValues.end(), 0.0);*/
            double accumulate = 0;
            eigenValues.ForEach((ii, vv) => accumulate += eigenValues[ii]);
            double enough = componentRetainedPercentage * accumulate;

            if (componentRetainedPercentage == 1.0)
            {
                // numerical glitches might cause some factors to be discarded
                enough *= 1.1;
            }
            // retain at least one factor
            double components      = eigenValues[0];
            int    retainedFactors = 1;
            for (int i = 1; components < enough && i < size; ++i)
            {
                components += eigenValues[i];
                retainedFactors++;
            }
            // output is granted to have a rank<=maxRank
            retainedFactors = Math.Min(retainedFactors, maxRank);

            Matrix diagonal = new Matrix(size, retainedFactors, 0.0);
            for (int i = 0; i < retainedFactors; ++i)
            {
                diagonal[i, i] = Math.Sqrt(eigenValues[i]);
            }
            Matrix result = jd.eigenvectors() * diagonal;

            normalizePseudoRoot(matrix, result);
            return(result);
        }
Beispiel #4
0
        //! Returns the pseudo square root of a real symmetric matrix

        /*! Given a matrix \f$ M \f$, the result \f$ S \f$ is defined
         *  as the matrix such that \f$ S S^T = M. \f$
         *  If the matrix is not positive semi definite, it can
         *  return an approximation of the pseudo square root
         *  using a (user selected) salvaging algorithm.
         *
         *  For more information see: "The most general methodology to create
         *  a valid correlation matrix for risk management and option pricing
         *  purposes", by R. Rebonato and P. Jдckel.
         *  The Journal of Risk, 2(2), Winter 1999/2000
         *  http://www.rebonato.com/correlationmatrix.pdf
         *
         *  Revised and extended in "Monte Carlo Methods in Finance",
         *  by Peter Jдckel, Chapter 6.
         *
         *  \pre the given matrix must be symmetric.
         *
         *  \relates Matrix
         *
         *  \warning Higham algorithm only works for correlation matrices.
         *
         *  \test
         *  - the correctness of the results is tested by reproducing
         *    known good data.
         *  - the correctness of the results is tested by checking
         *    returned values against numerical calculations.
         */
        public static Matrix pseudoSqrt(Matrix matrix, SalvagingAlgorithm sa)
        {
            int size = matrix.rows();

            #if QL_EXTRA_SAFETY_CHECKS
            checkSymmetry(matrix);
            #else
            if (size != matrix.columns())
            {
                throw new Exception("non square matrix: " + size + " rows, " + matrix.columns() + " columns");
            }
            #endif

            // spectral (a.k.a Principal Component) analysis
            SymmetricSchurDecomposition jd = new SymmetricSchurDecomposition(matrix);
            Matrix diagonal = new Matrix(size, size, 0.0);

            // salvaging algorithm
            Matrix result = new Matrix(size, size);
            bool   negative;
            switch (sa)
            {
            case SalvagingAlgorithm.None:
                // eigenvalues are sorted in decreasing order
                if (!(jd.eigenvalues()[size - 1] >= -1e-16))
                {
                    throw new Exception("negative eigenvalue(s) (" + jd.eigenvalues()[size - 1] + ")");
                }
                result = MatrixUtilities.CholeskyDecomposition(matrix, true);
                break;

            case SalvagingAlgorithm.Spectral:
                // negative eigenvalues set to zero
                for (int i = 0; i < size; i++)
                {
                    diagonal[i, i] = Math.Sqrt(Math.Max(jd.eigenvalues()[i], 0.0));
                }

                result = jd.eigenvectors() * diagonal;
                normalizePseudoRoot(matrix, result);
                break;

            case SalvagingAlgorithm.Hypersphere:
                // negative eigenvalues set to zero
                negative = false;
                for (int i = 0; i < size; ++i)
                {
                    diagonal[i, i] = Math.Sqrt(Math.Max(jd.eigenvalues()[i], 0.0));
                    if (jd.eigenvalues()[i] < 0.0)
                    {
                        negative = true;
                    }
                }
                result = jd.eigenvectors() * diagonal;
                normalizePseudoRoot(matrix, result);

                if (negative)
                {
                    result = hypersphereOptimize(matrix, result, false);
                }
                break;

            case SalvagingAlgorithm.LowerDiagonal:
                // negative eigenvalues set to zero
                negative = false;
                for (int i = 0; i < size; ++i)
                {
                    diagonal[i, i] = Math.Sqrt(Math.Max(jd.eigenvalues()[i], 0.0));
                    if (jd.eigenvalues()[i] < 0.0)
                    {
                        negative = true;
                    }
                }
                result = jd.eigenvectors() * diagonal;

                normalizePseudoRoot(matrix, result);

                if (negative)
                {
                    result = hypersphereOptimize(matrix, result, true);
                }
                break;

            case SalvagingAlgorithm.Higham:
                int    maxIterations = 40;
                double tol           = 1e-6;
                result = highamImplementation(matrix, maxIterations, tol);
                result = MatrixUtilities.CholeskyDecomposition(result, true);
                break;

            default:
                throw new Exception("unknown salvaging algorithm");
            }

            return(result);
        }
Beispiel #5
0
        //! Returns the pseudo square root of a real symmetric matrix
        /*! Given a matrix \f$ M \f$, the result \f$ S \f$ is defined
            as the matrix such that \f$ S S^T = M. \f$
            If the matrix is not positive semi definite, it can
            return an approximation of the pseudo square root
            using a (user selected) salvaging algorithm.

            For more information see: "The most general methodology to create
            a valid correlation matrix for risk management and option pricing
            purposes", by R. Rebonato and P. Jдckel.
            The Journal of Risk, 2(2), Winter 1999/2000
            http://www.rebonato.com/correlationmatrix.pdf

            Revised and extended in "Monte Carlo Methods in Finance",
            by Peter Jдckel, Chapter 6.

            \pre the given matrix must be symmetric.

            \relates Matrix

            \warning Higham algorithm only works for correlation matrices.

            \test
            - the correctness of the results is tested by reproducing
              known good data.
            - the correctness of the results is tested by checking
              returned values against numerical calculations.
        */
        public static Matrix pseudoSqrt(Matrix matrix, SalvagingAlgorithm sa)
        {
            int size = matrix.rows();

            #if QL_EXTRA_SAFETY_CHECKS
            checkSymmetry(matrix);
            #else
            if (size != matrix.columns())
                throw new ApplicationException("non square matrix: " + size + " rows, " + matrix.columns() + " columns");
            #endif

            // spectral (a.k.a Principal Component) analysis
            SymmetricSchurDecomposition jd = new SymmetricSchurDecomposition(matrix);
            Matrix diagonal = new Matrix(size, size, 0.0);

            // salvaging algorithm
            Matrix result = new Matrix(size, size);
            bool negative;
            switch (sa) {
                case SalvagingAlgorithm.None:
                    // eigenvalues are sorted in decreasing order
                    if (!(jd.eigenvalues()[size-1]>=-1e-16))
                        throw new ApplicationException("negative eigenvalue(s) (" + jd.eigenvalues()[size-1] + ")");
                    result = MatrixUtilities.CholeskyDecomposition(matrix, true);
                    break;

                case SalvagingAlgorithm.Spectral:
                    // negative eigenvalues set to zero
                    for (int i=0; i<size; i++)
                        diagonal[i,i] = Math.Sqrt(Math.Max(jd.eigenvalues()[i], 0.0));

                    result = jd.eigenvectors() * diagonal;
                    normalizePseudoRoot(matrix, result);
                    break;

                case SalvagingAlgorithm.Hypersphere:
                    // negative eigenvalues set to zero
                    negative=false;
                    for (int i=0; i<size; ++i){
                        diagonal[i,i] = Math.Sqrt(Math.Max(jd.eigenvalues()[i], 0.0));
                        if (jd.eigenvalues()[i]<0.0) negative=true;
                    }
                    result = jd.eigenvectors() * diagonal;
                    normalizePseudoRoot(matrix, result);

                    if (negative)
                        result = hypersphereOptimize(matrix, result, false);
                    break;

                case SalvagingAlgorithm.LowerDiagonal:
                    // negative eigenvalues set to zero
                    negative=false;
                    for (int i=0; i<size; ++i){
                        diagonal[i,i] = Math.Sqrt(Math.Max(jd.eigenvalues()[i], 0.0));
                        if (jd.eigenvalues()[i]<0.0) negative=true;
                    }
                    result = jd.eigenvectors() * diagonal;

                    normalizePseudoRoot(matrix, result);

                    if (negative)
                        result = hypersphereOptimize(matrix, result, true);
                    break;

                case SalvagingAlgorithm.Higham:
                    int maxIterations = 40;
                    double tol = 1e-6;
                    result = highamImplementation(matrix, maxIterations, tol);
                    result = MatrixUtilities.CholeskyDecomposition(result, true);
                    break;

                default:
                    throw new ApplicationException("unknown salvaging algorithm");
            }

            return result;
        }
Beispiel #6
0
        // Take a matrix and make all the eigenvalues non-negative
        private static Matrix projectToPositiveSemidefiniteMatrix(Matrix M)
        {
            int size = M.rows();
            if (size != M.columns())
                throw new ApplicationException("matrix not square");

            Matrix diagonal = new Matrix(size, size);
            SymmetricSchurDecomposition jd = new SymmetricSchurDecomposition(M);
            for (int i=0; i<size; ++i)
                diagonal[i,i] = Math.Max(jd.eigenvalues()[i], 0.0);

            Matrix result =
                jd.eigenvectors()*diagonal*Matrix.transpose(jd.eigenvectors());
            return result;
        }
Beispiel #7
0
        public static Matrix rankReducedSqrt(Matrix matrix,
                                             int maxRank,
                                             double componentRetainedPercentage,
                                             SalvagingAlgorithm sa)
        {
            int size = matrix.rows();

            #if QL_EXTRA_SAFETY_CHECKS
                checkSymmetry(matrix);
            #else
            if (size != matrix.columns())
                throw new ApplicationException("non square matrix: " + size + " rows, " + matrix.columns() + " columns");
            #endif

            if (!(componentRetainedPercentage > 0.0))
                throw new ApplicationException("no eigenvalues retained");

            if (!(componentRetainedPercentage <= 1.0))
                throw new ApplicationException("percentage to be retained > 100%");

            if (!(maxRank >= 1))
                throw new ApplicationException("max rank required < 1");

            // spectral (a.k.a Principal Component) analysis
            SymmetricSchurDecomposition jd = new SymmetricSchurDecomposition(matrix);
            Vector eigenValues = jd.eigenvalues();

            // salvaging algorithm
            switch (sa)
            {
                case SalvagingAlgorithm.None:
                    // eigenvalues are sorted in decreasing order
                    if (!(eigenValues[size - 1] >= -1e-16))
                        throw new ApplicationException("negative eigenvalue(s) (" + eigenValues[size - 1] + ")");
                    break;
                case SalvagingAlgorithm.Spectral:
                    // negative eigenvalues set to zero
                    for (int i = 0; i < size; ++i)
                        eigenValues[i] = Math.Max(eigenValues[i], 0.0);
                    break;
                case SalvagingAlgorithm.Higham:
                    {
                        int maxIterations = 40;
                        double tolerance = 1e-6;
                        Matrix adjustedMatrix = highamImplementation(matrix, maxIterations, tolerance);
                        jd = new SymmetricSchurDecomposition(adjustedMatrix);
                        eigenValues = jd.eigenvalues();
                    }
                    break;
                default:
                    throw new ApplicationException("unknown or invalid salvaging algorithm");

            }

            // factor reduction
            /*std::accumulate(eigenValues.begin(),
                              eigenValues.end(), 0.0);*/
            double accumulate = 0;
            eigenValues.ForEach((ii, vv) => accumulate += eigenValues[ii]);
            double enough = componentRetainedPercentage * accumulate;

            if (componentRetainedPercentage == 1.0)
            {
                // numerical glitches might cause some factors to be discarded
                enough *= 1.1;
            }
            // retain at least one factor
            double components = eigenValues[0];
            int retainedFactors = 1;
            for (int i = 1; components < enough && i < size; ++i)
            {
                components += eigenValues[i];
                retainedFactors++;
            }
            // output is granted to have a rank<=maxRank
            retainedFactors = Math.Min(retainedFactors, maxRank);

            Matrix diagonal = new Matrix(size, retainedFactors, 0.0);
            for (int i = 0; i < retainedFactors; ++i)
                diagonal[i, i] = Math.Sqrt(eigenValues[i]);
            Matrix result = jd.eigenvectors() * diagonal;

            normalizePseudoRoot(matrix, result);
            return result;
        }