using System;
using System.Collections.Generic;
using System.Linq;
using DanielVaughan.AI.NeuralNetworking;
using DanielVaughan.Tests.AI.NeuralNetworking;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace DanielVaughan.Tests
{
/// <summary>
///This is a test class for NeuralNetworkTest and is intended
///to contain all NeuralNetworkTest Unit Tests
///</summary>
[TestClass]
public class NeuralNetworkTest
{
const double high = .99;
const double middle = .5;
const double low = .01;
/// <summary>
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///</summary>
public TestContext TestContext { get; set; }
#region Additional test attributes
//
//You can use the following additional attributes as you write your tests:
//
//Use ClassInitialize to run code before running the first test in the class
//[ClassInitialize()]
//public static void MyClassInitialize(TestContext testContext)
//{
//}
//
//Use ClassCleanup to run code after all tests in a class have run
//[ClassCleanup()]
//public static void MyClassCleanup()
//{
//}
//
//Use TestInitialize to run code before running each test
//[TestInitialize()]
//public void MyTestInitialize()
//{
//}
//
//Use TestCleanup to run code after each test has run
//[TestCleanup()]
//public void MyTestCleanup()
//{
//}
//
#endregion
/// <summary>
///A test for Train
///</summary>
[TestMethod]
public void TrainShouldBuildNetworkForXor()
{
double lowLow, lowHigh, highLow, highHigh;
double[][] input = new [] { new[] { high, high }, new[] { low, high }, new[] { high, low }, new[] { low, low }};
double[][] expectedOutput = new [] {new[] {low}, new[] {high}, new[] {high}, new[] {low}};
var trainingSet = new TrainingSet(new List<LayerStimulus>
{
new LayerStimulus(new[] { high, high }),
new LayerStimulus(new[] { low, high }),
new LayerStimulus(new[] { high, low }),
new LayerStimulus(new[] { low, low })
},
new List<LayerStimulus> {
new LayerStimulus(new[] { low }),
new LayerStimulus(new[] { high }),
new LayerStimulus(new[] { high }),
new LayerStimulus(new[] { low })
});
var target = new NeuralNetwork(2, 2, 1);
int iterations = 50;
int count = 0;
do
{
count++;
target.Train(trainingSet, iterations);
target.SetInputValue(0, false);
target.SetInputValue(1, false);
target.Pulse();
lowLow = target.GetOutputValue(0);
target.SetInputValue(0, true);
target.SetInputValue(1, false);
target.Pulse();
highLow = target.GetOutputValue(0);
target.SetInputValue(0, false);
target.SetInputValue(1, true);
target.Pulse();
lowHigh = target.GetOutputValue(0);
target.SetInputValue(0, true);
target.SetInputValue(1, true);
target.Pulse();
highHigh = target.GetOutputValue(0);
} while (count < 90001 &&
(highHigh > (middle + low) / 2
|| lowHigh < (middle + high) / 2
|| highLow < (middle + low) / 2
|| lowLow > (middle + high) / 2));
Assert.IsTrue(count < 90000, "Number of iterations exceeded expected value.");
}
readonly bool[][] xorBoolInput = new[] { new[] { true, true }, new[] { false, true }, new[] { true, false }, new[] { false, false } };
readonly bool[][] xorBoolOutput = new[] { new[] { false }, new[] { true }, new[] { true }, new[] { false } };
/// <summary>
///A test for Train
///</summary>
[TestMethod]
public void TrainShouldBuildNetworkForXorBool()
{
bool falseFalse, falseTrue, trueFalse, trueTrue;
var input = xorBoolInput;
var expectedOutput = xorBoolOutput;
var target = new NeuralNetwork(2, 2, 1) { LearningRate = 3 };
int iterations = 5;
target.Train(input, expectedOutput, iterations);
int count = 0;
do
{
count++;
target.Train(input, expectedOutput, iterations);
target.InputAsBooleans = new[] {false, false};
target.Pulse();
falseFalse = target[0];
target.InputAsBooleans = new[] { true, false };
target.Pulse();
trueFalse = target[0];
target.InputAsBooleans = new[] { false, true };
target.Pulse();
falseTrue = target[0];
target.InputAsBooleans = new[] { true, true };
target.Pulse();
trueTrue = target[0];
} while (count < 90001 &&
(trueTrue
|| !falseTrue
|| !trueFalse
|| falseFalse));
Assert.IsTrue(count < 90000, "Number of iterations exceeded expected value.");
}
/// <summary>
///A test for MeasureAccuracy
///</summary>
[TestMethod]
public void MeasureAccuracyShouldReturnALowResultBeforeTraining()
{
var input = xorBoolInput;
var expectedOutput = xorBoolOutput;
var target = new NeuralNetwork(2, 2, 1) { LearningRate = 3 };
double accuracy = target.MeasureAccuracy(input, expectedOutput);
/* Accuracy should be around 50% because we haven't trained it yet. */
double expectedAccuracy = .6;
Assert.IsTrue(accuracy < expectedAccuracy, "Expected accuracy to be less than "
+ expectedAccuracy + " but it was " + accuracy);
}
/// <summary>
///A test for MeasureAccuracy
///</summary>
[TestMethod]
public void MeasureAccuracyShouldReturnAHighResultAfterTraining()
{
var input = xorBoolInput;
var expectedOutput = xorBoolOutput;
var target = new NeuralNetwork(2, 2, 1);
int iterations = 5000;
target.Train(input, expectedOutput, iterations);
double accuracy = target.MeasureAccuracy();
double expectedAccuracy = .5;
Assert.IsTrue(accuracy > expectedAccuracy, "Expected accuracy to be greater than "
+ expectedAccuracy + " but it was " + accuracy);
target.Train(input, expectedOutput, iterations);
accuracy = target.MeasureAccuracy();
expectedAccuracy = .7;
Assert.IsTrue(accuracy > expectedAccuracy, "Expected accuracy to be greater than "
+ expectedAccuracy + " but it was " + accuracy);
target.Train(input, expectedOutput, iterations);
accuracy = target.MeasureAccuracy();
expectedAccuracy = .7;
Assert.IsTrue(accuracy > expectedAccuracy, "Expected accuracy to be greater than "
+ expectedAccuracy + " but it was " + accuracy);
}
[TestMethod]
public void TrainShouldTimeoutIfAccuracyNotReached()
{
var input = xorBoolInput;
var expectedOutput = xorBoolOutput;
var target = new NeuralNetwork(2, 2, 1);
var timedTrainingResult = target.Train(input, expectedOutput, 1, 1);
Assert.AreEqual(TrainingResult.RanOutOfTime, timedTrainingResult.TrainingResult);
Assert.IsTrue(timedTrainingResult.AccuracyAttained < 1, "Accuracy obtained should be less than 1.");
target = new NeuralNetwork(2, 2, 1);
timedTrainingResult = target.Train(input, expectedOutput, 1, 1000);
Assert.AreEqual(TrainingResult.RanOutOfTime, timedTrainingResult.TrainingResult);
Assert.IsTrue(timedTrainingResult.AccuracyAttained < 1, "Accuracy obtained should be less than 1.");
}
[TestMethod]
public void TrainShouldNotTimeoutIfAccuracyReached()
{
var input = xorBoolInput;
var expectedOutput = xorBoolOutput;
var target = new NeuralNetwork(2, 2, 1);
double soughtAccuracy = .01;
var timedTrainingResult = target.Train(input, expectedOutput, soughtAccuracy, 100);
string message = string.Format("Accuracy obtained should be greater than {0}, but was only {1}.",
soughtAccuracy, timedTrainingResult.AccuracyAttained);
Assert.AreEqual(TrainingResult.Success, timedTrainingResult.TrainingResult, message);
Assert.IsTrue(timedTrainingResult.AccuracyAttained > soughtAccuracy, message);
target = new NeuralNetwork(2, 2, 1);
soughtAccuracy = .7;
timedTrainingResult = target.Train(input, expectedOutput, soughtAccuracy, 1000);
message = string.Format("Accuracy obtained should be greater than {0}, but was only {1}.",
soughtAccuracy, timedTrainingResult.AccuracyAttained);
Assert.AreEqual(TrainingResult.Success, timedTrainingResult.TrainingResult, message);
Assert.IsTrue(timedTrainingResult.AccuracyAttained > soughtAccuracy, message);
soughtAccuracy = .72;
timedTrainingResult = target.Train(input, expectedOutput, soughtAccuracy, 10000);
message = string.Format("Accuracy obtained should be greater than {0}, but was only {1}.",
soughtAccuracy, timedTrainingResult.AccuracyAttained);
Assert.AreEqual(TrainingResult.Success, timedTrainingResult.TrainingResult, message);
Assert.IsTrue(timedTrainingResult.AccuracyAttained > soughtAccuracy, message);
}
[TestMethod]
public void TrainShouldCorrectlyTrainForOneOutput()
{
var inputNeuronCount = 5;
var outputNeuronCount = 50;
var hiddenNeuronCount = inputNeuronCount;
var input = new double[inputNeuronCount];
for (int i = 0; i < input.Length; i++)
{
input[i] = low;
}
var output = new double[outputNeuronCount];
for (int i = 0; i < output.Length; i++)
{
output[i] = low;
}
var neuralNetwork = new NeuralNetwork(inputNeuronCount, hiddenNeuronCount, outputNeuronCount);
neuralNetwork.Input = input;
neuralNetwork.Pulse();
var toto = neuralNetwork.Output;
output[0] = high;
var trainingSet = new TrainingSet(new List<LayerStimulus> { new LayerStimulus(input) },
new List<LayerStimulus> { new LayerStimulus(output) });
neuralNetwork.Train(trainingSet, 500);
neuralNetwork.Input = input;
neuralNetwork.Pulse();
toto = neuralNetwork.Output;
var indexOfHighest = NeuralNetworkTimeSeries.GetIndexOfHighest(toto);
Assert.AreEqual(0, indexOfHighest);
}
[TestMethod]
public void TrainShouldLearnCorrectlyOnRepeatTraining()
{
var neuralNetwork = new NeuralNetwork(4, 4, 4);
int trainingIterations = 1000;
var input = new[] {low, high, low, high};
var output = new [] {low, low, low, high};
var trainingSet = new TrainingSet(new List<LayerStimulus> {new LayerStimulus(input)},
new List<LayerStimulus> {new LayerStimulus(output)});
neuralNetwork.Train(trainingSet, trainingIterations);
neuralNetwork.Input = new [] {low, high, low, high};
neuralNetwork.Pulse();
var actualOutput = neuralNetwork.Output.ToList();
var indexOfHighest = NeuralNetworkTimeSeries.GetIndexOfHighest(actualOutput);
Assert.AreEqual(3, indexOfHighest);
input = new[] { low, high, high, high };
output = new[] { low, low, high, low };
trainingSet = new TrainingSet(new List<LayerStimulus> { new LayerStimulus(input) },
new List<LayerStimulus> { new LayerStimulus(output) });
neuralNetwork.Train(trainingSet, trainingIterations);
neuralNetwork.Input = input;
neuralNetwork.Pulse();
actualOutput = neuralNetwork.Output.ToList();
indexOfHighest = NeuralNetworkTimeSeries.GetIndexOfHighest(actualOutput);
Assert.AreEqual(2, indexOfHighest);
input = new[] { low, high, low, high };
output = new[] { low, low, low, high };
trainingSet = new TrainingSet(new List<LayerStimulus> { new LayerStimulus(input) },
new List<LayerStimulus> { new LayerStimulus(output) });
neuralNetwork.Train(trainingSet, trainingIterations);
neuralNetwork.Input = new[] { low, high, low, high };
neuralNetwork.Pulse();
actualOutput = neuralNetwork.Output.ToList();
indexOfHighest = NeuralNetworkTimeSeries.GetIndexOfHighest(actualOutput);
Assert.AreEqual(3, indexOfHighest);
input = new[] { low, high, high, high };
output = new[] { low, low, high, low };
trainingSet = new TrainingSet(new List<LayerStimulus> { new LayerStimulus(input) },
new List<LayerStimulus> { new LayerStimulus(output) });
neuralNetwork.Train(trainingSet, trainingIterations);
neuralNetwork.Input = input;
neuralNetwork.Pulse();
actualOutput = neuralNetwork.Output.ToList();
indexOfHighest = NeuralNetworkTimeSeries.GetIndexOfHighest(actualOutput);
Assert.AreEqual(2, indexOfHighest);
neuralNetwork.Input = new[] { low, high, low, high };
neuralNetwork.Pulse();
actualOutput = neuralNetwork.Output.ToList();
indexOfHighest = NeuralNetworkTimeSeries.GetIndexOfHighest(actualOutput);
Assert.AreEqual(3, indexOfHighest, string.Format(
"Output: {0}, {1}, {2}, {3}", actualOutput[0], actualOutput[1], actualOutput[2], actualOutput[3]));
}
}
}