aboutsummaryrefslogtreecommitdiffstats
path: root/src/jcgp/backend/modules/problem/SymbolicRegressionProblem.java
blob: 52df0f24948ddc8b96084b796f96ab8dee917d0d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package jcgp.backend.modules.problem;

import jcgp.backend.function.DoubleArithmetic;
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<Double> {
	
	private DoubleParameter errorThreshold, perfectionThreshold;
	private BooleanParameter hitsBasedFitness;
	
	public SymbolicRegressionProblem(Resources resources) {
		super(resources);
		functionSet = new DoubleArithmetic();
		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) {
		// set fittest to 0, change it whenever a fitter one is found
		population.setFittest(0);
		
		// 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);
			if (fitness >= population.getFittest().getFitness()) {
				population.setFittest(i);
			}
		}
	}
	
	
	@Override
	public String toString() {
		return "Symbolic regression";
	}

	@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<Double>(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};
	}

	@Override
	public String getFileExtension() {
		return ".dat";
	}
}