aboutsummaryrefslogtreecommitdiffstats
path: root/src/jcgp/backend/modules/problem/TestCaseProblem.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jcgp/backend/modules/problem/TestCaseProblem.java')
-rw-r--r--src/jcgp/backend/modules/problem/TestCaseProblem.java148
1 files changed, 95 insertions, 53 deletions
diff --git a/src/jcgp/backend/modules/problem/TestCaseProblem.java b/src/jcgp/backend/modules/problem/TestCaseProblem.java
index 7ce0327..c11fab4 100644
--- a/src/jcgp/backend/modules/problem/TestCaseProblem.java
+++ b/src/jcgp/backend/modules/problem/TestCaseProblem.java
@@ -1,100 +1,144 @@
package jcgp.backend.modules.problem;
import java.io.File;
-import java.util.List;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import jcgp.backend.parsers.TestCaseParser;
import jcgp.backend.resources.ModifiableResources;
import jcgp.backend.resources.Resources;
-import jcgp.backend.resources.parameters.DoubleParameter;
-import jcgp.backend.resources.parameters.Parameter;
/**
+ * Abstract model for a problem that uses test cases. A test case
+ * problem is any problem that compares the chromosome output to
+ * an expected output taken from a table of input-output mappings.
+ * <br><br>
+ * This class defines a basic data type for storing test cases,
+ * TestCase, and provides core functionality to add and manipulate
+ * test cases in the problem. A subclass of {@code TestCaseProblem}
+ * must simply override {@code parseTestCase()} to convert parsed
+ * problem data strings into the required data type (T).
*
- * This fitness function module implements a simple test case evaluator.
- *
- * A TestCase object is a
- *
- *
+ * @see Problem
* @author Eduardo Pedroni
- *
+ * @param <T> the data type to be used by the TestCaseProblem.
*/
-public abstract class TestCaseProblem<U extends Object> extends Problem {
+public abstract class TestCaseProblem<T> extends Problem {
- public static class TestCase<T> {
- private T[] inputs;
- private T[] outputs;
+ /**
+ * Basic data type for encapsulating test cases, it simply
+ * contains arrays of inputs and outputs and associated getters.
+ *
+ * @author Eduardo Pedroni
+ * @param <U>
+ */
+ public static class TestCase<U> {
+ private U[] inputs;
+ private U[] outputs;
- public TestCase(T[] inputs, T[] outputs) {
+ /**
+ * Creates a new test case, inputs and outputs
+ * must be specified upon instantiation.
+ *
+ * @param inputs the array of inputs.
+ * @param outputs the array of outputs.
+ */
+ public TestCase(U[] inputs, U[] outputs) {
this.inputs = inputs;
this.outputs = outputs;
}
- public T getInput(int index) {
+ /**
+ * @param index the index to return.
+ * @return the indexed input.
+ */
+ public U getInput(int index) {
return inputs[index];
}
- public T getOutput(int index) {
+ /**
+ * @param index the index to return.
+ * @return the indexed output.
+ */
+ public U getOutput(int index) {
return outputs[index];
}
- public T[] getInputs() {
+ /**
+ * @return the complete array of inputs.
+ */
+ public U[] getInputs() {
return inputs;
}
- public T[] getOutputs() {
+ /**
+ * @return the complete array of outputs.
+ */
+ public U[] getOutputs() {
return outputs;
}
}
- protected ObservableList<TestCase<U>> testCases;
- protected DoubleParameter maxFitness;
+ protected ObservableList<TestCase<T>> testCases;
protected Resources resources;
+ /**
+ * Creates a new TestCaseProblem object.
+ *
+ * @param resources a reference to the experiment's resources.
+ */
public TestCaseProblem(Resources resources) {
super();
-
this.resources = resources;
-
- maxFitness = new DoubleParameter(0, "Max fitness", true, false) {
- @Override
- public void validate(Number newValue) {
- // blank
- }
- };
testCases = FXCollections.observableArrayList();
}
- @Override
- public Parameter<?>[] getLocalParameters() {
- return new Parameter[]{maxFitness};
- }
-
+ /**
+ * For internal use only, this method computes and returns the maximum fitness
+ * based on the number of test cases. Subclasses should override this method
+ * as necessary.
+ *
+ * @return the maximum fitness based on number of test cases.
+ */
protected double getMaxFitness() {
int fitness = 0;
-
- for (TestCase<U> tc : testCases) {
+ for (TestCase<T> tc : testCases) {
fitness += tc.getOutputs().length;
}
-
return fitness;
}
- public void setTestCases(List<TestCase<U>> testCases) {
- this.testCases.clear();
- this.testCases.addAll(testCases);
- maxFitness.set(getMaxFitness());
- }
-
- public ObservableList<TestCase<U>> getTestCases() {
+ /**
+ * @return a list containing the test cases.
+ */
+ public ObservableList<TestCase<T>> getTestCases() {
return testCases;
}
- public abstract void addTestCase(String[] inputs, String[] outputs);
+ /**
+ * This method is used internally by {@code addTestCase()} in order
+ * to appropriately parse strings into the right data type for the
+ * test cases. Since the data type is problem-dependent, subclasses must
+ * implement this method. This method must return a built {@code TestCase}
+ * object from the arguments given.
+ *
+ * @param inputs the inputs represented as strings.
+ * @param outputs the outputs represented as strings.
+ * @return the parsed test case.
+ */
+ protected abstract TestCase<T> parseTestCase(String[] inputs, String[] outputs);
- protected final void addTestCase(TestCase<U> testCase) {
+ /**
+ * Adds test cases to the problem instance as they get parsed from a
+ * problem data file. This template method uses {@code parseTestCase}, which
+ * must be implemented by subclasses.
+ *
+ * @param inputs the inputs represented as strings.
+ * @param outputs the outputs represented as strings.
+ */
+ public final void addTestCase(String[] inputs, String[] outputs) {
+ TestCase<T> testCase = parseTestCase(inputs, outputs);
+
if (testCase.getInputs().length != resources.inputs()) {
throw new IllegalArgumentException("Received test case with " + testCase.getInputs().length +
" inputs but need exactly " + resources.inputs());
@@ -106,20 +150,18 @@ public abstract class TestCaseProblem<U extends Object> extends Problem {
maxFitness.set(getMaxFitness());
}
}
-
- public int getInputCount() {
- return resources.inputs();
- }
-
- public int getOutputCount() {
- return resources.outputs();
- }
+ /**
+ * Remove all test cases.
+ */
public void clearTestCases() {
testCases.clear();
+ maxFitness.set(getMaxFitness());
}
+ @Override
public void parseProblemData(File file, ModifiableResources resources) {
+ // use standard test case parser for this
TestCaseParser.parse(file, this, resources);
}
}