All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gov.sandia.cognition.statistics.distribution.UniformIntegerDistribution Maven / Gradle / Ivy

There is a newer version: 4.0.1
Show newest version
/*
 * File:            UniformIntegerDistribution.java
 * Authors:         Justin Basilico
 * Project:         Cognitive Foundry
 * 
 * Copyright 2015 Cognitive Foundry. All rights reserved.
 */

package gov.sandia.cognition.statistics.distribution;

import gov.sandia.cognition.annotation.PublicationReference;
import gov.sandia.cognition.annotation.PublicationType;
import gov.sandia.cognition.collection.IntegerSpan;
import gov.sandia.cognition.math.LogMath;
import gov.sandia.cognition.math.MathUtil;
import gov.sandia.cognition.math.UnivariateStatisticsUtil;
import gov.sandia.cognition.math.matrix.Vector;
import gov.sandia.cognition.math.matrix.VectorFactory;
import gov.sandia.cognition.statistics.AbstractClosedFormIntegerDistribution;
import gov.sandia.cognition.statistics.ClosedFormCumulativeDistributionFunction;
import gov.sandia.cognition.statistics.ClosedFormDiscreteUnivariateDistribution;
import gov.sandia.cognition.statistics.DistributionEstimator;
import gov.sandia.cognition.statistics.EstimableDistribution;
import gov.sandia.cognition.statistics.ProbabilityMassFunction;
import gov.sandia.cognition.util.AbstractCloneableSerializable;
import gov.sandia.cognition.util.Pair;
import java.util.Collection;
import java.util.Random;
import java.util.Set;

/**
 * Contains the (very simple) definition of a continuous Uniform distribution,
 * parameterized between the minimum and maximum bounds. The uniform 
 * distribution has equal mass on all of the integers between the two bounds,
 * and including them. For example, if the bounds were (10, 14) then the values
 * 10, 11, 12, 13, and 14 would all have probability 1/5 of being sampled.
 * 
 * @author  Justin Basilico
 * @since   3.4.3
 */
