/*
* File: MarkovChainTest.java
* Authors: Kevin R. Dixon
* Company: Sandia National Laboratories
* Project: Cognitive Foundry
*
* Copyright Feb 3, 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.learning.algorithm.hmm;
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.mtj.DenseMatrix;
import gov.sandia.cognition.math.matrix.mtj.decomposition.EigenDecompositionRightMTJ;
import junit.framework.TestCase;
import java.util.Random;
/**
* Unit tests for MarkovChainTest.
*
* @author krdixon
*/
public class MarkovChainTest
extends TestCase
{
/**
* Random number generator to use for a fixed random seed.
*/
public final Random RANDOM = new Random( 1 );
/**
* Default tolerance of the regression tests, {@value}.
*/
public final double TOLERANCE = 1e-5;
/**
* Tests for class MarkovChainTest.
* @param testName Name of the test.
*/
public MarkovChainTest(
String testName)
{
super(testName);
}
/**
* Creates an instance.
* @return
* Markov chain
*/
public MarkovChain createInstance()
{
int numStates = RANDOM.nextInt( 10 ) + 3;
Matrix A = MatrixFactory.getDefault().createUniformRandom(
numStates, numStates, 0.0, 1.0, RANDOM);
Vector pi = VectorFactory.getDefault().createUniformRandom(
numStates, 0.0, 1.0, RANDOM);
pi.scaleEquals(1.0/pi.norm1());
MarkovChain retval = new MarkovChain( numStates );
retval.normalizeTransitionMatrix(A);
retval.setTransitionProbability(A);
retval.setInitialProbability(pi);
return retval;
}
/**
* Tests the constructors of class MarkovChainTest.
*/
public void testMarkovChainConstructors()
{
System.out.println( "Constructors" );
MarkovChain f = new MarkovChain();
assertEquals( MarkovChain.DEFAULT_NUM_STATES, f.getNumStates() );
assertEquals( 1.0, f.getInitialProbability().norm1(), TOLERANCE );
for( int j = 0; j < f.getNumStates(); j++ )
{
assertEquals( 1.0, f.getTransitionProbability().getColumn(j).norm1(), TOLERANCE );
}
int k = RANDOM.nextInt(10) + 10;
f = new MarkovChain( k );
assertEquals( k, f.getNumStates() );
assertEquals( 1.0, f.getInitialProbability().norm1(), TOLERANCE );
for( int j = 0; j < f.getNumStates(); j++ )
{
assertEquals( 1.0, f.getTransitionProbability().getColumn(j).norm1(), TOLERANCE );
}
MarkovChain f2 = new MarkovChain(
f.getInitialProbability(), f.getTransitionProbability() );
assertSame( f.getInitialProbability(), f2.getInitialProbability() );
assertSame( f.getTransitionProbability(), f2.getTransitionProbability() );
Matrix A = MatrixFactory.getDefault().createUniformRandom(
f.getNumStates(), 1, 0.0, 1.0, RANDOM);
try
{
MarkovChain f3 = new MarkovChain( f2.getInitialProbability(), A );
fail( "Transition matrix must be square" );
}
catch (Exception e)
{
System.out.println( "Good: " + e );
}
}
/**
* Test of clone method, of class MarkovChain.
*/
public void testClone()
{
System.out.println("clone");
MarkovChain instance = this.createInstance();
MarkovChain clone = instance.clone();
assertNotSame( instance, clone );
assertNotSame( instance.getInitialProbability(), clone.getInitialProbability() );
assertEquals( instance.getInitialProbability(), clone.getInitialProbability() );
assertNotSame( instance.getTransitionProbability(), clone.getTransitionProbability() );
if( !instance.getTransitionProbability().equals( clone.getTransitionProbability(), TOLERANCE ) )
{
assertEquals( instance.getTransitionProbability(), clone.getTransitionProbability() );
}
}
/**
* Test of createUniformInitialProbability method, of class MarkovChain.
*/
public void testCreateUniformInitialProbability()
{
System.out.println("createUniformInitialProbability");
int numStates = RANDOM.nextInt(10) + 2;
Vector result = MarkovChain.createUniformInitialProbability(numStates);
assertEquals( 1.0, result.norm1(), TOLERANCE );
for( int i = 0; i < numStates; i++ )
{
assertEquals( 1.0/numStates, result.getElement(i) );
}
}
/**
* Test of createUniformTransitionProbability method, of class MarkovChain.
*/
public void testCreateUniformTransitionProbability()
{
System.out.println("createUniformTransitionProbability");
int numStates = RANDOM.nextInt(10) + 2;
Matrix result = MarkovChain.createUniformTransitionProbability(numStates);
assertEquals( numStates, result.getNumRows() );
assertEquals( numStates, result.getNumColumns() );
for( int j = 0; j < numStates; j++ )
{
assertEquals( 1.0, result.getColumn(j).norm1(), TOLERANCE );
for( int i = 0; i < numStates; i++ )
{
assertEquals( 1.0/numStates, result.getElement(i, j), TOLERANCE );
}
}
}
/**
* Test of getInitialProbability method, of class MarkovChain.
*/
public void testGetInitialProbability()
{
System.out.println("getInitialProbability");
MarkovChain instance = this.createInstance();
Vector pi = instance.getInitialProbability();
assertEquals( 1.0, pi.norm1(), TOLERANCE );
}
/**
* Test of setInitialProbability method, of class MarkovChain.
*/
public void testSetInitialProbability()
{
System.out.println("setInitialProbability");
MarkovChain instance = this.createInstance();
Vector pi = instance.getInitialProbability();
assertEquals( 1.0, pi.norm1(), TOLERANCE );
Vector p2 = pi.scale(RANDOM.nextDouble());
instance.setInitialProbability(p2);
assertSame( p2, instance.getInitialProbability() );
assertEquals( 1.0, p2.norm1(), TOLERANCE );
}
/**
* Test of getTransitionProbability method, of class MarkovChain.
*/
public void testGetTransitionProbability()
{
System.out.println("getTransitionProbability");
MarkovChain instance = this.createInstance();
Matrix A = instance.getTransitionProbability();
assertTrue( A.isSquare() );
for( int j = 0; j < A.getNumColumns(); j++ )
{
assertEquals( 1.0, A.getColumn(j).norm1(), TOLERANCE );
}
}
/**
* Test of setTransitionProbability method, of class MarkovChain.
*/
public void testSetTransitionProbability()
{
System.out.println("setTransitionProbability");
MarkovChain instance = this.createInstance();
Matrix A = instance.getTransitionProbability();
assertTrue( A.isSquare() );
for( int j = 0; j < A.getNumColumns(); j++ )
{
assertEquals( 1.0, A.getColumn(j).norm1(), TOLERANCE );
}
Matrix A2 = A.scale( RANDOM.nextDouble() );
instance.setTransitionProbability(A2);
assertSame( A2, instance.getTransitionProbability() );
for( int j = 0; j < A.getNumColumns(); j++ )
{
assertEquals( 1.0, A.getColumn(j).norm1(), TOLERANCE );
}
Matrix A3 = MatrixFactory.getDefault().createUniformRandom(
4, 3, 0.0, 1.0, RANDOM);
try
{
instance.setTransitionProbability(A3);
fail( "Must be square" );
}
catch (Exception e)
{
System.out.println( "Good: " + e );
}
}
/**
* Test of getNumStates method, of class MarkovChain.
*/
public void testGetNumStates()
{
System.out.println("getNumStates");
MarkovChain instance = this.createInstance();
assertEquals( instance.getInitialProbability().getDimensionality(), instance.getNumStates() );
}
/**
* Test of toString method, of class MarkovChain.
*/
public void testToString()
{
System.out.println("toString");
MarkovChain instance = this.createInstance();
String result = instance.toString();
System.out.println( "Result =\n" + result );
assertTrue( result.length() > 0 );
}
/**
* Test of getSteadyStateDistribution method, of class MarkovChain.
*/
public void testGetSteadyStateDistribution()
{
System.out.println("getSteadyStateDistribution");
MarkovChain instance = this.createInstance();
Vector phat = instance.getSteadyStateDistribution();
EigenDecompositionRightMTJ evd = EigenDecompositionRightMTJ.create(
(DenseMatrix) instance.getTransitionProbability() );
Vector p = evd.getEigenVectorsRealPart().getColumn(0);
// We do the manual sum (instead of norm1) in case the EVD found
// the negative of the eigenvector.
double sum = 0.0;
for( int i = 0; i < p.getDimensionality(); i++ )
{
sum += p.getElement(i);
}
p.scaleEquals( 1.0/sum );
System.out.println( "P: " + p );
System.out.println( "Phat: " + phat );
assertTrue( p.equals( phat, TOLERANCE ) );
}
/**
* Test of getFutureStateDistribution method, of class MarkovChain.
*/
public void testGetFutureStateDistribution()
{
System.out.println("getFutureStateDistribution");
MarkovChain instance = this.createInstance();
Vector expected = instance.transitionProbability.times(
instance.getInitialProbability() );
Vector result = instance.getFutureStateDistribution(
instance.getInitialProbability(), 1);
if( !expected.equals( result ) )
{
assertEquals( expected, result );
}
expected = instance.getInitialProbability();
assertEquals( expected, instance.getFutureStateDistribution( instance.getInitialProbability(), -1 ) );
assertEquals( expected, instance.getFutureStateDistribution( instance.getInitialProbability(), 0 ) );
for( int i = 1; i < 100; i++ )
{
expected = instance.getTransitionProbability().times( expected );
expected = expected.scale( 1.0/result.norm1() );
result = instance.getFutureStateDistribution(
instance.getInitialProbability(), i );
if( !expected.equals( result, TOLERANCE ) )
{
assertEquals( expected, result );
}
}
}
}