aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/README (renamed from README)0
-rw-r--r--res/cgp0.chr (renamed from src/cgp0.chr)0
-rw-r--r--res/epar3.plu (renamed from src/epar3.plu)0
-rw-r--r--res/mult2.plu (renamed from src/mult2.plu)0
-rw-r--r--res/parameters.par (renamed from src/parameters.par)0
-rw-r--r--res/quintic-polynomial.dat (renamed from src/quintic-polynomial.dat)0
-rw-r--r--res/test (renamed from test)0
-rw-r--r--res/test.chr (renamed from test.chr)0
-rw-r--r--res/test~ (renamed from test~)0
-rw-r--r--src/jcgp/JCGP.java6
-rw-r--r--src/jcgp/backend/exceptions/InsufficientConnectionsException.java10
-rw-r--r--src/jcgp/backend/exceptions/InvalidArgumentsException.java20
-rw-r--r--src/jcgp/backend/exceptions/ParameterMismatchException.java10
-rw-r--r--src/jcgp/backend/modules/es/MuPlusLambda.java10
-rw-r--r--src/jcgp/backend/modules/mutator/ProbabilisticMutator.java8
-rw-r--r--src/jcgp/backend/modules/problem/Problem.java21
-rw-r--r--src/jcgp/backend/modules/problem/TestCaseProblem.java3
-rw-r--r--src/jcgp/backend/modules/problem/TravellingSalesmanProblem.java2
-rw-r--r--src/jcgp/backend/parsers/ChromosomeParser.java14
-rw-r--r--src/jcgp/backend/parsers/FunctionParser.java75
-rw-r--r--src/jcgp/backend/parsers/ParameterParser.java117
-rw-r--r--src/jcgp/backend/parsers/TestCaseParser.java74
-rw-r--r--src/jcgp/backend/population/Chromosome.java5
-rw-r--r--src/jcgp/backend/population/Node.java19
-rw-r--r--src/jcgp/backend/tests/ChromosomeTests.java10
-rw-r--r--src/jcgp/backend/tests/NodeTests.java13
-rw-r--r--src/jcgp/backend/tests/TestFunctionSet.java54
27 files changed, 287 insertions, 184 deletions
diff --git a/README b/res/README
index b73e257..b73e257 100644
--- a/README
+++ b/res/README
diff --git a/src/cgp0.chr b/res/cgp0.chr
index 3157c03..3157c03 100644
--- a/src/cgp0.chr
+++ b/res/cgp0.chr
diff --git a/src/epar3.plu b/res/epar3.plu
index b554b66..b554b66 100644
--- a/src/epar3.plu
+++ b/res/epar3.plu
diff --git a/src/mult2.plu b/res/mult2.plu
index e629d28..e629d28 100644
--- a/src/mult2.plu
+++ b/res/mult2.plu
diff --git a/src/parameters.par b/res/parameters.par
index bf38c11..bf38c11 100644
--- a/src/parameters.par
+++ b/res/parameters.par
diff --git a/src/quintic-polynomial.dat b/res/quintic-polynomial.dat
index 347b95a..347b95a 100644
--- a/src/quintic-polynomial.dat
+++ b/res/quintic-polynomial.dat
diff --git a/test b/res/test
index 2957b44..2957b44 100644
--- a/test
+++ b/res/test
diff --git a/test.chr b/res/test.chr
index 34664df..34664df 100644
--- a/test.chr
+++ b/res/test.chr
diff --git a/test~ b/res/test~
index 2957b44..2957b44 100644
--- a/test~
+++ b/res/test~
diff --git a/src/jcgp/JCGP.java b/src/jcgp/JCGP.java
index 1e6d628..f36ac7c 100644
--- a/src/jcgp/JCGP.java
+++ b/src/jcgp/JCGP.java
@@ -264,13 +264,13 @@ public class JCGP {
}
public void loadParameters(File file) {
- ParameterParser.parseParameters(file, resources);
- FunctionParser.parseFunctions(file, problem, resources);
+ ParameterParser.parse(file, resources);
+ FunctionParser.parse(file, problem.getFunctionSet(), resources);
reset();
}
public void loadProblemData(File file) {
- problem.parse(file, resources);
+ problem.parseProblemData(file, resources);
reset();
}
diff --git a/src/jcgp/backend/exceptions/InsufficientConnectionsException.java b/src/jcgp/backend/exceptions/InsufficientConnectionsException.java
deleted file mode 100644
index 15ac845..0000000
--- a/src/jcgp/backend/exceptions/InsufficientConnectionsException.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package jcgp.backend.exceptions;
-
-public class InsufficientConnectionsException extends RuntimeException {
-
- /**
- *
- */
- private static final long serialVersionUID = 660740514800883541L;
-
-}
diff --git a/src/jcgp/backend/exceptions/InvalidArgumentsException.java b/src/jcgp/backend/exceptions/InvalidArgumentsException.java
deleted file mode 100644
index bbae976..0000000
--- a/src/jcgp/backend/exceptions/InvalidArgumentsException.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package jcgp.backend.exceptions;
-
-public class InvalidArgumentsException extends RuntimeException {
-
- /**
- *
- */
- private static final long serialVersionUID = 2675108124600817777L;
- private String reason;
-
- public InvalidArgumentsException(String reason) {
- super();
- this.reason = reason;
- }
-
- public String getReason() {
- return reason;
- }
-
-}
diff --git a/src/jcgp/backend/exceptions/ParameterMismatchException.java b/src/jcgp/backend/exceptions/ParameterMismatchException.java
deleted file mode 100644
index 83e2ba2..0000000
--- a/src/jcgp/backend/exceptions/ParameterMismatchException.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package jcgp.backend.exceptions;
-
-public class ParameterMismatchException extends RuntimeException {
-
- /**
- *
- */
- private static final long serialVersionUID = -3161318886125868134L;
-
-}
diff --git a/src/jcgp/backend/modules/es/MuPlusLambda.java b/src/jcgp/backend/modules/es/MuPlusLambda.java
index 50bf265..754e89b 100644
--- a/src/jcgp/backend/modules/es/MuPlusLambda.java
+++ b/src/jcgp/backend/modules/es/MuPlusLambda.java
@@ -76,6 +76,11 @@ public class MuPlusLambda implements EvolutionaryStrategy {
}
@Override
+ public Parameter<?>[] getLocalParameters() {
+ return new Parameter[] {mu, lambda, report};
+ }
+
+ @Override
public void evolve(Population population, Mutator mutator, Resources resources) {
/* Population is sorted in ascending order of fitness, so leave the last
* mu chromosomes intact
@@ -95,11 +100,6 @@ public class MuPlusLambda implements EvolutionaryStrategy {
}
@Override
- public Parameter<?>[] getLocalParameters() {
- return new Parameter[] {mu, lambda, report};
- }
-
- @Override
public String toString() {
return "(μ + λ)";
}
diff --git a/src/jcgp/backend/modules/mutator/ProbabilisticMutator.java b/src/jcgp/backend/modules/mutator/ProbabilisticMutator.java
index e3c1d03..cacb451 100644
--- a/src/jcgp/backend/modules/mutator/ProbabilisticMutator.java
+++ b/src/jcgp/backend/modules/mutator/ProbabilisticMutator.java
@@ -70,7 +70,7 @@ public class ProbabilisticMutator implements Mutator {
for (int c = 0; c < resources.columns(); c++) {
// go through all connections
for (int a = 0; a < resources.arity(); a++) {
- if (mutate()) {
+ if (mutateGene()) {
Node n = chromosome.getNode(r, c);
if (report.get()) resources.report("[Mutator] Mutating " + n +
@@ -83,7 +83,7 @@ public class ProbabilisticMutator implements Mutator {
}
}
// deal with node function next
- if (mutate()) {
+ if (mutateGene()) {
Node n = chromosome.getNode(r, c);
if (report.get()) resources.report("[Mutator] Mutating " + n +
", changed function from " + n.getFunction());
@@ -96,7 +96,7 @@ public class ProbabilisticMutator implements Mutator {
}
// finally, mutate outputs
for (int o = 0; o < resources.outputs(); o++) {
- if (mutate()) {
+ if (mutateGene()) {
Output out = chromosome.getOutput(o);
if (report.get()) resources.report("[Mutator] Mutating " + out +
@@ -120,7 +120,7 @@ public class ProbabilisticMutator implements Mutator {
*
* @return true if a mutation should be performed, false if otherwise.
*/
- private boolean mutate() {
+ private boolean mutateGene() {
return resources.getRandomDouble(100) < mutationProbability.get();
}
diff --git a/src/jcgp/backend/modules/problem/Problem.java b/src/jcgp/backend/modules/problem/Problem.java
index 07183ea..368d512 100644
--- a/src/jcgp/backend/modules/problem/Problem.java
+++ b/src/jcgp/backend/modules/problem/Problem.java
@@ -9,6 +9,25 @@ import jcgp.backend.population.Population;
import jcgp.backend.resources.ModifiableResources;
import jcgp.backend.resources.Resources;
+/**
+ * Defines the general behaviour of a CGP problem. The primary function of Problem
+ * is to evaluate a population and assign
+ * <br><br>
+ * Parameters may be specified to control the implemented problem. Any parameters
+ * returned by {@code getLocalParameters()} should be displayed by the user interface,
+ * if it is being used. See {@link Parameter} for more information.
+ * <br><br>
+ * It is advisable to use {@code Resources.reportln()} and {@code Resources.report()}
+ * to print any relevant information. Note that reportln() and report() are affected
+ * by the report interval base parameter. Use {@code Resources.println()} and
+ * {@code Resources.print()} to print information regardless of the current generation.
+ * See {@link Resources} for more information.
+ *
+ * @see Module
+ *
+ * @author Eduardo Pedroni
+ *
+ */
public abstract class Problem implements Module {
protected FunctionSet functionSet;
@@ -23,7 +42,7 @@ public abstract class Problem implements Module {
public abstract boolean isPerfectSolution(Chromosome fittest);
- public abstract void parse(File file, ModifiableResources resources);
+ public abstract void parseProblemData(File file, ModifiableResources resources);
public void setFileExtension(String fileExtension) {
this.fileExtension = fileExtension;
diff --git a/src/jcgp/backend/modules/problem/TestCaseProblem.java b/src/jcgp/backend/modules/problem/TestCaseProblem.java
index 6c4a7dc..7ce0327 100644
--- a/src/jcgp/backend/modules/problem/TestCaseProblem.java
+++ b/src/jcgp/backend/modules/problem/TestCaseProblem.java
@@ -119,8 +119,7 @@ public abstract class TestCaseProblem<U extends Object> extends Problem {
testCases.clear();
}
- public void parse(File file, ModifiableResources resources) {
- TestCaseParser.parseParameters(file, resources);
+ public void parseProblemData(File file, ModifiableResources resources) {
TestCaseParser.parse(file, this, resources);
}
}
diff --git a/src/jcgp/backend/modules/problem/TravellingSalesmanProblem.java b/src/jcgp/backend/modules/problem/TravellingSalesmanProblem.java
index 6491ec6..8363ef8 100644
--- a/src/jcgp/backend/modules/problem/TravellingSalesmanProblem.java
+++ b/src/jcgp/backend/modules/problem/TravellingSalesmanProblem.java
@@ -36,7 +36,7 @@ public class TravellingSalesmanProblem extends Problem {
}
@Override
- public void parse(File file, ModifiableResources resources) {
+ public void parseProblemData(File file, ModifiableResources resources) {
// TODO Auto-generated method stub
}
diff --git a/src/jcgp/backend/parsers/ChromosomeParser.java b/src/jcgp/backend/parsers/ChromosomeParser.java
index ed1399a..92568cc 100644
--- a/src/jcgp/backend/parsers/ChromosomeParser.java
+++ b/src/jcgp/backend/parsers/ChromosomeParser.java
@@ -14,7 +14,7 @@ import jcgp.backend.resources.ModifiableResources;
import jcgp.backend.resources.Resources;
/**
- * This class includes a method for parsing .chr files and another
+ * This class contains a method for parsing .chr files and another
* for writing .chr files from given chromosomes.
*
* @author Eduardo Pedroni
@@ -50,7 +50,7 @@ public abstract class ChromosomeParser {
try {
fr = new FileReader(file);
} catch (FileNotFoundException e) {
- resources.println("[Parser] Error: could not find " + file.getAbsolutePath() + ".");
+ resources.println("[Parser] Error: could not find " + file.getAbsolutePath());
return;
}
Scanner in = new Scanner(fr);
@@ -70,7 +70,7 @@ public abstract class ChromosomeParser {
try {
fr = new FileReader(file);
} catch (FileNotFoundException e) {
- resources.println("[Parser] Error: could not find " + file.getAbsolutePath() + ".");
+ resources.println("[Parser] Error: could not find " + file.getAbsolutePath());
return;
}
in = new Scanner(fr);
@@ -122,10 +122,10 @@ public abstract class ChromosomeParser {
}
in.close();
- resources.println("[Parser] File parsed successfully.");
+ resources.println("[Parser] File parsed successfully");
} else {
- resources.println("[Parser] Error: the topology of the chromosome in " + file.getName() + " does not match that of the experiment.");
+ resources.println("[Parser] Error: the topology of the chromosome in " + file.getName() + " does not match that of the experiment");
}
}
@@ -143,7 +143,7 @@ public abstract class ChromosomeParser {
try {
writer = new PrintWriter(file);
} catch (FileNotFoundException e) {
- resources.println("[Parser] Error: could not find " + file.getAbsolutePath() + ".");
+ resources.println("[Parser] Error: could not find " + file.getAbsolutePath());
return;
}
@@ -184,7 +184,7 @@ public abstract class ChromosomeParser {
writer.close();
- resources.println("[Parser] Chromosome saved successfully.");
+ resources.println("[Parser] Chromosome saved successfully");
}
}
diff --git a/src/jcgp/backend/parsers/FunctionParser.java b/src/jcgp/backend/parsers/FunctionParser.java
index cc52ce9..806099e 100644
--- a/src/jcgp/backend/parsers/FunctionParser.java
+++ b/src/jcgp/backend/parsers/FunctionParser.java
@@ -6,21 +6,35 @@ import java.io.FileReader;
import java.util.Scanner;
import jcgp.backend.function.FunctionSet;
-import jcgp.backend.modules.problem.Problem;
-import jcgp.backend.resources.ModifiableResources;
+import jcgp.backend.resources.Resources;
/**
- * Parses the functions from a .par file.
- * Functions marked with a 1 are enabled,
- * and those marked with 0 are disabled.
+ * Contains a static method for parsing functions from a
+ * .par file.
*
* @author Eduardo Pedroni
*
*/
public abstract class FunctionParser {
- public static void parseFunctions(File file, Problem problem, ModifiableResources resources) {
-
+ /**
+ * Reads the specified file and attempts to enable
+ * and disable the functions in the FunctionSet
+ * accordingly.
+ * <br><br>
+ * Standard CGP .par files do not contain enough information
+ * to determine if they match the currently selected function set.
+ * For this reason, the parser assumes the function set is correct
+ * and treats functions by their index rather than their name. Any
+ * index outside the bounds of the function set is ignored and a
+ * warning message is printed once parsing is complete.
+ *
+ * @param file the .par file to parse.
+ * @param functionSet the function set whose functions should be modified.
+ * @param resources used for printing console messages.
+ */
+ public static void parse(File file, FunctionSet functionSet, Resources resources) {
+ // create file reader and scanner to parse, return if file does not exist
FileReader fr;
try {
fr = new FileReader(file);
@@ -30,23 +44,56 @@ public abstract class FunctionParser {
}
Scanner in = new Scanner(fr);
- FunctionSet functionSet = problem.getFunctionSet();
+ boolean excessFunctions = false;
resources.println("[Parser] Parsing file: " + file.getAbsolutePath() + "...");
+ /*
+ * The encoding used in .par files is quite simple, so regex matches are used to extract
+ * the values.
+ *
+ * A standard .par file contains functions in the following format:
+ *
+ * 0 1 modulus-0
+ * 0 1 sqrt-1
+ * 0 1 reciprocal-2
+ *
+ * The first integer signals whether to enable or disable the function. Any non-zero value
+ * is treated as "enable". The second integer is the function arity. The integer following
+ * the function name is the function index.
+ *
+ * The scanner is used to return each line separately. Every line that ends in a number
+ * is treated as a function line and split into an array, which holds its composing integers.
+ * This array is then used to enable or disabled the indexed function.
+ *
+ * A flag is raised if the index exceeds the total number of functions, and a warning is
+ * printed once parsing is complete regarding the index mismatch.
+ *
+ */
while (in.hasNextLine()) {
String line = in.nextLine();
if (line.substring(line.length() - 1).matches("[0-9]")) {
String[] splitString = line.split("[^0-9]+");
int functionIndex = Integer.parseInt(splitString[splitString.length - 1]);
- if (Integer.parseInt(splitString[0]) != 0 && !functionSet.isEnabled(functionSet.getFunction(functionIndex))) {
- functionSet.enableFunction(functionIndex);
- resources.println("[Parser] Enabled function: " + functionSet.getFunction(functionIndex));
- } else if (Integer.parseInt(splitString[0]) == 0 && functionSet.isEnabled(functionSet.getFunction(functionIndex))) {
- functionSet.disableFunction(functionIndex);
- resources.println("[Parser] Disabled function: " + functionSet.getFunction(functionIndex));
+
+ if (functionIndex < functionSet.getTotalFunctionCount()) {
+ if (Integer.parseInt(splitString[0]) != 0) {
+ functionSet.enableFunction(functionIndex);
+ resources.println("[Parser] Enabled function: " + functionSet.getFunction(functionIndex));
+ } else if (Integer.parseInt(splitString[0]) == 0) {
+ functionSet.disableFunction(functionIndex);
+ resources.println("[Parser] Disabled function: " + functionSet.getFunction(functionIndex));
+ }
+ } else {
+ excessFunctions = true;
}
}
}
+
+ // warn the user function index went out of bounds
+ if (excessFunctions) {
+ resources.println("[Parser] Warning: the parameter file contained more functions than the current function set");
+ }
+
in.close();
resources.println("[Parser] Finished parsing functions");
}
diff --git a/src/jcgp/backend/parsers/ParameterParser.java b/src/jcgp/backend/parsers/ParameterParser.java
index ae72126..711b4d2 100644
--- a/src/jcgp/backend/parsers/ParameterParser.java
+++ b/src/jcgp/backend/parsers/ParameterParser.java
@@ -7,71 +7,94 @@ import java.util.Scanner;
import jcgp.backend.resources.ModifiableResources;
+/**
+ * Contains a static method for parsing parameters from a
+ * .par file.
+ *
+ * @author Eduardo Pedroni
+ *
+ */
public abstract class ParameterParser {
- public static void parseParameters(File file, ModifiableResources resources) {
-
+ /**
+ * Parses the parameters from a specified CGP parameter file and
+ * modifies the experiment resources appropriately.
+ * <br><br>
+ * CGP .par files do not follow a very strict convention, so this
+ * parser does its best to cope with format irregularities. Parsing
+ * works even if the parameters are in the wrong order, and unknown
+ * parameters are simply ignored.
+ *
+ * @param file the .par file to parse.
+ * @param resources a reference to the resources object that must be modified.
+ */
+ public static void parse(File file, ModifiableResources resources) {
+ // create reader and scanner, print message if file is missing
FileReader fr;
try {
fr = new FileReader(file);
} catch (FileNotFoundException e) {
- resources.println("[Parser] Error: could not find " + file.getAbsolutePath() + ".");
+ resources.println("[Parser] Error: could not find " + file.getAbsolutePath());
return;
}
Scanner in = new Scanner(fr);
resources.println("[Parser] Parsing file: " + file.getAbsolutePath() + "...");
+ // parse line by line
while (in.hasNextLine()) {
+ // split if one or more tabs or one or more spaces are found
String[] splitString = in.nextLine().split("( |\t)+");
-
- switch (splitString[1]) {
- case "population_size":
- resources.setPopulationSize(Integer.parseInt(splitString[0]));
- resources.println("[Parser] Population size is now " + resources.populationSize() + ".");
- break;
-
- case "num_generations":
- resources.setGenerations(Integer.parseInt(splitString[0]));
- resources.println("[Parser] Total generations is now " + resources.generations() + ".");
- break;
-
- case "num_runs_total":
- resources.setRuns(Integer.parseInt(splitString[0]));
- resources.println("[Parser] Total runs is now " + resources.runs() + ".");
- break;
-
- case "num_rows":
- resources.setRows(Integer.parseInt(splitString[0]));
- resources.println("[Parser] Row number is now " + resources.rows() + ".");
- break;
-
- case "num_cols":
- resources.setColumns(Integer.parseInt(splitString[0]));
- resources.println("[Parser] Column number is now " + resources.columns() + ".");
- break;
+ // expected length is 2, anything beyond that should also work
+ if (splitString.length >= 2) {
+ switch (splitString[1]) {
+ case "population_size":
+ resources.setPopulationSize(Integer.parseInt(splitString[0]));
+ resources.println("[Parser] Population size is now " + resources.populationSize());
+ break;
+
+ case "num_generations":
+ resources.setGenerations(Integer.parseInt(splitString[0]));
+ resources.println("[Parser] Total generations is now " + resources.generations());
+ break;
+
+ case "num_runs_total":
+ resources.setRuns(Integer.parseInt(splitString[0]));
+ resources.println("[Parser] Total runs is now " + resources.runs());
+ break;
+
+ case "num_rows":
+ resources.setRows(Integer.parseInt(splitString[0]));
+ resources.println("[Parser] Row number is now " + resources.rows());
+ break;
+
+ case "num_cols":
+ resources.setColumns(Integer.parseInt(splitString[0]));
+ resources.println("[Parser] Column number is now " + resources.columns());
+ break;
+
+ case "levels_back":
+ resources.setLevelsBack(Integer.parseInt(splitString[0]));
+ resources.println("[Parser] Levels back is now " + resources.levelsBack());
+ break;
+
+ case "report_interval":
+ resources.setReportInterval(Integer.parseInt(splitString[0]));
+ resources.println("[Parser] Report interval is now " + resources.levelsBack());
+ break;
+
+ case "global_seed":
+ resources.setSeed(Integer.parseInt(splitString[0]));
+ resources.println("[Parser] Seed is now " + resources.seed());
+ break;
- case "levels_back":
- resources.setLevelsBack(Integer.parseInt(splitString[0]));
- resources.println("[Parser] Levels back is now " + resources.levelsBack() + ".");
- break;
-
- case "report_interval":
- resources.setReportInterval(Integer.parseInt(splitString[0]));
- resources.println("[Parser] Report interval is now " + resources.levelsBack() + ".");
- break;
-
- case "global_seed":
- resources.setSeed(Integer.parseInt(splitString[0]));
- resources.println("[Parser] Seed is now " + resources.seed() + ".");
- break;
-
- default:
- break;
+ default:
+ break;
+ }
}
}
in.close();
- resources.println("[Parser] Finished parsing parameters.");
+ resources.println("[Parser] Finished parsing parameters");
}
}
diff --git a/src/jcgp/backend/parsers/TestCaseParser.java b/src/jcgp/backend/parsers/TestCaseParser.java
index cef018e..bcfa8a9 100644
--- a/src/jcgp/backend/parsers/TestCaseParser.java
+++ b/src/jcgp/backend/parsers/TestCaseParser.java
@@ -8,14 +8,34 @@ import java.util.Scanner;
import jcgp.backend.modules.problem.TestCaseProblem;
import jcgp.backend.resources.ModifiableResources;
+/**
+ * Contains a static method for parsing values from a
+ * CGP problem data file. The actual file extension
+ * varies from problem to problem, and is therefore
+ * defined in the experiment's Problem instance.
+ *
+ *
+ * @author Eduardo Pedroni
+ *
+ */
public abstract class TestCaseParser {
+ /**
+ * Sets the number of inputs and outputs in the resources
+ * to match the given file, and parses each test case
+ * from the file into the specified problem.
+ *
+ * @param file the problem file to parse.
+ * @param problem the problem into which to parse the problem data.
+ * @param resources a modifiable reference to the experiment's resources
+ */
public static void parse(File file, TestCaseProblem<?> problem, ModifiableResources resources) {
+ // create reader and scanner, print error message if file is missing
FileReader fr;
try {
fr = new FileReader(file);
} catch (FileNotFoundException e) {
- resources.println("[Parser] Error: could not find " + file.getAbsolutePath() + ".");
+ resources.println("[Parser] Error: could not find " + file.getAbsolutePath());
return;
}
resources.println("[Parser] Parsing file: " + file.getAbsolutePath() + "...");
@@ -24,28 +44,44 @@ public abstract class TestCaseParser {
int inputs = 0, outputs = 0;
int cases = 0;
+ // this overwrites any previously added test cases
problem.clearTestCases();
while (in.hasNextLine()) {
String nextLine = in.nextLine();
-
+ // set resources input count to parsed value
if (nextLine.startsWith(".i")) {
String[] split = nextLine.split(" +");
inputs = Integer.parseInt(split[1]);
- } else if (nextLine.startsWith(".o")) {
+ resources.setInputs(inputs);
+ resources.println("[Parser] Number of inputs set to " + resources.inputs());
+ }
+ // set resources output count to parsed value
+ else if (nextLine.startsWith(".o")) {
String[] split = nextLine.split(" +");
outputs = Integer.parseInt(split[1]);
+ resources.setOutputs(outputs);
+ resources.println("[Parser] Number of outputs set to " + resources.outputs());
+
} else if (nextLine.startsWith(".p") || nextLine.startsWith(".t")) {
readingTestCases = true;
+
} else if (nextLine.startsWith(".e")) {
readingTestCases = false;
+
+ /*
+ * Split every line at one or more spaces or tabs, and
+ * parse the two sides into inputs and outputs.
+ */
} else if (readingTestCases) {
String[] split = nextLine.split("( |\t)+");
String[] inputCases = new String[inputs];
String[] outputCases = new String[outputs];
+
for (int i = 0; i < inputs; i++) {
inputCases[i] = split[i];
}
+
for (int o = 0; o < outputs; o++) {
outputCases[o] = split[o + inputs];
}
@@ -54,37 +90,7 @@ public abstract class TestCaseParser {
cases++;
}
}
- resources.println("[Parser] Finished, added " + cases + " test cases.");
- in.close();
- }
-
- public static void parseParameters(File file, ModifiableResources resources) {
-
- FileReader fr;
- try {
- fr = new FileReader(file);
- } catch (FileNotFoundException e) {
- resources.println("[Parser] Error: could not find " + file.getAbsolutePath() + ".");
- return;
- }
-
- resources.println("[Parser] Parsing parameters...");
- Scanner in = new Scanner(fr);
-
- while (in.hasNextLine()) {
- String nextLine = in.nextLine();
- if (nextLine.startsWith(".i")) {
- String[] split = nextLine.split(" +");
- resources.setInputs(Integer.parseInt(split[1]));
- resources.println("[Parser] Number of inputs set to " + resources.inputs());
- } else if (nextLine.startsWith(".o")) {
- String[] split = nextLine.split(" +");
- resources.setOutputs(Integer.parseInt(split[1]));
- resources.println("[Parser] Number of outputs set to " + resources.outputs());
- }
- }
+ resources.println("[Parser] Finished, added " + cases + " test cases");
in.close();
-
- resources.println("[Parser] Finished parsing parameters.");
}
}
diff --git a/src/jcgp/backend/population/Chromosome.java b/src/jcgp/backend/population/Chromosome.java
index 9e53f85..d23f43c 100644
--- a/src/jcgp/backend/population/Chromosome.java
+++ b/src/jcgp/backend/population/Chromosome.java
@@ -2,7 +2,6 @@ package jcgp.backend.population;
import java.util.ArrayList;
-import jcgp.backend.exceptions.ParameterMismatchException;
import jcgp.backend.resources.Resources;
public class Chromosome implements Comparable<Chromosome> {
@@ -168,7 +167,7 @@ public class Chromosome implements Comparable<Chromosome> {
* @param values
* @throws ParameterMismatchException
*/
- public void setInputs(Object ... values) throws ParameterMismatchException {
+ public void setInputs(Object ... values) {
// if the values provided don't match the specified number of inputs, the user should be warned
if (values.length == inputs.length) {
// set inputs for evaluation
@@ -176,7 +175,7 @@ public class Chromosome implements Comparable<Chromosome> {
inputs[i].setValue(values[i]);
}
} else {
- throw new ParameterMismatchException();
+ throw new IllegalArgumentException("Received " + values.length + " inputs but needed exactly " + inputs.length);
}
}
diff --git a/src/jcgp/backend/population/Node.java b/src/jcgp/backend/population/Node.java
index 1ac5b10..74f6b54 100644
--- a/src/jcgp/backend/population/Node.java
+++ b/src/jcgp/backend/population/Node.java
@@ -1,9 +1,7 @@
package jcgp.backend.population;
import java.util.ArrayList;
-import java.util.Arrays;
-import jcgp.backend.exceptions.InsufficientConnectionsException;
import jcgp.backend.function.Function;
@@ -22,7 +20,11 @@ public class Node extends Gene implements MutableElement, Connection {
@Override
public Object getValue() {
- return function.run(Arrays.copyOfRange(connections, 0, function.getArity()));
+ Object[] args = new Object[function.getArity()];
+ for (int i = 0; i < function.getArity(); i++) {
+ args[i] = connections[i].getValue();
+ }
+ return function.run(args);
}
public void setFunction(Function newFunction) {
@@ -31,23 +33,18 @@ public class Node extends Gene implements MutableElement, Connection {
@Override
public void setConnection(int index, Connection newConnection) {
- if (newConnection instanceof Node) {
- if (((Node) newConnection).getColumn() < column) {
- connections[index] = newConnection;
- chromosome.recomputeActiveNodes();
- }
- } else if (newConnection instanceof Input) {
+ if (newConnection != null) {
connections[index] = newConnection;
chromosome.recomputeActiveNodes();
}
}
- public void initialise(Function newFunction, Connection ... newConnections) throws InsufficientConnectionsException {
+ public void initialise(Function newFunction, Connection ... newConnections) {
function = newFunction;
if (newConnections.length == chromosome.getResources().arity()) {
connections = newConnections;
} else {
- throw new InsufficientConnectionsException();
+ throw new IllegalArgumentException("Received " + newConnections.length + " connections but needed exactly " + chromosome.getResources().arity());
}
}
diff --git a/src/jcgp/backend/tests/ChromosomeTests.java b/src/jcgp/backend/tests/ChromosomeTests.java
index bc0c57d..c326805 100644
--- a/src/jcgp/backend/tests/ChromosomeTests.java
+++ b/src/jcgp/backend/tests/ChromosomeTests.java
@@ -2,7 +2,6 @@ package jcgp.backend.tests;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import jcgp.backend.function.SymbolicRegressionFunctions;
import jcgp.backend.population.Chromosome;
import jcgp.backend.population.Connection;
import jcgp.backend.population.Input;
@@ -46,7 +45,7 @@ public class ChromosomeTests {
@BeforeClass
public static void setUpBeforeClass() {
resources = new ModifiableResources();
- resources.setFunctionSet(new SymbolicRegressionFunctions());
+ resources.setFunctionSet(new TestFunctionSet());
}
@Before
@@ -225,9 +224,12 @@ public class ChromosomeTests {
chromosome.setInputs(5, 8, 4);
+ Integer output0 = (Integer) chromosome.getOutput(0).calculate();
+ Integer output1 = (Integer) chromosome.getOutput(1).calculate();
+
// with this configuration, the outputs should be 13 and 25.
- assertTrue("Incorrect output returned.", (Integer) chromosome.getOutput(0).calculate() == 13);
- assertTrue("Incorrect output returned.", (Integer) chromosome.getOutput(1).calculate() == 25);
+ assertTrue("Incorrect output returned: " + output0, output0 == 13.0);
+ assertTrue("Incorrect output returned: " + output1, output1 == 25.0);
}
/**
diff --git a/src/jcgp/backend/tests/NodeTests.java b/src/jcgp/backend/tests/NodeTests.java
index c63b41e..ee940a0 100644
--- a/src/jcgp/backend/tests/NodeTests.java
+++ b/src/jcgp/backend/tests/NodeTests.java
@@ -1,8 +1,6 @@
package jcgp.backend.tests;
import static org.junit.Assert.assertTrue;
-import jcgp.backend.exceptions.InvalidArgumentsException;
-import jcgp.backend.function.SymbolicRegressionFunctions;
import jcgp.backend.function.Function;
import jcgp.backend.population.Chromosome;
import jcgp.backend.population.Connection;
@@ -41,15 +39,15 @@ public class NodeTests {
public static void setUpBeforeClass() {
resources = new ModifiableResources();
- resources.setFunctionSet(new SymbolicRegressionFunctions());
+ resources.setFunctionSet(new TestFunctionSet());
chromosome = new Chromosome(resources);
}
@Before
public void setUp() throws Exception {
node = new Node(chromosome, 0, 0, resources.arity());
- // make node with anonymous addition function and hard-coded value connections
- node.initialise(new SymbolicRegressionFunctions.Addition(),
+ // make node with addition function and hard-coded value connections
+ node.initialise(resources.getFunction(0),
new Connection[]{new Connection() {
@Override
@@ -107,7 +105,7 @@ public class NodeTests {
((int) node.getValue()) == arg1 + arg2);
// put in a different function, check the output has changed appropriately
- node.setFunction(new SymbolicRegressionFunctions.Subtraction());
+ node.setFunction(resources.getFunction(1));
assertTrue("Node did not return expected value (difference of arguments).", ((Integer) node.getValue()) == arg1 - arg2);
@@ -136,8 +134,7 @@ public class NodeTests {
Function function = new Function() {
@Override
- public Object run(Object... connections)
- throws InvalidArgumentsException {
+ public Object run(Object... connections) {
// blank
return null;
}
diff --git a/src/jcgp/backend/tests/TestFunctionSet.java b/src/jcgp/backend/tests/TestFunctionSet.java
new file mode 100644
index 0000000..1910d2a
--- /dev/null
+++ b/src/jcgp/backend/tests/TestFunctionSet.java
@@ -0,0 +1,54 @@
+package jcgp.backend.tests;
+
+import jcgp.backend.function.Function;
+import jcgp.backend.function.FunctionSet;
+
+public class TestFunctionSet extends FunctionSet {
+
+ public TestFunctionSet() {
+
+ functionList = new Function[] {
+ new Function() {
+ @Override
+ public Object run(Object... args) {
+ return (Integer) args[0] + (Integer) args[1];
+ }
+ @Override
+ public int getArity() {
+ return 2;
+ }
+ },
+ new Function() {
+ @Override
+ public Object run(Object... args) {
+ return (Integer) args[0] - (Integer) args[1];
+ }
+ @Override
+ public int getArity() {
+ return 2;
+ }
+ },
+ new Function() {
+ @Override
+ public Object run(Object... args) {
+ return (Integer) args[0] * (Integer) args[1];
+ }
+ @Override
+ public int getArity() {
+ return 2;
+ }
+ },
+ new Function() {
+ @Override
+ public Object run(Object... args) {
+ return (Integer) args[0] / (Integer) args[1];
+ }
+ @Override
+ public int getArity() {
+ return 2;
+ }
+ }
+ };
+ enableAll();
+ }
+} \ No newline at end of file