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.statistics.distribution;
019
020import org.apache.commons.rng.UniformRandomProvider;
021import org.apache.commons.rng.sampling.distribution.ContinuousUniformSampler;
022
023/**
024 * Implementation of the <a href="http://en.wikipedia.org/wiki/Uniform_distribution_(continuous)">uniform distribution</a>.
025 */
026public class UniformContinuousDistribution extends AbstractContinuousDistribution {
027    /** Lower bound of this distribution (inclusive). */
028    private final double lower;
029    /** Upper bound of this distribution (exclusive). */
030    private final double upper;
031
032    /**
033     * Creates a uniform distribution.
034     *
035     * @param lower Lower bound of this distribution (inclusive).
036     * @param upper Upper bound of this distribution (exclusive).
037     * @throws IllegalArgumentException if {@code lower >= upper}.
038     */
039    public UniformContinuousDistribution(double lower,
040                                         double upper) {
041        if (lower >= upper) {
042            throw new DistributionException(DistributionException.TOO_LARGE,
043                                            lower, upper);
044        }
045
046        this.lower = lower;
047        this.upper = upper;
048    }
049
050    /** {@inheritDoc} */
051    @Override
052    public double density(double x) {
053        if (x < lower ||
054            x > upper) {
055            return 0;
056        }
057        return 1 / (upper - lower);
058    }
059
060    /** {@inheritDoc} */
061    @Override
062    public double cumulativeProbability(double x)  {
063        if (x <= lower) {
064            return 0;
065        }
066        if (x >= upper) {
067            return 1;
068        }
069        return (x - lower) / (upper - lower);
070    }
071
072    /** {@inheritDoc} */
073    @Override
074    public double inverseCumulativeProbability(final double p) {
075        if (p < 0 ||
076            p > 1) {
077            throw new DistributionException(DistributionException.INVALID_PROBABILITY, p);
078        }
079        return p * (upper - lower) + lower;
080    }
081
082    /**
083     * {@inheritDoc}
084     *
085     * For lower bound {@code lower} and upper bound {@code upper}, the mean is
086     * {@code 0.5 * (lower + upper)}.
087     */
088    @Override
089    public double getMean() {
090        return 0.5 * (lower + upper);
091    }
092
093    /**
094     * {@inheritDoc}
095     *
096     * For lower bound {@code lower} and upper bound {@code upper}, the
097     * variance is {@code (upper - lower)^2 / 12}.
098     */
099    @Override
100    public double getVariance() {
101        final double ul = upper - lower;
102        return ul * ul / 12;
103    }
104
105    /**
106     * {@inheritDoc}
107     *
108     * The lower bound of the support is equal to the lower bound parameter
109     * of the distribution.
110     *
111     * @return lower bound of the support
112     */
113    @Override
114    public double getSupportLowerBound() {
115        return lower;
116    }
117
118    /**
119     * {@inheritDoc}
120     *
121     * The upper bound of the support is equal to the upper bound parameter
122     * of the distribution.
123     *
124     * @return upper bound of the support
125     */
126    @Override
127    public double getSupportUpperBound() {
128        return upper;
129    }
130
131    /**
132     * {@inheritDoc}
133     *
134     * The support of this distribution is connected.
135     *
136     * @return {@code true}
137     */
138    @Override
139    public boolean isSupportConnected() {
140        return true;
141    }
142
143    /** {@inheritDoc} */
144    @Override
145    public ContinuousDistribution.Sampler createSampler(final UniformRandomProvider rng) {
146        // Uniform distribution sampler.
147        return new ContinuousUniformSampler(rng, lower, upper)::sample;
148    }
149}