package net.woodyfolsom.msproj.ann;

import java.util.List;
import java.util.Set;

import org.encog.engine.network.activation.ActivationSigmoid;
import org.encog.ml.data.MLData;
import org.encog.ml.data.MLDataPair;
import org.encog.ml.data.MLDataSet;
import org.encog.ml.data.basic.BasicMLData;
import org.encog.ml.train.MLTrain;
import org.encog.neural.networks.BasicNetwork;
import org.encog.neural.networks.layers.BasicLayer;
import org.encog.neural.networks.training.propagation.back.Backpropagation;

/**
 * Based on sample code from http://neuroph.sourceforge.net
 * 
 * @author Woody
 * 
 */
public class XORFilter extends AbstractNeuralNetFilter implements
		NeuralNetFilter {
	
	public XORFilter() {
		// create a neural network, without using a factory
		BasicNetwork network = new BasicNetwork();
		network.addLayer(new BasicLayer(null, false, 2));
		network.addLayer(new BasicLayer(new ActivationSigmoid(), true, 3));
		network.addLayer(new BasicLayer(new ActivationSigmoid(), true, 1));
		network.getStructure().finalizeStructure();
		network.reset();

		this.neuralNetwork = network;
	}

	public double compute(double x, double y) {
		return compute(new BasicMLData(new double[]{x,y})).getData(0);
	}
	
	@Override
	public int getInputSize() {
		return 2;
	}

	@Override
	public int getOutputSize() {
		// TODO Auto-generated method stub
		return 1;
	}

	@Override
	public void learn(MLDataSet trainingSet) {

		// train the neural network
		final MLTrain train = new Backpropagation(neuralNetwork, trainingSet,
				0.7, 0.8);

		actualTrainingEpochs = 0;

		do {
			train.iteration();
			System.out.println("Epoch #" + actualTrainingEpochs + " Error:"
					+ train.getError());
			actualTrainingEpochs++;
		} while (train.getError() > 0.01
				&& actualTrainingEpochs <= maxTrainingEpochs);
	}
	
	@Override
	public void learn(Set<List<MLDataPair>> trainingSet) {
		throw new UnsupportedOperationException(
				"This Filter learns an MLDataSet, not a Set<List<MLData>>.");
	}
}