/*
* File: MultinomialDistributionTest.java
* Authors: Kevin R. Dixon
* Company: Sandia National Laboratories
* Project: Cognitive Foundry
*
* Copyright Dec 16, 2009, 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.matrix.Vector;
import gov.sandia.cognition.math.matrix.VectorFactory;
import gov.sandia.cognition.statistics.MultivariateClosedFormComputableDiscreteDistributionTestHarness;
import gov.sandia.cognition.statistics.ProbabilityMassFunction;
import gov.sandia.cognition.statistics.method.ChiSquareConfidence;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* Unit tests for MultinomialDistributionTest.
*
* @author krdixon
*/
public class MultinomialDistributionTest
extends MultivariateClosedFormComputableDiscreteDistributionTestHarness<Vector>
{
/**
* Default confidence test, {@value}.
*/
public double CONFIDENCE = 0.95;
/**
* Tests for class DirichletDistributionTest.
* @param testName Name of the test.
*/
public MultinomialDistributionTest(
String testName)
{
super(testName);
}
@Override
public MultinomialDistribution createInstance()
{
int numClasses = 3;
Vector parameters = VectorFactory.getDefault().createVector(numClasses);
for( int i = 0; i < numClasses; i++ )
{
parameters.setElement(i, i+1.0);
}
int numTrials = 6;
return new MultinomialDistribution( parameters, numTrials );
}
@Override
public void testConstructors()
{
System.out.println( "constructors" );
MultinomialDistribution instance = new MultinomialDistribution();
assertEquals( MultinomialDistribution.DEFAULT_NUM_TRIALS, instance.getNumTrials() );
assertEquals( MultinomialDistribution.DEFAULT_NUM_CLASSES, instance.getParameters().getDimensionality() );
for( int i = 0; i < MultinomialDistribution.DEFAULT_NUM_CLASSES; i++ )
{
assertEquals( 1.0, instance.getParameters().getElement(i) );
}
int nt = RANDOM.nextInt( 10 ) + 2;
int nc = RANDOM.nextInt( 100 ) + nt + 1;
instance = new MultinomialDistribution( nc, nt );
assertEquals( nt, instance.getNumTrials() );
assertEquals( nc, instance.getParameters().getDimensionality() );
for( int i = 0; i < nc; i++ )
{
assertEquals( 1.0, instance.getParameters().getElement(i) );
}
Vector parameters = VectorFactory.getDefault().copyValues( 1.0, 2.0, 3.0 );
instance = new MultinomialDistribution( parameters, nt );
assertSame( parameters, instance.getParameters() );
assertEquals( nt, instance.getNumTrials() );
}
/**
* PMF constructors
*/
public void testProbabilityFunctionConstructors()
{
System.out.println( "constructors.PMF" );
MultinomialDistribution.PMF instance = new MultinomialDistribution.PMF();
assertEquals( MultinomialDistribution.DEFAULT_NUM_TRIALS, instance.getNumTrials() );
assertEquals( MultinomialDistribution.DEFAULT_NUM_CLASSES, instance.getParameters().getDimensionality() );
for( int i = 0; i < MultinomialDistribution.DEFAULT_NUM_CLASSES; i++ )
{
assertEquals( 1.0, instance.getParameters().getElement(i) );
}
int nt = RANDOM.nextInt( 10 ) + 2;
int nc = RANDOM.nextInt( 100 ) + nt + 1;
instance = new MultinomialDistribution.PMF( nc, nt );
assertEquals( nt, instance.getNumTrials() );
assertEquals( nc, instance.getParameters().getDimensionality() );
for( int i = 0; i < nc; i++ )
{
assertEquals( 1.0, instance.getParameters().getElement(i) );
}
Vector parameters = VectorFactory.getDefault().copyValues( 1.0, 2.0, 3.0 );
instance = new MultinomialDistribution.PMF( parameters, nt );
assertSame( parameters, instance.getParameters() );
assertEquals( nt, instance.getNumTrials() );
}
@Override
public void testKnownValues()
{
System.out.println( "Known values" );
MultinomialDistribution instance = this.createInstance();
// Make sure that the samples are from the domain.
Collection<Vector> data = instance.sample( RANDOM,NUM_SAMPLES );
MultinomialDistribution.Domain domain = instance.getDomain();
for( Vector x : data )
{
assertTrue( domain.contains(x) );
}
}
@Override
public void testGetMean()
{
double temp = TOLERANCE;
TOLERANCE = 1e-1;
super.testGetMean();
TOLERANCE = temp;
}
/**
* Test of getParameters method, of class MultinomialDistribution.
*/
public void testGetParameters()
{
System.out.println("getParameters");
MultinomialDistribution instance = this.createInstance();
Vector parameters = instance.getParameters();
assertNotNull( parameters );
}
/**
* Test of setParameters method, of class MultinomialDistribution.
*/
public void testSetParameters()
{
System.out.println("setParameters");
MultinomialDistribution instance = this.createInstance();
Vector parameters = instance.getParameters();
assertNotNull( parameters );
Vector p2 = parameters.scale( RANDOM.nextDouble() );
instance.setParameters(p2);
assertSame( p2, instance.getParameters() );
Vector p3 = p2.clone();
p3.setElement(0, 0.0);
instance.setParameters(p3);
Vector p4 = p3.clone();
p4.setElement(0, -1.0);
try
{
instance.setParameters(p4);
fail( "Each element must be > 0.0" );
}
catch (Exception e)
{
System.out.println( "Good: " + e );
}
try
{
instance.setParameters(null);
fail( "Cannot be null" );
}
catch (Exception e)
{
System.out.println( "Good: " + e );
}
}
/**
* Test of getNumTrials method, of class MultinomialDistribution.
*/
public void testGetNumTrials()
{
System.out.println("getNumTrials");
MultinomialDistribution instance = this.createInstance();
assertTrue( instance.getNumTrials() > 0 );
}
/**
* Test of setNumTrials method, of class MultinomialDistribution.
*/
public void testSetNumTrials()
{
System.out.println("setNumTrials");
MultinomialDistribution instance = this.createInstance();
assertTrue( instance.getNumTrials() > 0 );
int numTrials = RANDOM.nextInt(10) + 10;
instance.setNumTrials(numTrials);
assertEquals( numTrials, instance.getNumTrials() );
try
{
instance.setNumTrials(0);
fail( "numTrials must be > 0" );
}
catch (Exception e)
{
System.out.println( "Good: " + e );
}
}
/**
* Test of getDomain method, of class MultinomialDistribution.
*/
public void testKnownGetDomain()
{
System.out.println("getDomain");
MultinomialDistribution instance = this.createInstance();
int count = 0;
MultinomialDistribution.Domain domain = instance.getDomain();
System.out.println( "Enumerating all subsets: " + domain.size() );
for( Vector subset : domain )
{
System.out.println( "Subset: " + subset );
count++;
}
assertEquals( count, domain.size() );
Iterator<Vector> iterator = domain.iterator();
try
{
iterator.remove();
fail( "Cannot remove" );
}
catch (Exception e)
{
System.out.println( "Good: " + e );
}
try
{
iterator = new MultinomialDistribution.Domain( 0, 10 ).iterator();
fail( "numClasses must be > 0" );
}
catch (Exception e)
{
System.out.println( "Good: " + e );
}
try
{
iterator = new MultinomialDistribution.Domain( 3, -1 ).iterator();
fail( "numTrials must be >= 0" );
}
catch (Exception e)
{
System.out.println( "Good: " + e );
}
}
/**
* PMF known values
*/
public void testProbabilityFunctionKnownValues()
{
System.out.println( "PMF known values" );
// http://en.wikipedia.org/wiki/Multinomial_distribution#Example
Vector parameters = VectorFactory.getDefault().copyValues( 0.2, 0.3, 0.5 );
MultinomialDistribution.PMF pmf = new MultinomialDistribution.PMF(
parameters, 6 );
Vector x = VectorFactory.getDefault().copyValues( 1.0, 2.0, 3.0 );
assertEquals( 0.135, pmf.evaluate(x), TOLERANCE );
Vector p = VectorFactory.getDefault().copyValues( 0.5, 0.5, 1.0 );
int numTrials = 3;
pmf = new MultinomialDistribution.PMF( p, numTrials );
Vector xbad1 = VectorFactory.getDefault().copyValues( 1.0, 0.0, 1.0 );
try
{
pmf.evaluate(xbad1);
fail( "x doesn't add up to numTrials" );
}
catch (Exception e)
{
System.out.println( "Good: " + e );
}
Vector xbad2 = VectorFactory.getDefault().copyValues( 1.5, 0.5, 1.0 );
try
{
pmf.evaluate(xbad2);
fail( "int(x) doesn't add up to numTrials" );
}
catch (Exception e)
{
System.out.println( "Good: " + e );
}
p.setElement(0,0.0);
pmf.setParameters(p);
Vector xok1 = VectorFactory.getDefault().copyValues( 1.0, 0.0, 2.0 );
assertEquals( 0.0, pmf.evaluate(xok1) );
Vector xok2 = VectorFactory.getDefault().copyValues( 0.0, 1.0, 2.0 );
assertEquals( 4.0/9.0, pmf.evaluate(xok2), TOLERANCE );
}
/**
* PMF properties
*/
public void testPMFProperties()
{
System.out.println( "PMF properties" );
MultinomialDistribution.PMF pmf =
new MultinomialDistribution.PMF( this.createInstance() );
double sum = 0.0;
for( Vector x : pmf.getDomain() )
{
double p = pmf.evaluate(x);
assertTrue( 0.0 <= p );
assertTrue( p <= 1.0 );
sum += p;
}
assertEquals( 1.0, sum, TOLERANCE );
}
/**
* PMF.sample
*/
public void testPMFSample()
{
System.out.println( "PMF.sample" );
MultinomialDistribution.PMF pmf =
new MultinomialDistribution.PMF( this.createInstance() );
// Make sure that the samples are from the domain.
Collection<Vector> data = pmf.sample( RANDOM,NUM_SAMPLES );
ChiSquareConfidence.Statistic chiSquare =
ChiSquareConfidence.evaluateNullHypothesis(data, pmf);
System.out.println( "Chi Square: " + chiSquare );
assertEquals( 1.0, chiSquare.getNullHypothesisProbability(), CONFIDENCE );
}
/**
* logEvaluate
*/
public void testLogEvaluate()
{
System.out.println( "logEvaluate" );
ProbabilityMassFunction<Vector> pmf =
this.createInstance().getProbabilityFunction();
ArrayList<? extends Vector> samples = pmf.sample(RANDOM, NUM_SAMPLES);
for( Vector sample : samples )
{
double plog = pmf.logEvaluate(sample);
double p = pmf.evaluate(sample);
double phat = Math.exp(plog);
assertEquals( p, phat, TOLERANCE );
}
}
@Override
public void testKnownConvertToVector()
{
System.out.println( "Known convertToVector" );
MultinomialDistribution instance = this.createInstance();
Vector p = instance.convertToVector();
assertEquals( instance.getParameters(), p );
assertNotSame( instance.getParameters(), p );
}
}