diff options
Diffstat (limited to 'src/jcgp/backend/modules/problem/TestCaseProblem.java')
-rw-r--r-- | src/jcgp/backend/modules/problem/TestCaseProblem.java | 148 |
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); } } |