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 */
017
018package org.apache.commons.math3.distribution;
019
020import org.apache.commons.math3.exception.NotStrictlyPositiveException;
021import org.apache.commons.math3.exception.NumberIsTooLargeException;
022import org.apache.commons.math3.exception.util.LocalizedFormats;
023import org.apache.commons.math3.random.RandomGenerator;
024import org.apache.commons.math3.random.Well19937c;
025import org.apache.commons.math3.util.FastMath;
026
027/**
028 * Implementation of the Pareto distribution.
029 *
030 * <p>
031 * <strong>Parameters:</strong>
032 * The probability distribution function of {@code X} is given by (for {@code x >= k}):
033 * <pre>
034 *  α * k^α / x^(α + 1)
035 * </pre>
036 * <p>
037 * <ul>
038 * <li>{@code k} is the <em>scale</em> parameter: this is the minimum possible value of {@code X},</li>
039 * <li>{@code α} is the <em>shape</em> parameter: this is the Pareto index</li>
040 * </ul>
041 *
042 * @see <a href="http://en.wikipedia.org/wiki/Pareto_distribution">
043 * Pareto distribution (Wikipedia)</a>
044 * @see <a href="http://mathworld.wolfram.com/ParetoDistribution.html">
045 * Pareto distribution (MathWorld)</a>
046 *
047 * @since 3.3
048 */
049public class ParetoDistribution extends AbstractRealDistribution {
050
051    /** Default inverse cumulative probability accuracy. */
052    public static final double DEFAULT_INVERSE_ABSOLUTE_ACCURACY = 1e-9;
053
054    /** Serializable version identifier. */
055    private static final long serialVersionUID = 20130424;
056
057    /** The scale parameter of this distribution. */
058    private final double scale;
059
060    /** The shape parameter of this distribution. */
061    private final double shape;
062
063    /** Inverse cumulative probability accuracy. */
064    private final double solverAbsoluteAccuracy;
065
066    /**
067     * Create a Pareto distribution with a scale of {@code 1} and a shape of {@code 1}.
068     */
069    public ParetoDistribution() {
070        this(1, 1);
071    }
072
073    /**
074     * Create a Pareto distribution using the specified scale and shape.
075     * <p>
076     * <b>Note:</b> this constructor will implicitly create an instance of
077     * {@link Well19937c} as random generator to be used for sampling only (see
078     * {@link #sample()} and {@link #sample(int)}). In case no sampling is
079     * needed for the created distribution, it is advised to pass {@code null}
080     * as random generator via the appropriate constructors to avoid the
081     * additional initialisation overhead.
082     *
083     * @param scale the scale parameter of this distribution
084     * @param shape the shape parameter of this distribution
085     * @throws NotStrictlyPositiveException if {@code scale <= 0} or {@code shape <= 0}.
086     */
087    public ParetoDistribution(double scale, double shape)
088        throws NotStrictlyPositiveException {
089        this(scale, shape, DEFAULT_INVERSE_ABSOLUTE_ACCURACY);
090    }
091
092    /**
093     * Create a Pareto distribution using the specified scale, shape and
094     * inverse cumulative distribution accuracy.
095     * <p>
096     * <b>Note:</b> this constructor will implicitly create an instance of
097     * {@link Well19937c} as random generator to be used for sampling only (see
098     * {@link #sample()} and {@link #sample(int)}). In case no sampling is
099     * needed for the created distribution, it is advised to pass {@code null}
100     * as random generator via the appropriate constructors to avoid the
101     * additional initialisation overhead.
102     *
103     * @param scale the scale parameter of this distribution
104     * @param shape the shape parameter of this distribution
105     * @param inverseCumAccuracy Inverse cumulative probability accuracy.
106     * @throws NotStrictlyPositiveException if {@code scale <= 0} or {@code shape <= 0}.
107     */
108    public ParetoDistribution(double scale, double shape, double inverseCumAccuracy)
109        throws NotStrictlyPositiveException {
110        this(new Well19937c(), scale, shape, inverseCumAccuracy);
111    }
112
113    /**
114     * Creates a Pareto distribution.
115     *
116     * @param rng Random number generator.
117     * @param scale Scale parameter of this distribution.
118     * @param shape Shape parameter of this distribution.
119     * @throws NotStrictlyPositiveException if {@code scale <= 0} or {@code shape <= 0}.
120     */
121    public ParetoDistribution(RandomGenerator rng, double scale, double shape)
122        throws NotStrictlyPositiveException {
123        this(rng, scale, shape, DEFAULT_INVERSE_ABSOLUTE_ACCURACY);
124    }
125
126    /**
127     * Creates a Pareto distribution.
128     *
129     * @param rng Random number generator.
130     * @param scale Scale parameter of this distribution.
131     * @param shape Shape parameter of this distribution.
132     * @param inverseCumAccuracy Inverse cumulative probability accuracy.
133     * @throws NotStrictlyPositiveException if {@code scale <= 0} or {@code shape <= 0}.
134     */
135    public ParetoDistribution(RandomGenerator rng,
136                              double scale,
137                              double shape,
138                              double inverseCumAccuracy)
139        throws NotStrictlyPositiveException {
140        super(rng);
141
142        if (scale <= 0) {
143            throw new NotStrictlyPositiveException(LocalizedFormats.SCALE, scale);
144        }
145
146        if (shape <= 0) {
147            throw new NotStrictlyPositiveException(LocalizedFormats.SHAPE, shape);
148        }
149
150        this.scale = scale;
151        this.shape = shape;
152        this.solverAbsoluteAccuracy = inverseCumAccuracy;
153    }
154
155    /**
156     * Returns the scale parameter of this distribution.
157     *
158     * @return the scale parameter
159     */
160    public double getScale() {
161        return scale;
162    }
163
164    /**
165     * Returns the shape parameter of this distribution.
166     *
167     * @return the shape parameter
168     */
169    public double getShape() {
170        return shape;
171    }
172
173    /**
174     * {@inheritDoc}
175     * <p>
176     * For scale {@code k}, and shape {@code α} of this distribution, the PDF
177     * is given by
178     * <ul>
179     * <li>{@code 0} if {@code x < k},</li>
180     * <li>{@code α * k^α / x^(α + 1)} otherwise.</li>
181     * </ul>
182     */
183    public double density(double x) {
184        if (x < scale) {
185            return 0;
186        }
187        return FastMath.pow(scale, shape) / FastMath.pow(x, shape + 1) * shape;
188    }
189
190    /** {@inheritDoc}
191     *
192     * See documentation of {@link #density(double)} for computation details.
193     */
194    @Override
195    public double logDensity(double x) {
196        if (x < scale) {
197            return Double.NEGATIVE_INFINITY;
198        }
199        return FastMath.log(scale) * shape - FastMath.log(x) * (shape + 1) + FastMath.log(shape);
200    }
201
202    /**
203     * {@inheritDoc}
204     * <p>
205     * For scale {@code k}, and shape {@code α} of this distribution, the CDF is given by
206     * <ul>
207     * <li>{@code 0} if {@code x < k},</li>
208     * <li>{@code 1 - (k / x)^α} otherwise.</li>
209     * </ul>
210     */
211    public double cumulativeProbability(double x)  {
212        if (x <= scale) {
213            return 0;
214        }
215        return 1 - FastMath.pow(scale / x, shape);
216    }
217
218    /**
219     * {@inheritDoc}
220     *
221     * @deprecated See {@link RealDistribution#cumulativeProbability(double,double)}
222     */
223    @Override
224    @Deprecated
225    public double cumulativeProbability(double x0, double x1)
226        throws NumberIsTooLargeException {
227        return probability(x0, x1);
228    }
229
230    /** {@inheritDoc} */
231    @Override
232    protected double getSolverAbsoluteAccuracy() {
233        return solverAbsoluteAccuracy;
234    }
235
236    /**
237     * {@inheritDoc}
238     * <p>
239     * For scale {@code k} and shape {@code α}, the mean is given by
240     * <ul>
241     * <li>{@code ∞} if {@code α <= 1},</li>
242     * <li>{@code α * k / (α - 1)} otherwise.</li>
243     * </ul>
244     */
245    public double getNumericalMean() {
246        if (shape <= 1) {
247            return Double.POSITIVE_INFINITY;
248        }
249        return shape * scale / (shape - 1);
250    }
251
252    /**
253     * {@inheritDoc}
254     * <p>
255     * For scale {@code k} and shape {@code α}, the variance is given by
256     * <ul>
257     * <li>{@code ∞} if {@code 1 < α <= 2},</li>
258     * <li>{@code k^2 * α / ((α - 1)^2 * (α - 2))} otherwise.</li>
259     * </ul>
260     */
261    public double getNumericalVariance() {
262        if (shape <= 2) {
263            return Double.POSITIVE_INFINITY;
264        }
265        double s = shape - 1;
266        return scale * scale * shape / (s * s) / (shape - 2);
267    }
268
269    /**
270     * {@inheritDoc}
271     * <p>
272     * The lower bound of the support is equal to the scale parameter {@code k}.
273     *
274     * @return lower bound of the support
275     */
276    public double getSupportLowerBound() {
277        return scale;
278    }
279
280    /**
281     * {@inheritDoc}
282     * <p>
283     * The upper bound of the support is always positive infinity no matter the parameters.
284     *
285     * @return upper bound of the support (always {@code Double.POSITIVE_INFINITY})
286     */
287    public double getSupportUpperBound() {
288        return Double.POSITIVE_INFINITY;
289    }
290
291    /** {@inheritDoc} */
292    public boolean isSupportLowerBoundInclusive() {
293        return true;
294    }
295
296    /** {@inheritDoc} */
297    public boolean isSupportUpperBoundInclusive() {
298        return false;
299    }
300
301    /**
302     * {@inheritDoc}
303     * <p>
304     * The support of this distribution is connected.
305     *
306     * @return {@code true}
307     */
308    public boolean isSupportConnected() {
309        return true;
310    }
311
312    /** {@inheritDoc} */
313    @Override
314    public double sample()  {
315        final double n = random.nextDouble();
316        return scale / FastMath.pow(n, 1 / shape);
317    }
318}