/* * File: RecursiveBayesianEstimatorTestHarness.java * Authors: Kevin R. Dixon * Company: Sandia National Laboratories * Project: Cognitive Foundry * * Copyright Apr 13, 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.bayesian; import gov.sandia.cognition.math.Ring; import gov.sandia.cognition.statistics.ClosedFormDistribution; import gov.sandia.cognition.statistics.Distribution; import gov.sandia.cognition.statistics.DistributionWithMean; import java.util.Collection; import java.util.Iterator; import junit.framework.TestCase; import java.util.Random; /** * Unit tests for RecursiveBayesianEstimatorTestHarness. * * @param <ObservationType> * @param <ParameterType> * @param <BeliefType> * @author krdixon */ public abstract class RecursiveBayesianEstimatorTestHarness<ObservationType,ParameterType,BeliefType extends Distribution<ParameterType>> extends TestCase { /** * Random number generator to use for a fixed random seed. */ public Random RANDOM = new Random( 1 ); /** * Default tolerance of the regression tests, {@value}. */ public double TOLERANCE = 1e-5; /** * Default number of samples to draw, {@value}. */ public int NUM_SAMPLES = 100; /** * Tests for class RecursiveBayesianEstimatorTestHarness. * @param testName Name of the test. */ public RecursiveBayesianEstimatorTestHarness( String testName) { super(testName); } /** * Creates a new instance * @return * new instance. */ public abstract RecursiveBayesianEstimator<ObservationType,ParameterType,BeliefType> createInstance(); /** * Creates the estimated type * @return * estimate type distribution */ public abstract ClosedFormDistribution<ObservationType> createConditionalDistribution(); /** * Creates data sampled from the conditional distribution. * @param conditional Conditional to sample from. * @return * Sampled data. */ public Collection<? extends ObservationType> createData( Distribution<ObservationType> conditional ) { return conditional.sample(RANDOM, NUM_SAMPLES); } /** * * @param <DataType> * @param d1 * @param d2 * @return */ public <DataType> boolean identical( DistributionWithMean<? extends DataType> d1, DistributionWithMean<? extends DataType> d2 ) { if( !this.equals( d1.getMean(), d2.getMean() ) ) { return false; } final int seed = RANDOM.nextInt(100); Random r1 = new Random(seed); Random r2 = new Random(seed); return this.identical( d1.sample(r1, NUM_SAMPLES), d2.sample(r2, NUM_SAMPLES) ); } /** * * @param <DataType> * @param s1 * @param s2 * @return */ public <DataType> boolean identical( Collection<? extends DataType> s1, Collection<? extends DataType> s2 ) { if( s1.size() != s2.size() ) { return false; } Iterator<? extends DataType> i1 = s1.iterator(); Iterator<? extends DataType> i2 = s2.iterator(); while( i1.hasNext() ) { if( !this.equals( i1.next(), i2.next() ) ) { return false; } } return true; } /** * Checks for equality * @param <DataType> * @param o1 * @param o2 * @return */ @SuppressWarnings("unchecked") public <DataType> boolean equals( DataType o1, DataType o2 ) { if( o1 instanceof Ring ) { return ((Ring) o1).equals( (Ring) o2, TOLERANCE); } else if( o1 instanceof Number ) { return Math.abs( ((Number) o1).doubleValue() - ((Number) o2).doubleValue() ) <= TOLERANCE; } else { return o1.equals( o2 ); } } /** * Harness methods */ public void testHarnessMethods() { System.out.println( "Harness Methods" ); Distribution<ObservationType> conditional = this.createConditionalDistribution(); assertNotNull( conditional ); Collection<? extends ObservationType> data = this.createData( conditional ); assertEquals( NUM_SAMPLES, data.size() ); RecursiveBayesianEstimator<ObservationType,ParameterType,BeliefType> estimator = this.createInstance(); assertNotNull( estimator ); assertNotNull( estimator.learn(data) ); } /** * Tests the constructors of class RecursiveBayesianEstimatorTestHarness. */ public abstract void testConstructors(); /** * Tests estimation against known values. */ public abstract void testKnownValues(); /** * Test of clone method, of class AbstractRecursiveBayesianEstimator. */ public void testRBEClone() { System.out.println("RBE clone"); RecursiveBayesianEstimator<ObservationType,ParameterType,BeliefType> instance = this.createInstance(); @SuppressWarnings("unchecked") RecursiveBayesianEstimator<ObservationType,ParameterType,BeliefType> clone = (RecursiveBayesianEstimator<ObservationType,ParameterType,BeliefType>) instance.clone(); assertNotSame( instance, clone ); assertNotNull( clone ); // if( instance instanceof Randomized ) // { // int seed = RANDOM.nextInt(); // Random r1 = new Random( seed ); // Random r2 = new Random( seed ); // ((Randomized) instance).setRandom(r1); // ((Randomized) clone).setRandom(r2); // } Distribution<ObservationType> conditional = this.createConditionalDistribution(); Collection<? extends ObservationType> data = this.createData( conditional ); assertNotSame( instance.createInitialLearnedObject(), clone.createInitialLearnedObject() ); BeliefType i1 = instance.learn(data); BeliefType i2 = clone.learn(data); assertNotSame( i1, i2 ); // assertTrue( this.identical(i1, i2) ); } /** * learn and online learning */ @SuppressWarnings("unchecked") public void testRBELearnAndOnlineLearning() { System.out.println( "RBE Learn and Online Learning" ); Distribution<ObservationType> conditional = this.createConditionalDistribution(); Collection<? extends ObservationType> data = this.createData( conditional ); RecursiveBayesianEstimator<ObservationType,ParameterType,BeliefType> instance = this.createInstance(); RecursiveBayesianEstimator<ObservationType,ParameterType,BeliefType> c1 = (RecursiveBayesianEstimator<ObservationType,ParameterType,BeliefType>) instance.clone(); BeliefType p1 = (BeliefType) c1.createInitialLearnedObject().clone(); for( ObservationType value : data ) { c1.update( p1, value ); } RecursiveBayesianEstimator<ObservationType,ParameterType,BeliefType> c2 = (RecursiveBayesianEstimator<ObservationType,ParameterType,BeliefType>) instance.clone(); BeliefType p2 = c2.learn(data); // We'll just make sure the means are approximately the same ParameterType onlineMean = ((DistributionWithMean<ParameterType>)p1).getMean(); ParameterType batchMean = ((DistributionWithMean<ParameterType>)p2).getMean(); System.out.println( "Conditional: " + conditional ); System.out.println( "Online Mean: " + onlineMean ); System.out.println( "Batch Mean: " + batchMean ); this.identical((DistributionWithMean<ParameterType>)p1, (DistributionWithMean<ParameterType>)p2); } /** * online and batch online learning */ @SuppressWarnings("unchecked") public void testRBEOnlineandBatchOnline() { System.out.println( "RBE Online and Batch Online" ); Distribution<ObservationType> conditional = this.createConditionalDistribution(); Collection<? extends ObservationType> data = this.createData( conditional ); RecursiveBayesianEstimator<ObservationType,ParameterType,BeliefType> instance = this.createInstance(); BeliefType p1 = instance.createInitialLearnedObject(); BeliefType pclone = (BeliefType) p1.clone(); for( ObservationType value : data ) { instance.update( p1, value ); } BeliefType p2 = instance.createInitialLearnedObject(); this.identical((DistributionWithMean<ParameterType>)pclone, (DistributionWithMean<ParameterType>)p2); instance.update(p2, data); this.identical((DistributionWithMean<ParameterType>)p1, (DistributionWithMean<ParameterType>)p2); } }