Example #1
0
  /**
   * Returns the value of log[Γ(b) / Γ(a + b)] for a ≥ 0 and b ≥ 10. Based on the <em>NSWC Library
   * of Mathematics Subroutines</em> double precision implementation, {@code DLGDIV}. In {@code
   * BetaTest.testLogGammaMinusLogGammaSum()}, this private method is accessed through reflection.
   *
   * @param a First argument.
   * @param b Second argument.
   * @return the value of {@code log(Gamma(b) / Gamma(a + b))}.
   * @throws NumberIsTooSmallException if {@code a < 0.0} or {@code b < 10.0}.
   */
  private static double logGammaMinusLogGammaSum(final double a, final double b)
      throws NumberIsTooSmallException {

    if (a < 0.0) {
      throw new NumberIsTooSmallException(a, 0.0, true);
    }
    if (b < 10.0) {
      throw new NumberIsTooSmallException(b, 10.0, true);
    }

    /*
     * d = a + b - 0.5
     */
    final double d;
    final double w;
    if (a <= b) {
      d = b + (a - 0.5);
      w = deltaMinusDeltaSum(a, b);
    } else {
      d = a + (b - 0.5);
      w = deltaMinusDeltaSum(b, a);
    }

    final double u = d * FastMath.log1p(a / b);
    final double v = a * (FastMath.log(b) - 1.0);

    return u <= v ? (w - u) - v : (w - v) - u;
  }
Example #2
0
  /**
   * Returns the value of log Γ(a + b) for 1 ≤ a, b ≤ 2. Based on the <em>NSWC Library of
   * Mathematics Subroutines</em> double precision implementation, {@code DGSMLN}. In {@code
   * BetaTest.testLogGammaSum()}, this private method is accessed through reflection.
   *
   * @param a First argument.
   * @param b Second argument.
   * @return the value of {@code log(Gamma(a + b))}.
   * @throws OutOfRangeException if {@code a} or {@code b} is lower than {@code 1.0} or greater than
   *     {@code 2.0}.
   */
  private static double logGammaSum(final double a, final double b) throws OutOfRangeException {

    if ((a < 1.0) || (a > 2.0)) {
      throw new OutOfRangeException(a, 1.0, 2.0);
    }
    if ((b < 1.0) || (b > 2.0)) {
      throw new OutOfRangeException(b, 1.0, 2.0);
    }

    final double x = (a - 1.0) + (b - 1.0);
    if (x <= 0.5) {
      return Gamma.logGamma1p(1.0 + x);
    } else if (x <= 1.5) {
      return Gamma.logGamma1p(x) + FastMath.log1p(x);
    } else {
      return Gamma.logGamma1p(x - 1.0) + FastMath.log(x * (1.0 + x));
    }
  }
 /** {@inheritDoc} * */
 @Override
 public double logDensity(double x) {
   recomputeZ();
   if (x < 0 || x > 1) {
     return Double.NEGATIVE_INFINITY;
   } else if (x == 0) {
     if (alpha < 1) {
       throw new NumberIsTooSmallException(
           LocalizedFormats.CANNOT_COMPUTE_BETA_DENSITY_AT_0_FOR_SOME_ALPHA, alpha, 1, false);
     }
     return Double.NEGATIVE_INFINITY;
   } else if (x == 1) {
     if (beta < 1) {
       throw new NumberIsTooSmallException(
           LocalizedFormats.CANNOT_COMPUTE_BETA_DENSITY_AT_1_FOR_SOME_BETA, beta, 1, false);
     }
     return Double.NEGATIVE_INFINITY;
   } else {
     double logX = FastMath.log(x);
     double log1mX = FastMath.log1p(-x);
     return (alpha - 1) * logX + (beta - 1) * log1mX - z;
   }
 }
 @Test
 public void testSamplerHelper1() {
   final double tol = 1e-12;
   final double[] testValues = {
     FastMath.nextUp(-1.),
     -1e-1,
     -1e-2,
     -1e-3,
     -1e-4,
     -1e-5,
     -1e-6,
     -1e-7,
     -1e-8,
     -1e-9,
     -1e-10,
     -1e-11,
     0.,
     1e-11,
     1e-10,
     1e-9,
     1e-8,
     1e-7,
     1e-6,
     1e-5,
     1e-4,
     1e-3,
     1e-2,
     1e-1,
     1e0
   };
   for (final double testValue : testValues) {
     final double expected = FastMath.log1p(testValue);
     TestUtils.assertRelativelyEquals(
         expected, ZipfRejectionInversionSampler.helper1(testValue) * testValue, tol);
   }
 }
