package ec.app.complexregression;

import java.util.List;

import library.semantics.TestCase;

import org.apache.commons.math3.complex.Complex;

import ec.EvolutionState;
import ec.Individual;
import ec.app.regression.testcases.TestCaseFactory;
import ec.gp.GPIndividual;
import ec.gp.GPProblem;
import ec.gp.koza.KozaFitness;
import ec.gp.semantic.ISemanticProblem;
import ec.gp.semantic.ISemantics;
import ec.gp.semantic.func.SimpleNodeBase;
import ec.util.Parameter;

public class ComplexRegressionProblem extends GPProblem implements ISemanticProblem<Complex> {

	private final double HIT_THRESHOLD = 1E-10;

	//private final SortedMap<Complex, Complex> testCases = new TreeMap<Complex, Complex>();
	private List<TestCase<Complex>> testCases;
	private ComplexData[] data;

	@Override
	public void setup(EvolutionState state, Parameter base) {
		super.setup(state, base);

		data = new ComplexData[state.evalthreads];
		for (int i = 0; i < state.evalthreads; ++i) {
			data[i] = new ComplexData();
		}

		testCases = TestCaseFactory.getFactory(state).generateTraining(state);
	}

	@Override
	public void evaluate(EvolutionState state, Individual individual, int subpopulation, int threadnum) {
		if (individual.evaluated)
			return;

		GPIndividual ind = (GPIndividual) individual;

		double totalError = 0;
		double error;
		int hits = 0;

		for (TestCase<Complex> testCase : this.testCases) {
			Complex expectedVal = testCase.getValue();

			data[threadnum].x = testCase.getArguments()[0];
			ind.trees[0].child.eval(state, threadnum, data[threadnum], stack, ind, this);

			error = Math.abs(expectedVal.getReal() - data[threadnum].x.getReal())
					+ Math.abs(expectedVal.getImaginary() - data[threadnum].x.getImaginary());

			if (error < HIT_THRESHOLD) {
				++hits;
			} else {
				if (error > 1E300)
					error = 1E300;

				totalError += Math.log1p(error);
			}
		}

		totalError /= this.testCases.size();

		KozaFitness f = (KozaFitness) ind.fitness;
		f.hits = hits;
		f.setStandardizedFitness(state, (float) totalError);
	}

	@Override
	public ISemantics getTargetSemantics() {
		throw new RuntimeException("Not implemented");
	}
	
	@Override
	public List<TestCase<Complex>> getFitnessCases() {
		return this.testCases;
	}

}
