From 6e7747e5b85f4ca93683ed5166f6e480cc58e6fa Mon Sep 17 00:00:00 2001 From: Eduardo Pedroni Date: Mon, 10 Feb 2014 09:33:54 +0000 Subject: Refactored the resources mechanics, implemented a few of the chromosome tests --- src/jcgp/CGP.java | 362 ++---------------------------- src/jcgp/Parameters.java | 114 ++++++++++ src/jcgp/TruthTable.java | 21 ++ src/jcgp/Utilities.java | 169 ++++++++++++++ src/jcgp/ea/StandardMutator.java | 6 +- src/jcgp/fitness/TestCase.java | 2 +- src/jcgp/fitness/TruthTableEvaluator.java | 4 +- src/jcgp/function/Addition.java | 2 +- src/jcgp/function/Subtraction.java | 2 +- src/jcgp/population/Chromosome.java | 26 ++- src/jcgp/population/Connection.java | 2 +- src/jcgp/population/Input.java | 2 +- src/jcgp/population/MutableElement.java | 2 + src/jcgp/population/Node.java | 18 +- src/jcgp/population/Output.java | 14 +- src/jcgp/population/Population.java | 2 +- src/jcgp/tests/ChromosomeTests.java | 103 +++++++++ src/jcgp/tests/Tests.java | 22 -- 18 files changed, 475 insertions(+), 398 deletions(-) create mode 100644 src/jcgp/Parameters.java create mode 100644 src/jcgp/TruthTable.java create mode 100644 src/jcgp/Utilities.java create mode 100644 src/jcgp/tests/ChromosomeTests.java delete mode 100644 src/jcgp/tests/Tests.java diff --git a/src/jcgp/CGP.java b/src/jcgp/CGP.java index 5111508..6cf5429 100644 --- a/src/jcgp/CGP.java +++ b/src/jcgp/CGP.java @@ -1,7 +1,6 @@ package jcgp; import java.util.Random; - import jcgp.ea.EvolutionaryAlgorithm; import jcgp.ea.Mutator; import jcgp.ea.StandardEA; @@ -10,344 +9,12 @@ import jcgp.fitness.FitnessFunction; import jcgp.fitness.TestCase; import jcgp.fitness.TruthTableEvaluator; import jcgp.function.Addition; -import jcgp.function.Function; import jcgp.function.FunctionSet; import jcgp.function.Subtraction; -import jcgp.population.Chromosome; -import jcgp.population.Connection; -import jcgp.population.Input; -import jcgp.population.MutableElement; -import jcgp.population.Node; import jcgp.population.Population; public final class CGP { - public static class Parameters { - private static int rows, columns, inputs, outputs, mutationRate, generations, runs, populationSize, levelsBack, maxArity; - - /** - * @return the number of nodes - */ - public static int getNodeNumber() { - return rows * columns; - } - - /** - * @return the levelsBack - */ - public static int getLevelsBack() { - return levelsBack; - } - - /** - * @param levelsBack the levelsBack to set - */ - private static void setLevelsBack(int levelsBack) { - Parameters.levelsBack = levelsBack; - } - - /** - * @return the populationSize - */ - public static int getPopulationSize() { - return populationSize; - } - - /** - * @param populationSize the populationSize to set - */ - private static void setPopulationSize(int populationSize) { - Parameters.populationSize = populationSize; - } - - /** - * @return the rows - */ - public static int getRows() { - return rows; - } - - /** - * @return the columns - */ - public static int getColumns() { - return columns; - } - - /** - * @return the inputs - */ - public static int getInputs() { - return inputs; - } - - /** - * @return the outputs - */ - public static int getOutputs() { - return outputs; - } - - /** - * @return the mutationRate - */ - public static int getMutationRate() { - return mutationRate; - } - - /** - * @return the generations - */ - public static int getGenerations() { - return generations; - } - - /** - * @return the runs - */ - public static int getRuns() { - return runs; - } - - /** - * @param rows the rows to set - */ - private static void setRows(int rows) { - Parameters.rows = rows; - } - - /** - * @param columns the columns to set - */ - private static void setColumns(int columns) { - Parameters.columns = columns; - } - - /** - * @param inputs the inputs to set - */ - private static void setInputs(int inputs) { - Parameters.inputs = inputs; - } - - /** - * @param outputs the outputs to set - */ - private static void setOutputs(int outputs) { - Parameters.outputs = outputs; - } - - /** - * @param mutationRate the mutationRate to set - */ - private static void setMutationRate(int mutationRate) { - Parameters.mutationRate = mutationRate; - } - - /** - * @param generations the generations to set - */ - private static void setGenerations(int generations) { - Parameters.generations = generations; - } - - /** - * @param runs the runs to set - */ - private static void setRuns(int runs) { - Parameters.runs = runs; - } - - /** - * @return the maxArity - */ - public static int getMaxArity() { - return maxArity; - } - - /** - * @param maxArity the maxArity to set - */ - private static void setMaxArity(int maxArity) { - Parameters.maxArity = maxArity; - } - } - - public abstract static class Utilities { - - public static int getRandomInt(int limit){ - return numberGenerator.nextInt(limit); - } - - public static double getRandomDouble(int limit){ - return numberGenerator.nextDouble() * limit; - } - - /** - * Returns a random allowed connection respecting levels back. - * This method may always pick inputs, as they can be picked - * regardless of the column. - * - * @param chromosome the chromosome to pick from - * @param column the column to use as reference - * @return a random connection - */ - public static Connection getRandomConnection(Chromosome chromosome, int column){ - // work out the allowed range obeying levels back - int allowedColumns = ((column >= Parameters.getLevelsBack()) ? Parameters.getLevelsBack() : column); - int offset = column - allowedColumns; - - // choose input or node - int connectionType = getRandomInt(Parameters.getInputs() + (Parameters.getRows() * allowedColumns)); - if (connectionType < Parameters.getInputs()) { - // input - return chromosome.getInput(getRandomInt(Parameters.getInputs())); - } else { - // node - return chromosome.getNode(getRandomInt(Parameters.getRows()), getRandomInt(allowedColumns) + offset); - } - } - - /** - * Returns a random allowed connection. - * - * This method may always pick inputs, as they can be picked - * regardless of the column. - * - * @param chromosome the chromosome to pick from - * @param column the column to use as reference - * @param levelsBack whether or not to respect levels back - * @return a random connection - */ - public static Connection getRandomConnection(Chromosome chromosome, int column, boolean levelsBack){ - if (levelsBack) { - return getRandomConnection(chromosome, column); - } else { - // choose input or node - int connectionType = getRandomInt(Parameters.getInputs() + (Parameters.getRows() * column)); - if (connectionType < Parameters.getInputs()) { - // input - return chromosome.getInput(getRandomInt(Parameters.getInputs())); - } else { - // node - return chromosome.getNode(getRandomInt(Parameters.getRows()), getRandomInt(column)); - } - } - } - - /** - * @param chromosome the chromosome to choose from - * @return a random input - */ - public static Input getRandomInput(Chromosome chromosome){ - return chromosome.getInput(getRandomInt(Parameters.getInputs())); - } - - /** - * Returns a random allowed node respecting levels back. - * - * This method will NOT pick inputs. - * - * @param chromosome the chromosome to pick from - * @param column the column to use as reference - * @return a random node - */ - public static Node getRandomNode(Chromosome chromosome, int column){ - // work out the allowed range obeying levels back - int allowedColumns = ((column >= Parameters.getLevelsBack()) ? Parameters.getLevelsBack() : column); - int offset = column - allowedColumns; - - // pick a random allowed column and row - int randomColumn = (getRandomInt(allowedColumns) + offset); - int randomRow = (getRandomInt(Parameters.getRows())); - - return chromosome.getNode(randomRow, randomColumn); - } - - /** - * Returns a random allowed node. - * - * This method will NOT pick inputs. - * - * @param chromosome the chromosome to pick from - * @param column the column to use as reference - * @param levelsBack whether or not to respect levels back - * @return a random node - */ - public static Node getRandomNode(Chromosome chromosome, int column, boolean levelsBack){ - if (levelsBack) { - return getRandomNode(chromosome, column); - } else { - // pick any random column before the given column - int randomColumn = (getRandomInt(column)); - // pick a random rowgetColumns - int randomRow = (getRandomInt(Parameters.getRows())); - return chromosome.getNode(randomRow, randomColumn); - } - } - - /** - * This method picks a random mutable element from the given chromosome. - * - * It will pick outputs or nodes fairly. - * - * @param chromosome the chromosome to pick from - * @return a random mutable element - */ - public static MutableElement getRandomMutable(Chromosome chromosome){ - // choose output or node - int connectionType = getRandomInt(Parameters.getOutputs() + Parameters.getNodeNumber()); - - if (connectionType < Parameters.getOutputs()) { - // outputs - return chromosome.getOutput(getRandomInt(Parameters.getOutputs())); - } else { - // node - return chromosome.getNode(getRandomInt(Parameters.getRows()), getRandomInt(Parameters.getRows())); - } - } - - /** - * pick from any column - use this for setting outputs - * - * @param chromosome - * @return - */ - public static Node getRandomNode(Chromosome chromosome) { - return chromosome.getNode(getRandomInt(Parameters.getRows()), getRandomInt(Parameters.getColumns())); - } - - public static Function getRandomFunction() { - return functionSet.getFunction(Utilities.getRandomInt(functionSet.getFunctionCount())); - } - - public static Function getFunction(int index) { - return functionSet.getFunction(index); - } - } - - public static class TruthTable { - - private static TestCase[] testCases; - - private static void setTestCases(TestCase ... testCases) { - TruthTable.testCases = testCases; - } - - public static TestCase getTestCase(int index) { - return testCases[index]; - } - - public static int getTestCaseCount() { - return testCases.length; - } - - } - - // system-wide resources - private static FunctionSet functionSet; - private static Random numberGenerator; - // CGP components private EvolutionaryAlgorithm ea; private Mutator mutator; @@ -366,33 +33,30 @@ public final class CGP { * */ private void initialise() { - // initialise random number generator - numberGenerator = new Random(1234); - // initialise function set - functionSet = new FunctionSet(new Addition(), new Subtraction()); - + FunctionSet functionSet = new FunctionSet(new Addition(), new Subtraction()); + + // initialise utilities + Utilities.setResources(new Random(1234), functionSet); + // initialise parameters - Parameters.setInputs(3); Parameters.setColumns(3); Parameters.setRows(3); + Parameters.setInputs(3); Parameters.setOutputs(3); - Parameters.setGenerations(10); - Parameters.setMutationRate(1); - Parameters.setRuns(5); - Parameters.setPopulationSize(5); Parameters.setLevelsBack(1); - - // compute and set maximum arity + Parameters.setMutationRate(10); + Parameters.setTotalGenerations(100); + Parameters.setTotalRuns(5); Parameters.setMaxArity(functionSet.getMaxArity()); + + // initialise fitness function and truth table + TruthTable.setTestCases(new TestCase(new int[] {2, 5, 4}, new int[] {1, 10, 15})); + fitnessFunction = new TruthTableEvaluator(); // initialise EA ea = new StandardEA(); mutator = new StandardMutator(); - - // initialise fitness function and truth table - TruthTable.setTestCases(new TestCase(new int[] {2, 5, 4}, new int[] {1, 10, 15})); - fitnessFunction = new TruthTableEvaluator(); // initialise population population = new Population(); diff --git a/src/jcgp/Parameters.java b/src/jcgp/Parameters.java new file mode 100644 index 0000000..2a417db --- /dev/null +++ b/src/jcgp/Parameters.java @@ -0,0 +1,114 @@ +package jcgp; + +public class Parameters { + + private static int rows, columns, inputs, outputs, levelsBack, + mutationRate, populationSize, totalGenerations, + currentGeneration = 0, totalRuns, currentRun = 0, + maxArity; + + public static int getRows() { + return rows; + } + + public static int getColumns() { + return columns; + } + + public static int getNodeCount() { + return rows * columns; + } + + public static int getInputs() { + return inputs; + } + + public static int getOutputs() { + return outputs; + } + + public static int getLevelsBack() { + return levelsBack; + } + + public static int getMutationRate() { + return mutationRate; + } + + public static int getPopulationSize() { + return populationSize; + } + + public static int getTotalGenerations() { + return totalGenerations; + } + + public static int getCurrentGeneration() { + return currentGeneration; + } + + public static int getTotalRuns() { + return totalRuns; + } + + public static int getCurrentRun() { + return currentRun; + } + + public static int getMaxArity() { + return maxArity; + } + + public static void setRows(int rows) { + Parameters.rows = rows; + } + + public static void setColumns(int columns) { + Parameters.columns = columns; + } + + public static void setInputs(int inputs) { + Parameters.inputs = inputs; + } + + public static void setOutputs(int outputs) { + Parameters.outputs = outputs; + } + + public static void setLevelsBack(int levelsBack) { + Parameters.levelsBack = levelsBack; + } + + public static void setMutationRate(int mutationRate) { + Parameters.mutationRate = mutationRate; + } + + public static void setPopulationSize(int populationSize) { + Parameters.populationSize = populationSize; + } + + public static void setTotalGenerations(int totalGenerations) { + Parameters.totalGenerations = totalGenerations; + } + + public static void setCurrentGeneration(int currentGeneration) { + Parameters.currentGeneration = currentGeneration; + } + + public static void incrementCurrentGeneration() { + Parameters.currentGeneration++; + } + + public static void setTotalRuns(int totalRuns) { + Parameters.totalRuns = totalRuns; + } + + public static void setCurrentRun(int currentRun) { + Parameters.currentRun = currentRun; + } + + public static void setMaxArity(int maxArity) { + Parameters.maxArity = maxArity; + } + +} diff --git a/src/jcgp/TruthTable.java b/src/jcgp/TruthTable.java new file mode 100644 index 0000000..72712fc --- /dev/null +++ b/src/jcgp/TruthTable.java @@ -0,0 +1,21 @@ +package jcgp; + +import jcgp.fitness.TestCase; + +public class TruthTable { + + private static TestCase[] testCases; + + public static void setTestCases(TestCase ... testCases) { + TruthTable.testCases = testCases; + } + + public static TestCase getTestCase(int index) { + return testCases[index]; + } + + public static int getTestCaseCount() { + return testCases.length; + } + +} diff --git a/src/jcgp/Utilities.java b/src/jcgp/Utilities.java new file mode 100644 index 0000000..7de701a --- /dev/null +++ b/src/jcgp/Utilities.java @@ -0,0 +1,169 @@ +package jcgp; + +import java.util.Random; + +import jcgp.function.Function; +import jcgp.function.FunctionSet; +import jcgp.population.*; + +public class Utilities { + + private static Random numberGenerator; + private static FunctionSet functionSet; + + public static void setResources(Random numberGenerator, FunctionSet functionSet) { + Utilities.numberGenerator = numberGenerator; + Utilities.functionSet = functionSet; + } + + public static int getRandomInt(int limit){ + return numberGenerator.nextInt(limit); + } + + public static double getRandomDouble(int limit){ + return numberGenerator.nextDouble() * limit; + } + + /** + * Returns a random allowed connection respecting levels back. + * This method may always pick inputs, as they can be picked + * regardless of the column. + * + * @param chromosome the chromosome to pick from + * @param column the column to use as reference + * @return a random connection + */ + public static Connection getRandomConnection(Chromosome chromosome, int column){ + // work out the allowed range obeying levels back + int allowedColumns = ((column >= Parameters.getLevelsBack()) ? Parameters.getLevelsBack() : column); + int offset = column - allowedColumns; + + // choose input or node + int connectionType = getRandomInt(Parameters.getInputs() + (Parameters.getRows() * allowedColumns)); + if (connectionType < Parameters.getInputs()) { + // input + return chromosome.getInput(getRandomInt(Parameters.getInputs())); + } else { + // node + return chromosome.getNode(getRandomInt(Parameters.getRows()), getRandomInt(allowedColumns) + offset); + } + } + + /** + * Returns a random allowed connection. + * + * This method may always pick inputs, as they can be picked + * regardless of the column. + * + * @param chromosome the chromosome to pick from + * @param column the column to use as reference + * @param levelsBack whether or not to respect levels back + * @return a random connection + */ + public static Connection getRandomConnection(Chromosome chromosome, int column, boolean levelsBack){ + if (levelsBack) { + return getRandomConnection(chromosome, column); + } else { + // choose input or node + int connectionType = getRandomInt(Parameters.getInputs() + (Parameters.getRows() * column)); + if (connectionType < Parameters.getInputs()) { + // input + return chromosome.getInput(getRandomInt(Parameters.getInputs())); + } else { + // node + return chromosome.getNode(getRandomInt(Parameters.getRows()), getRandomInt(column)); + } + } + } + + /** + * @param chromosome the chromosome to choose from + * @return a random input + */ + public static Input getRandomInput(Chromosome chromosome){ + return chromosome.getInput(getRandomInt(Parameters.getInputs())); + } + + /** + * Returns a random allowed node respecting levels back. + * + * This method will NOT pick inputs. + * + * @param chromosome the chromosome to pick from + * @param column the column to use as reference + * @return a random node + */ + public static Node getRandomNode(Chromosome chromosome, int column){ + // work out the allowed range obeying levels back + int allowedColumns = ((column >= Parameters.getLevelsBack()) ? Parameters.getLevelsBack() : column); + int offset = column - allowedColumns; + + // pick a random allowed column and row + int randomColumn = (getRandomInt(allowedColumns) + offset); + int randomRow = (getRandomInt(Parameters.getRows())); + + return chromosome.getNode(randomRow, randomColumn); + } + + /** + * Returns a random allowed node. + * + * This method will NOT pick inputs. + * + * @param chromosome the chromosome to pick from + * @param column the column to use as reference + * @param levelsBack whether or not to respect levels back + * @return a random node + */ + public static Node getRandomNode(Chromosome chromosome, int column, boolean levelsBack){ + if (levelsBack) { + return getRandomNode(chromosome, column); + } else { + // pick any random column before the given column + int randomColumn = (getRandomInt(column)); + // pick a random rowgetColumns + int randomRow = (getRandomInt(Parameters.getRows())); + return chromosome.getNode(randomRow, randomColumn); + } + } + + /** + * This method picks a random mutable element from the given chromosome. + * + * It will pick outputs or nodes fairly. + * + * @param chromosome the chromosome to pick from + * @return a random mutable element + */ + public static MutableElement getRandomMutable(Chromosome chromosome){ + // choose output or node + int connectionType = getRandomInt(Parameters.getOutputs() + Parameters.getNodeCount()); + + if (connectionType < Parameters.getOutputs()) { + // outputs + return chromosome.getOutput(getRandomInt(Parameters.getOutputs())); + } else { + // node + return chromosome.getNode(getRandomInt(Parameters.getRows()), getRandomInt(Parameters.getRows())); + } + } + + /** + * pick from any column - use this for setting outputs + * + * @param chromosome + * @return + */ + public static Node getRandomNode(Chromosome chromosome) { + return chromosome.getNode(getRandomInt(Parameters.getRows()), getRandomInt(Parameters.getColumns())); + } + + public static Function getRandomFunction() { + return functionSet.getFunction(Utilities.getRandomInt(functionSet.getFunctionCount())); + } + + public static Function getFunction(int index) { + return functionSet.getFunction(index); + } + +} diff --git a/src/jcgp/ea/StandardMutator.java b/src/jcgp/ea/StandardMutator.java index cab5c76..8af3f5c 100644 --- a/src/jcgp/ea/StandardMutator.java +++ b/src/jcgp/ea/StandardMutator.java @@ -1,7 +1,7 @@ package jcgp.ea; -import jcgp.CGP.Parameters; -import jcgp.CGP.Utilities; +import jcgp.Parameters; +import jcgp.Utilities; import jcgp.population.Chromosome; import jcgp.population.MutableElement; import jcgp.population.Node; @@ -11,7 +11,7 @@ public class StandardMutator implements Mutator { @Override public void mutate(Chromosome chromosome) { - int mutations = (int) (Parameters.getMutationRate() * ((double) Parameters.getNodeNumber() / 100)); + int mutations = (int) (Parameters.getMutationRate() * ((double) Parameters.getNodeCount() / 100)); for (int i = 0; i < mutations; i++) { MutableElement m = Utilities.getRandomMutable(chromosome); diff --git a/src/jcgp/fitness/TestCase.java b/src/jcgp/fitness/TestCase.java index e2bd5ed..95129c6 100644 --- a/src/jcgp/fitness/TestCase.java +++ b/src/jcgp/fitness/TestCase.java @@ -1,6 +1,6 @@ package jcgp.fitness; -import jcgp.CGP.Parameters; +import jcgp.Parameters; public class TestCase { diff --git a/src/jcgp/fitness/TruthTableEvaluator.java b/src/jcgp/fitness/TruthTableEvaluator.java index 64ca209..987ea4c 100644 --- a/src/jcgp/fitness/TruthTableEvaluator.java +++ b/src/jcgp/fitness/TruthTableEvaluator.java @@ -1,7 +1,7 @@ package jcgp.fitness; -import jcgp.CGP.Parameters; -import jcgp.CGP.TruthTable; +import jcgp.Parameters; +import jcgp.TruthTable; import jcgp.population.Chromosome; import jcgp.population.Population; diff --git a/src/jcgp/function/Addition.java b/src/jcgp/function/Addition.java index 8c1e0b5..faf11d5 100644 --- a/src/jcgp/function/Addition.java +++ b/src/jcgp/function/Addition.java @@ -7,7 +7,7 @@ public class Addition extends Function { @Override public int run(Connection... connections) { if (connections.length > 0) { - return connections[0].evaluate() + connections[1].evaluate(); + return connections[0].getValue() + connections[1].getValue(); } else { return 0; } diff --git a/src/jcgp/function/Subtraction.java b/src/jcgp/function/Subtraction.java index 169f88c..f8b9c7d 100644 --- a/src/jcgp/function/Subtraction.java +++ b/src/jcgp/function/Subtraction.java @@ -7,7 +7,7 @@ public class Subtraction extends Function { @Override public int run(Connection... connections) { if (connections.length > 1) { - return connections[0].evaluate() - connections[1].evaluate(); + return connections[0].getValue() - connections[1].getValue(); } else { return 0; } diff --git a/src/jcgp/population/Chromosome.java b/src/jcgp/population/Chromosome.java index f060e14..328a608 100644 --- a/src/jcgp/population/Chromosome.java +++ b/src/jcgp/population/Chromosome.java @@ -1,7 +1,8 @@ package jcgp.population; -import jcgp.CGP.Parameters; -import jcgp.CGP.Utilities; +import jcgp.Parameters; +import jcgp.Utilities; +import jcgp.fitness.ParameterMismatchException; public class Chromosome { @@ -41,16 +42,16 @@ public class Chromosome { } // rows first - nodes = new Node[Parameters.getRows()][Parameters.getColumns()]; + nodes = new Node[rows][columns]; for (int r = 0; r < rows; r++) { //nodes[r] = new Node[Parameters.getColumns()]; for (int c = 0; c < columns; c++) { - nodes[r][c] = new Node(c); + nodes[r][c] = new Node(r, c); } } outputs = new Output[outputCount]; for (int o = 0; o < outputCount; o++) { - outputs[o] = new Output(); + outputs[o] = new Output(o); } } @@ -97,16 +98,25 @@ public class Chromosome { fitness = newFitness; } - public void setInputs(int ... values) { - // if the values provided dont match the specified number of inputs, the user should be warned + public void setInputs(int ... values) throws ParameterMismatchException { + // 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 for (int i = 0; i < values.length; i++) { inputs[i].setValue(values[i]); } } else { - System.out.println("Input mismatch: chromosome has a different number of inputs than the truth table."); + throw new ParameterMismatchException(); } } + + public MutableElement getMutableElement(int row, int column) { + if (column < Parameters.getColumns() && column >= 0) { + return nodes[row][column]; + } else if (column == Parameters.getColumns()) { + return outputs[row]; + } + return null; + } } diff --git a/src/jcgp/population/Connection.java b/src/jcgp/population/Connection.java index fa02a22..4e69e99 100644 --- a/src/jcgp/population/Connection.java +++ b/src/jcgp/population/Connection.java @@ -2,5 +2,5 @@ package jcgp.population; public interface Connection { - public abstract int evaluate(); + public abstract int getValue(); } diff --git a/src/jcgp/population/Input.java b/src/jcgp/population/Input.java index b9c127f..e00573e 100644 --- a/src/jcgp/population/Input.java +++ b/src/jcgp/population/Input.java @@ -9,7 +9,7 @@ public class Input implements Connection { } @Override - public int evaluate() { + public int getValue() { return value; } diff --git a/src/jcgp/population/MutableElement.java b/src/jcgp/population/MutableElement.java index 8ac3724..c21ee0b 100644 --- a/src/jcgp/population/MutableElement.java +++ b/src/jcgp/population/MutableElement.java @@ -5,5 +5,7 @@ public interface MutableElement { public void setConnection(Connection newConnection); public int getColumn(); + + public int getRow(); } diff --git a/src/jcgp/population/Node.java b/src/jcgp/population/Node.java index fd0cd47..3dbabb2 100644 --- a/src/jcgp/population/Node.java +++ b/src/jcgp/population/Node.java @@ -1,7 +1,7 @@ package jcgp.population; -import jcgp.CGP.Parameters; -import jcgp.CGP.Utilities; +import jcgp.Parameters; +import jcgp.Utilities; import jcgp.function.Function; @@ -9,14 +9,15 @@ public class Node implements MutableElement, Connection { private Function function; private Connection[] connections; - private int column; + private int column, row; - public Node(int col) { - column = col; + public Node(int row, int column) { + this.column = column; + this.row = row; } @Override - public int evaluate() { + public int getValue() { return function.run(connections); } @@ -45,4 +46,9 @@ public class Node implements MutableElement, Connection { return column; } + + @Override + public int getRow() { + return row; + } } diff --git a/src/jcgp/population/Output.java b/src/jcgp/population/Output.java index eeae743..ce4f776 100644 --- a/src/jcgp/population/Output.java +++ b/src/jcgp/population/Output.java @@ -1,14 +1,19 @@ package jcgp.population; -import jcgp.CGP.Parameters; +import jcgp.Parameters; public class Output implements MutableElement { private Connection source; + private int row; + + public Output(int row) { + this.row = row; + } public int calculate() { - return source.evaluate(); + return source.getValue(); } @Override @@ -22,4 +27,9 @@ public class Output implements MutableElement { return Parameters.getColumns(); } + @Override + public int getRow() { + return row; + } + } diff --git a/src/jcgp/population/Population.java b/src/jcgp/population/Population.java index c4a0776..b56d992 100644 --- a/src/jcgp/population/Population.java +++ b/src/jcgp/population/Population.java @@ -2,7 +2,7 @@ package jcgp.population; import java.util.Iterator; -import jcgp.CGP.Parameters; +import jcgp.Parameters; public class Population implements Iterable { diff --git a/src/jcgp/tests/ChromosomeTests.java b/src/jcgp/tests/ChromosomeTests.java new file mode 100644 index 0000000..123cbd1 --- /dev/null +++ b/src/jcgp/tests/ChromosomeTests.java @@ -0,0 +1,103 @@ +package jcgp.tests; + +import static org.junit.Assert.assertTrue; + +import java.util.Random; + +import jcgp.Parameters; +import jcgp.Utilities; +import jcgp.function.Addition; +import jcgp.function.FunctionSet; +import jcgp.function.Subtraction; +import jcgp.population.Chromosome; +import jcgp.population.Input; +import jcgp.population.Node; +import jcgp.population.Output; + +import org.junit.Before; +import org.junit.Test; + +/** + * + * Tests which cover the behaviour specified for a chromosome. + * + * - The chromosome should be able to return a specified node, input or output. + * - It should be able to return a MutableElement indexed by row and column, + * where column NodeCount returns outputs. + * - It should be able to return a Connection indexed by row and column, where + * column 0 returns inputs. + * - It should contain a freely modifiable fitness value. + * - It should be a good citizen - fully initialised upon instantiation. + * - It should feature a clone constructor, which creates a deep copy of a + * specified Chromosome object. + * - It should be able to return the number of active nodes. + * - For truth table evaluations, it should be able to have its inputs set. + * + * @author Eduardo Pedroni + * + */ +public class ChromosomeTests { + + Chromosome chromosome; + int inputCount = 3, + rows = 3, + columns = 3, + outputCount = 3; + + @Before + public void setUp() throws Exception { + // initialise function set + FunctionSet functionSet = new FunctionSet(new Addition(), new Subtraction()); + + // initialise utilities + Utilities.setResources(new Random(1234), functionSet); + + // initialise parameters + Parameters.setColumns(columns); + Parameters.setRows(rows); + Parameters.setInputs(inputCount); + Parameters.setOutputs(outputCount); + Parameters.setLevelsBack(1); + Parameters.setMutationRate(10); + Parameters.setTotalGenerations(100); + Parameters.setTotalRuns(5); + Parameters.setMaxArity(functionSet.getMaxArity()); + + chromosome = new Chromosome(inputCount, rows, columns, outputCount); + + } + + @Test + public void test() { + // pick arbitrary node, assume that if one node is right, all nodes are right + boolean nodeReturn = chromosome.getNode(1, 2).getColumn() == 2 + && chromosome.getNode(1, 2).getRow() == 1 + && chromosome.getNode(1, 2) instanceof Node; + assertTrue("Incorrect node returned.", nodeReturn); + + // set input values, check that acquired values are correct + chromosome.setInputs(4, 5, 6); + boolean inputReturn = chromosome.getInput(0).getValue() == 4 && chromosome.getInput(0) instanceof Input + && chromosome.getInput(1).getValue() == 5 && chromosome.getInput(0) instanceof Input + && chromosome.getInput(2).getValue() == 6 && chromosome.getInput(0) instanceof Input; + assertTrue("Incorrect inputs returned.", inputReturn); + + // connect outputs to inputs, check that calculated outputs return input values + for (int i = 0; i < outputCount; i++) { + chromosome.getOutput(i).setConnection(chromosome.getInput(0)); + } + boolean outputReturn = chromosome.getOutput(0).calculate() == 4 && chromosome.getOutput(0) instanceof Output + && chromosome.getOutput(1).calculate() == 4 && chromosome.getOutput(0) instanceof Output + && chromosome.getOutput(2).calculate() == 4 && chromosome.getOutput(0) instanceof Output; + assertTrue("Incorrect output returned.", outputReturn); + + // get a mutable element, that that it is a Mutable + boolean mutableReturn = chromosome.getMutable() instanceof Output; + + // set a fitness value, check if returned value is the same + chromosome.setFitness(10); + assertTrue("Incorrect fitness returned.", chromosome.getFitness() == 10); + + } + +} diff --git a/src/jcgp/tests/Tests.java b/src/jcgp/tests/Tests.java deleted file mode 100644 index 8fbf0be..0000000 --- a/src/jcgp/tests/Tests.java +++ /dev/null @@ -1,22 +0,0 @@ -package jcgp.tests; - -import static org.junit.Assert.fail; - -import org.junit.Before; -import org.junit.Test; - -public class Tests { - - @Before - public void setUp() throws Exception { - - - } - - @Test - public void test() { - fail("Not yet implemented"); - - } - -} -- cgit v1.2.3