SaddlePointExpansionUtils.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.statistics.distribution;

  18. /**
  19.  * Utility class used by various distributions to accurately compute their
  20.  * respective probability mass functions. The implementation for this class is
  21.  * based on the Catherine Loader's
  22.  * <a href="http://www.herine.net/stat/software/dbinom.html">dbinom</a> routines.
  23.  *
  24.  * This class is not intended to be called directly.
  25.  */
  26. final class SaddlePointExpansionUtils {
  27.     /** 2 &pi;. */
  28.     private static final double TWO_PI = 2 * Math.PI;
  29.     /** 1/10. */
  30.     private static final double ONE_TENTH = 0.1;
  31.     /** The threshold value for switching the method to compute th Stirling error. */
  32.     private static final int STIRLING_ERROR_THRESHOLD = 15;

  33.     /** Exact Stirling expansion error for certain values. */
  34.     private static final double[] EXACT_STIRLING_ERRORS = {
  35.         0.0, /* 0.0 */
  36.         0.1534264097200273452913848, /* 0.5 */
  37.         0.0810614667953272582196702, /* 1.0 */
  38.         0.0548141210519176538961390, /* 1.5 */
  39.         0.0413406959554092940938221, /* 2.0 */
  40.         0.03316287351993628748511048, /* 2.5 */
  41.         0.02767792568499833914878929, /* 3.0 */
  42.         0.02374616365629749597132920, /* 3.5 */
  43.         0.02079067210376509311152277, /* 4.0 */
  44.         0.01848845053267318523077934, /* 4.5 */
  45.         0.01664469118982119216319487, /* 5.0 */
  46.         0.01513497322191737887351255, /* 5.5 */
  47.         0.01387612882307074799874573, /* 6.0 */
  48.         0.01281046524292022692424986, /* 6.5 */
  49.         0.01189670994589177009505572, /* 7.0 */
  50.         0.01110455975820691732662991, /* 7.5 */
  51.         0.010411265261972096497478567, /* 8.0 */
  52.         0.009799416126158803298389475, /* 8.5 */
  53.         0.009255462182712732917728637, /* 9.0 */
  54.         0.008768700134139385462952823, /* 9.5 */
  55.         0.008330563433362871256469318, /* 10.0 */
  56.         0.007934114564314020547248100, /* 10.5 */
  57.         0.007573675487951840794972024, /* 11.0 */
  58.         0.007244554301320383179543912, /* 11.5 */
  59.         0.006942840107209529865664152, /* 12.0 */
  60.         0.006665247032707682442354394, /* 12.5 */
  61.         0.006408994188004207068439631, /* 13.0 */
  62.         0.006171712263039457647532867, /* 13.5 */
  63.         0.005951370112758847735624416, /* 14.0 */
  64.         0.005746216513010115682023589, /* 14.5 */
  65.         0.005554733551962801371038690 /* 15.0 */
  66.     };

  67.     /**
  68.      * Forbid construction.
  69.      */
  70.     private SaddlePointExpansionUtils() {}

  71.     /**
  72.      * Compute the error of Stirling's series at the given value.
  73.      * <p>
  74.      * References:
  75.      * <ol>
  76.      * <li>Eric W. Weisstein. "Stirling's Series." From MathWorld--A Wolfram Web
  77.      * Resource. <a target="_blank"
  78.      * href="https://mathworld.wolfram.com/StirlingsSeries.html">
  79.      * https://mathworld.wolfram.com/StirlingsSeries.html</a></li>
  80.      * </ol>
  81.      *
  82.      * <p>Note: This function has been modified for integer {@code z}.</p>
  83.      *
  84.      * @param z Value at which the function is evaluated.
  85.      * @return the Stirling's series error.
  86.      */
  87.     static double getStirlingError(int z) {
  88.         if (z <= STIRLING_ERROR_THRESHOLD) {
  89.             return EXACT_STIRLING_ERRORS[2 * z];
  90.         }
  91.         final double z2 = (double) z * z;
  92.         return (0.083333333333333333333 -
  93.                        (0.00277777777777777777778 -
  94.                                (0.00079365079365079365079365 -
  95.                                        (0.000595238095238095238095238 -
  96.                                                0.0008417508417508417508417508 /
  97.                                                z2) / z2) / z2) / z2) / z;
  98.     }

  99.     /**
  100.      * A part of the deviance portion of the saddle point approximation.
  101.      * <p>
  102.      * References:
  103.      * <ol>
  104.      * <li>Catherine Loader (2000). "Fast and Accurate Computation of Binomial
  105.      * Probabilities.". <a target="_blank"
  106.      * href="http://www.herine.net/stat/papers/dbinom.pdf">
  107.      * http://www.herine.net/stat/papers/dbinom.pdf</a></li>
  108.      * </ol>
  109.      *
  110.      * <p>Note: This function has been modified for integer {@code x}.</p>
  111.      *
  112.      * @param x Value at which the function is evaluated.
  113.      * @param mu Average.
  114.      * @return a part of the deviance.
  115.      */
  116.     static double getDeviancePart(int x, double mu) {
  117.         if (Math.abs(x - mu) < 0.1 * (x + mu)) {
  118.             final double d = x - mu;
  119.             double v = d / (x + mu);
  120.             double s1 = v * d;
  121.             double s = Double.NaN;
  122.             double ej = 2.0 * x * v;
  123.             v *= v;
  124.             int j = 1;
  125.             while (s1 != s) {
  126.                 s = s1;
  127.                 ej *= v;
  128.                 s1 = s + ej / ((j * 2) + 1);
  129.                 ++j;
  130.             }
  131.             return s1;
  132.         } else if (x == 0) {
  133.             return mu;
  134.         }
  135.         return x * Math.log(x / mu) + mu - x;
  136.     }

  137.     /**
  138.      * Compute the logarithm of the PMF for a binomial distribution
  139.      * using the saddle point expansion.
  140.      *
  141.      * @param x Value at which the probability is evaluated.
  142.      * @param n Number of trials.
  143.      * @param p Probability of success.
  144.      * @param q Probability of failure (1 - p).
  145.      * @return log(p(x)).
  146.      */
  147.     static double logBinomialProbability(int x, int n, double p, double q) {
  148.         if (x == 0) {
  149.             if (p < ONE_TENTH) {
  150.                 // Subtract from 0 avoids returning -0.0 for p=0.0
  151.                 return 0.0 - getDeviancePart(n, n * q) - n * p;
  152.             } else if (n == 0) {
  153.                 return 0;
  154.             }
  155.             return n * Math.log(q);
  156.         } else if (x == n) {
  157.             if (q < ONE_TENTH) {
  158.                 // Subtract from 0 avoids returning -0.0 for p=1.0
  159.                 return 0.0 - getDeviancePart(n, n * p) - n * q;
  160.             }
  161.             return n * Math.log(p);
  162.         }
  163.         final int nMx = n - x;
  164.         final double ret = getStirlingError(n) - getStirlingError(x) -
  165.                            getStirlingError(nMx) - getDeviancePart(x, n * p) -
  166.                            getDeviancePart(nMx, n * q);
  167.         final double f = (TWO_PI * x * nMx) / n;
  168.         return -0.5 * Math.log(f) + ret;
  169.     }
  170. }