/*
  Copyright 2006 by Sean Luke
  Licensed under the Academic Free License version 3.0
  See the file "LICENSE" for more information
*/


package ec.app.push;
import ec.gp.push.*;
import org.spiderland.Psh.*;
import ec.util.*;
import ec.*;
import ec.gp.*;
import ec.gp.koza.*;
import ec.simple.*;
import java.io.*;
import java.util.*;

public class Regression extends PushProblem implements SimpleProblemForm
    {
    private static final long serialVersionUID = 1;

    public static final String P_SIZE = "size";
    public static final String P_FILE = "file";
    public static final String P_USE_FUNCTION = "use-function";
    public static final String P_MAX_STEPS = "max-steps";

    public int trainingSetSize;
    public boolean useFunction;  // if we have a file, should we use the function to compute the output values?  Or are they also contained?
    
    // these are read-only during evaluation-time, so
    // they can be just light-cloned and not deep cloned.
    // cool, huh?
    
    public double inputs[];
    public double outputs[];

    public double func(double x)
        { return x*x*x*x + x*x*x + x*x + x; }

    public void setup(final EvolutionState state,
        final Parameter base)
        {
        // very important, remember this
        super.setup(state,base);

        trainingSetSize = state.parameters.getInt(base.push(P_SIZE),null,1);
        if (trainingSetSize<1) state.output.fatal("Training Set Size must be an integer greater than 0", base.push(P_SIZE)); 

        // should we load our x parameters from a file, or generate them randomly?
        //file = state.parameters.getFile(base.push(P_FILE), null);
        InputStream inputfile = state.parameters.getResource(base.push(P_FILE), null);

        // *IF* we load from a file, should we generate the output through the function, or load the output as well?
        useFunction = state.parameters.getBoolean(base.push(P_USE_FUNCTION), null, true);

        // Compute our inputs so they can be copied with clone later
        inputs = new double[trainingSetSize];
        outputs = new double[trainingSetSize];
        
        //if (file != null)  // use the file
        if (inputfile != null)
            {
            try
                {
                Scanner scan = new Scanner(inputfile);
                for(int x = 0; x < trainingSetSize; x++)
                    {
                    if (scan.hasNextDouble())
                        inputs[x] = scan.nextDouble();
                    else state.output.fatal("Not enough data points in file: expected " + (trainingSetSize * (useFunction ? 1 : 2)));
                    if (!useFunction)
                        {
                        if (scan.hasNextDouble())
                            outputs[x] = scan.nextDouble();
                        else state.output.fatal("Not enough data points in file: expected " + (trainingSetSize * (useFunction ? 1 : 2)));
                        }
                    }
                }
            catch (NumberFormatException e)
                {
                state.output.fatal("Some tokens in the file were not numbers.");
                }
            }
        else for(int x=0;x 0) // need to reset first
                    resetInterpreter(interpreter);
                
                // load it up and run it
                pushOntoFloatStack(interpreter, (float)(inputs[y]));
                executeProgram(program, interpreter, maxSteps);

                // It's possible to get NaN because cos(infinity) and
                // sin(infinity) are undefined (hence cos(exp(3000)) zings ya!)
                // So since NaN is NOT =,<,>,etc. any other number, including
                // NaN, we're CAREFULLY wording our cutoff to include NaN.
                // Interesting that this has never been reported before to
                // my knowledge.

                final double HIT_LEVEL = 0.01;
                final double PROBABLY_ZERO = 1E-6;  // The Psh interpreter seems less accurate, not sure why
                final double BIG_NUMBER = 1.0e15;  // the same as lilgp uses

                result = Math.abs(outputs[y] - topOfFloatStack(interpreter));  // will be 0 if float stack is empty

                if (! (result < BIG_NUMBER ) )   // *NOT* (input.x >= BIG_NUMBER)
                    result = BIG_NUMBER;

                if (isFloatStackEmpty(interpreter)) // uh oh, invalid value
                    result = BIG_NUMBER;

                // very slight math errors can creep in when evaluating
                // two equivalent by differently-ordered functions, like
                // x * (x*x*x + x*x)  vs. x*x*x*x + x*x

                else if (result 

Ads help maintain this website.