aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEduardo Pedroni <ep625@york.ac.uk>2014-02-11 16:50:27 +0000
committerEduardo Pedroni <ep625@york.ac.uk>2014-02-11 16:50:27 +0000
commitdd3b6446671f31d716eb07e546c6150b4d080abd (patch)
treeb30c1ac7599bce9a17f1ea621eecc427256e1486
parent3fc4bf4a2ea7c6cff9810b76964dd3c1388c0b3f (diff)
Implemented more tests, refactored chromosome more, added the beginnings of active node detection
-rw-r--r--README17
-rw-r--r--src/jcgp/Utilities.java78
-rw-r--r--src/jcgp/ea/StandardMutator.java24
-rw-r--r--src/jcgp/population/Chromosome.java198
-rw-r--r--src/jcgp/population/Input.java10
-rw-r--r--src/jcgp/population/MutableElement.java4
-rw-r--r--src/jcgp/population/Node.java16
-rw-r--r--src/jcgp/population/Output.java24
-rw-r--r--src/jcgp/population/Population.java5
-rw-r--r--src/jcgp/tests/ChromosomeTests.java216
10 files changed, 378 insertions, 214 deletions
diff --git a/README b/README
index 3095efa..18e3ebe 100644
--- a/README
+++ b/README
@@ -88,6 +88,19 @@ necessarily a problem.
7/2
The resource classes have been refactored so that tests can be implemented more easily. Parameters, Utilities and TruthTable
-are now top-level classes and work independently from CGP, allowing them to be initialised for testing purposes. Some chromosome
-tests have been written and more tests will be written in the next few days.
+are now top-level classes and work independently from CGP, allowing them to be initialised for testing purposes. Some
+chromosome tests have been written and more tests will be written in the next few days.
+11/2
+
+Methods to get random connections and mutable elements have been moved into Chromosome, as well as refactored to require
+less random number generations.
+
+Chromosome and its associated members (Node, Output, Input) have been refactored to allow copying. A copy constructor has been
+written which initialises a new chromosome as an exact copy of a given chromosome.
+
+Cloning has been tested and is working.
+
+Active node detection will be implemented via a getActiveNodes() method in Chromosome. The chromosome is notified whenever
+one of its nodes or outputs is mutated, and re-computes the list of active elements when it is required. It does so by recursively
+acquiring node connections and copying them to a separate list. \ No newline at end of file
diff --git a/src/jcgp/Utilities.java b/src/jcgp/Utilities.java
index f052595..394a481 100644
--- a/src/jcgp/Utilities.java
+++ b/src/jcgp/Utilities.java
@@ -25,62 +25,6 @@ public class Utilities {
}
/**
- * Returns a random allowed connection respecting levels back.
- * This method may always pick inputs, as they can be picked
- * regardless of the column.
- *
- * TODO remove?
- *
- * @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.
- *
- * TODO remove?
- *
- * @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
*/
@@ -131,28 +75,6 @@ public class Utilities {
}
}
- /**
- * This method picks a random mutable element from the given chromosome.
- *
- * It will pick outputs or nodes fairly.
- *
- * TODO probably remove this
- *
- * @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
diff --git a/src/jcgp/ea/StandardMutator.java b/src/jcgp/ea/StandardMutator.java
index 8af3f5c..6a4af1a 100644
--- a/src/jcgp/ea/StandardMutator.java
+++ b/src/jcgp/ea/StandardMutator.java
@@ -14,18 +14,18 @@ public class StandardMutator implements Mutator {
int mutations = (int) (Parameters.getMutationRate() * ((double) Parameters.getNodeCount() / 100));
for (int i = 0; i < mutations; i++) {
- MutableElement m = Utilities.getRandomMutable(chromosome);
-
- if (m instanceof Output) {
- m.setConnection(Utilities.getRandomConnection(chromosome, m.getColumn()));
- } else if (m instanceof Node) {
- int geneType = Utilities.getRandomInt(1 + Parameters.getMaxArity());
- if (geneType < 1) {
- ((Node) m).setFunction(Utilities.getRandomFunction());
- } else {
- m.setConnection(Utilities.getRandomConnection(chromosome, m.getColumn()));
- }
- }
+ MutableElement m = chromosome.getRandomMutableElement();
+//
+// if (m instanceof Output) {
+// m.setConnection(chromosome.getRandomConnection(m.getColumn()));
+// } else if (m instanceof Node) {
+// int geneType = Utilities.getRandomInt(1 + Parameters.getMaxArity());
+// if (geneType < 1) {
+// ((Node) m).setFunction(Utilities.getRandomFunction());
+// } else {
+// m.setConnection(chromosome.getRandomConnection(m.getColumn()));
+// }
+// }
}
}
}
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<Connection> 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.</br>
* 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<Connection> getActiveNodes() {
+ // lazy recomputation has been triggered, do it
+ if (recomputeActiveNodes) {
+ recomputeActiveNodes = false;
+ activeNodes = new ArrayList<Connection>();
+
+ 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<Chromosome> {
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();
}
}
diff --git a/src/jcgp/tests/ChromosomeTests.java b/src/jcgp/tests/ChromosomeTests.java
index 50d17b9..ece8203 100644
--- a/src/jcgp/tests/ChromosomeTests.java
+++ b/src/jcgp/tests/ChromosomeTests.java
@@ -1,15 +1,17 @@
package jcgp.tests;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
import java.util.Random;
import jcgp.Parameters;
import jcgp.Utilities;
+import jcgp.fitness.ParameterMismatchException;
import jcgp.function.Addition;
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;
@@ -24,24 +26,24 @@ import org.junit.Test;
*
* - The chromosome should be able to return a specified node, input or output.
* - It should be able to return a random MutableElement.
- * - It should be able to return a random Connection
+ * - It should be able to return a random allowed connection given a column
+ * - It should be able to return any random connection
* - It should contain a freely modifiable fitness value.
- * - It should be a good citizen - fully initialised upon instantiation.
+ * - For truth table evaluations, it should be able to have its inputs set.
+ * - For truth table evaluations, the output should return a value according to what
+ * it is set to.
* - 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.
+ * - It should be able to return a list of active nodes.
+ *
+ * WARNING: changing parameters may cause the tests to incorrectly fail!
*
* @author Eduardo Pedroni
*
*/
public class ChromosomeTests {
- Chromosome chromosome;
- int inputCount = 3,
- rows = 3,
- columns = 3,
- outputCount = 3;
+ private Chromosome chromosome;
@Before
public void setUp() throws Exception {
@@ -52,54 +54,180 @@ public class ChromosomeTests {
Utilities.setResources(new Random(1234), functionSet);
// initialise parameters
- Parameters.setColumns(columns);
- Parameters.setRows(rows);
- Parameters.setInputs(inputCount);
- Parameters.setOutputs(outputCount);
- Parameters.setLevelsBack(1);
+ Parameters.setColumns(20);
+ Parameters.setRows(10);
+ Parameters.setInputs(2);
+ Parameters.setOutputs(4);
+ Parameters.setLevelsBack(20);
Parameters.setMutationRate(10);
Parameters.setTotalGenerations(100);
Parameters.setTotalRuns(5);
Parameters.setMaxArity(functionSet.getMaxArity());
- chromosome = new Chromosome(inputCount, rows, columns, outputCount);
-
+ chromosome = new Chromosome();
+
}
+ /**
+ *
+ */
@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, check that it is a Mutable
- boolean mutableReturn = chromosome.getRandomMutableElement() != chromosome.getRandomMutableElement() && chromosome.getRandomMutableElement() instanceof MutableElement;
- assertTrue("Returned the same element.", mutableReturn);
+ public void cloneTest() {
+ int[] testInputs;
+ // create a clone, check to see if it really is a clone
+ Chromosome clone = new Chromosome(chromosome);
+ // set input values
+ testInputs = new int[Parameters.getInputs()];
+ for (int i = 0; i < Parameters.getInputs(); i++) {
+ testInputs[i] = i * 2 - 3;
+ }
+ chromosome.setInputs(testInputs);
+ clone.setInputs(testInputs);
+ // connect outputs to inputs, check that the outputs match
+ for (int i = 0; i < Parameters.getOutputs(); i++) {
+ chromosome.getOutput(i).setConnection(chromosome.getInput(i % Parameters.getInputs()));
+ clone.getOutput(i).setConnection(clone.getInput(i % Parameters.getInputs()));
+ assertTrue("Incorrect output returned.", chromosome.getOutput(i).calculate() ==
+ clone.getOutput(i).calculate());
+ }
+ // change clone inputs, outputs should no longer match
+ testInputs = new int[Parameters.getInputs()];
+ for (int i = 0; i < Parameters.getInputs(); i++) {
+ testInputs[i] = i * 2;
+ }
+ clone.setInputs(testInputs);
+ for (int i = 0; i < Parameters.getOutputs(); i++) {
+ assertTrue("Incorrect output returned.", chromosome.getOutput(i).calculate() !=
+ clone.getOutput(i).calculate());
+ }
+ }
+
+ /**
+ *
+ */
+ @Test
+ public void fitnessTest() {
// set a fitness value, check if returned value is the same
chromosome.setFitness(10);
assertTrue("Incorrect fitness returned.", chromosome.getFitness() == 10);
-
}
+ /**
+ *
+ */
+ @Test
+ public void randomConnectionTest() {
+ // get random connections with column 0, check that they are all inputs
+ for (int i = 0; i < 10000; i++) {
+ boolean connectionReturn = chromosome.getRandomConnection(0) instanceof Input;
+ assertTrue("Connection is not an input.", connectionReturn);
+ }
+
+ // get random connections with column 2
+ // they should all be nodes, and their columns should be within range
+ int connectionNodes = 0, connectionOutOfRange = 0, connectionInputs = 0, connectionPicks = 100000;
+ int chosenColumn = 2;
+ for (int i = 0; i < connectionPicks; i++) {
+ Connection c = chromosome.getRandomConnection(chosenColumn);
+ if (c instanceof Node) {
+ connectionNodes++;
+ if (((Node) c).getColumn() >= chosenColumn) {
+ connectionOutOfRange++;
+ }
+ assertTrue("Connection is not allowed : " + ((Node) c).getColumn(), ((Node) c).getColumn() < chosenColumn && ((Node) c).getColumn() < chosenColumn);
+ } else if (c instanceof Input) {
+ connectionInputs++;
+ } else {
+ fail("Return is neither Node nor Input.");
+
+ }
+ }
+ System.out.println("Out of " + connectionPicks + " connections picked from " + ((chosenColumn >= Parameters.getLevelsBack()) ? Parameters.getLevelsBack() : chosenColumn) * Parameters.getRows() +
+ " nodes and " + Parameters.getInputs() + " allowed nodes, " + connectionNodes + " were nodes and " + connectionInputs + " were inputs.");
+
+ System.out.println("Node/input ratio: " + ((double) ((chosenColumn >= Parameters.getLevelsBack()) ? Parameters.getLevelsBack() : chosenColumn) * Parameters.getRows()) / (double) Parameters.getInputs() +
+ ", picked ratio: " + (double) connectionNodes / (double) connectionInputs);
+
+ System.out.println(connectionOutOfRange + " nodes that disrespected levels back were picked.");
+ }
+
+ /**
+ *
+ */
+ @Test
+ public void randomMutableTest() {
+ // get mutable elements, check Node to Output ratio
+ int mutablePicks = 100000;
+ int mutableNodes = 0, mutableOutputs = 0;
+ for (int i = 0; i < mutablePicks; i++) {
+ MutableElement m = chromosome.getRandomMutableElement();
+
+ if (m instanceof Node) {
+ mutableNodes++;
+ } else if (m instanceof Output) {
+ mutableOutputs++;
+ } else {
+ fail("Return is neither Node nor Output.");
+ }
+ }
+ System.out.println("Out of " + mutablePicks + " mutable elements picked from " + Parameters.getNodeCount() +
+ " nodes and " + Parameters.getOutputs() + " outputs, " + mutableNodes + " were nodes and " +
+ mutableOutputs + " were outputs.");
+ System.out.println("Node/output ratio: " + (double) Parameters.getNodeCount() / (double) Parameters.getOutputs() +
+ ", picked ratio: " + (double) mutableNodes / (double) mutableOutputs + "\n");
+ }
+
+ /**
+ *
+ */
+ @Test
+ public void getOutputsTest() {
+ // connect outputs to inputs, check that calculated outputs return input values
+ for (int i = 0; i < Parameters.getOutputs(); i++) {
+ chromosome.getOutput(i).setConnection(chromosome.getInput(i % Parameters.getInputs()));
+ assertTrue("Incorrect output returned.", chromosome.getOutput(i).calculate() ==
+ chromosome.getInput(i % Parameters.getInputs()).getValue());
+ }
+ }
+
+ /**
+ * @throws ParameterMismatchException
+ */
+ @Test
+ public void setInputTest() throws ParameterMismatchException {
+ // set input values, check that acquired values are correct
+ int[] testInputs = new int[Parameters.getInputs()];
+ for (int i = 0; i < Parameters.getInputs(); i++) {
+ testInputs[i] = i * 2 - 3;
+ }
+ chromosome.setInputs(testInputs);
+ for (int i = 0; i < Parameters.getInputs(); i++) {
+ assertTrue("Incorrect input returned.", chromosome.getInput(i).getValue() == i * 2 - 3);
+ }
+ }
+
+ /**
+ *
+ */
+ @Test
+ public void getNodeTest() {
+ // get all nodes one by one, check that they are all correct
+ for (int r = 0; r < Parameters.getRows(); r++) {
+ for (int c = 0; c < Parameters.getColumns(); c++) {
+ assertTrue("Incorrect node returned.", chromosome.getNode(r, c).getColumn() == c &&
+ chromosome.getNode(r, c).getRow() == r);
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ @Test
+ public void activeNodeTest() {
+
+ }
}