package ac.essex.gp.problems.examples.maths;

import ac.essex.gp.params.GPParams;
import ac.essex.gp.params.NodeConstraints;
import ac.essex.gp.individuals.Individual;
import ac.essex.gp.problems.DataStack;
import ac.essex.gp.nodes.*;
import ac.essex.gp.Evolve;
import ac.essex.gp.tree.NodeExecutor;
import ac.essex.gp.util.GPStartDialog;
import ac.essex.gp.interfaces.graphical.GraphicalListener;
import ac.essex.gp.interfaces.console.ConsoleListener;
import ac.essex.gp.problems.Problem;
import ac.essex.gp.nodes.X;
import ac.essex.gp.nodes.math.Squared;
import ac.essex.gp.nodes.ercs.CustomRangeIntegerERC;
import ac.essex.ooechs.imaging.commons.fast.FastStatistics;

/**
 * The Simplest Example GP Problem
 *
 * Attempts to find a GP program which can find the function f(x) which relates
 * one number to the other.
 *
 * @author Olly Oechsle, University of Essex, Date: 15-Jan-2007
 * @version 1.0
 */
public class MathsProblem extends Problem {

    public static void main(String[] args) {
        Evolve.seed = 2357;

        FastStatistics f = new FastStatistics();

        for (int i = 0; i < 20; i++) {
            Evolve.seed++;
        MathsProblem p = new MathsProblem();
        long start = System.currentTimeMillis();
        Evolve e = new Evolve(p, new ConsoleListener(ConsoleListener.LOW_VERBOSITY));
        e.run();
        long end = System.currentTimeMillis();
        //System.out.println("Time: " + (end - start));
        //System.out.println(e.getBestIndividual().getTree(0).toLisp());
            float fitness = (float) e.getBestIndividual().getKozaFitness();
            f.addData(fitness);
            System.out.println("Fitness: " + fitness);
            
        }

        System.out.println("---");
        System.out.print(f.getMean());
        System.out.println(" +- " + f.getStandardDeviation());

    }

    public String getName() {
        return "Maths Problem";
    }

    public void initialise(Evolve e, GPParams params) {

        // register the nodes we want to use
        params.registerNode(new Add());
        params.registerNode(new Mul());
        params.registerNode(new Sub());
        params.registerNode(new Div());
        params.registerNode(new X());
        params.registerNode(new Squared());
        params.registerNode(new CustomRangeIntegerERC(0,10));

        // set up additional parameters
        params.setReturnType(NodeConstraints.NUMBER);

    }

    public void customiseParameters(GPParams params) {
        params.setPopulationSize(500);
        params.setGenerations(50);
        //params.setDynamicSizeLimiting(true);
        params.setTreeBuilder(GPParams.RAMPED_HALF_AND_HALF);
    }

    public void evaluate(Individual ind, DataStack data, Evolve e) {

        double fitness = 0;

        int hits = 0;

        // try a few different values of X
        for (int x = 2; x < 100; x++) {

            // maths problem - the function we expect
            double expected = Math.sqrt(x);

            // put this into the data stack
            data.setX(x);

            // see what we get back
            double received = ind.execute(data); //NodeExecutor.executeFast(ind.trees[0], data);//ind.execute(data);

            // count the number of hits
            if (received == expected) hits++;

            // regression - find the difference between expected and received
            fitness += Math.abs(expected - received);

        }

        ind.setKozaFitness(fitness);
        ind.setHits(hits);

    }

}
