001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.math3.distribution; 018 019import org.apache.commons.math3.exception.OutOfRangeException; 020import org.apache.commons.math3.random.RandomGenerator; 021import org.apache.commons.math3.random.Well19937c; 022import org.apache.commons.math3.special.Erf; 023import org.apache.commons.math3.util.FastMath; 024 025/** 026 * This class implements the <a href="http://en.wikipedia.org/wiki/L%C3%A9vy_distribution"> 027 * Lévy distribution</a>. 028 * 029 * @since 3.2 030 */ 031public class LevyDistribution extends AbstractRealDistribution { 032 033 /** Serializable UID. */ 034 private static final long serialVersionUID = 20130314L; 035 036 /** Location parameter. */ 037 private final double mu; 038 039 /** Scale parameter. */ 040 private final double c; // Setting this to 1 returns a cumProb of 1.0 041 042 /** Half of c (for calculations). */ 043 private final double halfC; 044 045 /** 046 * Build a new instance. 047 * <p> 048 * <b>Note:</b> this constructor will implicitly create an instance of 049 * {@link Well19937c} as random generator to be used for sampling only (see 050 * {@link #sample()} and {@link #sample(int)}). In case no sampling is 051 * needed for the created distribution, it is advised to pass {@code null} 052 * as random generator via the appropriate constructors to avoid the 053 * additional initialisation overhead. 054 * 055 * @param mu location parameter 056 * @param c scale parameter 057 * @since 3.4 058 */ 059 public LevyDistribution(final double mu, final double c) { 060 this(new Well19937c(), mu, c); 061 } 062 063 /** 064 * Creates a LevyDistribution. 065 * @param rng random generator to be used for sampling 066 * @param mu location 067 * @param c scale parameter 068 */ 069 public LevyDistribution(final RandomGenerator rng, final double mu, final double c) { 070 super(rng); 071 this.mu = mu; 072 this.c = c; 073 this.halfC = 0.5 * c; 074 } 075 076 /** {@inheritDoc} 077 * <p> 078 * From Wikipedia: The probability density function of the Lévy distribution 079 * over the domain is 080 * </p> 081 * <pre> 082 * f(x; μ, c) = √(c / 2π) * e<sup>-c / 2 (x - μ)</sup> / (x - μ)<sup>3/2</sup> 083 * </pre> 084 * <p> 085 * For this distribution, {@code X}, this method returns {@code P(X < x)}. 086 * If {@code x} is less than location parameter μ, {@code Double.NaN} is 087 * returned, as in these cases the distribution is not defined. 088 * </p> 089 */ 090 public double density(final double x) { 091 if (x < mu) { 092 return Double.NaN; 093 } 094 095 final double delta = x - mu; 096 final double f = halfC / delta; 097 return FastMath.sqrt(f / FastMath.PI) * FastMath.exp(-f) /delta; 098 } 099 100 /** {@inheritDoc} 101 * 102 * See documentation of {@link #density(double)} for computation details. 103 */ 104 @Override 105 public double logDensity(double x) { 106 if (x < mu) { 107 return Double.NaN; 108 } 109 110 final double delta = x - mu; 111 final double f = halfC / delta; 112 return 0.5 * FastMath.log(f / FastMath.PI) - f - FastMath.log(delta); 113 } 114 115 /** {@inheritDoc} 116 * <p> 117 * From Wikipedia: the cumulative distribution function is 118 * </p> 119 * <pre> 120 * f(x; u, c) = erfc (√ (c / 2 (x - u ))) 121 * </pre> 122 */ 123 public double cumulativeProbability(final double x) { 124 if (x < mu) { 125 return Double.NaN; 126 } 127 return Erf.erfc(FastMath.sqrt(halfC / (x - mu))); 128 } 129 130 /** {@inheritDoc} */ 131 @Override 132 public double inverseCumulativeProbability(final double p) throws OutOfRangeException { 133 if (p < 0.0 || p > 1.0) { 134 throw new OutOfRangeException(p, 0, 1); 135 } 136 final double t = Erf.erfcInv(p); 137 return mu + halfC / (t * t); 138 } 139 140 /** Get the scale parameter of the distribution. 141 * @return scale parameter of the distribution 142 */ 143 public double getScale() { 144 return c; 145 } 146 147 /** Get the location parameter of the distribution. 148 * @return location parameter of the distribution 149 */ 150 public double getLocation() { 151 return mu; 152 } 153 154 /** {@inheritDoc} */ 155 public double getNumericalMean() { 156 return Double.POSITIVE_INFINITY; 157 } 158 159 /** {@inheritDoc} */ 160 public double getNumericalVariance() { 161 return Double.POSITIVE_INFINITY; 162 } 163 164 /** {@inheritDoc} */ 165 public double getSupportLowerBound() { 166 return mu; 167 } 168 169 /** {@inheritDoc} */ 170 public double getSupportUpperBound() { 171 return Double.POSITIVE_INFINITY; 172 } 173 174 /** {@inheritDoc} */ 175 public boolean isSupportLowerBoundInclusive() { 176 // there is a division by x-mu in the computation, so density 177 // is not finite at lower bound, bound must be excluded 178 return false; 179 } 180 181 /** {@inheritDoc} */ 182 public boolean isSupportUpperBoundInclusive() { 183 // upper bound is infinite, so it must be excluded 184 return false; 185 } 186 187 /** {@inheritDoc} */ 188 public boolean isSupportConnected() { 189 return true; 190 } 191 192}