Source

GrayIbis / src / main / scala / pl / put / regression / RegressionProblem.scala

Full commit
package pl.put.regression

import ec.simple.SimpleProblemForm
import ec.Problem
import ec.EvolutionState
import ec.util.Parameter
import ec.gp.koza.KozaFitness
import ec.Individual

/**
 * Base class for regression problems. Responsible for iterating through test cases,
 * loading them, applying metrics to the result and so on...
 * 
 * TODO: the applied metric should be changeable, the precision levels should also be changeable.
 */
abstract trait RegressionProblem {

    // precision goes in the percentage - this is one of hundred 
    val precision = 0.01
    val penalty = 1000

    protected var testCaseReader: ITestCaseReader = null
    protected var testCases: Seq[(RegressionCase, Double)] = null

    protected def loadTestCases(state: EvolutionState, base: Parameter) = {

        // TODO: make test case reading injected
        testCaseReader = new ExtendedFileTestCaseReader()
        testCases = testCaseReader.load(state, base)
    }

    protected def evaluateTestCase(testCase: RegressionCase, state: EvolutionState, thread: Int): Double

    def evaluateTestCases(state: EvolutionState, ind: Individual, thread: Int) = {
        var sumError = 0.0
        var sumHits = 0

        for (testCase <- testCases) {
            val (input, output) = testCase

            val y = this.evaluateTestCase(input, state, thread)

            // setting penalty must be done on this level (this is NaN)
            val error = if (y != y) {
                penalty
            } else {
                // NOTE: this code as a metric should be done as injectable one !
                math.abs(y - output)
            }

            if (error <= 0.01) {
                sumHits += 1
            } else {
                sumError += error
            }
        }

        // the first condition is NaN checking which is missing from Scala
        // the last condition is for values which may excess Float.MaxValue
        if (sumError != sumError || Float.PositiveInfinity == sumError || Float.NegativeInfinity == sumError || sumError >= Float.MaxValue) {
            sumError = Float.MaxValue
        }

        val kozaFitness = ind.fitness.asInstanceOf[KozaFitness]
        kozaFitness.setStandardizedFitness(state, sumError.toFloat)
        kozaFitness.hits = sumHits
        ind.evaluated = true
    }
}