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

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

There is a newer version: 4.0.1
Show newest version
/*
 * File:                ParetoDistribution.java
 * Authors:             Kevin R. Dixon
 * Company:             Sandia National Laboratories
 * Project:             Cognitive Foundry
 * 
 * Copyright Mar 10, 2010, Sandia Corporation.
 * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
 * license for use of this work by or on behalf of the U.S. Government.
 * Export of this program may require a license from the United States
 * Government. See CopyrightHistory.txt for complete details.
 * 
 */

package gov.sandia.cognition.statistics.distribution;

import gov.sandia.cognition.annotation.PublicationReference;
import gov.sandia.cognition.annotation.PublicationType;
import gov.sandia.cognition.math.matrix.Vector;
import gov.sandia.cognition.math.matrix.VectorFactory;
import gov.sandia.cognition.statistics.AbstractClosedFormSmoothUnivariateDistribution;
import gov.sandia.cognition.statistics.InvertibleCumulativeDistributionFunction;
import gov.sandia.cognition.statistics.UnivariateProbabilityDensityFunction;
import gov.sandia.cognition.statistics.SmoothCumulativeDistributionFunction;
import java.util.ArrayList;
import java.util.Random;

/**
 * This class describes the Pareto distribution, sometimes called the Bradford
 * Distribution.  The Pareto distribution tends to be used to model social
 * phenomena, such as the distribution of wealth in a society, price returns of
 * stocks, file sizes on a computer, etc.  It encapsulates the notion that
 * there are few large entities and many smaller ones (80 percent of the wealth
 * is controlled by 20 percent of the population).
 * @author Kevin R. Dixon
 * @since 3.0
 */