Example #5
0
 /** {@inheritDoc} */
 public double value(double x) {
   return FastMath.log1p(x);
 }
Example #6
0
  /**
   * Returns the value of log B(p, q) for 0 ≤ x ≤ 1 and p, q > 0. Based on the <em>NSWC Library of
   * Mathematics Subroutines</em> implementation, {@code DBETLN}.
   *
   * @param p First argument.
   * @param q Second argument.
   * @return the value of {@code log(Beta(p, q))}, {@code NaN} if {@code p <= 0} or {@code q <= 0}.
   */
  public static double logBeta(final double p, final double q) {
    if (Double.isNaN(p) || Double.isNaN(q) || (p <= 0.0) || (q <= 0.0)) {
      return Double.NaN;
    }

    final double a = FastMath.min(p, q);
    final double b = FastMath.max(p, q);
    if (a >= 10.0) {
      final double w = sumDeltaMinusDeltaSum(a, b);
      final double h = a / b;
      final double c = h / (1.0 + h);
      final double u = -(a - 0.5) * FastMath.log(c);
      final double v = b * FastMath.log1p(h);
      if (u <= v) {
        return (((-0.5 * FastMath.log(b) + HALF_LOG_TWO_PI) + w) - u) - v;
      } else {
        return (((-0.5 * FastMath.log(b) + HALF_LOG_TWO_PI) + w) - v) - u;
      }
    } else if (a > 2.0) {
      if (b > 1000.0) {
        final int n = (int) FastMath.floor(a - 1.0);
        double prod = 1.0;
        double ared = a;
        for (int i = 0; i < n; i++) {
          ared -= 1.0;
          prod *= ared / (1.0 + ared / b);
        }
        return (FastMath.log(prod) - n * FastMath.log(b))
            + (Gamma.logGamma(ared) + logGammaMinusLogGammaSum(ared, b));
      } else {
        double prod1 = 1.0;
        double ared = a;
        while (ared > 2.0) {
          ared -= 1.0;
          final double h = ared / b;
          prod1 *= h / (1.0 + h);
        }
        if (b < 10.0) {
          double prod2 = 1.0;
          double bred = b;
          while (bred > 2.0) {
            bred -= 1.0;
            prod2 *= bred / (ared + bred);
          }
          return FastMath.log(prod1)
              + FastMath.log(prod2)
              + (Gamma.logGamma(ared) + (Gamma.logGamma(bred) - logGammaSum(ared, bred)));
        } else {
          return FastMath.log(prod1) + Gamma.logGamma(ared) + logGammaMinusLogGammaSum(ared, b);
        }
      }
    } else if (a >= 1.0) {
      if (b > 2.0) {
        if (b < 10.0) {
          double prod = 1.0;
          double bred = b;
          while (bred > 2.0) {
            bred -= 1.0;
            prod *= bred / (a + bred);
          }
          return FastMath.log(prod)
              + (Gamma.logGamma(a) + (Gamma.logGamma(bred) - logGammaSum(a, bred)));
        } else {
          return Gamma.logGamma(a) + logGammaMinusLogGammaSum(a, b);
        }
      } else {
        return Gamma.logGamma(a) + Gamma.logGamma(b) - logGammaSum(a, b);
      }
    } else {
      if (b >= 10.0) {
        return Gamma.logGamma(a) + logGammaMinusLogGammaSum(a, b);
      } else {
        // The following command is the original NSWC implementation.
        // return Gamma.logGamma(a) +
        // (Gamma.logGamma(b) - Gamma.logGamma(a + b));
        // The following command turns out to be more accurate.
        return FastMath.log(Gamma.gamma(a) * Gamma.gamma(b) / Gamma.gamma(a + b));
      }
    }
  }