LevyDistribution.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.math3.distribution;

  18. import org.apache.commons.math3.exception.OutOfRangeException;
  19. import org.apache.commons.math3.random.RandomGenerator;
  20. import org.apache.commons.math3.random.Well19937c;
  21. import org.apache.commons.math3.special.Erf;
  22. import org.apache.commons.math3.util.FastMath;

  23. /**
  24.  * This class implements the <a href="http://en.wikipedia.org/wiki/L%C3%A9vy_distribution">
  25.  * L&eacute;vy distribution</a>.
  26.  *
  27.  * @since 3.2
  28.  */
  29. public class LevyDistribution extends AbstractRealDistribution {

  30.     /** Serializable UID. */
  31.     private static final long serialVersionUID = 20130314L;

  32.     /** Location parameter. */
  33.     private final double mu;

  34.     /** Scale parameter. */
  35.     private final double c;  // Setting this to 1 returns a cumProb of 1.0

  36.     /** Half of c (for calculations). */
  37.     private final double halfC;

  38.     /**
  39.      * Build a new instance.
  40.      * <p>
  41.      * <b>Note:</b> this constructor will implicitly create an instance of
  42.      * {@link Well19937c} as random generator to be used for sampling only (see
  43.      * {@link #sample()} and {@link #sample(int)}). In case no sampling is
  44.      * needed for the created distribution, it is advised to pass {@code null}
  45.      * as random generator via the appropriate constructors to avoid the
  46.      * additional initialisation overhead.
  47.      *
  48.      * @param mu location parameter
  49.      * @param c scale parameter
  50.      * @since 3.4
  51.      */
  52.     public LevyDistribution(final double mu, final double c) {
  53.         this(new Well19937c(), mu, c);
  54.     }

  55.     /**
  56.      * Creates a LevyDistribution.
  57.      * @param rng random generator to be used for sampling
  58.      * @param mu location
  59.      * @param c scale parameter
  60.      */
  61.     public LevyDistribution(final RandomGenerator rng, final double mu, final double c) {
  62.         super(rng);
  63.         this.mu    = mu;
  64.         this.c     = c;
  65.         this.halfC = 0.5 * c;
  66.     }

  67.     /** {@inheritDoc}
  68.     * <p>
  69.     * From Wikipedia: The probability density function of the L&eacute;vy distribution
  70.     * over the domain is
  71.     * </p>
  72.     * <pre>
  73.     * f(x; &mu;, c) = &radic;(c / 2&pi;) * e<sup>-c / 2 (x - &mu;)</sup> / (x - &mu;)<sup>3/2</sup>
  74.     * </pre>
  75.     * <p>
  76.     * For this distribution, {@code X}, this method returns {@code P(X < x)}.
  77.     * If {@code x} is less than location parameter &mu;, {@code Double.NaN} is
  78.     * returned, as in these cases the distribution is not defined.
  79.     * </p>
  80.     */
  81.     public double density(final double x) {
  82.         if (x < mu) {
  83.             return Double.NaN;
  84.         }

  85.         final double delta = x - mu;
  86.         final double f     = halfC / delta;
  87.         return FastMath.sqrt(f / FastMath.PI) * FastMath.exp(-f) /delta;
  88.     }

  89.     /** {@inheritDoc}
  90.      *
  91.      * See documentation of {@link #density(double)} for computation details.
  92.      */
  93.     @Override
  94.     public double logDensity(double x) {
  95.         if (x < mu) {
  96.             return Double.NaN;
  97.         }

  98.         final double delta = x - mu;
  99.         final double f     = halfC / delta;
  100.         return 0.5 * FastMath.log(f / FastMath.PI) - f - FastMath.log(delta);
  101.     }

  102.     /** {@inheritDoc}
  103.      * <p>
  104.      * From Wikipedia: the cumulative distribution function is
  105.      * </p>
  106.      * <pre>
  107.      * f(x; u, c) = erfc (&radic; (c / 2 (x - u )))
  108.      * </pre>
  109.      */
  110.     public double cumulativeProbability(final double x) {
  111.         if (x < mu) {
  112.             return Double.NaN;
  113.         }
  114.         return Erf.erfc(FastMath.sqrt(halfC / (x - mu)));
  115.     }

  116.     /** {@inheritDoc} */
  117.     @Override
  118.     public double inverseCumulativeProbability(final double p) throws OutOfRangeException {
  119.         if (p < 0.0 || p > 1.0) {
  120.             throw new OutOfRangeException(p, 0, 1);
  121.         }
  122.         final double t = Erf.erfcInv(p);
  123.         return mu + halfC / (t * t);
  124.     }

  125.     /** Get the scale parameter of the distribution.
  126.      * @return scale parameter of the distribution
  127.      */
  128.     public double getScale() {
  129.         return c;
  130.     }

  131.     /** Get the location parameter of the distribution.
  132.      * @return location parameter of the distribution
  133.      */
  134.     public double getLocation() {
  135.         return mu;
  136.     }

  137.     /** {@inheritDoc} */
  138.     public double getNumericalMean() {
  139.         return Double.POSITIVE_INFINITY;
  140.     }

  141.     /** {@inheritDoc} */
  142.     public double getNumericalVariance() {
  143.         return Double.POSITIVE_INFINITY;
  144.     }

  145.     /** {@inheritDoc} */
  146.     public double getSupportLowerBound() {
  147.         return mu;
  148.     }

  149.     /** {@inheritDoc} */
  150.     public double getSupportUpperBound() {
  151.         return Double.POSITIVE_INFINITY;
  152.     }

  153.     /** {@inheritDoc} */
  154.     public boolean isSupportLowerBoundInclusive() {
  155.         // there is a division by x-mu in the computation, so density
  156.         // is not finite at lower bound, bound must be excluded
  157.         return false;
  158.     }

  159.     /** {@inheritDoc} */
  160.     public boolean isSupportUpperBoundInclusive() {
  161.         // upper bound is infinite, so it must be excluded
  162.         return false;
  163.     }

  164.     /** {@inheritDoc} */
  165.     public boolean isSupportConnected() {
  166.         return true;
  167.     }

  168. }