R1NonCentral.java

  1. package org.drip.measure.chisquare;

  2. /*
  3.  * -*- mode: java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  4.  */

  5. /*!
  6.  * Copyright (C) 2020 Lakshmi Krishnamurthy
  7.  * Copyright (C) 2019 Lakshmi Krishnamurthy
  8.  *
  9.  *  This file is part of DROP, an open-source library targeting analytics/risk, transaction cost analytics,
  10.  *      asset liability management analytics, capital, exposure, and margin analytics, valuation adjustment
  11.  *      analytics, and portfolio construction analytics within and across fixed income, credit, commodity,
  12.  *      equity, FX, and structured products. It also includes auxiliary libraries for algorithm support,
  13.  *      numerical analysis, numerical optimization, spline builder, model validation, statistical learning,
  14.  *      and computational support.
  15.  *  
  16.  *      https://lakshmidrip.github.io/DROP/
  17.  *  
  18.  *  DROP is composed of three modules:
  19.  *  
  20.  *  - DROP Product Core - https://lakshmidrip.github.io/DROP-Product-Core/
  21.  *  - DROP Portfolio Core - https://lakshmidrip.github.io/DROP-Portfolio-Core/
  22.  *  - DROP Computational Core - https://lakshmidrip.github.io/DROP-Computational-Core/
  23.  *
  24.  *  DROP Product Core implements libraries for the following:
  25.  *  - Fixed Income Analytics
  26.  *  - Loan Analytics
  27.  *  - Transaction Cost Analytics
  28.  *
  29.  *  DROP Portfolio Core implements libraries for the following:
  30.  *  - Asset Allocation Analytics
  31.  *  - Asset Liability Management Analytics
  32.  *  - Capital Estimation Analytics
  33.  *  - Exposure Analytics
  34.  *  - Margin Analytics
  35.  *  - XVA Analytics
  36.  *
  37.  *  DROP Computational Core implements libraries for the following:
  38.  *  - Algorithm Support
  39.  *  - Computation Support
  40.  *  - Function Analysis
  41.  *  - Model Validation
  42.  *  - Numerical Analysis
  43.  *  - Numerical Optimizer
  44.  *  - Spline Builder
  45.  *  - Statistical Learning
  46.  *
  47.  *  Documentation for DROP is Spread Over:
  48.  *
  49.  *  - Main                     => https://lakshmidrip.github.io/DROP/
  50.  *  - Wiki                     => https://github.com/lakshmiDRIP/DROP/wiki
  51.  *  - GitHub                   => https://github.com/lakshmiDRIP/DROP
  52.  *  - Repo Layout Taxonomy     => https://github.com/lakshmiDRIP/DROP/blob/master/Taxonomy.md
  53.  *  - Javadoc                  => https://lakshmidrip.github.io/DROP/Javadoc/index.html
  54.  *  - Technical Specifications => https://github.com/lakshmiDRIP/DROP/tree/master/Docs/Internal
  55.  *  - Release Versions         => https://lakshmidrip.github.io/DROP/version.html
  56.  *  - Community Credits        => https://lakshmidrip.github.io/DROP/credits.html
  57.  *  - Issues Catalog           => https://github.com/lakshmiDRIP/DROP/issues
  58.  *  - JUnit                    => https://lakshmidrip.github.io/DROP/junit/index.html
  59.  *  - Jacoco                   => https://lakshmidrip.github.io/DROP/jacoco/index.html
  60.  *
  61.  *  Licensed under the Apache License, Version 2.0 (the "License");
  62.  *      you may not use this file except in compliance with the License.
  63.  *  
  64.  *  You may obtain a copy of the License at
  65.  *      http://www.apache.org/licenses/LICENSE-2.0
  66.  *  
  67.  *  Unless required by applicable law or agreed to in writing, software
  68.  *      distributed under the License is distributed on an "AS IS" BASIS,
  69.  *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  70.  *  
  71.  *  See the License for the specific language governing permissions and
  72.  *      limitations under the License.
  73.  */

  74. /**
  75.  * <i>R1NonCentral</i> implements the Distribution Table for the R<sup>1</sup> Non-central Chi-Square
  76.  *  Distribution. The References are:
  77.  *
  78.  * <br><br>
  79.  *  <ul>
  80.  *      <li>
  81.  *          Johnson, N. L., S. Kotz, and N. Balakrishnan (1995): <i>Continuous Univariate Distributions
  82.  *              2<sup>nd</sup> Edition</i> <b>John Wiley and Sons</b>
  83.  *      </li>
  84.  *      <li>
  85.  *          Muirhead, R. (2005): <i>Aspects of Multivariate Statistical Theory 2<sup>nd</sup> Edition</i>
  86.  *              <b>Wiley</b>
  87.  *      </li>
  88.  *      <li>
  89.  *          Non-central Chi-Squared Distribution (2019): Chi-Squared Function
  90.  *              https://en.wikipedia.org/wiki/Noncentral_chi-squared_distribution
  91.  *      </li>
  92.  *      <li>
  93.  *          Sankaran, M. (1963): Approximations to the Non-Central Chi-Square Distribution <i>Biometrika</i>
  94.  *              <b>50 (1-2)</b> 199-204
  95.  *      </li>
  96.  *      <li>
  97.  *          Young, D. S. (2010): tolerance: An R Package for Estimating Tolerance Intervals <i>Journal of
  98.  *              Statistical Software</i> <b>36 (5)</b> 1-39
  99.  *      </li>
  100.  *  </ul>
  101.  *
  102.  *  <br><br>
  103.  *  <ul>
  104.  *      <li><b>Module </b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/ComputationalCore.md">Computational Core Module</a></li>
  105.  *      <li><b>Library</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/NumericalAnalysisLibrary.md">Numerical Analysis Library</a></li>
  106.  *      <li><b>Project</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/measure/README.md">R<sup>d</sup> Continuous/Discrete Probability Measures</a></li>
  107.  *      <li><b>Package</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/measure/chisquare/README.md">Chi-Square Distribution Implementation/Properties</a></li>
  108.  *  </ul>
  109.  *
  110.  * @author Lakshmi Krishnamurthy
  111.  */

  112. public class R1NonCentral
  113.     extends org.drip.measure.continuous.R1Univariate
  114. {
  115.     private double _cdfScaler = java.lang.Double.NaN;
  116.     private org.drip.function.definition.R1ToR1 _gammaEstimator = null;
  117.     private org.drip.function.definition.R1ToR1 _digammaEstimator = null;
  118.     private org.drip.function.definition.R2ToR1 _lowerIncompleteGammaEstimator = null;
  119.     private org.drip.measure.chisquare.R1NonCentralParameters _r1NonCentralParameters = null;
  120.     private org.drip.specialfunction.definition.ModifiedBesselFirstKindEstimator
  121.         _modifiedBesselFirstKindEstimator = null;

  122.     private double nonCentralMoment (
  123.         final int n,
  124.         final double[] fourLeadingRawMoments)
  125.         throws java.lang.Exception
  126.     {
  127.         if (n <= 3)
  128.         {
  129.             return fourLeadingRawMoments[n - 1];
  130.         }

  131.         double nonCentralMoment = cumulant (
  132.             n
  133.         );

  134.         double degreesOfFreedom = _r1NonCentralParameters.degreesOfFreedom();

  135.         double nonCentralityParameter = _r1NonCentralParameters.nonCentralityParameter();

  136.         for (int j = 1;
  137.             j < n;
  138.             ++j)
  139.         {
  140.             nonCentralMoment = nonCentralMoment +
  141.                 _gammaEstimator.evaluate (
  142.                     n
  143.                 ) * java.lang.Math.pow (
  144.                     2.,
  145.                     j - 1.
  146.                 ) * (
  147.                     degreesOfFreedom + j * nonCentralityParameter
  148.                 ) * nonCentralMoment (
  149.                     n - j,
  150.                     fourLeadingRawMoments
  151.                 ) / _gammaEstimator.evaluate (
  152.                     n - j + 1
  153.                 );
  154.         }

  155.         return nonCentralMoment;
  156.     }

  157.     /**
  158.      * Construct the Standard Instance of R1NonCentral
  159.      *
  160.      * @param degreesOfFreedom Degrees of Freedom
  161.      * @param nonCentralityParameter Non-centrality Parameter
  162.      * @param gammaEstimator Gamma Estimator
  163.      * @param digammaEstimator Digamma Estimator
  164.      * @param lowerIncompleteGammaEstimator Lower Incomplete Gamma Estimator
  165.      * @param modifiedBesselFirstKindEstimator Modified Bessel First Kind Estimator
  166.      *
  167.      * @return The Standard Instance of R1NonCentral
  168.      */

  169.     public static final R1NonCentral Standard (
  170.         final double degreesOfFreedom,
  171.         final double nonCentralityParameter,
  172.         final org.drip.function.definition.R1ToR1 gammaEstimator,
  173.         final org.drip.function.definition.R1ToR1 digammaEstimator,
  174.         final org.drip.function.definition.R2ToR1 lowerIncompleteGammaEstimator,
  175.         final org.drip.specialfunction.definition.ModifiedBesselFirstKindEstimator
  176.             modifiedBesselFirstKindEstimator)
  177.     {
  178.         try
  179.         {
  180.             return new R1NonCentral (
  181.                 new org.drip.measure.chisquare.R1NonCentralParameters (
  182.                     degreesOfFreedom,
  183.                     nonCentralityParameter
  184.                 ),
  185.                 gammaEstimator,
  186.                 digammaEstimator,
  187.                 lowerIncompleteGammaEstimator,
  188.                 modifiedBesselFirstKindEstimator
  189.             );
  190.         }
  191.         catch (java.lang.Exception e)
  192.         {
  193.             e.printStackTrace();
  194.         }

  195.         return null;
  196.     }

  197.     /**
  198.      * R1NonCentral Constructor
  199.      *
  200.      * @param r1NonCentralParameters R<sup>1</sup> Non-central Parameters
  201.      * @param gammaEstimator Gamma Estimator
  202.      * @param digammaEstimator Digamma Estimator
  203.      * @param lowerIncompleteGammaEstimator Lower Incomplete Gamma Estimator
  204.      * @param modifiedBesselFirstKindEstimator Modified Bessel First Kind Estimator
  205.      *
  206.      * @throws java.lang.Exception Thrown if the Inputs are Invalid
  207.      */

  208.     public R1NonCentral (
  209.         final org.drip.measure.chisquare.R1NonCentralParameters r1NonCentralParameters,
  210.         final org.drip.function.definition.R1ToR1 gammaEstimator,
  211.         final org.drip.function.definition.R1ToR1 digammaEstimator,
  212.         final org.drip.function.definition.R2ToR1 lowerIncompleteGammaEstimator,
  213.         final org.drip.specialfunction.definition.ModifiedBesselFirstKindEstimator
  214.             modifiedBesselFirstKindEstimator)
  215.         throws java.lang.Exception
  216.     {
  217.         if (null == (_r1NonCentralParameters = r1NonCentralParameters) ||
  218.             null == (_gammaEstimator = gammaEstimator) ||
  219.             null == (_digammaEstimator = digammaEstimator) ||
  220.             null == (_lowerIncompleteGammaEstimator = lowerIncompleteGammaEstimator) ||
  221.             null == (_modifiedBesselFirstKindEstimator = modifiedBesselFirstKindEstimator)
  222.         )
  223.         {
  224.             throw new java.lang.Exception (
  225.                 "R1NonCentral Constructor => Invalid Inputs"
  226.             );
  227.         }

  228.         _cdfScaler = java.lang.Math.exp (
  229.             -0.5 * _r1NonCentralParameters.nonCentralityParameter()
  230.         );
  231.     }

  232.     /**
  233.      * Retrieve the R<sup>1</sup> Non-Central Parameters
  234.      *
  235.      * @return The R<sup>1</sup> Non-Central Parameters
  236.      */

  237.     public org.drip.measure.chisquare.R1NonCentralParameters parameters()
  238.     {
  239.         return _r1NonCentralParameters;
  240.     }

  241.     /**
  242.      * Retrieve the Gamma Estimator
  243.      *
  244.      * @return Gamma Estimator
  245.      */

  246.     public org.drip.function.definition.R1ToR1 gammaEstimator()
  247.     {
  248.         return _gammaEstimator;
  249.     }

  250.     /**
  251.      * Retrieve the Digamma Estimator
  252.      *
  253.      * @return Digamma Estimator
  254.      */

  255.     public org.drip.function.definition.R1ToR1 digammaEstimator()
  256.     {
  257.         return _digammaEstimator;
  258.     }

  259.     /**
  260.      * Retrieve the Lower Incomplete Gamma Estimator
  261.      *
  262.      * @return Lower Incomplete Gamma Estimator
  263.      */

  264.     public org.drip.function.definition.R2ToR1 lowerIncompleteGammaEstimator()
  265.     {
  266.         return _lowerIncompleteGammaEstimator;
  267.     }

  268.     /**
  269.      * Retrieve the Modified Bessel First Kind Estimator
  270.      *
  271.      * @return Modified Bessel First Kind Estimator
  272.      */

  273.     public org.drip.specialfunction.definition.ModifiedBesselFirstKindEstimator
  274.         modifiedBesselFirstKindEstimator()
  275.     {
  276.         return _modifiedBesselFirstKindEstimator;
  277.     }

  278.     @Override public double[] support()
  279.     {
  280.         return new double[]
  281.         {
  282.             0.,
  283.             java.lang.Double.POSITIVE_INFINITY
  284.         };
  285.     }

  286.     @Override public double density (
  287.         final double x)
  288.         throws java.lang.Exception
  289.     {
  290.         if (!supported (
  291.             x
  292.         ))
  293.         {
  294.             throw new java.lang.Exception (
  295.                 "R1NonCentral::density => Variate not in Range"
  296.             );
  297.         }

  298.         double degreesOfFreedom = _r1NonCentralParameters.degreesOfFreedom();

  299.         double nonCentralityParameter = _r1NonCentralParameters.nonCentralityParameter();

  300.         return 0.5 * java.lang.Math.pow (
  301.             x / nonCentralityParameter,
  302.             0.25 * degreesOfFreedom - 0.5
  303.         ) * java.lang.Math.exp (
  304.             -0.5 * (x + nonCentralityParameter)
  305.         ) * _modifiedBesselFirstKindEstimator.bigI (
  306.             0.5 * degreesOfFreedom - 1.,
  307.             java.lang.Math.sqrt (
  308.                 x * nonCentralityParameter
  309.             )
  310.         );
  311.     }

  312.     @Override public double cumulative (
  313.         final double t)
  314.         throws java.lang.Exception
  315.     {
  316.         if (!supported (
  317.             t
  318.         ))
  319.         {
  320.             throw new java.lang.Exception (
  321.                 "R1NonCentral::cumulative => Invalid Inputs"
  322.             );
  323.         }

  324.         int termCount = 10;
  325.         double cumulative = 0.;

  326.         double degreesOfFreedom = _r1NonCentralParameters.degreesOfFreedom();

  327.         double nonCentralityParameter = _r1NonCentralParameters.nonCentralityParameter();

  328.         for (int termIndex = 0;
  329.             termIndex < termCount;
  330.             ++termIndex)
  331.         {
  332.             cumulative = cumulative +
  333.                 java.lang.Math.pow (
  334.                     0.5 * nonCentralityParameter,
  335.                     termIndex
  336.                 ) * new org.drip.measure.chisquare.R1Central (
  337.                     degreesOfFreedom + 2 * termIndex,
  338.                     _gammaEstimator,
  339.                     _digammaEstimator,
  340.                     _lowerIncompleteGammaEstimator
  341.                 ).cumulative (
  342.                     t
  343.                 ) / org.drip.numerical.common.NumberUtil.Factorial (
  344.                     termIndex
  345.                 );
  346.         }

  347.         return _cdfScaler * cumulative;
  348.     }

  349.     @Override public double mean()
  350.         throws java.lang.Exception
  351.     {
  352.         return _r1NonCentralParameters.degreesOfFreedom() + _r1NonCentralParameters.nonCentralityParameter();
  353.     }

  354.     @Override public double variance()
  355.         throws java.lang.Exception
  356.     {
  357.         return 2. * _r1NonCentralParameters.degreesOfFreedom() +
  358.             4. * _r1NonCentralParameters.nonCentralityParameter();
  359.     }

  360.     @Override public double skewness()
  361.         throws java.lang.Exception
  362.     {
  363.         double degreesOfFreedom = _r1NonCentralParameters.degreesOfFreedom();

  364.         double nonCentralityParameter = _r1NonCentralParameters.nonCentralityParameter();

  365.         return (degreesOfFreedom + 3. * nonCentralityParameter) * java.lang.Math.pow (
  366.             2.,
  367.             degreesOfFreedom + 2. * nonCentralityParameter
  368.         );
  369.     }

  370.     @Override public double excessKurtosis()
  371.         throws java.lang.Exception
  372.     {
  373.         double degreesOfFreedom = _r1NonCentralParameters.degreesOfFreedom();

  374.         double nonCentralityParameter = _r1NonCentralParameters.nonCentralityParameter();

  375.         double kPlusTwoLambda = degreesOfFreedom + 2. * nonCentralityParameter;
  376.         return 12. * (degreesOfFreedom + 4. * nonCentralityParameter) /
  377.             (kPlusTwoLambda* kPlusTwoLambda);
  378.     }

  379.     @Override public org.drip.function.definition.R1ToR1 momentGeneratingFunction()
  380.     {
  381.         return new org.drip.function.definition.R1ToR1 (
  382.             null
  383.         )
  384.         {
  385.             @Override public double evaluate (
  386.                 final double t)
  387.                 throws java.lang.Exception
  388.             {
  389.                 if (!org.drip.numerical.common.NumberUtil.IsValid (
  390.                         t
  391.                     ) || t > 0.5
  392.                 )
  393.                 {
  394.                     throw new java.lang.Exception (
  395.                         "R1NonCentral::momentGeneratingFunction::evaluate => Invalid Input"
  396.                     );
  397.                 }

  398.                 double oneMinusTwoT = 1. - 2. * t;

  399.                 return java.lang.Math.exp (
  400.                     _r1NonCentralParameters.nonCentralityParameter() * t / oneMinusTwoT
  401.                 ) / java.lang.Math.pow (
  402.                     oneMinusTwoT,
  403.                     0.5 * _r1NonCentralParameters.degreesOfFreedom()
  404.                 );
  405.             }
  406.         };
  407.     }

  408.     /**
  409.      * Compute the Cumulant
  410.      *
  411.      * @param n Cumulant Index
  412.      *
  413.      * @return The Cumulant
  414.      *
  415.      * @throws java.lang.Exception Thrown if the Inputs are Invalid
  416.      */

  417.     public double cumulant (
  418.         final int n)
  419.         throws java.lang.Exception
  420.     {
  421.         if (0 > n)
  422.         {
  423.             throw new java.lang.Exception (
  424.                 "R1NonCentral::cumulant => Invalid Inputs"
  425.             );
  426.         }

  427.         return (
  428.             _r1NonCentralParameters.degreesOfFreedom() + n * _r1NonCentralParameters.nonCentralityParameter()
  429.         ) * java.lang.Math.pow (
  430.             2.,
  431.             n - 1.
  432.         ) * _gammaEstimator.evaluate (
  433.             n
  434.         );
  435.     }

  436.     /**
  437.      * Compute the Leading Non-central Moments
  438.      *
  439.      * @return Leading Non-central Moments
  440.      */

  441.     public double[] leadingRawMoments()
  442.     {
  443.         double degreesOfFreedom = _r1NonCentralParameters.degreesOfFreedom();

  444.         double nonCentralityParameter = _r1NonCentralParameters.nonCentralityParameter();

  445.         double[] fourLeadingRawMomentArray = new double[4];
  446.         fourLeadingRawMomentArray[0] = nonCentralityParameter + degreesOfFreedom;
  447.         fourLeadingRawMomentArray[1] =
  448.             fourLeadingRawMomentArray[0] * fourLeadingRawMomentArray[0] +
  449.             2. * (nonCentralityParameter + 2. * degreesOfFreedom);
  450.         fourLeadingRawMomentArray[2] =
  451.             fourLeadingRawMomentArray[0] * fourLeadingRawMomentArray[0] * fourLeadingRawMomentArray[0] +
  452.             6. * fourLeadingRawMomentArray[0] * (nonCentralityParameter + 2. * degreesOfFreedom) +
  453.             8. * (nonCentralityParameter + 3. * degreesOfFreedom);
  454.         fourLeadingRawMomentArray[3] =
  455.             fourLeadingRawMomentArray[0] * fourLeadingRawMomentArray[0] * fourLeadingRawMomentArray[0] *
  456.                 fourLeadingRawMomentArray[0] +
  457.             12. * fourLeadingRawMomentArray[0] * fourLeadingRawMomentArray[0] *
  458.                 (nonCentralityParameter + 2. * degreesOfFreedom) +
  459.             4. * (
  460.                 11. * degreesOfFreedom * degreesOfFreedom +
  461.                 44. * degreesOfFreedom * nonCentralityParameter +
  462.                 36. * nonCentralityParameter * nonCentralityParameter
  463.             ) +
  464.             48. * (nonCentralityParameter + 4. * degreesOfFreedom);
  465.         return fourLeadingRawMomentArray;
  466.     }

  467.     /**
  468.      * Compute the Leading central Moments
  469.      *
  470.      * @return Leading central Moments
  471.      */

  472.     public double[] leadingCentralMoments()
  473.     {
  474.         double degreesOfFreedom = _r1NonCentralParameters.degreesOfFreedom();

  475.         double nonCentralityParameter = _r1NonCentralParameters.nonCentralityParameter();

  476.         double[] fourLeadingCentralMomentArray = new double[4];
  477.         fourLeadingCentralMomentArray[0] = 0.;
  478.         fourLeadingCentralMomentArray[1] =
  479.             2. * (nonCentralityParameter + 2. * degreesOfFreedom);
  480.         fourLeadingCentralMomentArray[2] =
  481.             8. * (nonCentralityParameter + 3. * degreesOfFreedom);
  482.         fourLeadingCentralMomentArray[3] =
  483.             12. * (nonCentralityParameter + 2. * degreesOfFreedom) *
  484.                 (nonCentralityParameter + 2. * degreesOfFreedom) +
  485.             48. * (nonCentralityParameter + 4. * degreesOfFreedom);
  486.         return fourLeadingCentralMomentArray;
  487.     }

  488.     /**
  489.      * Compute the Non-central Moment
  490.      *
  491.      * @param n Moment Index
  492.      *
  493.      * @return The Non-central Moment
  494.      *
  495.      * @throws java.lang.Exception Thrown if the Inputs are Invalid
  496.      */

  497.     public double nonCentralMoment (
  498.         final int n)
  499.         throws java.lang.Exception
  500.     {
  501.         if (0 >= n)
  502.         {
  503.             throw new java.lang.Exception (
  504.                 "R1NonCentral::nonCentralMoment => Invalid Inputs"
  505.             );
  506.         }

  507.         return nonCentralMoment (
  508.             n,
  509.             leadingRawMoments()
  510.         );
  511.     }
  512. }