package jcgp.backend.modules.problem; import jcgp.backend.function.SymbolicRegressionFunctions; import jcgp.backend.population.Chromosome; import jcgp.backend.population.Population; import jcgp.backend.resources.Resources; import jcgp.backend.resources.parameters.BooleanParameter; import jcgp.backend.resources.parameters.DoubleParameter; import jcgp.backend.resources.parameters.Parameter; import jcgp.backend.resources.parameters.ParameterStatus; public class SymbolicRegressionProblem extends TestCaseProblem { private DoubleParameter errorThreshold, perfectionThreshold; private BooleanParameter hitsBasedFitness; public SymbolicRegressionProblem(Resources resources) { super(resources); functionSet = new SymbolicRegressionFunctions(); setProblemName("Symbolic regression"); setFileExtension(".dat"); errorThreshold = new DoubleParameter(0.01, "Error threshold") { @Override public void validate(Number newValue) { if (newValue.doubleValue() < 0) { status = ParameterStatus.INVALID; status.setDetails("Error threshold must be a positive value."); } else if (newValue.doubleValue() == 0) { status = ParameterStatus.WARNING; status.setDetails("An error threshold of 0 is very rigorous and difficult to achieve."); } else { status = ParameterStatus.VALID; } } }; perfectionThreshold = new DoubleParameter(0.000001, "Perfection threshold") { @Override public void validate(Number newValue) { if (newValue.doubleValue() < 0) { status = ParameterStatus.INVALID; status.setDetails("Perfection threshold must be a positive value."); } else if (newValue.doubleValue() == 0) { status = ParameterStatus.WARNING; status.setDetails("A perfection threshold of 0 is very rigorous and difficult to achieve."); } else { status = ParameterStatus.VALID; } } }; hitsBasedFitness = new BooleanParameter(true, "HITS-based fitness") { @Override public void validate(Boolean newValue) { // blank } }; } @Override public void evaluate(Population population, Resources resources) { // for every chromosome in the population for (int i = 0; i < resources.populationSize(); i++) { // assume an initial fitness of 0 double fitness = 0; // for each test case for (int t = 0; t < testCases.size(); t++) { population.getChromosome(i).setInputs((Object[]) testCases.get(t).getInputs()); // check each output for (int o = 0; o < resources.outputs(); o++) { Double cgpValue = (Double) population.getChromosome(i).getOutput(o).calculate(); Double dataValue = testCases.get(t).getOutput(o); if (hitsBasedFitness.get()) { if (Math.abs(cgpValue - dataValue) <= errorThreshold.get()) { fitness++; } } else { fitness += 1 - Math.abs(cgpValue - dataValue); } } } // assign the resulting fitness to the respective individual population.getChromosome(i).setFitness(fitness); } // sort population population.sortAscending(); } @Override public void addTestCase(String[] inputs, String[] outputs) { Double[] inputCases = new Double[inputs.length]; Double[] outputCases = new Double[outputs.length]; for (int i = 0; i < inputCases.length; i++) { inputCases[i] = Double.parseDouble(inputs[i]); } for (int o = 0; o < outputCases.length; o++) { outputCases[o] = Double.parseDouble(outputs[o]); } addTestCase(new TestCase(inputCases, outputCases)); } @Override public boolean isPerfectSolution(Chromosome fittest) { return fittest.getFitness() >= maxFitness.get() - perfectionThreshold.get(); } @Override public Parameter[] getLocalParameters() { return new Parameter[]{maxFitness, errorThreshold, perfectionThreshold, hitsBasedFitness}; } }