@PublicationReference(
    author="Wikipedia",
    title="Uniform distribution (discrete)",
    type=PublicationType.WebPage,
    year=2015,
    url="https://en.wikipedia.org/wiki/Uniform_distribution_(discrete)"
)
public class UniformIntegerDistribution
    extends AbstractClosedFormIntegerDistribution
    implements ClosedFormDiscreteUnivariateDistribution,
        EstimableDistribution
{

    /** The default minimum support is {@value}. */
    public static final int DEFAULT_MIN_SUPPORT = 0;

    /** The default maximum support is {@value}. */
    public static final int DEFAULT_MAX_SUPPORT = 0;
    
    /** The minimum bound on the distribution (inclusive). */
    private int minSupport;
    
    /** The maximum bound on the distribution (inclusive). */    
    private int maxSupport;
    
    /**
     * Creates a new {@link UniformIntegerDistribution} with default parameters.
     */
    public UniformIntegerDistribution()
    {
        this(DEFAULT_MIN_SUPPORT, DEFAULT_MAX_SUPPORT);
    }

    /**
     * Creates a new {@link UniformIntegerDistribution} with the given bounds.
     * 
     * @param minSupport
     *      The minimum bound on the distribution (inclusive).
     * @param maxSupport 
     *      The maximum bound on the distribution (exclusive).
     */
    public UniformIntegerDistribution(
        final int minSupport,
        final int maxSupport)
    {
        super();
        
        this.setMinSupport(minSupport);
        this.setMaxSupport(maxSupport);
    }
    
    /**
     * Creates a new {@link UniformIntegerDistribution} that is a copy of the
     * given other distribution.
     * 
     * @param other 
     *      The distribution to copy.
     */
    public UniformIntegerDistribution(
        final UniformIntegerDistribution other)
    {
        this(other.getMinSupport(), other.getMaxSupport());
    }

    @Override
    public UniformIntegerDistribution clone()
    {
        return (UniformIntegerDistribution) super.clone();
    }
    
    @Override
    public UniformIntegerDistribution.PMF getProbabilityFunction()
    {
        return new UniformIntegerDistribution.PMF(this);
    }

    @Override
    public UniformIntegerDistribution.CDF getCDF()
    {
        return new UniformIntegerDistribution.CDF(this);
    }

    @Override
    public Number getMean()
    {
        return this.getMeanAsDouble();
    }

    @Override
    public Vector convertToVector()
    {
        return VectorFactory.getDenseDefault().copyValues(
            this.getMinSupport(), this.getMaxSupport());
    }

    @Override
    public void convertFromVector(
        final Vector parameters)
    {
        parameters.assertDimensionalityEquals(2);
        final int a = (int) parameters.getElement(0);
        final int b = (int) parameters.getElement(1);

        this.setMinSupport(Math.min(a, b));
        this.setMaxSupport(Math.max(a, b));
    }

    @Override
    public Integer getMinSupport()
    {
        return this.minSupport;
    }

    /**
     * Sets the minimum support. It is the smallest value in the uniform
     * distribution, and is inclusive. It should be less than (or equal to) 
     * the maximum support.
     * 
     * @param   minSupport 
     *      The minimum support.
     */
    public void setMinSupport(
        final int minSupport)
    {
        this.minSupport = minSupport;
    }

    @Override
    public Integer getMaxSupport()
    {
        return this.maxSupport;
    }

    /**
     * Sets the maximum support. It is the largest value in the uniform
     * distribution, and is inclusive. It should be greater than (or equal to)
     * the minimum support.
     * 
     * @param   maxSupport 
     *      The maximum support.
     */
    public void setMaxSupport(
        final int maxSupport)
    {
        this.maxSupport = maxSupport;
    }

    @Override
    public double getMeanAsDouble()
    {
        return (this.maxSupport + this.minSupport) / 2.0;
    }

    @Override
    public double getVariance()
    {
        final double difference = this.maxSupport - this.minSupport + 1;
        return (difference * difference - 1) / 12.0;
    }

    @Override
    public Set getDomain()
    {
        return new IntegerSpan(this.minSupport, this.maxSupport);
    }

    @Override
    public int getDomainSize()
    {
        return (this.maxSupport - this.minSupport + 1);
    }

    @Override
    public int sampleAsInt(
        final Random random)
    {
        return this.minSupport 
            + random.nextInt(this.maxSupport - this.minSupport + 1);
    }
    
    @Override
    public void sampleInto(
        final Random random,
        final int sampleCount,
        final Collection output)
    {
        for (int i = 0; i < sampleCount; i++)
        {
            output.add(this.sampleAsInt(random));
        }
    }

    @Override
    public UniformIntegerDistribution.MaximumLikelihoodEstimator getEstimator()
    {
        return new MaximumLikelihoodEstimator();
    }
    
    /**
     * Probability mass function of a discrete uniform distribution.
     */
    public static class PMF
        extends UniformIntegerDistribution
        implements ProbabilityMassFunction
    {
        
        /**
         * Creates a new {@link UniformIntegerDistribution.PMF} with min and
         * max 0.
         */
        public PMF()
        {
            super();
        }

        /**
         * Creates a new {@link UniformIntegerDistribution.PMF} with the given
         * min and max.
         * 
         * @param   minSupport
         *      The minimum support. Should be less-than-or-equal to the max
         *      support.
         * @param   maxSupport
         *      The maximum support. Should be greater-than-or-equal to the min
         *      support.
         */
        public PMF(
            final int minSupport,
            final int maxSupport)
        {
            super(minSupport, maxSupport);
        }
        
        /**
         * Creates a new {@link UniformIntegerDistribution.PMF} as a copy
         * of the given other uniform distribution.
         * 
         * @param   other
         *      The other distribution.
         */
        public PMF(
            final UniformIntegerDistribution other)
        {
            super(other);
        }

        @Override
        public double getEntropy()
        {
            return MathUtil.log2(this.getDomainSize());
        }

        @Override
        public double logEvaluate(
            final Number input)
        {
            return logEvaluate(input.intValue(), 
                this.getMinSupport(), this.getMaxSupport());
        }

        @Override
        public Double evaluate(
            final Number input)
        {
            return this.evaluateAsDouble(input.intValue());
        }
        
        /**
         * Evaluates the input value for the PMF to compute its mass as a
         * double.
         * 
         * @param   input
         *      The input value.
         * @return 
         *      The probability mass for the input value.
         */
        public double evaluateAsDouble(
            final int input)
        {
            return evaluate(input, this.getMinSupport(), this.getMaxSupport());
        }
        
        /**
         * Evaluates the probability mass function of the discrete uniform
         * distribution. The mass is a uniform value if the input is between
         * the supports (inclusive) and 0 if it is not.
         * 
         * @param   input
         *      The input value.
         * @param   minSupport
         *      The minimum support. Should be less-than-or-equal to the max
         *      support.
         * @param   maxSupport
         *      The maximum support. Should be greater-than-or-equal to the min
         *      support.
         * @return 
         *      The probability mass value for the input.
         */
        public static double evaluate(
            final int input,
            final int minSupport,
            final int maxSupport)
        {
            if (input < minSupport || input > maxSupport)
            {
                // Outside the support range.
                return 0.0;
            }
            else
            {
                // Uniform within support range.
                return 1.0 / (maxSupport - minSupport + 1);
            }
        }
        
        /**
         * Evaluates the log of the probability mass function of the discrete 
         * uniform distribution. The mass is a uniform value if the input is 
         * between the supports (inclusive) and 0 if it is not.
         * 
         * @param   input
         *      The input value.
         * @param   minSupport
         *      The minimum support. Should be less-than-or-equal to the max
         *      support.
         * @param   maxSupport
         *      The maximum support. Should be greater-than-or-equal to the min
         *      support.
         * @return 
         *      The log of the probability mass value for the input.
         */
        public static double logEvaluate(
            final int input,
            final int minSupport,
            final int maxSupport)
        {
            if (input < minSupport || input > maxSupport)
            {
                return LogMath.LOG_0;
            }
            else
            {
                return -Math.log(maxSupport - minSupport + 1);
            }
        }

        @Override
        public PMF getProbabilityFunction()
        {
            return this;
        }
        
    }
    
    /**
     * Implements the cumulative distribution function for the discrete
     * uniform distribution.
     */
    public static class CDF
        extends UniformIntegerDistribution
        implements ClosedFormCumulativeDistributionFunction
    {

        /**
         * Creates a new {@link UniformIntegerDistribution.PMF} with min and
         * max 0.
         */
        public CDF()
        {
            super();
        }

        /**
         * Creates a new {@link UniformIntegerDistribution.CDF} with the given
         * min and max.
         * 
         * @param   minSupport
         *      The minimum support. Should be less-than-or-equal to the max
         *      support.
         * @param   maxSupport
         *      The maximum support. Should be greater-than-or-equal to the min
         *      support.
         */
        public CDF(
            final int minSupport,
            final int maxSupport)
        {
            super(minSupport, maxSupport);
        }
        
        /**
         * Creates a new {@link UniformIntegerDistribution.CDF} as a copy
         * of the given other uniform distribution.
         * 
         * @param   other
         *      The other distribution.
         */
        public CDF(
            final UniformIntegerDistribution other)
        {
            super(other);
        }
        
        @Override
        public Double evaluate(
            final Number input)
        {
            return this.evaluateAsDouble(input.intValue());
        }
        
        /**
         * Evaluates the cumulative distribution function for the input.
         * 
         * @param   input
         *      The input value.
         * @return 
         *      The cumulative distribution value at the input.
         */
        public double evaluateAsDouble(
            final int input)
        {
            return evaluate(input, this.getMinSupport(), this.getMaxSupport());
        }
        
        /**
         * Evaluates the cumulative density function of the discrete uniform
         * distribution. 
         * 
         * @param   input
         *      The input value.
         * @param   minSupport
         *      The minimum support. Should be less-than-or-equal to the max
         *      support.
         * @param   maxSupport
         *      The maximum support. Should be greater-than-or-equal to the min
         *      support.
         * @return 
         *      The cumulative density value for the input.
         */
        public static double evaluate(
            final int input,
            final int minSupport,
            final int maxSupport)
        {
            final double p;
            if (input < minSupport)
            {
                // Before the support range.
                p = 0.0;
            }
            else if (input > maxSupport)
            {
                // After the support range.
                p = 1.0;
            }
            else
            {
                // Within the support range.
                p = (input - minSupport + 1.0) / (maxSupport - minSupport + 1.0);
            }

            return p;
        }
        
        @Override
        public UniformIntegerDistribution.CDF getCDF()
        {
            return this;
        }
    }
    
    /**
     * Implements a maximum likelihood estimator for the discrete uniform
     * distribution.
     */
    @PublicationReference(
        author="Wikipedia",
        title="German tank problem",
        type=PublicationType.WebPage,
        year=2010,
        url="http://en.wikipedia.org/wiki/German_tank_problem"
    )
    public static class MaximumLikelihoodEstimator
        extends AbstractCloneableSerializable
        implements DistributionEstimator
    {

        /**
         * Creates a new {@link UniformIntegerDistribution.MaximumLikelihoodEstimator}.
         */
        public MaximumLikelihoodEstimator()
        {
            super();
        }

        @Override
        public UniformIntegerDistribution.PMF learn(
            final Collection data)
        {
            final Pair result = 
                UnivariateStatisticsUtil.computeMinAndMax(data);
            final int min = result.getFirst().intValue();
            final int max = result.getSecond().intValue();
            
            return new UniformIntegerDistribution.PMF(min, max);
        }
        
    }
    
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy