From dd3b6446671f31d716eb07e546c6150b4d080abd Mon Sep 17 00:00:00 2001 From: Eduardo Pedroni Date: Tue, 11 Feb 2014 16:50:27 +0000 Subject: Implemented more tests, refactored chromosome more, added the beginnings of active node detection --- src/jcgp/population/Chromosome.java | 198 +++++++++++++++++++++++--------- src/jcgp/population/Input.java | 10 +- src/jcgp/population/MutableElement.java | 4 - src/jcgp/population/Node.java | 16 ++- src/jcgp/population/Output.java | 24 ++-- src/jcgp/population/Population.java | 5 +- 6 files changed, 179 insertions(+), 78 deletions(-) (limited to 'src/jcgp/population') diff --git a/src/jcgp/population/Chromosome.java b/src/jcgp/population/Chromosome.java index 0dc3ff9..1f264f2 100644 --- a/src/jcgp/population/Chromosome.java +++ b/src/jcgp/population/Chromosome.java @@ -1,5 +1,7 @@ package jcgp.population; +import java.util.ArrayList; + import jcgp.Parameters; import jcgp.Utilities; import jcgp.fitness.ParameterMismatchException; @@ -9,11 +11,15 @@ public class Chromosome { private Input[] inputs; private Node[][] nodes; private Output[] outputs; + + private ArrayList activeNodes; private int fitness = 0; + private boolean recomputeActiveNodes = true; /** - * Good citizen. + * Initialise a chromosome with the specified parameters. Random valid connections + * are created. * * @param outputs * @param columns @@ -21,61 +27,110 @@ public class Chromosome { * @param inputs * */ - public Chromosome(int inputCount, int rows, int columns, int outputCount) { - - instantiateElements(inputCount, rows, columns, outputCount); - + public Chromosome() { + // allocate memory for all elements of the chromosome + instantiateElements(); + // set random connections so that the chromosome can be evaluated initialiseConnections(); + } + /** + * Copy constructor. + * + * Initialise a new chromosome with the exact same connections as a given instance of Chromosome. + * + * @param clone the chromosome to be copied + */ + public Chromosome(Chromosome clone) { + // allocate memory for all elements of the chromosome + instantiateElements(); + // initialise all connections based on argument + copyConnections(clone); } /** - * @param inputCount - * @param rows - * @param columns - * @param outputCount + * */ - private void instantiateElements(int inputCount, int rows, int columns, int outputCount) { - inputs = new Input[inputCount]; - for (int i = 0; i < inputCount; i++) { - inputs[i] = new Input(); + private void instantiateElements() { + inputs = new Input[Parameters.getInputs()]; + for (int i = 0; i < Parameters.getInputs(); i++) { + inputs[i] = new Input(i); } // rows first - 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(r, c); + nodes = new Node[Parameters.getRows()][Parameters.getColumns()]; + for (int r = 0; r < Parameters.getRows(); r++) { + for (int c = 0; c < Parameters.getColumns(); c++) { + nodes[r][c] = new Node(this, r, c); } } - outputs = new Output[outputCount]; - for (int o = 0; o < outputCount; o++) { - outputs[o] = new Output(o); + outputs = new Output[Parameters.getOutputs()]; + for (int o = 0; o < Parameters.getOutputs(); o++) { + outputs[o] = new Output(this, o); } } + /** + * + */ private void initialiseConnections() { // initialise nodes - [rows][columns] for (int r = 0; r < nodes.length; r++) { - for (int c = 0; c < nodes.length; c++) { + for (int c = 0; c < nodes[r].length; c++) { Connection[] connections = new Connection[Parameters.getMaxArity()]; for (int i = 0; i < connections.length; i++) { - connections[i] = Utilities.getRandomConnection(this, c); + connections[i] = getRandomConnection(c); } nodes[r][c].initialise(Utilities.getRandomFunction(), connections); } } for (Output output : outputs) { - output.setConnection(Utilities.getRandomNode(this)); + output.setConnection(getRandomConnection()); } } - public int getActiveNodeCount() { - return 0; + /** + * @param clone + */ + private void copyConnections(Chromosome clone) { + // copy nodes - [rows][columns] + for (int r = 0; r < nodes.length; r++) { + for (int c = 0; c < nodes[r].length; c++) { + // make array of connections to initialise with + Connection[] connections = new Connection[Parameters.getMaxArity()]; + // populate with connections equivalent to clone + Connection copyConnection; + for (int i = 0; i < connections.length; i++) { + copyConnection = clone.getNode(r, c).getConnections(i); + if (copyConnection instanceof Input) { + connections[i] = inputs[((Input) copyConnection).getIndex()]; + } else if (copyConnection instanceof Node) { + connections[i] = nodes[((Node) copyConnection).getRow()][((Node) copyConnection).getColumn()]; + } else { + System.out.println("Warning: Connection of subtype " + copyConnection.getClass().toString() + " is not explicitly handled by copy constructor."); + } + } + // initialise with copied arguments + nodes[r][c].initialise(clone.getNode(r, c).getFunction(), connections); + } + } + + // do the same to outputs + Connection copyOutput; + for (int o = 0; o < outputs.length; o++) { + copyOutput = clone.getOutput(o).getSource(); + if (copyOutput instanceof Input) { + outputs[o].setConnection(inputs[((Input) copyOutput).getIndex()]); + } else if (copyOutput instanceof Node) { + outputs[o].setConnection(nodes[((Node) copyOutput).getRow()][((Node) copyOutput).getColumn()]); + } else { + // something bad happened + System.out.println("Warning: Connection of subtype " + copyOutput.getClass().toString() + " is not explicitly handled by copy constructor."); + } + } } public Node getNode(int row, int column) { @@ -110,6 +165,11 @@ public class Chromosome { } } + /** + * This method is useful for mutating chromosomes. + * + * @return a random element that can be mutated - Node or Output + */ public MutableElement getRandomMutableElement() { // choose output or node int index = Utilities.getRandomInt(outputs.length + Parameters.getNodeCount()); @@ -123,9 +183,9 @@ public class Chromosome { return nodes[index / Parameters.getColumns()][index % Parameters.getColumns()]; } } - + /** - * Returns a random allowed connection respecting levels back. + * Returns a random allowed connection respecting levels back.
* This method may always pick inputs, as they can be picked * regardless of the column. * @@ -133,41 +193,71 @@ public class Chromosome { * @return a random connection */ public Connection getRandomConnection(int column) { - - - - return null; - + // work out the allowed range obeying levels back + int allowedColumns = ((column >= Parameters.getLevelsBack()) ? Parameters.getLevelsBack() : column); + int offset = ((column - allowedColumns) * nodes.length) - inputs.length; + + // choose input or allowed node + int index = Utilities.getRandomInt(inputs.length + (nodes.length * allowedColumns)); + if (index < inputs.length) { + // input + return inputs[index]; + } else { + // node + // offset it to address the right columns + index += offset; + return nodes[index % nodes.length][index / nodes.length]; + } } - + /** - * Returns a random allowed connection. + * This method will pick a completely random connection, independently + * of levels back, including inputs. * - * This method may always pick inputs, as they can be picked - * regardless of the column. + * Useful for setting outputs. * - * TODO optimise for less random generations * - * @param column the column to use as reference - * @param levelsBack whether or not to respect levels back * @return a random connection */ - public Connection getRandomConnection(int column, boolean levelsBack) { - - if (levelsBack) { - return getRandomConnection(chromosome, column); + public Connection getRandomConnection() { + // choose output or node + int index = Utilities.getRandomInt(inputs.length + Parameters.getNodeCount()); + + if (index < inputs.length) { + // outputs + return inputs[index]; } else { - // choose input or node - int connectionType = Utilities.getRandomInt(inputs.length + (nodes.length * column)); - if (connectionType < inputs.length) { - // input - return chromosome.getInput(getRandomInt(Parameters.getInputs())); - } else { - // node - return chromosome.getNode(getRandomInt(Parameters.getRows()), getRandomInt(column)); - } + // node + index -= inputs.length; + return nodes[index / Parameters.getColumns()][index % Parameters.getColumns()]; } - + } + + /** + * This causes the list of active nodes to be recomputed lazily (once it is actually requested). + */ + public void recomputeActiveNodes() { + recomputeActiveNodes = true; + } + + /** + * This method computes a list of active nodes (if necessary) and returns it. + * + * @return + */ + public ArrayList getActiveNodes() { + // lazy recomputation has been triggered, do it + if (recomputeActiveNodes) { + recomputeActiveNodes = false; + activeNodes = new ArrayList(); + + for (int r = 0; r < nodes.length; r++) { + for (int c = 0; c < nodes[r].length; c++) { + + } + } + } + return activeNodes; } } diff --git a/src/jcgp/population/Input.java b/src/jcgp/population/Input.java index e00573e..ee008ce 100644 --- a/src/jcgp/population/Input.java +++ b/src/jcgp/population/Input.java @@ -2,7 +2,11 @@ package jcgp.population; public class Input implements Connection { - private int value = 0; + private int value = 0, index; + + public Input(int index) { + this.index = index; + } public void setValue(int newValue) { value = newValue; @@ -13,4 +17,8 @@ public class Input implements Connection { return value; } + public int getIndex() { + return index; + } + } diff --git a/src/jcgp/population/MutableElement.java b/src/jcgp/population/MutableElement.java index c21ee0b..5eae4ef 100644 --- a/src/jcgp/population/MutableElement.java +++ b/src/jcgp/population/MutableElement.java @@ -4,8 +4,4 @@ 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 3dbabb2..40ffa52 100644 --- a/src/jcgp/population/Node.java +++ b/src/jcgp/population/Node.java @@ -10,8 +10,10 @@ public class Node implements MutableElement, Connection { private Function function; private Connection[] connections; private int column, row; + private Chromosome chromosome; - public Node(int row, int column) { + public Node(Chromosome chromosome, int row, int column) { + this.chromosome = chromosome; this.column = column; this.row = row; } @@ -23,11 +25,13 @@ public class Node implements MutableElement, Connection { public void setFunction(Function newFunction) { function = newFunction; + chromosome.recomputeActiveNodes(); } @Override public void setConnection(Connection newConnection) { connections[Utilities.getRandomInt(connections.length)] = newConnection; + chromosome.recomputeActiveNodes(); } public void initialise(Function newFunction, Connection ... newConnections) throws InsufficientConnectionsException { @@ -41,14 +45,20 @@ public class Node implements MutableElement, Connection { } } - @Override public int getColumn() { return column; } - @Override public int getRow() { return row; } + + public Function getFunction() { + return function; + } + + public Connection getConnections(int index) { + return connections[index]; + } } diff --git a/src/jcgp/population/Output.java b/src/jcgp/population/Output.java index ce4f776..68045b0 100644 --- a/src/jcgp/population/Output.java +++ b/src/jcgp/population/Output.java @@ -1,15 +1,15 @@ package jcgp.population; -import jcgp.Parameters; - public class Output implements MutableElement { private Connection source; - private int row; + private Chromosome chromosome; + private int index; - public Output(int row) { - this.row = row; + public Output(Chromosome chromosome, int index) { + this.chromosome = chromosome; + this.index = index; } public int calculate() { @@ -19,17 +19,17 @@ public class Output implements MutableElement { @Override public void setConnection(Connection newConnection) { source = newConnection; - + chromosome.recomputeActiveNodes(); } - @Override - public int getColumn() { - return Parameters.getColumns(); + public int getIndex() { + return index; } - @Override - public int getRow() { - return row; + public Connection getSource() { + return source; } + + } diff --git a/src/jcgp/population/Population.java b/src/jcgp/population/Population.java index b56d992..fb968fb 100644 --- a/src/jcgp/population/Population.java +++ b/src/jcgp/population/Population.java @@ -11,10 +11,7 @@ public class Population implements Iterable { public Population() { population = new Chromosome[Parameters.getPopulationSize()]; for (int c = 0; c < population.length; c++) { - population[c] = new Chromosome(Parameters.getInputs(), - Parameters.getRows(), - Parameters.getColumns(), - Parameters.getOutputs()); + population[c] = new Chromosome(); } } -- cgit v1.2.3