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 ++++++++++++++++++++++++++---------- 1 file changed, 144 insertions(+), 54 deletions(-) (limited to 'src/jcgp/population/Chromosome.java') 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; } } -- cgit v1.2.3