gov.sandia.cognition.statistics.distribution.MultivariateStudentTDistribution Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cognitive-foundry Show documentation
Show all versions of cognitive-foundry Show documentation
A single jar with all the Cognitive Foundry components.
/*
* File: MultivariateStudentTDistribution.java
* Authors: Kevin R. Dixon
* Company: Sandia National Laboratories
* Project: Cognitive Foundry
*
* Copyright Mar 29, 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.PublicationReferences;
import gov.sandia.cognition.annotation.PublicationType;
import gov.sandia.cognition.math.MathUtil;
import gov.sandia.cognition.math.matrix.Matrix;
import gov.sandia.cognition.math.matrix.MatrixFactory;
import gov.sandia.cognition.math.matrix.Vector;
import gov.sandia.cognition.math.matrix.VectorFactory;
import gov.sandia.cognition.math.matrix.VectorInputEvaluator;
import gov.sandia.cognition.statistics.AbstractDistribution;
import gov.sandia.cognition.statistics.ClosedFormComputableDistribution;
import gov.sandia.cognition.statistics.ProbabilityDensityFunction;
import gov.sandia.cognition.util.ObjectUtil;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Random;
/**
* Multivariate generalization of the noncentral Student's t-distribution.
* @author Kevin R. Dixon
* @since 3.0
*/
@PublicationReferences(
references={
@PublicationReference(
author="Christopher M. Bishop",
title="Pattern Recognition and Machine Learning",
type=PublicationType.Book,
year=2006,
pages={104,105}
)
,
@PublicationReference(
author="Wikipedia",
title="Multivariate Student distribution",
type=PublicationType.WebPage,
year=2010,
url="http://en.wikipedia.org/wiki/Multivariate_Student_distribution"
)
}
)
public class MultivariateStudentTDistribution
extends AbstractDistribution
implements ClosedFormComputableDistribution
{
/**
* Default dimensionality, {@value}.
*/
public static final int DEFAULT_DIMENSIONALITY = 2;
/**
* Default degrees of freedom, {@value}.
*/
public static final double DEFAULT_DEGREES_OF_FREEDOM = 3.0;
/**
* Degrees of freedom in the distribution, usually the number of
* datapoints - 1, DOFs must be greater than zero.
*/
protected double degreesOfFreedom;
/**
* Mean, or noncentrality parameter, of the distribution
*/
protected Vector mean;
/**
* Precision, which is proportionate to the inverse of variance, of the
* distribution, must be symmetric and positive definite.
*/
private Matrix precision;
/**
* Creates a new instance of MultivariateStudentTDistribution
*/
public MultivariateStudentTDistribution()
{
this( DEFAULT_DIMENSIONALITY );
}
/**
* Creates a distribution with the given dimensionality.
* @param dimensionality
* Dimensionality of the distribution.
*/
public MultivariateStudentTDistribution(
int dimensionality )
{
this( DEFAULT_DEGREES_OF_FREEDOM,
VectorFactory.getDefault().createVector(dimensionality),
MatrixFactory.getDefault().createIdentity(dimensionality,dimensionality) );
}
/**
* Creates a distribution with the given dimensionality.
* @param degreesOfFreedom
* Degrees of freedom in the distribution, usually the number of
* datapoints - 1, DOFs must be greater than zero.
* @param mean
* Mean, or noncentrality parameter, of the distribution
* @param precision
* Precision, which is proportionate to the inverse of variance, of the
* distribution, must be symmetric and positive definite.
*/
public MultivariateStudentTDistribution(
double degreesOfFreedom,
Vector mean,
Matrix precision)
{
this.degreesOfFreedom = degreesOfFreedom;
this.mean = mean;
this.precision = precision;
}
/**
* Copy constructor
* @param other
* MultivariateStudentTDistribution to copy
*/
public MultivariateStudentTDistribution(
MultivariateStudentTDistribution other )
{
this( other.getDegreesOfFreedom(),
ObjectUtil.cloneSafe( other.getMean() ),
ObjectUtil.cloneSafe( other.getPrecision() ) );
}
@Override
public MultivariateStudentTDistribution clone()
{
MultivariateStudentTDistribution clone =
(MultivariateStudentTDistribution) super.clone();
clone.setMean( ObjectUtil.cloneSafe(this.getMean() ) );
clone.setPrecision( ObjectUtil.cloneSafe( this.getPrecision() ) );
return clone;
}
/**
* Getter for degreesOfFreedom
* @return
* Degrees of freedom in the distribution, usually the number of
* datapoints - 1, DOFs must be greater than zero.
*/
public double getDegreesOfFreedom()
{
return this.degreesOfFreedom;
}
/**
* Setter for degreesOfFreedom
* @param degreesOfFreedom
* Degrees of freedom in the distribution, usually the number of
* datapoints - 1, DOFs must be greater than zero.
*/
public void setDegreesOfFreedom(
double degreesOfFreedom)
{
if( degreesOfFreedom <= 0.0 )
{
throw new IllegalArgumentException(
"DOFs must be > 0.0" );
}
this.degreesOfFreedom = degreesOfFreedom;
}
public Vector getMean()
{
return this.mean;
}
/**
* Setter for mean
* @param mean
* Mean, or noncentrality parameter, of the distribution
*/
public void setMean(
Vector mean)
{
this.mean = mean;
}
/**
* Getter for precision
* @return
* Precision, which is proportionate to the inverse of variance, of the
* distribution, must be symmetric and positive definite.
*/
public Matrix getPrecision()
{
return this.precision;
}
/**
* Setter for precision
* @param precision
* Precision, which is proportionate to the inverse of variance, of the
* distribution, must be symmetric and positive definite.
*/
public void setPrecision(
Matrix precision)
{
if( !precision.isSymmetric() )
{
throw new IllegalArgumentException(
"Precision must be symmetric and positive definite!" );
}
this.precision = precision;
}
/**
* Computes the covariance of the distribution, which involves inverting
* the precision matrix.
* @return
* covariance of the distribution, which involves inverting the
* precision matrix.
*/
public Matrix getCovariance()
{
final double scale = this.degreesOfFreedom / (this.degreesOfFreedom-2.0);
Matrix C = this.getPrecision().inverse();
C.scaleEquals(scale);
return C;
}
@Override
public void sampleInto(
final Random random,
final int sampleCount,
final Collection super Vector> output)
{
final int dim = this.getInputDimensionality();
Vector zeroMean = VectorFactory.getDefault().createVector(dim);
MultivariateGaussian mvg = new MultivariateGaussian(
zeroMean, this.precision.inverse() );
double[] Vs = ChiSquareDistribution.sampleAsDoubles(
this.degreesOfFreedom, random, sampleCount);
ArrayList Zs = mvg.sample(random, sampleCount);
for( int n = 0; n < sampleCount; n++ )
{
Vector z = Zs.get(n);
double v = Vs[n];
z.scaleEquals( Math.sqrt(this.degreesOfFreedom/v) );
z.plusEquals(this.mean);
output.add( z );
}
}
public Vector convertToVector()
{
Vector parameters = VectorFactory.getDefault().copyValues(
this.getDegreesOfFreedom() );
parameters = parameters.stack( this.getMean() );
parameters = parameters.stack( this.getPrecision().convertToVector() );
return parameters;
}
public void convertFromVector(
Vector parameters)
{
final int dim = this.getInputDimensionality();
parameters.assertDimensionalityEquals(1+dim+dim*dim);
this.setDegreesOfFreedom( parameters.getElement(0) );
this.setMean( parameters.subVector(1, dim) );
Matrix p = this.getPrecision();
p.convertFromVector( parameters.subVector(
dim+1, parameters.getDimensionality()-1) );
this.setPrecision(p);
}
/**
* Gets the dimensionality of the distribution.
* @return
* Dimensionality of the distribution.
*/
public int getInputDimensionality()
{
return this.getMean().getDimensionality();
}
public MultivariateStudentTDistribution.PDF getProbabilityFunction()
{
return new MultivariateStudentTDistribution.PDF( this );
}
/**
* PDF of the MultivariateStudentTDistribution
*/
public static class PDF
extends MultivariateStudentTDistribution
implements ProbabilityDensityFunction,
VectorInputEvaluator
{
/**
* Log determinant of the precision matrix.
*/
private Double logDeterminantPrecision;
/**
* Creates a new instance of MultivariateStudentTDistribution
*/
public PDF()
{
super();
}
/**
* Creates a distribution with the given dimensionality.
* @param dimensionality
* Dimensionality of the distribution.
*/
public PDF(
int dimensionality )
{
super( dimensionality );
}
/**
* Creates a distribution with the given dimensionality.
* @param degreesOfFreedom
* Degrees of freedom in the distribution, usually the number of
* datapoints - 1, DOFs must be greater than zero.
* @param mean
* Mean, or noncentrality parameter, of the distribution
* @param precision
* Precision, which is proportionate to the inverse of variance, of the
* distribution, must be symmetric and positive definite.
*/
public PDF(
double degreesOfFreedom,
Vector mean,
Matrix precision)
{
super( degreesOfFreedom, mean, precision );
}
/**
* Copy constructor
* @param other
* MultivariateStudentTDistribution to copy
*/
public PDF(
MultivariateStudentTDistribution other )
{
super( other );
}
@Override
public MultivariateStudentTDistribution.PDF getProbabilityFunction()
{
return this;
}
public double logEvaluate(
Vector input)
{
final int dim = this.getInputDimensionality();
final double logDet = this.getLogDeterminantPrecision();
final Vector delta = input.minus(this.mean);
final double z2 = delta.times(this.getPrecision()).dotProduct(delta);
final double d2pv2 = dim/2.0+this.degreesOfFreedom/2.0;
double logSum = 0.0;
logSum += MathUtil.logGammaFunction( d2pv2 );
logSum -= MathUtil.logGammaFunction( this.degreesOfFreedom/2.0 );
logSum += 0.5 * logDet;
logSum -= (dim/2.0)*Math.log(Math.PI*this.degreesOfFreedom);
logSum -= d2pv2*Math.log( 1.0 + z2/this.degreesOfFreedom );
return logSum;
}
public Double evaluate(
Vector input)
{
return Math.exp( this.logEvaluate(input) );
}
/**
* Getter for logDeterminantPrecision
* @return
* Log determinant of the precision matrix.
*/
public Double getLogDeterminantPrecision()
{
if( this.logDeterminantPrecision == null )
{
this.logDeterminantPrecision =
this.getPrecision().logDeterminant().getRealPart();
}
return this.logDeterminantPrecision;
}
@Override
public void setPrecision(
Matrix precision)
{
this.logDeterminantPrecision = null;
super.setPrecision(precision);
}
}
}