aboutsummaryrefslogtreecommitdiffstats
path: root/src/jcgp
diff options
context:
space:
mode:
Diffstat (limited to 'src/jcgp')
-rw-r--r--src/jcgp/function/Addition.java2
-rw-r--r--src/jcgp/function/Function.java3
-rw-r--r--src/jcgp/function/InsufficientArgumentsException.java10
-rw-r--r--src/jcgp/function/Subtraction.java2
-rw-r--r--src/jcgp/population/Output.java1
-rw-r--r--src/jcgp/population/Population.java18
-rw-r--r--src/jcgp/tests/ChromosomeTests.java43
-rw-r--r--src/jcgp/tests/InputTests.java47
-rw-r--r--src/jcgp/tests/NodeTests.java212
-rw-r--r--src/jcgp/tests/OutputTests.java108
-rw-r--r--src/jcgp/tests/PopulationTests.java94
11 files changed, 504 insertions, 36 deletions
diff --git a/src/jcgp/function/Addition.java b/src/jcgp/function/Addition.java
index faf11d5..45a8d35 100644
--- a/src/jcgp/function/Addition.java
+++ b/src/jcgp/function/Addition.java
@@ -9,7 +9,7 @@ public class Addition extends Function {
if (connections.length > 0) {
return connections[0].getValue() + connections[1].getValue();
} else {
- return 0;
+ throw new InsufficientArgumentsException();
}
}
diff --git a/src/jcgp/function/Function.java b/src/jcgp/function/Function.java
index f2d1125..4900c68 100644
--- a/src/jcgp/function/Function.java
+++ b/src/jcgp/function/Function.java
@@ -1,10 +1,11 @@
package jcgp.function;
import jcgp.population.Connection;
+import jcgp.population.InsufficientConnectionsException;
public abstract class Function {
- public abstract int run(Connection ... connections);
+ public abstract int run(Connection ... connections) throws InsufficientConnectionsException;
public abstract int getArity();
diff --git a/src/jcgp/function/InsufficientArgumentsException.java b/src/jcgp/function/InsufficientArgumentsException.java
new file mode 100644
index 0000000..a591b20
--- /dev/null
+++ b/src/jcgp/function/InsufficientArgumentsException.java
@@ -0,0 +1,10 @@
+package jcgp.function;
+
+public class InsufficientArgumentsException extends RuntimeException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 2675108124600817777L;
+
+}
diff --git a/src/jcgp/function/Subtraction.java b/src/jcgp/function/Subtraction.java
index f8b9c7d..8f107b1 100644
--- a/src/jcgp/function/Subtraction.java
+++ b/src/jcgp/function/Subtraction.java
@@ -9,7 +9,7 @@ public class Subtraction extends Function {
if (connections.length > 1) {
return connections[0].getValue() - connections[1].getValue();
} else {
- return 0;
+ throw new InsufficientArgumentsException();
}
}
diff --git a/src/jcgp/population/Output.java b/src/jcgp/population/Output.java
index b3cb648..0171d7b 100644
--- a/src/jcgp/population/Output.java
+++ b/src/jcgp/population/Output.java
@@ -2,7 +2,6 @@ package jcgp.population;
import java.util.ArrayList;
-
public class Output implements MutableElement {
private Connection source;
diff --git a/src/jcgp/population/Population.java b/src/jcgp/population/Population.java
index fb968fb..56f1b50 100644
--- a/src/jcgp/population/Population.java
+++ b/src/jcgp/population/Population.java
@@ -8,15 +8,15 @@ public class Population implements Iterable<Chromosome> {
private Chromosome[] population;
- public Population() {
- population = new Chromosome[Parameters.getPopulationSize()];
- for (int c = 0; c < population.length; c++) {
- population[c] = new Chromosome();
- }
- }
-
public Population(Chromosome ... chromosomes) {
- population = chromosomes;
+ if (chromosomes.length > 0) {
+ population = chromosomes;
+ } else {
+ population = new Chromosome[Parameters.getPopulationSize()];
+ for (int c = 0; c < population.length; c++) {
+ population[c] = new Chromosome();
+ }
+ }
}
@Override
@@ -45,7 +45,7 @@ public class Population implements Iterable<Chromosome> {
public void remove() {
// not allowed
// since this would shift everything back one position, increment index
- index++;
+ // index++;
}
};
diff --git a/src/jcgp/tests/ChromosomeTests.java b/src/jcgp/tests/ChromosomeTests.java
index 3b7319f..cb2cb95 100644
--- a/src/jcgp/tests/ChromosomeTests.java
+++ b/src/jcgp/tests/ChromosomeTests.java
@@ -18,6 +18,7 @@ import jcgp.population.Node;
import jcgp.population.Output;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
/**
@@ -26,8 +27,8 @@ 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 allowed connection given a column
- * - It should be able to return any random connection
+ * - It should be able to return a random allowed connection given a column.
+ * - It should be able to return a random connection.
* - It should contain a freely modifiable fitness value.
* - 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
@@ -36,6 +37,8 @@ import org.junit.Test;
* specified Chromosome object.
* - It should be able to return a list of active nodes.
*
+ * TODO: bashing (strange value ranges, etc)
+ *
* WARNING: changing parameters may cause the tests to incorrectly fail!
*
* @author Eduardo Pedroni
@@ -45,8 +48,8 @@ public class ChromosomeTests {
private Chromosome chromosome;
- @Before
- public void setUp() throws Exception {
+ @BeforeClass
+ public static void setUpBeforeClass() {
// initialise function set
FunctionSet functionSet = new FunctionSet(new Addition(), new Subtraction());
@@ -54,18 +57,20 @@ public class ChromosomeTests {
Utilities.setResources(new Random(1234), functionSet);
// initialise parameters
- Parameters.setColumns(20);
- Parameters.setRows(10);
+ Parameters.setColumns(1);
+ Parameters.setRows(20);
Parameters.setInputs(2);
Parameters.setOutputs(4);
- Parameters.setLevelsBack(20);
+ Parameters.setLevelsBack(1);
Parameters.setMutationRate(10);
Parameters.setTotalGenerations(100);
Parameters.setTotalRuns(5);
Parameters.setMaxArity(functionSet.getMaxArity());
+ }
+ @Before
+ public void setUp() throws Exception {
chromosome = new Chromosome();
-
}
/**
@@ -76,7 +81,7 @@ public class ChromosomeTests {
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++) {
@@ -84,15 +89,15 @@ public class ChromosomeTests {
}
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());
+ 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++) {
@@ -101,7 +106,7 @@ public class ChromosomeTests {
clone.setInputs(testInputs);
for (int i = 0; i < Parameters.getOutputs(); i++) {
assertTrue("Incorrect output returned.", chromosome.getOutput(i).calculate() !=
- clone.getOutput(i).calculate());
+ clone.getOutput(i).calculate());
}
}
@@ -126,10 +131,10 @@ public class ChromosomeTests {
assertTrue("Connection is not an input.", connectionReturn);
}
- // get random connections with column 2
+ // get random connections with column 1
// they should all be nodes, and their columns should be within range
int connectionNodes = 0, connectionOutOfRange = 0, connectionInputs = 0, connectionPicks = 100000;
- int chosenColumn = 2;
+ int chosenColumn = 1;
for (int i = 0; i < connectionPicks; i++) {
Connection c = chromosome.getRandomConnection(chosenColumn);
if (c instanceof Node) {
@@ -222,7 +227,7 @@ public class ChromosomeTests {
}
}
}
-
+
/**
*
*/
@@ -233,12 +238,12 @@ public class ChromosomeTests {
for (int i = 0; i < Parameters.getOutputs(); i++) {
chromosome.getOutput(i).setConnection(chromosome.getNode(0, 0));
}
-
+
chromosome.getNode(0, 0).setConnection(chromosome.getInput(0));
-
+
assertTrue("Active connection not in list.", chromosome.getActiveNodes().contains(chromosome.getInput(0)));
assertTrue("Active connection not in list.", chromosome.getActiveNodes().contains(chromosome.getNode(0, 0)));
-
+
// change outputs, print list
chromosome.getOutput(0).setConnection(chromosome.getNode(0, Parameters.getColumns() - 1));
diff --git a/src/jcgp/tests/InputTests.java b/src/jcgp/tests/InputTests.java
new file mode 100644
index 0000000..3803990
--- /dev/null
+++ b/src/jcgp/tests/InputTests.java
@@ -0,0 +1,47 @@
+package jcgp.tests;
+
+import static org.junit.Assert.assertTrue;
+import jcgp.population.Input;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ *
+ * Tests which cover the behaviour specified for an input.
+ *
+ * - An input contains a single set value. This value can be freely set for
+ * fitness evaluation purposes. TODO this value should be generically typed.
+ * - It must be addressable by an index set upon construction only.
+ *
+ *
+ * @author Eduardo Pedroni
+ *
+ */
+public class InputTests {
+
+ private Input input;
+ // these are the test values
+ private final int inputValue = 19;
+ private final int inputIndex = 12;
+
+ @Before
+ public void setUp() throws Exception {
+ input = new Input(inputIndex);
+ }
+
+ @Test
+ public void valueTest() {
+ // assign a value to input, check that the returned value is correct
+ input.setValue(inputValue);
+
+ assertTrue("Incorrect value returned.", input.getValue() == inputValue);
+ }
+
+ @Test
+ public void indexTest() {
+ // check that the index returned is the one passed to the constructor
+ assertTrue("Incorrect index returned.", input.getIndex() == inputIndex);
+ }
+
+}
diff --git a/src/jcgp/tests/NodeTests.java b/src/jcgp/tests/NodeTests.java
index 921879f..ecc87ff 100644
--- a/src/jcgp/tests/NodeTests.java
+++ b/src/jcgp/tests/NodeTests.java
@@ -1,8 +1,21 @@
package jcgp.tests;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Random;
+
+import jcgp.Parameters;
+import jcgp.Utilities;
+import jcgp.function.Function;
+import jcgp.function.InsufficientArgumentsException;
+import jcgp.population.Chromosome;
+import jcgp.population.Connection;
+import jcgp.population.InsufficientConnectionsException;
+import jcgp.population.Node;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
/**
@@ -12,7 +25,8 @@ import org.junit.Test;
* - A node should contain read-only row and column values which are set upon construction.
* - It should contain a fully accessible Function object.
* - It should contain a set of connections which can be initialised and randomly
- * modified.
+ * modified. It should be able to return an addressed connection.
+ * - It should be able to compute a value using its function with its connections as arguments.
*
* WARNING: changing parameters may cause the tests to incorrectly fail!
*
@@ -21,13 +35,203 @@ import org.junit.Test;
*/
public class NodeTests {
+ private Node node;
+ private static Chromosome chromosome;
+ // these numbers will be used by the node under test
+ private final int arg1 = 2;
+ private final int arg2 = 5;
+
+ @BeforeClass
+ public static void setUpBeforeClass() {
+ // initialise utilities
+ Utilities.setResources(new Random(1234), null);
+
+ // initialise parameters
+ Parameters.setColumns(0);
+ Parameters.setRows(0);
+ Parameters.setInputs(0);
+ Parameters.setOutputs(0);
+ Parameters.setLevelsBack(0);
+ Parameters.setMutationRate(10);
+ Parameters.setTotalGenerations(100);
+ Parameters.setTotalRuns(5);
+ Parameters.setMaxArity(2);
+
+ chromosome = new Chromosome();
+ }
+
@Before
public void setUp() throws Exception {
-
+ node = new Node(chromosome, 0, 0);
+ // make node with anonymous addition function and hard-coded value connections
+ node.initialise(new Function() {
+ private int arity = 2;
+
+ @Override
+ public int run(Connection... connections) {
+
+ // add together the first n inputs if they exist, else throw exception
+ if (connections.length >= arity) {
+ return connections[0].getValue() + connections[1].getValue();
+ } else {
+ throw new InsufficientArgumentsException();
+ }
+ }
+
+ @Override
+ public int getArity() {
+ // addition with arity 2
+ return arity;
+ }
+
+ }, new Connection[]{new Connection() {
+
+ @Override
+ public int getValue() {
+ // hardcode a value
+ return arg1;
+ }
+
+ @Override
+ public void getActive(ArrayList<Connection> activeNodes) {
+ // irrelevant for this test
+ }
+
+ },
+ new Connection() {
+
+ @Override
+ public int getValue() {
+ // hardcode a value
+ return arg2;
+ }
+
+ @Override
+ public void getActive(ArrayList<Connection> activeNodes) {
+ // irrelevant for this test
+ }
+
+ }});
+ }
+
+ @Test
+ public void rowAndColumnTest() {
+ assertTrue("Incorrect row.", node.getRow() == 0);
+ assertTrue("Incorrect column.", node.getColumn() == 0);
}
@Test
- public void test() {
+ public void functionTest() {
+ // make a new function and assign to node
+ Function f = new Function() {
+
+ @Override
+ public int run(Connection... connections)
+ throws InsufficientConnectionsException {
+ // blank
+ return 0;
+ }
+
+ @Override
+ public int getArity() {
+ // blank
+ return 0;
+ }
+ };
+
+ node.setFunction(f);
+
+ // check that the function returned by the node is f
+ assertTrue("Incorrect function returned.", node.getFunction() == f);
+ // check that it outputs 0 as it should
+ assertTrue("Incorrect function output.", node.getValue() == 0);
+ }
+
+ @Test
+ public void evaluationTest() {
+ // check that addition is working
+ assertTrue("Node did not return expected value (sum of arguments).", node.getValue() == arg1 + arg2);
+
+ // put in a different function, check the output has changed appropriately
+ node.setFunction(new Function() {
+
+ private int arity = 2;
+
+ @Override
+ public int run(Connection... connections) throws InsufficientConnectionsException {
+ // add together the first n inputs if they exist, else throw exception
+ if (connections.length >= arity) {
+ return connections[0].getValue() - connections[1].getValue();
+ } else {
+ throw new InsufficientArgumentsException();
+ }
+ }
+
+ @Override
+ public int getArity() {
+ return arity;
+ }
+ });
+
+ assertTrue("Node did not return expected value (difference of arguments).", node.getValue() == arg1 - arg2);
+
+ }
+
+ @Test
+ public void connectionsTest() {
+ // make new blank connections, check that they are returned correctly when addressed
+ Connection conn0, conn1, conn2;
+ conn0 = new Connection() {
+
+ @Override
+ public int getValue() {
+ // blank
+ return 0;
+ }
+
+ @Override
+ public void getActive(ArrayList<Connection> activeNodes) {
+ // blank
+
+ }
+ };
+ conn1 = new Connection() {
+
+ @Override
+ public int getValue() {
+ // blank
+ return 0;
+ }
+
+ @Override
+ public void getActive(ArrayList<Connection> activeNodes) {
+ // blank
+
+ }
+ };
+ node.initialise(null, conn0, conn1);
+
+ assertTrue("Connection 0 is incorrect.", node.getConnection(0) == conn0);
+ assertTrue("Connection 1 is incorrect.", node.getConnection(1) == conn1);
+
+ // make yet another connection, set it randomly, check that it is one of the node's connections
+ conn2 = new Connection() {
+
+ @Override
+ public int getValue() {
+ // blank
+ return 0;
+ }
+
+ @Override
+ public void getActive(ArrayList<Connection> activeNodes) {
+ // blank
+
+ }
+ };
+ node.setConnection(conn2);
+
+ assertTrue("Connection was not found in node.", node.getConnection(0) == conn2 || node.getConnection(1) == conn2);
}
diff --git a/src/jcgp/tests/OutputTests.java b/src/jcgp/tests/OutputTests.java
new file mode 100644
index 0000000..06295ae
--- /dev/null
+++ b/src/jcgp/tests/OutputTests.java
@@ -0,0 +1,108 @@
+package jcgp.tests;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Random;
+
+import jcgp.Parameters;
+import jcgp.Utilities;
+import jcgp.population.Chromosome;
+import jcgp.population.Connection;
+import jcgp.population.Output;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * Tests which cover the behaviour specified for an output.
+ *
+ * - An output contains a single source Connection, which can be set and got.
+ * - It should return the value of its source connection.
+ * - It must be addressable by an index set upon construction only.
+ *
+ *
+ * @author Eduardo Pedroni
+ *
+ */
+public class OutputTests {
+
+ private Output output;
+ private static Chromosome chromosome;
+ // these are the test values
+ private final int outputValue = 10;
+ private final int outputIndex = 2;
+
+ @BeforeClass
+ public static void setUpBeforeClass() {
+ // initialise utilities
+ Utilities.setResources(new Random(1234), null);
+
+ // initialise parameters
+ Parameters.setColumns(0);
+ Parameters.setRows(0);
+ Parameters.setInputs(0);
+ Parameters.setOutputs(0);
+ Parameters.setLevelsBack(0);
+ Parameters.setMutationRate(10);
+ Parameters.setTotalGenerations(100);
+ Parameters.setTotalRuns(5);
+ Parameters.setMaxArity(2);
+
+ chromosome = new Chromosome();
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ output = new Output(chromosome, outputIndex);
+ }
+
+ @Test
+ public void evaluationsTest() {
+ // set source connection, check that the appropriate value is returned
+ output.setConnection(new Connection() {
+
+ @Override
+ public int getValue() {
+ // test value
+ return outputValue;
+ }
+
+ @Override
+ public void getActive(ArrayList<Connection> activeNodes) {
+ // blank
+ }
+ });
+
+ assertTrue("Incorrect evaluation.", output.calculate() == outputValue);
+ }
+
+ @Test
+ public void connectionTest() {
+ // set a new connection, check that it is correctly returned
+ Connection newConn = new Connection() {
+
+ @Override
+ public int getValue() {
+ // blank
+ return 0;
+ }
+
+ @Override
+ public void getActive(ArrayList<Connection> activeNodes) {
+ // blank
+ }
+ };
+ output.setConnection(newConn);
+
+ assertTrue("Incorrect connection returned.", output.getSource() == newConn);
+ }
+
+ @Test
+ public void indexTest() {
+ // check that the index returned is the one passed to the constructor
+ assertTrue("Incorrect index returned.", output.getIndex() == outputIndex);
+ }
+}
diff --git a/src/jcgp/tests/PopulationTests.java b/src/jcgp/tests/PopulationTests.java
new file mode 100644
index 0000000..16a8d89
--- /dev/null
+++ b/src/jcgp/tests/PopulationTests.java
@@ -0,0 +1,94 @@
+package jcgp.tests;
+
+import static org.junit.Assert.*;
+
+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.Population;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * Tests which cover the behaviour specified for a population.
+ *
+ * - A population is a collection of chromosomes. It should be Iterable
+ * so the chromosomes can be accessed. Chromosomes should never be removed
+ * via the iterator.
+ * - When constructed with no arguments, it should generate populationSize
+ * random chromosomes.
+ * - If an array of chromosomes is passed as an argument to the constructor,
+ * it should use those chromosomes as the population.
+ *
+ *
+ * @author Eduardo Pedroni
+ *
+ */
+public class PopulationTests {
+
+ private Population population;
+
+ @BeforeClass
+ public static void setUpBeforeClass() 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(20);
+ Parameters.setRows(20);
+ Parameters.setInputs(2);
+ Parameters.setOutputs(4);
+ Parameters.setLevelsBack(1);
+ Parameters.setMutationRate(10);
+ Parameters.setTotalGenerations(100);
+ Parameters.setTotalRuns(5);
+ Parameters.setPopulationSize(5);
+ Parameters.setMaxArity(functionSet.getMaxArity());
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ population = new Population();
+ }
+
+ @Test
+ public void iterableTest() {
+ // check that Population is really Iterable
+ assertTrue("Population must implement Iterable.", population instanceof Iterable);
+
+ // iterate through, check that different chromosomes are returned and no chromosome can be removed
+ Chromosome comparison = null;
+ int iterationCount = 0;
+ for (Chromosome chromosome : population) {
+ iterationCount++;
+ assertTrue("Same chromosome returned twice.", comparison != chromosome);
+ comparison = chromosome;
+ population.iterator().remove();
+ assertTrue("Chromosome removed.", comparison == chromosome);
+ }
+ // check that all chromosomes were iterated through
+ assertTrue("Not enough itearations occurred.", iterationCount == Parameters.getPopulationSize());
+ }
+
+ @Test
+ public void contentsTest() {
+ // check that the constructor really generates populationSize chromosomes when none is given
+ int populationCount = 0;
+ for (Chromosome chromosome : population) {
+ populationCount++;
+ }
+ assertTrue("Incorrect number of chromosomes generated.", populationCount == Parameters.getPopulationSize());
+ }
+
+}