@PublicationReference(
    author="Wikipedia",
    title="Normal distribution",
    type=PublicationType.WebPage,
    year=2010,
    url="http://en.wikipedia.org/wiki/Pareto_distribution"
)
public class ParetoDistribution 
    extends AbstractClosedFormSmoothUnivariateDistribution
{

    /**
     * Default shape, {@value}.
     */
    public static final double DEFAULT_SHAPE = 2.0;

    /**
     * Default scale, {@value}.
     */
    public static final double DEFALUT_SCALE = 1.0;

    /**
     * Default shift, {@value}.
     */
    public static final double DEFAULT_SHIFT = 0.0;

    /**
     * Scale parameter, must be greater than zero.
     */
    protected double shape;

    /**
     * Scale parameter, must be greater than zero.
     */
    protected double scale;

    /**
     * Amount to shift the distribution to the left.
     */
    protected double shift;

    /** 
     * Creates a new instance of ParetoDistribution 
     */
    public ParetoDistribution()
    {
        this( DEFAULT_SHAPE, DEFALUT_SCALE, DEFAULT_SHIFT );
    }

    /**
     * Creates a new instance of ParetoDistribution 
     * @param shape
     * Scale parameter, must be greater than zero.
     * @param scale
     * Scale parameter, must be greater than zero.
     * @param shift
     * Amount to shift the distribution to the left.
     */
    public ParetoDistribution(
        final double shape,
        final double scale,
        final double shift )
    {
        this.setShape(shape);
        this.setScale(scale);
        this.setShift(shift);
    }

    /**
     * Copy constructor
     * @param other
     * ParetoDistribution to copy
     */
    public ParetoDistribution(
        final ParetoDistribution other )
    {
        this( other.getShape(), other.getScale(), other.getShift() );
    }

    @Override
    public ParetoDistribution clone()
    {
        return (ParetoDistribution) super.clone();
    }

    /**
     * Getter for shape
     * @return
     * Shape parameter, must be greater than zero.
     */
    public double getShape()
    {
        return this.shape;
    }

    /**
     * Setter for shape
     * @param shape
     * Shape parameter, must be greater than zero.
     */
    public void setShape(
        final double shape)
    {
        if( shape <= 0.0 )
        {
            throw new IllegalArgumentException(
                "Shape must be > 0.0 " );
        }

        this.shape = shape;
    }

    /**
     * Getter for scale.
     * @return 
     * Scale parameter, must be greater than zero.
     */
    public double getScale()
    {
        return this.scale;
    }

    /**
     * Setter for scale
     * @param scale
     * Scale parameter, must be greater than zero.
     */
    public void setScale(
        final double scale)
    {
        if( scale <= 0.0 )
        {
            throw new IllegalArgumentException(
                "Scale must be > 0.0 " );
        }
        this.scale = scale;
    }

    @Override
    public double getMeanAsDouble()
    {
        if( this.shape > 1.0 )
        {
            return this.shape * this.scale / (this.shape-1.0) - this.shift;
        }
        else
        {
            throw new IllegalArgumentException(
                "Mean is undefined when shape is <= 1.0" );
        }
    }


    @Override
    public double getVariance()
    {
        if( this.shape > 2.0 )
        {
            final double numerator = this.scale*this.scale * this.shape;
            final double am1 = this.shape-1.0;
            final double am2 = this.shape-2.0;
            final double denominator = am1*am1*am2;
            return numerator / denominator;
        }
        else
        {
            throw new IllegalArgumentException(
                "Variance is undefined when shape is <= 2.0" );
        }
    }

    @Override
    public double sampleAsDouble(
        final Random random)
    {
        final double exp = 1.0 / this.shape;        
        final double u = random.nextDouble();
        return this.scale / Math.pow(u, exp) - this.shift;
    }
    
    @Override
    public void sampleInto(
        final Random random,
        final double[] output,
        final int start,
        final int length)
    {
        final double exp = 1.0 / this.shape;
        
        final int end = start + length;
        for (int i = start; i < end; i++)
        {
            final double u = random.nextDouble();
            output[i] = this.scale / Math.pow(u, exp) - this.shift;
        }
    }

    @Override
    public Vector convertToVector()
    {
        return VectorFactory.getDefault().copyValues(
            this.shape, this.scale, this.shift );
    }

    @Override
    public void convertFromVector(
        Vector parameters)
    {
        parameters.assertDimensionalityEquals(3);
        this.setShape( parameters.getElement(0) );
        this.setScale( parameters.getElement(1) );
        this.setShift( parameters.getElement(2) );
    }

    @Override
    public ParetoDistribution.PDF getProbabilityFunction()
    {
        return new ParetoDistribution.PDF( this );
    }

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

    @Override
    public Double getMinSupport()
    {
        return this.scale - this.shift;
    }

    @Override
    public Double getMaxSupport()
    {
        return Double.POSITIVE_INFINITY;
    }

    @Override
    public String toString()
    {
        return "Shape = " + this.getShape() + ", Scale = " + this.getScale() + ", Shift = " + this.getShift();
    }

    /**
     * Getter for shift.
     * @return
     * Amount to shift the distribution to the left.
     */
    double getShift()
    {
        return this.shift;
    }

    /**
     * Setter for shift.
     * @param shift
     * Amount to shift the distribution to the left.
     */
    public void setShift(
        final double shift)
    {
        this.shift = shift;
    }

    /**
     * CDF of the Pareto Distribution.
     */
    public static class CDF
        extends ParetoDistribution
        implements SmoothCumulativeDistributionFunction,
        InvertibleCumulativeDistributionFunction
    {

        /**
         * Creates a new instance of CDF
         */
        public CDF()
        {
            super();
        }

        /**
         * Creates a new instance of CDF
         * @param shape
         * Scale parameter, must be greater than zero.
         * @param scale
         * Scale parameter, must be greater than zero.
         * @param shift
         * Amount to shift the distribution to the left.
         */
        public CDF(
            final double shape,
            final double scale,
            final double shift )
        {
            super( shape, scale, shift );
        }

        /**
         * Copy constructor
         * @param other
         * ParetoDistribution to copy
         */
        public CDF(
            final ParetoDistribution other )
        {
            super( other );
        }

        @Override
        public Double evaluate(
            Double input)
        {
            return this.evaluate(input.doubleValue());
        }
        
        @Override
        public double evaluateAsDouble(
            final Double input)
        {
            return this.evaluate(input.doubleValue());
        }

        @Override
        public double evaluate(
            double input)
        {
            if( (input+this.shift) > this.scale )
            {
                return 1.0 - Math.pow( this.scale/(input+this.shift), this.shape);
            }
            else
            {
                return 0.0;
            }
        }

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

        @Override
        public ParetoDistribution.PDF getDerivative()
        {
            return this.getProbabilityFunction();
        }

        @Override
        public Double differentiate(
            final Double input)
        {
            return this.getDerivative().evaluate(input);
        }

        @Override
        public Double inverse(
            final double probability)
        {
            if( probability <= 0.0 )
            {
                return this.getMinSupport();
            }
            else if( probability >= 1.0 )
            {
                return this.getMaxSupport();
            }
            else
            {
                return this.scale / Math.pow(1.0-probability, 1.0/this.shape)-this.shift;
            }
        }

    }

    /**
     * PDF of the ParetoDistribution
     */
    public static class PDF
        extends ParetoDistribution
        implements UnivariateProbabilityDensityFunction
    {

        /**
         * Creates a new instance of PDF
         */
        public PDF()
        {
            super();
        }

        /**
         * Creates a new instance of PDF
         * @param shape
         * Scale parameter, must be greater than zero.
         * @param scale
         * Scale parameter, must be greater than zero.
         * @param shift
         * Amount to shift the distribution to the left.
         */
        public PDF(
            final double shape,
            final double scale,
            final double shift )
        {
            super( shape, scale, shift );
        }

        /**
         * Copy constructor
         * @param other
         * ParetoDistribution to copy
         */
        public PDF(
            final ParetoDistribution other )
        {
            super( other );
        }

        @Override
        public ParetoDistribution.PDF getProbabilityFunction()
        {
            return this;
        }

        @Override
        public double logEvaluate(
            final Double input)
        {
            return this.logEvaluate((double) input);
        }

        @Override
        public double logEvaluate(
            final double input)
        {
//            if( input > this.scale )
            if( (input+this.shift) > this.scale )
            {
                double numerator = Math.log(this.shape) + this.shape*Math.log(this.scale);
                double denominator = (this.shape+1.0)*Math.log(input+this.shift);
                return numerator - denominator;
            }
            else
            {
                return Math.log(0.0);
            }
        }

        @Override
        public Double evaluate(
            final Double input)
        {
            return this.evaluate(input.doubleValue());
        }
        
        @Override
        public double evaluateAsDouble(
            final Double input)
        {
            return this.evaluate(input.doubleValue());
        }

        @Override
        public double evaluate(
            final double input)
        {
            return Math.exp(this.logEvaluate(input));
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy