/*
* File: SimulatedAnnealerTest.java
* Authors: Jonathan McClain and Kevin R. Dixon
* Company: Sandia National Laboratories
* Project: Cognitive Foundry
*
* Copyright March 16, 2006, 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.annealing;
import gov.sandia.cognition.annotation.CodeReview;
import gov.sandia.cognition.learning.function.cost.CostFunction;
import gov.sandia.cognition.learning.function.cost.EuclideanDistanceCostFunction;
import gov.sandia.cognition.math.matrix.Vectorizable;
import gov.sandia.cognition.math.matrix.VectorFactory;
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.util.AbstractCloneableSerializable;
import java.util.Random;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* This class implements JUnit tests for the following classes:
*
* SimulatedAnnealer
*
* @author Jonathan McClain
* @author Kevin R. Dixon
* @since 1.0
*/
@CodeReview(
reviewer="Justin Basilico",
date="2006-10-02",
changesNeeded=false,
comments="Looks fine."
)
public class SimulatedAnnealerTest
extends TestCase
{
/** The simulated annealer to use in the tests. */
private SimulatedAnnealer<Vectorizable, Vectorizable> simulatedAnnealer;
/** The cost function to use in the tests. */
private EuclideanDistanceCostFunction cost;
/** The random number generator for the tests. */
protected Random random = new Random(2);
/**
* The test constructor.
*
* @param testName The name of the test.
*/
public SimulatedAnnealerTest(
String testName)
{
super(testName);
}
/**
* Called before each test is run. Prepares the SimulatedAnnealer for the
* tests.
*/
@Override
protected void setUp()
{
int N = 2;
double range = 2;
Vector goal = VectorFactory.getDefault().createUniformRandom(N,-range,range, random);
System.out.println("Goal = " + goal );
this.cost = new EuclideanDistanceCostFunction(goal);
Matrix covariance = MatrixFactory.getDefault().createIdentity(N,N).scale(1e-3);
VectorizablePerturber perturber =
new VectorizablePerturber(new Random(3), covariance);
Vectorizable initialVector = VectorFactory.getDefault().createUniformRandom(N,-range,range, random);
this.simulatedAnnealer =
new SimulatedAnnealer<Vectorizable, Vectorizable>(
initialVector,
perturber,
this.cost,
10000);
}
/**
* Called after each test is run.
*/
@Override
protected void tearDown()
{
this.cost = null;
this.simulatedAnnealer = null;
}
/**
* Returns the test.
* @return Test
*/
public static Test suite()
{
TestSuite suite = new TestSuite(SimulatedAnnealerTest.class);
return suite;
}
public void testClone()
{
SimulatedAnnealer<?,?> clone = this.simulatedAnnealer.clone();
assertNotNull( clone );
assertNotSame( this.simulatedAnnealer, clone );
}
/**
* Test of minimizeCost method, of class
* gov.sandia.isrc.learning.reinforcement.SimulatedAnnealer.
*/
public void testMinimize()
{
System.out.println("minimize");
Vectorizable result =
this.simulatedAnnealer.learn(this.cost.getCostParameters());
System.out.println("Result = " + result );
assertEquals("minimizeCost did not reach the expected minimum cost",
0.0, this.cost.evaluate(result), 0.1);
}
/**
* Test of step method, of class gov.sandia.isrc.learning.annealing.SimulatedAnnealer.
*/
public void testStep()
{
this.simulatedAnnealer.learn(this.cost.getCostParameters());
boolean expected = false;
boolean result = this.simulatedAnnealer.step();
assertEquals(expected, result);
}
/**
* Test of getCostFunction method, of class
* gov.sandia.isrc.learning.reinforcement.SimulatedAnnealer.
*/
public void testGetCostFunction()
{
System.out.println("getCostFunction");
EuclideanDistanceCostFunction expected = null;
this.simulatedAnnealer.setCostFunction(expected);
CostFunction<?,?> actual = this.simulatedAnnealer.getCostFunction();
assertEquals(
"getCostFunction did not return the expected CostFunction",
expected,
actual);
}
/**
* Test of getPerturber method, of class
* gov.sandia.isrc.learning.reinforcement.SimulatedAnnealer.
*/
public void testGetPerturber()
{
System.out.println("getPerturber");
Perturber<Vectorizable> expected = null;
this.simulatedAnnealer.setPerturber(expected);
Perturber<Vectorizable> actual = this.simulatedAnnealer.getPerturber();
assertEquals(
"getPerturber did not return the expected Perturber",
expected,
actual);
}
/**
* Test of getTemperature method, of class
* gov.sandia.isrc.learning.reinforcement.SimulatedAnnealer.
*/
public void testGetTemperature()
{
System.out.println("getTemperature");
double expected = 1.0;
this.simulatedAnnealer.setTemperature(expected);
double actual = this.simulatedAnnealer.getTemperature();
assertEquals(
"getTemperature did not return the expected temperature",
expected,
actual,
0.0);
}
/**
* Test of getMaxIterations method, of class
* gov.sandia.isrc.learning.reinforcement.SimulatedAnnealer.
*/
public void testGetMaxIterations()
{
System.out.println("getMaxIterations");
int expected = 1;
this.simulatedAnnealer.setMaxIterations(expected);
int actual = this.simulatedAnnealer.getMaxIterations();
assertEquals(
"getMaxIterations did not return the expected iteration",
expected,
actual);
}
/**
* Test of getMaxIterationsWithoutImprovement method, of class
* gov.sandia.isrc.learning.reinforcement.SimulatedAnnealer.
*/
public void testGetMaxIterationsWithoutImprovement()
{
System.out.println("getMaxIterationsWithoutImprovement");
int expected = 1;
this.simulatedAnnealer.setMaxIterationsWithoutImprovement(expected);
int actual =
this.simulatedAnnealer.getMaxIterationsWithoutImprovement();
assertEquals(
"getMaxIterationsWithoutImprovement did not return the "
+ "expected iteration",
expected,
actual);
}
/**
* Test of getIterationsWithoutImprovement method, of class
* gov.sandia.isrc.learning.reinforcement.SimulatedAnnealer.
*/
public void testGetIterationsWithoutImprovement()
{
System.out.println("getIterationsWithoutImprovement");
int expected = 0;
this.simulatedAnnealer.setIterationsWithoutImprovement(expected);
int actual =
this.simulatedAnnealer.getIterationsWithoutImprovement();
assertEquals(
"getIterationsWithoutImprovement did not return the expected"
+ "iteration",
expected,
actual);
}
/**
* Test of getCoolingFactor method, of class
* gov.sandia.isrc.learning.reinforcement.SimulatedAnnealer.
*/
public void testGetCoolingFactor()
{
System.out.println("getCoolingFactor");
double expected = 0.5;
this.simulatedAnnealer.setCoolingFactor(expected);
double actual = this.simulatedAnnealer.getCoolingFactor();
assertEquals(
"getCoolingFactor did not return the expected cooling factor",
expected,
actual,
0.0);
}
/**
* Test of getRandom method, of class
* gov.sandia.isrc.learning.reinforcement.SimulatedAnnealer.
*/
public void testGetRandom()
{
System.out.println("getRandom");
Random expected = new Random(4);
this.simulatedAnnealer.setRandom(expected);
Random actual = this.simulatedAnnealer.getRandom();
assertEquals(
"getRandom did not return the expected Random",
expected,
actual);
}
/**
* Test of setCostFunction method, of class
* gov.sandia.isrc.learning.reinforcement.SimulatedAnnealer.
*/
public void testSetCostFunction()
{
System.out.println("setCostFunction");
EuclideanDistanceCostFunction expected = null;
this.simulatedAnnealer.setCostFunction(expected);
CostFunction<?,?> actual =
this.simulatedAnnealer.getCostFunction();
assertEquals(
"setCostFunction did not set the expected CostFunction",
expected,
actual);
}
/**
* Test of setPerturber method, of class
* gov.sandia.isrc.learning.reinforcement.SimulatedAnnealer.
*/
public void testSetPerturber()
{
System.out.println("setPerturber");
Perturber<Vectorizable> expected = null;
this.simulatedAnnealer.setPerturber(expected);
Perturber<Vectorizable> actual = this.simulatedAnnealer.getPerturber();
assertEquals(
"setPerturber did not set the expected Perturber",
expected,
actual);
}
/**
* Test of setMaxIterations method, of class
* gov.sandia.isrc.learning.reinforcement.SimulatedAnnealer.
*/
public void testSetMaxIterations()
{
System.out.println("setMaxIterations");
int expected = 1;
this.simulatedAnnealer.setMaxIterations(expected);
int actual = this.simulatedAnnealer.getMaxIterations();
assertEquals(
"setMaxIterations did not set the expected integer",
expected,
actual);
}
/**
* Test of setMaxIterationsWithoutImprovement method, of class
* gov.sandia.isrc.learning.reinforcement.SimulatedAnnealer.
*/
public void testSetMaxIterationsWithoutImprovement()
{
System.out.println("setMaxIterationsWithoutImprovement");
int expected = 0;
this.simulatedAnnealer.setMaxIterationsWithoutImprovement(expected);
int actual =
this.simulatedAnnealer.getMaxIterationsWithoutImprovement();
assertEquals(
"setMaxIterationsWithoutImprovement did not set the expected "
+ "integer",
expected,
actual);
}
/**
* Test of setIterationsWithoutImprovement method, of class
* gov.sandia.isrc.learning.reinforcement.SimulatedAnnealer.
*/
public void testSetIterationsWithoutImprovement()
{
System.out.println("setIterationsWithoutImprovement");
int expected = 0;
this.simulatedAnnealer.setIterationsWithoutImprovement(expected);
int actual = this.simulatedAnnealer.getIterationsWithoutImprovement();
assertEquals(
"setIterationsWithoutImprovement did not set the expected integer",
expected,
actual);
}
/**
* Test of setCoolingFactor method, of class
* gov.sandia.isrc.learning.reinforcement.SimulatedAnnealer.
*/
public void testSetCoolingFactor()
{
System.out.println("setCoolingFactor");
double expected = 0.5;
this.simulatedAnnealer.setCoolingFactor(expected);
double actual = this.simulatedAnnealer.getCoolingFactor();
assertEquals(
"setCoolingFactor did not set the expected double",
expected,
actual);
this.simulatedAnnealer.setCoolingFactor(0.1);
assertEquals(0.1, this.simulatedAnnealer.getCoolingFactor());
this.simulatedAnnealer.setCoolingFactor(1.0);
assertEquals(1.0, this.simulatedAnnealer.getCoolingFactor());
boolean exceptionThrown = false;
try
{
this.simulatedAnnealer.setCoolingFactor(0.0);
}
catch ( IllegalArgumentException e )
{
exceptionThrown = true;
}
finally
{
assertTrue(exceptionThrown);
}
exceptionThrown = false;
try
{
this.simulatedAnnealer.setCoolingFactor(1.1);
}
catch ( IllegalArgumentException e )
{
exceptionThrown = true;
}
finally
{
assertTrue(exceptionThrown);
}
}
/**
* Test of setRandom method, of class
* gov.sandia.isrc.learning.reinforcement.SimulatedAnnealer.
*/
public void testSetRandom() {
System.out.println("setRandom");
Random expected = null;
this.simulatedAnnealer.setRandom(expected);
Random actual = this.simulatedAnnealer.getRandom();
assertEquals(
"setRandom did not set the expected Random",
expected,
actual);
}
/**
* The DoublePerturber implements a Perturber for doubles.
*
* @author Jonathan McClain
* @since 1.0
*/
private class DoublePerturber
extends AbstractCloneableSerializable
implements Perturber<Double>
{
/** The random number generator to use. */
private Random random;
/** The difference between max and min. */
private double span;
/** The minimum for the random number generator. */
private double min;
/** The maximum for the random number generator. */
private double max;
/**
* Creates a new instance of DoublePerturber.
*
* @param min The minimum for the random number generator.
* @param max The maximum for the random number generator.
*/
public DoublePerturber(
double min,
double max)
{
if(max < min)
{
throw new IllegalArgumentException("Max is less than min!");
}
this.setRandom(new Random(5));
this.setSpan(max - min);
this.setMin(min);
this.setMax(max);
}
/**
* Perturbs the given number by generating a random number between max
* and min and adding it to the number.
*
* @param input The number to perturb.
* @return The perturbed version of the number.
*/
public Double perturb(
Double input)
{
double perturbedValue =
input + (this.getMin()
+ (this.random.nextDouble() * this.getSpan()));
return perturbedValue;
}
/**
* Sets the random number generator.
*
* @param random The new random number generator.
*/
private void setRandom(
Random random)
{
this.random = random;
}
/**
* Sets the difference between max and min.
*
* @param span The new span.
*/
private void setSpan(
double span)
{
this.span = span;
}
/**
* Sets the minimum for the random number generator.
*
* @param min The new minimum.
*/
private void setMin(
double min)
{
this.min = min;
}
/**
* Sets the maximum for the random number generator.
*
* @param max The new maximum.
*/
private void setMax(
double max)
{
this.max = max;
}
/**
* Gets the random number generator.
*
* @return The random number generator.
*/
private Random getRandom()
{
return this.random;
}
/**
* Gets the difference between max and min.
*
* @return The span.
*/
private double getSpan()
{
return this.span;
}
/**
* Gets the minimum for the random number generator.
*
* @return The minimum.
*/
private double getMin()
{
return this.min;
}
/**
* Gets the maximum for the random number generator.
*
* @return The maximum.
*/
private double getMax()
{
return this.max;
}
}
/**
* The DoubleCostFunction implements a cost function for functions that take
* as input a double and return a double.
*
* @author Jonathan McClain
* @since 1.0
*/
private class DoubleCostFunction
extends AbstractCloneableSerializable
implements CostFunction<Double, Double>
{
/** The goal of the search */
private double goal;
/**
* Creates a new instance of DoubleCostFunction.
*
* @param goal The goal of the search.
*/
DoubleCostFunction(
double goal)
{
this.setGoal(goal);
}
@Override
public DoubleCostFunction clone()
{
return (DoubleCostFunction) super.clone();
}
/**
* Computes the cost of the given target.
*
* @param target The double to evaluate.
* @return The cost of the given double.
*/
public Double evaluate(
Double target)
{
return ((this.getGoal() - target) * (this.getGoal() - target));
}
/**
* Sets the goal of the search.
*
* @param goal The new goal of the search.
*/
private void setGoal(
double goal)
{
this.goal = goal;
}
/**
* Gets the goal of the search.
*
* @return The goal.
*/
private double getGoal()
{
return this.goal;
}
public void setCostParameters(
Double costParameters)
{
this.setGoal(costParameters);
}
public Double getCostParameters()
{
return this.getGoal();
}
}
/**
* Creates an empty default annealer for testing.
*
* @return An empty default annealer.
*/
public SimulatedAnnealer<Vectorizable, Vectorizable> createInstance()
{
return new SimulatedAnnealer<Vectorizable, Vectorizable>(
null, null, null);
}
/**
* Test of getBestSoFar method, of class gov.sandia.isrc.learning.annealing.SimulatedAnnealer.
*/
public void testGetBestSoFar()
{
SimulatedAnnealer<Vectorizable, Vectorizable> instance =
this.createInstance();
assertNull(instance.getBestSoFar());
}
/**
* Test of getBestSoFarScore method, of class gov.sandia.isrc.learning.annealing.SimulatedAnnealer.
*/
public void testGetBestSoFarScore()
{
SimulatedAnnealer<Vectorizable, Vectorizable> instance =
this.createInstance();
assertEquals(0.0, instance.getBestSoFarScore());
}
/**
* Test of getCurrent method, of class gov.sandia.isrc.learning.annealing.SimulatedAnnealer.
*/
public void testGetCurrent()
{
SimulatedAnnealer<Vectorizable, Vectorizable> instance =
this.createInstance();
assertNull(instance.getCurrent());
}
/**
* Test of getCurrentScore method, of class gov.sandia.isrc.learning.annealing.SimulatedAnnealer.
*/
public void testGetCurrentScore()
{
SimulatedAnnealer<Vectorizable, Vectorizable> instance =
this.createInstance();
assertEquals(0.0, instance.getCurrentScore());
}
/**
* Test of getIteration method, of class gov.sandia.isrc.learning.annealing.SimulatedAnnealer.
*/
public void testGetIteration()
{
SimulatedAnnealer<Vectorizable, Vectorizable> instance =
this.createInstance();
assertEquals(0, instance.getIteration());
}
/**
* Test of setTemperature method, of class gov.sandia.isrc.learning.annealing.SimulatedAnnealer.
*/
public void testSetTemperature()
{
double expected = random.nextDouble();
this.simulatedAnnealer.setTemperature(expected);
assertEquals(expected, this.simulatedAnnealer.getTemperature());
}
/**
* Test of setBestSoFar method, of class gov.sandia.isrc.learning.annealing.SimulatedAnnealer.
*/
public void testSetBestSoFar()
{
Vectorizable expected = VectorFactory.getDefault().createVector(3);
this.simulatedAnnealer.setBestSoFar(expected);
assertSame(expected, this.simulatedAnnealer.getBestSoFar());
}
/**
* Test of setBestSoFarScore method, of class gov.sandia.isrc.learning.annealing.SimulatedAnnealer.
*/
public void testSetBestSoFarScore()
{
double expected = 1.0;
this.simulatedAnnealer.setBestSoFarScore(expected);
assertEquals(expected, this.simulatedAnnealer.getBestSoFarScore());
}
/**
* Test of setCurrent method, of class gov.sandia.isrc.learning.annealing.SimulatedAnnealer.
*/
public void testSetCurrent()
{
Vectorizable expected = VectorFactory.getDefault().createVector(3);
this.simulatedAnnealer.setCurrent(expected);
assertSame(expected, this.simulatedAnnealer.getCurrent());
}
/**
* Test of setCurrentScore method, of class gov.sandia.isrc.learning.annealing.SimulatedAnnealer.
*/
public void testSetCurrentScore()
{
double expected = 4.0;
this.simulatedAnnealer.setCurrentScore(expected);
assertEquals(expected, this.simulatedAnnealer.getCurrentScore());
}
}