Example #1
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
            Utils.QL_REQUIRE(size == matrix.columns(), () =>
                             "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
                Utils.QL_REQUIRE(jd.eigenvalues()[size - 1] >= -1e-16, () =>
                                 "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:
                Utils.QL_FAIL("unknown salvaging algorithm");
                break;
            }

            return(result);
        }
Example #2
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
            Utils.QL_REQUIRE(size == matrix.columns(), () =>
                             "non square matrix: " + size + " rows, " + matrix.columns() + " columns");
#endif

            Utils.QL_REQUIRE(componentRetainedPercentage > 0.0, () => "no eigenvalues retained");
            Utils.QL_REQUIRE(componentRetainedPercentage <= 1.0, () => "percentage to be retained > 100%");
            Utils.QL_REQUIRE(maxRank >= 1, () => "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
                Utils.QL_REQUIRE(eigenValues[size - 1] >= -1e-16, () =>
                                 "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:
                Utils.QL_FAIL("unknown or invalid salvaging algorithm");
                break;
            }

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

            if (componentRetainedPercentage.IsEqual(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);
        }
 internal static global::System.Runtime.InteropServices.HandleRef getCPtr(SalvagingAlgorithm obj)
 {
     return((obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr);
 }
Example #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 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;
        }
Example #5
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;
        }
Example #6
0
 public static Matrix pseudoSqrt(Matrix m, SalvagingAlgorithm.Type a) {
   Matrix ret = new Matrix(NQuantLibcPINVOKE.pseudoSqrt(Matrix.getCPtr(m), (int)a), true);
   if (NQuantLibcPINVOKE.SWIGPendingException.Pending) throw NQuantLibcPINVOKE.SWIGPendingException.Retrieve();
   return ret;
 }
Example #7
0
 internal static global::System.Runtime.InteropServices.HandleRef getCPtr(SalvagingAlgorithm obj) {
   return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr;
 }