Source

GrayIbis / src / main / scala / pl / put / regression / psh / ClassicIntegerPshRegressionProblem.scala

package pl.put.regression.psh

import org.ecj.psh.PshEvaluator
import org.ecj.psh.PshIndividual
import org.ecj.psh.PshEvolutionState
import org.spiderland.Psh.Interpreter
import org.spiderland.Psh.Program
import ec.EvolutionState
import ec.Individual
import ec.Problem
import ec.simple.SimpleProblemForm
import ec.util.Parameter
import pl.put.regression.RegressionCase
import pl.put.regression.RegressionProblem
import org.ecj.psh.PshProblem

/**
 * Concrete class implementing the symbolic regression problem with PushGP. Based on
 * work by Tomasz Kamiński from ecj-psh.
 *
 * Works on the integer domain.
 */
class ClassicIntegerPshRegressionProblem extends PshProblem with RegressionProblem {

    // there protected values are used by inherited classes
    protected var interpreter: Interpreter = null
    protected var program: Program = null

    val P_REPEATINTSTACK = "repeat-stack"
    private var repeatsInStack = 10

    override def setup(state: EvolutionState, base: Parameter) = {
        super.setup(state, base)

        // use the method defined in regression problem to load the test cases
        loadTestCases(state, base)

        repeatsInStack = state.parameters.getIntWithDefault(base.push(P_REPEATINTSTACK), null, 1);

        // safe check
        state.output.exitIfErrors()
    }

    override def evaluate(state: EvolutionState, ind: Individual, subpopulation: Int, thread: Int): Unit = {

        if (ind.evaluated) {
            return
        }

        // get interpreter
        val evaluator = state.evaluator.asInstanceOf[PshEvaluator]
        interpreter = state.asInstanceOf[PshEvolutionState].interpreter(thread)

        // get program from the individuals
        program = ind.asInstanceOf[PshIndividual].program

        // go with the code from regression problem
        evaluateTestCases(state, ind, thread)

    }

    override def evaluateTestCase(testCase: RegressionCase, state: EvolutionState, thread: Int): Double = {

        interpreter.ClearStacks()

        // pushing input value to float stack
        for (i <- 0 until repeatsInStack) {
            for (value <- testCase.variables) {

                interpreter.intStack().push(value.toInt)
            }
        }

        // setting input value to input stack
        interpreter.inputStack.push(testCase.variables.head)

        // executing the program
        interpreter.Execute(program, interpreter.getExecutionLimit());

        // penalize individual if there is no result on the stack
        // passing NaN means that penalization is maximal
        if (interpreter.intStack().size() == 0) {
            return Float.NaN
        }

        // return the first element from the stack
        return interpreter.intStack().top()
    }
}