/*
* File: UnivariateGaussianTest.java
* Authors: Kevin R. Dixon
* Company: Sandia National Laboratories
* Project: Cognitive Foundry
*
* Copyright July 16, 2007, 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.math.UnivariateStatisticsUtil;
import gov.sandia.cognition.math.matrix.Vector;
import gov.sandia.cognition.statistics.SmoothUnivariateDistributionTestHarness;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
/**
*
* @author Kevin R. Dixon
*/
public class UnivariateGaussianTest
extends SmoothUnivariateDistributionTestHarness
{
/**
* Constructor
* @param testName Name
*/
public UnivariateGaussianTest(
String testName )
{
super( testName );
}
@Override
public UnivariateGaussian createInstance()
{
double mean = RANDOM.nextGaussian();
double variance = RANDOM.nextDouble();
return new UnivariateGaussian( mean, variance );
}
@Override
public void testDistributionGetVariance()
{
int temp = NUM_SAMPLES;
NUM_SAMPLES = 10000;
super.testDistributionGetVariance();
NUM_SAMPLES = temp;
}
/**
* Error function
*/
public void testErrorFunction()
{
System.out.println( "ErrorFunction.evaluate" );
double tol = 1e-6;
// These values were computed from octave's erf() function
assertEquals( 0.0, UnivariateGaussian.ErrorFunction.INSTANCE.evaluate( new Double(0.0) ), tol );
assertEquals( 1.128342e-2, UnivariateGaussian.ErrorFunction.INSTANCE.evaluate( 0.01 ), tol );
assertEquals( -1.128342e-2, UnivariateGaussian.ErrorFunction.INSTANCE.evaluate( -0.01 ), tol );
assertEquals( 1.124629e-1, UnivariateGaussian.ErrorFunction.INSTANCE.evaluate( 0.1 ), tol );
assertEquals( 2.227026e-1, UnivariateGaussian.ErrorFunction.INSTANCE.evaluate( 0.2 ), tol );
assertEquals( 8.427008e-1, UnivariateGaussian.ErrorFunction.INSTANCE.evaluate( 1.0 ), tol );
assertEquals( -8.427008e-1, UnivariateGaussian.ErrorFunction.INSTANCE.evaluate( -1.0 ), tol );
assertEquals( 9.999779e-1, UnivariateGaussian.ErrorFunction.INSTANCE.evaluate( 3.0 ), tol );
assertEquals( 1.0, UnivariateGaussian.ErrorFunction.INSTANCE.evaluate( 3.9 ), tol );
assertEquals( -1.0, UnivariateGaussian.ErrorFunction.INSTANCE.evaluate( -3.9 ), tol );
}
/**
* ErrorFunction.Inverse.evaluate
*/
public void testErrorFunctionInverse()
{
System.out.println( "ErrorFunction.Inverse.evaluate" );
// These values were computes from octave's erfinv() function
assertEquals( 0.0, UnivariateGaussian.ErrorFunction.Inverse.INSTANCE.evaluate( new Double(0.0) ), TOLERANCE );
assertEquals( 0.0888559905, UnivariateGaussian.ErrorFunction.Inverse.INSTANCE.evaluate( 0.1 ), TOLERANCE );
assertEquals( 0.0888559905, UnivariateGaussian.ErrorFunction.Inverse.INSTANCE.evaluate( 0.1 ), TOLERANCE );
assertEquals( -0.0888559905, UnivariateGaussian.ErrorFunction.Inverse.INSTANCE.evaluate( -0.1 ), TOLERANCE );
assertEquals( 0.1791434546, UnivariateGaussian.ErrorFunction.Inverse.INSTANCE.evaluate( 0.2 ), TOLERANCE );
assertEquals( -0.1791434546, UnivariateGaussian.ErrorFunction.Inverse.INSTANCE.evaluate( -0.2 ), TOLERANCE );
assertEquals( 0.2724627147, UnivariateGaussian.ErrorFunction.Inverse.INSTANCE.evaluate( 0.3 ), TOLERANCE );
assertEquals( 0.4769362762, UnivariateGaussian.ErrorFunction.Inverse.INSTANCE.evaluate( 0.5 ), TOLERANCE );
assertEquals( 0.7328690780, UnivariateGaussian.ErrorFunction.Inverse.INSTANCE.evaluate( 0.7 ), TOLERANCE );
assertEquals( -0.7328690780, UnivariateGaussian.ErrorFunction.Inverse.INSTANCE.evaluate( -0.7 ), TOLERANCE );
assertEquals( -1.1630871537, UnivariateGaussian.ErrorFunction.Inverse.INSTANCE.evaluate( -0.9 ), TOLERANCE );
assertEquals( 1.1630871537, UnivariateGaussian.ErrorFunction.Inverse.INSTANCE.evaluate( 0.9 ), TOLERANCE );
assertEquals( 2.3267537655, UnivariateGaussian.ErrorFunction.Inverse.INSTANCE.evaluate( 0.999 ), TOLERANCE );
assertEquals( -2.3267537655, UnivariateGaussian.ErrorFunction.Inverse.INSTANCE.evaluate( -0.999 ), TOLERANCE );
assertEquals( 3.1234132743, UnivariateGaussian.ErrorFunction.Inverse.INSTANCE.evaluate( 0.99999 ), TOLERANCE );
assertEquals( -3.1234132743, UnivariateGaussian.ErrorFunction.Inverse.INSTANCE.evaluate( -0.99999 ), TOLERANCE );
assertEquals( Double.POSITIVE_INFINITY, UnivariateGaussian.ErrorFunction.Inverse.INSTANCE.evaluate( 1.0 ), TOLERANCE );
assertEquals( Double.POSITIVE_INFINITY, UnivariateGaussian.ErrorFunction.Inverse.INSTANCE.evaluate( 10.0 ), TOLERANCE );
assertEquals( Double.NEGATIVE_INFINITY, UnivariateGaussian.ErrorFunction.Inverse.INSTANCE.evaluate( -1.0 ), TOLERANCE );
assertEquals( Double.NEGATIVE_INFINITY, UnivariateGaussian.ErrorFunction.Inverse.INSTANCE.evaluate( -10.0 ), TOLERANCE );
for (int i = 0; i < 100; i++)
{
double y = RANDOM.nextDouble() * 2 - 1;
double x = UnivariateGaussian.ErrorFunction.Inverse.INSTANCE.evaluate( y );
double yhat = UnivariateGaussian.ErrorFunction.INSTANCE.evaluate( x );
assertEquals( y, yhat, TOLERANCE );
}
}
/**
* CDF.Inverse
*/
public void testCDFInverse()
{
System.out.println( "CDF.Inverse" );
UnivariateGaussian instance = this.createInstance();
UnivariateGaussian.CDF.Inverse cdfi =
new UnivariateGaussian.CDF.Inverse( instance );
assertNotSame( instance, cdfi );
assertEquals( instance.convertToVector(), cdfi.convertToVector() );
UnivariateGaussian clone = cdfi.clone();
assertNotNull( clone );
assertNotSame( cdfi, clone );
assertEquals( cdfi.convertToVector(), clone.convertToVector() );
UnivariateGaussian.CDF cdf = new UnivariateGaussian.CDF( cdfi );
assertNotNull( cdf );
assertNotSame( cdfi, cdf );
assertEquals( cdfi.convertToVector(), cdf.convertToVector() );
double p = RANDOM.nextDouble();
double x = cdfi.evaluate(p);
double phat = cdf.evaluate(x);
assertEquals( p, phat, TOLERANCE );
assertEquals( Double.NEGATIVE_INFINITY, cdfi.evaluate(0.0) );
assertEquals( Double.POSITIVE_INFINITY, cdfi.evaluate(1.0) );
assertEquals( Double.NEGATIVE_INFINITY, cdfi.evaluate(-1.0) );
assertEquals( Double.POSITIVE_INFINITY, cdfi.evaluate(2.0) );
}
/**
* Test of getMean method, of class gov.sandia.cognition.learning.util.statistics.UnivariateGaussian.
*/
public void testGetMean()
{
System.out.println( "getMean" );
double mean = RANDOM.nextGaussian();
double variance = RANDOM.nextDouble();
UnivariateGaussian.CDF instance = new UnivariateGaussian.CDF( mean, variance );
assertEquals( mean, instance.getMean() );
}
/**
* Test of setMean method, of class gov.sandia.cognition.learning.util.statistics.UnivariateGaussian.
*/
public void testSetMean()
{
System.out.println( "setMean" );
double mean = RANDOM.nextGaussian();
double variance = RANDOM.nextDouble();
UnivariateGaussian.PDF instance = new UnivariateGaussian.PDF( mean, variance );
assertEquals( mean, instance.getMean() );
double m2 = mean + RANDOM.nextGaussian();
instance.setMean( m2 );
assertEquals( m2, instance.getMean() );
}
/**
* Test of getVariance method, of class gov.sandia.cognition.learning.util.statistics.UnivariateGaussian.
*/
public void testGetVariance()
{
System.out.println( "getVariance" );
double mean = RANDOM.nextGaussian();
double variance = RANDOM.nextDouble();
UnivariateGaussian instance = new UnivariateGaussian( mean, variance );
assertEquals( variance, instance.getVariance() );
}
/**
* Test of setVariance method, of class gov.sandia.cognition.learning.util.statistics.UnivariateGaussian.
*/
public void testSetVariance()
{
System.out.println( "setVariance" );
double mean = RANDOM.nextGaussian();
double variance = RANDOM.nextDouble();
UnivariateGaussian.PDF instance = new UnivariateGaussian.PDF( mean, variance );
assertEquals( variance, instance.getVariance() );
double v2 = variance + RANDOM.nextDouble();
instance.setVariance( v2 );
assertEquals( v2, instance.getVariance() );
try
{
instance.setVariance( 0.0 );
fail( "Variance must be > 0.0" );
}
catch (Exception e)
{
System.out.println( "Good: " + e );
}
try
{
instance.setVariance( -RANDOM.nextDouble() );
fail( "Variance must be > 0.0" );
}
catch (Exception e)
{
System.out.println( "Good: " + e );
}
}
@Override
public void testKnownConvertToVector()
{
System.out.println( "CDF.convertToVector" );
UnivariateGaussian instance = this.createInstance();
Vector v = instance.convertToVector();
assertEquals( 2, v.getDimensionality() );
assertEquals( instance.getMean(), v.getElement( 0 ) );
assertEquals( instance.getVariance(), v.getElement( 1 ) );
}
@Override
public void testPDFKnownValues()
{
System.out.println( "PDF.known values" );
for (int i = 0; i < NUM_SAMPLES; i++)
{
UnivariateGaussian.PDF pdf = this.createInstance().getProbabilityFunction();
double mean = pdf.getMean();
double variance = pdf.getVariance();
double x = RANDOM.nextGaussian();
double p = pdf.evaluate( x );
Double P = pdf.evaluate( new Double( x ) );
assertEquals( p, P.doubleValue() );
double delta = x - mean;
double top = Math.exp( (delta * delta) / (-2.0 * variance) );
double bottom = Math.sqrt( 2.0 * Math.PI * variance );
double phat = top / bottom;
assertEquals( p, phat, TOLERANCE );
}
}
@Override
public void testCDFKnownValues()
{
UnivariateGaussian.CDF cdf = this.createInstance().getCDF();
double m1 = cdf.getMean();
assertEquals( 0.5, cdf.evaluate( m1 ), TOLERANCE );
assertEquals( 0.0, UnivariateGaussian.CDF.evaluate( Double.NEGATIVE_INFINITY, 0, 1 ), TOLERANCE );
assertEquals( 1.0, UnivariateGaussian.CDF.evaluate( Double.POSITIVE_INFINITY, 0, 1 ), TOLERANCE );
for (int i = 0; i < 100; i++)
{
double x = RANDOM.nextDouble() * 10 - 5;
double expected = 0.5 * (1.0 + UnivariateGaussian.ErrorFunction.INSTANCE.evaluate( x / Math.sqrt( 2 ) ));
assertEquals( expected, UnivariateGaussian.CDF.evaluate( x, 0, 1 ), TOLERANCE );
}
}
/**
* Learner
*/
public void testLearner()
{
System.out.println( "Learner" );
UnivariateGaussian.MaximumLikelihoodEstimator learner =
new UnivariateGaussian.MaximumLikelihoodEstimator();
this.distributionEstimatorTest(learner);
}
/**
* Weighted learner
*/
public void testWeightedLearner()
{
System.out.println( "Weighted Learner" );
UnivariateGaussian.WeightedMaximumLikelihoodEstimator learner =
new UnivariateGaussian.WeightedMaximumLikelihoodEstimator();
this.weightedDistributionEstimatorTest(learner);
}
@Override
public void testPDFConstructors()
{
System.out.println( "PDF Constructor" );
UnivariateGaussian.PDF g = new UnivariateGaussian.PDF();
assertEquals( UnivariateGaussian.DEFAULT_MEAN, g.getMean() );
assertEquals( UnivariateGaussian.DEFAULT_VARIANCE, g.getVariance() );
double mean = RANDOM.nextGaussian();
double variance = Math.abs(RANDOM.nextGaussian());
g = new UnivariateGaussian.PDF( mean, variance );
UnivariateGaussian.PDF g2 = new UnivariateGaussian.PDF( g );
assertEquals( g.getMean(), g2.getMean() );
assertEquals( g.getVariance(), g2.getVariance() );
}
@Override
public void testDistributionConstructors()
{
System.out.println( "Constructor" );
UnivariateGaussian g = new UnivariateGaussian();
assertEquals( UnivariateGaussian.DEFAULT_MEAN, g.getMean() );
assertEquals( UnivariateGaussian.DEFAULT_VARIANCE, g.getVariance() );
double mean = RANDOM.nextGaussian();
double variance = Math.abs(RANDOM.nextGaussian());
g = new UnivariateGaussian( mean, variance );
UnivariateGaussian g2 = new UnivariateGaussian( g );
assertEquals( g.getMean(), g2.getMean() );
assertEquals( g.getVariance(), g2.getVariance() );
}
@Override
public void testCDFConstructors()
{
System.out.println( "CDF Constructor" );
UnivariateGaussian.CDF g = new UnivariateGaussian.CDF();
assertEquals( UnivariateGaussian.DEFAULT_MEAN, g.getMean() );
assertEquals( UnivariateGaussian.DEFAULT_VARIANCE, g.getVariance() );
double mean = RANDOM.nextGaussian();
double variance = Math.abs(RANDOM.nextGaussian());
g = new UnivariateGaussian.CDF( mean, variance );
UnivariateGaussian.CDF g2 = new UnivariateGaussian.CDF( g );
assertEquals( g.getMean(), g2.getMean() );
assertEquals( g.getVariance(), g2.getVariance() );
}
/**
* times
*/
public void testTimes()
{
System.out.println( "times" );
UnivariateGaussian g1 = this.createInstance();
UnivariateGaussian g2 = this.createInstance();
UnivariateGaussian result = g1.times( g2 );
System.out.println( "G1: " + g1 );
System.out.println( "G2: " + g2 );
System.out.println( "Result: " + result );
double vhat = 1.0 / (1.0/g1.getVariance() + 1.0/g2.getVariance());
double meanHat = (vhat/g1.getVariance())*g1.getMean() + (vhat/g2.getVariance())*g2.getMean();
assertEquals( meanHat, result.getMean(), TOLERANCE );
assertEquals( vhat, result.getVariance(), TOLERANCE );
}
/**
* convolve
*/
public void testConvolve()
{
System.out.println( "convolve" );
UnivariateGaussian g1 = this.createInstance();
UnivariateGaussian g2 = this.createInstance();
UnivariateGaussian result = g1.convolve( g2 );
System.out.println( "G1: " + g1 );
System.out.println( "G2: " + g2 );
System.out.println( "Result: " + result );
double vhat = g1.getVariance() + g2.getVariance();
double meanHat = g1.getMean() + g2.getMean();
assertEquals( meanHat, result.getMean(), TOLERANCE );
assertEquals( vhat, result.getVariance(), TOLERANCE );
}
/**
* tests the incremental estimator
*/
public void testIncrementalEstimator()
{
System.out.println( "Incremental Estimator" );
UnivariateGaussian.IncrementalEstimator estimator =
new UnivariateGaussian.IncrementalEstimator();
UnivariateGaussian target = new UnivariateGaussian(
RANDOM.nextGaussian(), RANDOM.nextDouble() );
ArrayList<Double> samples = target.sample(RANDOM,NUM_SAMPLES);
double mean = UnivariateStatisticsUtil.computeMean(samples);
UnivariateGaussian.SufficientStatistic ss = estimator.learn(samples);
assertEquals( samples.size(), ss.getCount() );
assertEquals( mean, ss.getMean(), TOLERANCE );
assertEquals( UnivariateStatisticsUtil.computeVariance(samples, mean), ss.getVariance(), TOLERANCE );
UnivariateGaussian result = ss.create();
UnivariateGaussian batch =
UnivariateGaussian.MaximumLikelihoodEstimator.learn(samples, 0.0);
System.out.println( "Target: " + target );
System.out.println( "Result: " + result );
System.out.println( "Batch : " + batch );
assertEquals( batch.getMean(), result.getMean(), TOLERANCE );
assertEquals( batch.getVariance(), result.getVariance(), TOLERANCE );
UnivariateGaussian.SufficientStatistic clone = ss.clone();
assertEquals( ss.getCount(), clone.getCount() );
assertEquals( ss.getMean(), clone.getMean() );
assertEquals( ss.getVariance(), clone.getVariance() );
// This example is from the Wikipedia page: http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
// First demonstrate that for these simple values the mean is 10 and variance is 30.
double epsilon = 1E-10;
estimator.setDefaultVariance(epsilon);
Collection<Double> xd = Arrays.asList(4.0, 7.0, 13.0, 16.0);
ss = estimator.createInitialLearnedObject();
ss = estimator.learn(xd);
result = ss.create();
assertEquals(10.0, result.getMean(), epsilon);
assertEquals(30.0, result.getVariance(), epsilon);
// Now shift the mean by adding 10^9 and check that the variance remains
// 30.
xd = Arrays.asList(1.0e9 + 4.0, 1e9 + 7, 1e9 + 13, 1e9 + 16);
ss = estimator.createInitialLearnedObject();
ss = estimator.learn(xd);
result = ss.create();
assertEquals(1e9 + 10.0, result.getMean(), epsilon);
assertEquals(30.0, result.getVariance(), epsilon);
}
/**
* Tests adding together sufficient statistics
*/
public void testSufficientStatisticsPlus()
{
// This example is from the Wikipedia page: http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
// First demonstrate that for these simple values the mean is 10 and variance is 30.
double epsilon = 1E-10;
List<Double> xd = Arrays.asList(4.0, 7.0, 13.0, 16.0);
UnivariateGaussian.SufficientStatistic instance =
new UnivariateGaussian.SufficientStatistic();
int count = 1;
int i = 0;
while (i < xd.size())
{
UnivariateGaussian.SufficientStatistic other =
new UnivariateGaussian.SufficientStatistic();
for (int j = 0; j < count && i < xd.size(); j++)
{
other.update(xd.get(i));
i++;
}
instance.plusEquals(other);
count++;
}
assertEquals(10.0, instance.getMean(), epsilon);
assertEquals(30.0, instance.getVariance(), epsilon);
// Now shift the mean by adding 10^9 and check that the variance remains
// 30.
xd = Arrays.asList(1.0e9 + 4.0, 1e9 + 7, 1e9 + 13, 1e9 + 16);
instance.clear();
count = 1;
i = 0;
while (i < xd.size())
{
UnivariateGaussian.SufficientStatistic other =
new UnivariateGaussian.SufficientStatistic();
for (int j = 0; j < count && i < xd.size(); j++)
{
other.update(xd.get(i));
i++;
}
instance.plusEquals(other);
count++;
}
assertEquals(count, instance.getCount());
assertEquals(1e9 + 10.0, instance.getMean(), epsilon);
assertEquals(30.0, instance.getVariance(), epsilon);
assertEquals(22.5, instance.getSampleVariance(), epsilon);
UnivariateGaussian target = new UnivariateGaussian(
RANDOM.nextGaussian(), RANDOM.nextDouble() );
ArrayList<Double> samples = target.sample(RANDOM,NUM_SAMPLES);
instance.clear();
count = 1;
i = 0;
while (i < samples.size())
{
UnivariateGaussian.SufficientStatistic other =
new UnivariateGaussian.SufficientStatistic();
for (int j = 0; j < count && i < samples.size(); j++)
{
other.update(samples.get(i));
i++;
}
instance.plusEquals(other);
count++;
}
double mean = UnivariateStatisticsUtil.computeMean(samples);
double variance = UnivariateStatisticsUtil.computeVariance(samples, mean);
double sampleVariance = variance * (i - 1) / i;
assertEquals(i, instance.getCount());
assertEquals(mean, instance.getMean(), epsilon);
assertEquals(variance, instance.getVariance(), epsilon);
assertEquals(sampleVariance, instance.getSampleVariance(), epsilon);
}
public void testSufficientStatisticsRemove()
{
// This example is from the Wikipedia page: http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
// First demonstrate that for these simple values the mean is 10 and variance is 30.
double epsilon = 1E-10;
List<Double> xd = Arrays.asList(4.0, 7.0, 13.0, 16.0);
for (int i = 0; i < xd.size(); i++)
{
UnivariateGaussian.SufficientStatistic instance =
new UnivariateGaussian.SufficientStatistic();
instance.update(xd);
assertEquals(10.0, instance.getMean(), epsilon);
assertEquals(30.0, instance.getVariance(), epsilon);
instance.remove(xd.get(i));
List<Double> samples = new LinkedList<Double>(xd);
samples.remove(i);
double mean = UnivariateStatisticsUtil.computeMean(samples);
double variance = UnivariateStatisticsUtil.computeVariance(samples, mean);
assertEquals(mean, instance.getMean(), epsilon);
assertEquals(variance, instance.getVariance(), epsilon);
instance.update(xd.get(i));
for (double value : xd)
{
instance.remove(value);
}
assertEquals(0, instance.getCount());
assertEquals(0.0, instance.getMean(), epsilon);
assertEquals(0.0, instance.getVariance(), epsilon);
assertEquals(0.0, instance.getSampleVariance(), epsilon);
}
// Now shift the mean by adding 10^9 and check that the variance remains
// 30.
xd = Arrays.asList(1.0e9 + 4.0, 1e9 + 7, 1e9 + 13, 1e9 + 16);
for (int i = 0; i < xd.size(); i++)
{
UnivariateGaussian.SufficientStatistic instance =
new UnivariateGaussian.SufficientStatistic();
instance.update(xd);
assertEquals(1e9 + 10.0, instance.getMean(), epsilon);
assertEquals(30.0, instance.getVariance(), epsilon);
assertEquals(22.5, instance.getSampleVariance(), epsilon);
instance.remove(xd.get(i));
List<Double> samples = new LinkedList<Double>(xd);
samples.remove(i);
int count = xd.size() - 1;
double mean = UnivariateStatisticsUtil.computeMean(samples);
double variance = UnivariateStatisticsUtil.computeVariance(samples, mean);
double sampleVariance = variance * (count - 1) / count;
assertEquals(count, instance.getCount());
assertEquals(mean, instance.getMean(), epsilon);
assertEquals(variance, instance.getVariance(), epsilon);
assertEquals(sampleVariance, instance.getSampleVariance(), epsilon);
}
}
}