aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEduardo Pedroni <ep625@york.ac.uk>2014-02-15 21:43:35 +0000
committerEduardo Pedroni <ep625@york.ac.uk>2014-02-15 21:45:21 +0000
commite9290a500b228e2561a8537adbc13e86f1356747 (patch)
tree5e76280ddefc5bf9dcf9cdb55e80ca4831998115 /src
parentafa484021ba94d12e98da682a9ff69c3837d5dbb (diff)
Population and Chromosome classes refactored so that EAs are easier to implement.
Diffstat (limited to 'src')
-rw-r--r--src/jcgp/CGP.java18
-rw-r--r--src/jcgp/Main.java4
-rw-r--r--src/jcgp/Parameters.java34
-rw-r--r--src/jcgp/ea/EvolutionaryAlgorithm.java8
-rw-r--r--src/jcgp/ea/StandardEA.java41
-rw-r--r--src/jcgp/ea/StandardMutator.java2
-rw-r--r--src/jcgp/exceptions/InsufficientConnectionsException.java (renamed from src/jcgp/population/InsufficientConnectionsException.java)2
-rw-r--r--src/jcgp/exceptions/InvalidArgumentsException.java (renamed from src/jcgp/function/InvalidArgumentsException.java)2
-rw-r--r--src/jcgp/exceptions/ParameterMismatchException.java (renamed from src/jcgp/fitness/ParameterMismatchException.java)2
-rw-r--r--src/jcgp/fitness/TestCase.java1
-rw-r--r--src/jcgp/fitness/TruthTableEvaluator.java17
-rw-r--r--src/jcgp/function/Addition.java8
-rw-r--r--src/jcgp/function/Function.java4
-rw-r--r--src/jcgp/function/Multiplication.java31
-rw-r--r--src/jcgp/function/Subtraction.java8
-rw-r--r--src/jcgp/population/Chromosome.java4
-rw-r--r--src/jcgp/population/Connection.java1
-rw-r--r--src/jcgp/population/Input.java1
-rw-r--r--src/jcgp/population/Node.java1
-rw-r--r--src/jcgp/population/Output.java4
-rw-r--r--src/jcgp/population/Population.java96
-rw-r--r--src/jcgp/tests/ChromosomeTests.java12
-rw-r--r--src/jcgp/tests/PopulationTests.java141
23 files changed, 246 insertions, 196 deletions
diff --git a/src/jcgp/CGP.java b/src/jcgp/CGP.java
index d2be161..0ccd74e 100644
--- a/src/jcgp/CGP.java
+++ b/src/jcgp/CGP.java
@@ -1,6 +1,7 @@
package jcgp;
import java.util.Random;
+
import jcgp.ea.EvolutionaryAlgorithm;
import jcgp.ea.Mutator;
import jcgp.ea.StandardEA;
@@ -10,6 +11,7 @@ import jcgp.fitness.TestCase;
import jcgp.fitness.TruthTableEvaluator;
import jcgp.function.Addition;
import jcgp.function.FunctionSet;
+import jcgp.function.Multiplication;
import jcgp.function.Subtraction;
import jcgp.population.Population;
@@ -28,9 +30,10 @@ public final class CGP {
Parameters.setCurrentGeneration(i);
fitnessFunction.evaluate(population);
ea.evolve(population, mutator);
- }
-
-
+ if (ea.getBestFitness() >= 3) {
+ break;
+ }
+ }
}
/**
@@ -38,19 +41,20 @@ public final class CGP {
*/
private void initialise() {
// initialise function set
- FunctionSet functionSet = new FunctionSet(new Addition(), new Subtraction());
+ FunctionSet functionSet = new FunctionSet(new Addition(), new Subtraction(), new Multiplication());
// initialise utilities
Utilities.setResources(new Random(1234), functionSet);
// initialise parameters
Parameters.setColumns(3);
- Parameters.setRows(3);
+ Parameters.setRows(6);
Parameters.setInputs(3);
Parameters.setOutputs(3);
- Parameters.setLevelsBack(1);
+ Parameters.setLevelsBack(3);
+ Parameters.setPopulationSize(1, 4);
Parameters.setMutationRate(10);
- Parameters.setTotalGenerations(100);
+ Parameters.setTotalGenerations(5000);
Parameters.setTotalRuns(5);
Parameters.setMaxArity(functionSet.getMaxArity());
diff --git a/src/jcgp/Main.java b/src/jcgp/Main.java
index 598c720..97b5c4a 100644
--- a/src/jcgp/Main.java
+++ b/src/jcgp/Main.java
@@ -1,10 +1,10 @@
package jcgp;
public class Main {
-
+
public static void main(String[] args) {
CGP cgp = new CGP();
cgp.getClass();
+
}
-
}
diff --git a/src/jcgp/Parameters.java b/src/jcgp/Parameters.java
index 26eb61c..0a6abd9 100644
--- a/src/jcgp/Parameters.java
+++ b/src/jcgp/Parameters.java
@@ -2,11 +2,12 @@ package jcgp;
public class Parameters {
- private static int rows, columns, inputs, outputs, levelsBack,
- mutationRate, populationSize, totalGenerations,
- currentGeneration = 0, totalRuns, currentRun = 0,
- maxArity, maxFitness;
+ private static int rows = 0, columns = 0, inputs = 0, outputs = 0, levelsBack = 0,
+ mutationRate = 0, totalGenerations = 0, parents = 0, offspring = 0,
+ currentGeneration = 0, totalRuns = 0, currentRun = 0,
+ maxArity = 0, maxFitness = 0;
+
public static int getRows() {
return rows;
}
@@ -36,9 +37,17 @@ public class Parameters {
}
public static int getPopulationSize() {
- return populationSize;
+ return offspring + parents;
}
-
+
+ public static int getOffspringCount() {
+ return offspring;
+ }
+
+ public static int getParentCount() {
+ return parents;
+ }
+
public static int getTotalGenerations() {
return totalGenerations;
}
@@ -87,8 +96,17 @@ public class Parameters {
Parameters.mutationRate = mutationRate;
}
- public static void setPopulationSize(int populationSize) {
- Parameters.populationSize = populationSize;
+ public static void setPopulationSize(int parents, int offspring) {
+ Parameters.parents = parents;
+ Parameters.offspring = offspring;
+ }
+
+ public static void setOffspringCount(int offspring) {
+ Parameters.offspring = offspring;
+ }
+
+ public static void setParentCount(int parents) {
+ Parameters.parents = parents;
}
public static void setTotalGenerations(int totalGenerations) {
diff --git a/src/jcgp/ea/EvolutionaryAlgorithm.java b/src/jcgp/ea/EvolutionaryAlgorithm.java
index 9e72a1b..e084da0 100644
--- a/src/jcgp/ea/EvolutionaryAlgorithm.java
+++ b/src/jcgp/ea/EvolutionaryAlgorithm.java
@@ -4,12 +4,8 @@ import jcgp.population.Population;
public interface EvolutionaryAlgorithm {
-// protected Mutator mutator;
-//
-// public EvolutionaryAlgorithm(Mutator mutator) {
-// this.mutator = mutator;
-// }
-
public abstract void evolve(Population population, Mutator mutator);
+ public abstract int getBestFitness();
+
}
diff --git a/src/jcgp/ea/StandardEA.java b/src/jcgp/ea/StandardEA.java
index b34c421..901333b 100644
--- a/src/jcgp/ea/StandardEA.java
+++ b/src/jcgp/ea/StandardEA.java
@@ -1,18 +1,45 @@
package jcgp.ea;
+import jcgp.Parameters;
import jcgp.population.Chromosome;
import jcgp.population.Population;
+/**
+ * (1 + λ) EA.
+ *
+ *
+ * @author Eduardo Pedroni
+ *
+ */
public class StandardEA implements EvolutionaryAlgorithm {
+
+ private int bestFitness = 0;
@Override
- public void evolve(Population population, Mutator mutator) {
- Chromosome select;
- for (Chromosome chromosome : population) {
-
-
- mutator.mutate(chromosome);
+ public void evolve(Population population, Mutator mutator) {
+ // select fittest chromosome
+ int fittest = 0;
+
+ for (int i = 1; i < Parameters.getPopulationSize(); i++) {
+ if (population.getChromosome(i).getFitness() >= population.getChromosome(fittest).getFitness()) {
+ fittest = i;
+ }
+ }
+ bestFitness = population.getChromosome(fittest).getFitness();
+ population.setBestIndividual(fittest);
+ System.out.println("Best fitness: " + bestFitness);
+ // create copies of fittest chromosome, mutate them
+ Chromosome fc = population.getChromosome(fittest);
+ for (int i = 0; i < Parameters.getPopulationSize(); i++) {
+ if (i != fittest) {
+ population.getChromosome(i).copyConnections(fc);
+ mutator.mutate(population.getChromosome(i));
+ }
}
}
-
+
+ @Override
+ public int getBestFitness() {
+ return bestFitness;
+ }
}
diff --git a/src/jcgp/ea/StandardMutator.java b/src/jcgp/ea/StandardMutator.java
index 447338a..b9c0a4e 100644
--- a/src/jcgp/ea/StandardMutator.java
+++ b/src/jcgp/ea/StandardMutator.java
@@ -11,7 +11,7 @@ public class StandardMutator implements Mutator {
@Override
public void mutate(Chromosome chromosome) {
- int mutations = (int) (Parameters.getMutationRate() * ((double) Parameters.getNodeCount() / 100));
+ int mutations = (int) (Parameters.getMutationRate() * (((double) Parameters.getNodeCount() + Parameters.getOutputs()) / 100));
for (int i = 0; i < mutations; i++) {
MutableElement m = chromosome.getRandomMutableElement();
diff --git a/src/jcgp/population/InsufficientConnectionsException.java b/src/jcgp/exceptions/InsufficientConnectionsException.java
index 807ec53..2ffc10f 100644
--- a/src/jcgp/population/InsufficientConnectionsException.java
+++ b/src/jcgp/exceptions/InsufficientConnectionsException.java
@@ -1,4 +1,4 @@
-package jcgp.population;
+package jcgp.exceptions;
public class InsufficientConnectionsException extends RuntimeException {
diff --git a/src/jcgp/function/InvalidArgumentsException.java b/src/jcgp/exceptions/InvalidArgumentsException.java
index cf55937..537018d 100644
--- a/src/jcgp/function/InvalidArgumentsException.java
+++ b/src/jcgp/exceptions/InvalidArgumentsException.java
@@ -1,4 +1,4 @@
-package jcgp.function;
+package jcgp.exceptions;
public class InvalidArgumentsException extends RuntimeException {
diff --git a/src/jcgp/fitness/ParameterMismatchException.java b/src/jcgp/exceptions/ParameterMismatchException.java
index 0ca69a7..93a8f10 100644
--- a/src/jcgp/fitness/ParameterMismatchException.java
+++ b/src/jcgp/exceptions/ParameterMismatchException.java
@@ -1,4 +1,4 @@
-package jcgp.fitness;
+package jcgp.exceptions;
public class ParameterMismatchException extends RuntimeException {
diff --git a/src/jcgp/fitness/TestCase.java b/src/jcgp/fitness/TestCase.java
index 4c10de7..e506d38 100644
--- a/src/jcgp/fitness/TestCase.java
+++ b/src/jcgp/fitness/TestCase.java
@@ -1,6 +1,7 @@
package jcgp.fitness;
import jcgp.Parameters;
+import jcgp.exceptions.ParameterMismatchException;
public class TestCase {
diff --git a/src/jcgp/fitness/TruthTableEvaluator.java b/src/jcgp/fitness/TruthTableEvaluator.java
index 4c26d60..2281b3f 100644
--- a/src/jcgp/fitness/TruthTableEvaluator.java
+++ b/src/jcgp/fitness/TruthTableEvaluator.java
@@ -2,26 +2,27 @@ package jcgp.fitness;
import jcgp.Parameters;
import jcgp.TruthTable;
-import jcgp.population.Chromosome;
import jcgp.population.Population;
public class TruthTableEvaluator implements FitnessFunction {
@Override
public void evaluate(Population population) {
- for (Chromosome chromosome : population) {
+ // for every chromosome in the population
+ for (int i = 0; i < Parameters.getPopulationSize(); i++) {
+ int fitness = 0;
+ // for every test case
for (int t = 0; t < TruthTable.getTestCaseCount(); t++) {
- chromosome.setInputs(TruthTable.getTestCase(t).getInputs());
- int fitness = 0;
+ population.getChromosome(i).setInputs(TruthTable.getTestCase(t).getInputs());
+ // check every output
for (int o = 0; o < Parameters.getOutputs(); o++) {
- if (chromosome.getOutput(o).calculate() == TruthTable.getTestCase(t).getOutput(o)) {
+ if (population.getChromosome(i).getOutput(o).calculate() == TruthTable.getTestCase(t).getOutput(o)) {
fitness++;
}
}
- chromosome.setFitness(fitness);
- System.out.println("Fitness: " + fitness);
}
+ population.getChromosome(i).setFitness(fitness);
+ System.out.println("active nodes: " + population.getChromosome(i).getActiveNodes().size());
}
}
-
}
diff --git a/src/jcgp/function/Addition.java b/src/jcgp/function/Addition.java
index f40bc24..3a8f123 100644
--- a/src/jcgp/function/Addition.java
+++ b/src/jcgp/function/Addition.java
@@ -1,5 +1,6 @@
package jcgp.function;
+import jcgp.exceptions.InvalidArgumentsException;
import jcgp.population.Connection;
public class Addition extends Function {
@@ -11,7 +12,12 @@ public class Addition extends Function {
if (connections.length < arity) {
throw new InvalidArgumentsException("Not enough connections were given.");
} else if (connections[0].getValue() instanceof Integer) {
- return ((Integer) connections[0].getValue()) + ((Integer) connections[1].getValue());
+ Integer arg1 = ((Integer) connections[0].getValue());
+ Integer arg2 = ((Integer) connections[1].getValue());
+ Integer result = arg1 + arg2;
+
+ System.out.println(arg1 + " + " + arg2 + " = " + result);
+ return result;
} else {
throw new InvalidArgumentsException("Wrong data type, this function takes Integer.");
}
diff --git a/src/jcgp/function/Function.java b/src/jcgp/function/Function.java
index 118131a..584421a 100644
--- a/src/jcgp/function/Function.java
+++ b/src/jcgp/function/Function.java
@@ -1,11 +1,11 @@
package jcgp.function;
+import jcgp.exceptions.InvalidArgumentsException;
import jcgp.population.Connection;
-import jcgp.population.InsufficientConnectionsException;
public abstract class Function {
- public abstract Object run(Connection ... connections) throws InsufficientConnectionsException;
+ public abstract Object run(Connection ... connections) throws InvalidArgumentsException;
public abstract int getArity();
diff --git a/src/jcgp/function/Multiplication.java b/src/jcgp/function/Multiplication.java
new file mode 100644
index 0000000..986faa8
--- /dev/null
+++ b/src/jcgp/function/Multiplication.java
@@ -0,0 +1,31 @@
+package jcgp.function;
+
+import jcgp.exceptions.InvalidArgumentsException;
+import jcgp.population.Connection;
+
+public class Multiplication extends Function {
+
+ private int arity = 2;
+
+ @Override
+ public Object run(Connection... connections) {
+ if (connections.length < arity) {
+ throw new InvalidArgumentsException("Not enough connections were given.");
+ } else if (connections[0].getValue() instanceof Integer) {
+ Integer arg1 = ((Integer) connections[0].getValue());
+ Integer arg2 = ((Integer) connections[1].getValue());
+ Integer result = arg1 * arg2;
+
+ System.out.println(arg1 + " * " + arg2 + " = " + result);
+ return result;
+ } else {
+ throw new InvalidArgumentsException("Wrong data type, this function takes Integer.");
+ }
+ }
+
+ @Override
+ public int getArity() {
+ return arity;
+ }
+
+}
diff --git a/src/jcgp/function/Subtraction.java b/src/jcgp/function/Subtraction.java
index d785614..cfbb907 100644
--- a/src/jcgp/function/Subtraction.java
+++ b/src/jcgp/function/Subtraction.java
@@ -1,5 +1,6 @@
package jcgp.function;
+import jcgp.exceptions.InvalidArgumentsException;
import jcgp.population.Connection;
public class Subtraction extends Function {
@@ -11,7 +12,12 @@ public class Subtraction extends Function {
if (connections.length < arity) {
throw new InvalidArgumentsException("Not enough connections were given.");
} else if (connections[0].getValue() instanceof Integer) {
- return ((Integer) connections[0].getValue()) - ((Integer) connections[1].getValue());
+ Integer arg1 = ((Integer) connections[0].getValue());
+ Integer arg2 = ((Integer) connections[1].getValue());
+ Integer result = arg1 - arg2;
+
+ System.out.println(arg1 + " - " + arg2 + " = " + result);
+ return result;
} else {
throw new InvalidArgumentsException("Wrong data type, this function takes Integer.");
}
diff --git a/src/jcgp/population/Chromosome.java b/src/jcgp/population/Chromosome.java
index 12a8978..3e61a10 100644
--- a/src/jcgp/population/Chromosome.java
+++ b/src/jcgp/population/Chromosome.java
@@ -4,7 +4,7 @@ import java.util.ArrayList;
import jcgp.Parameters;
import jcgp.Utilities;
-import jcgp.fitness.ParameterMismatchException;
+import jcgp.exceptions.ParameterMismatchException;
public class Chromosome {
@@ -95,7 +95,7 @@ public class Chromosome {
/**
* @param clone
*/
- private void copyConnections(Chromosome clone) {
+ public 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++) {
diff --git a/src/jcgp/population/Connection.java b/src/jcgp/population/Connection.java
index ff11d7c..751fe10 100644
--- a/src/jcgp/population/Connection.java
+++ b/src/jcgp/population/Connection.java
@@ -3,5 +3,6 @@ package jcgp.population;
public interface Connection {
public Object getValue();
+
}
diff --git a/src/jcgp/population/Input.java b/src/jcgp/population/Input.java
index 2154dd9..e793bf6 100644
--- a/src/jcgp/population/Input.java
+++ b/src/jcgp/population/Input.java
@@ -21,5 +21,4 @@ public class Input implements Connection {
public int getIndex() {
return index;
}
-
}
diff --git a/src/jcgp/population/Node.java b/src/jcgp/population/Node.java
index e58c1a4..35d33cb 100644
--- a/src/jcgp/population/Node.java
+++ b/src/jcgp/population/Node.java
@@ -5,6 +5,7 @@ import java.util.Arrays;
import jcgp.Parameters;
import jcgp.Utilities;
+import jcgp.exceptions.InsufficientConnectionsException;
import jcgp.function.Function;
diff --git a/src/jcgp/population/Output.java b/src/jcgp/population/Output.java
index dae7278..b3ce74f 100644
--- a/src/jcgp/population/Output.java
+++ b/src/jcgp/population/Output.java
@@ -14,7 +14,9 @@ public class Output implements MutableElement {
}
public Object calculate() {
- return source.getValue();
+ Object result = source.getValue();
+ System.out.println("Output " + index + ": " + result);
+ return result;
}
@Override
diff --git a/src/jcgp/population/Population.java b/src/jcgp/population/Population.java
index 4153e0f..9cd7430 100644
--- a/src/jcgp/population/Population.java
+++ b/src/jcgp/population/Population.java
@@ -1,54 +1,72 @@
package jcgp.population;
-import java.util.Iterator;
-
import jcgp.Parameters;
-public class Population implements Iterable<Chromosome> {
+public class Population {
- private Chromosome[] population;
+ private Chromosome[] parents;
+ private Chromosome[] offspring;
+ private Chromosome bestIndividual;
- public Population(Chromosome chromosome) {
- population = new Chromosome[Parameters.getPopulationSize()];
- for (int c = 0; c < population.length; c++) {
- population[c] = new Chromosome(chromosome);
+ public Population(Chromosome parent) {
+ parents = new Chromosome[Parameters.getParentCount()];
+ // make a clone for safety
+ this.parents[0] = new Chromosome(parent);
+ // generate the rest of parents
+ for (int c = 1; c < parents.length; c++) {
+ parents[c] = new Chromosome();
+ }
+
+ offspring = new Chromosome[Parameters.getOffspringCount()];
+ for (int c = 0; c < offspring.length; c++) {
+ // completely random offspring? depending on EA, this means the given parent won't be selected
+ offspring[c] = new Chromosome();
}
}
public Population() {
- population = new Chromosome[Parameters.getPopulationSize()];
- for (int c = 0; c < population.length; c++) {
- population[c] = new Chromosome();
+ parents = new Chromosome[Parameters.getParentCount()];
+ for (int c = 0; c < parents.length; c++) {
+ parents[c] = new Chromosome();
}
- }
-
- @Override
- public Iterator<Chromosome> iterator() {
- return new Iterator<Chromosome>() {
-
- private int index = 0;
-
- @Override
- public boolean hasNext() {
- if (index < population.length) {
- return true;
- } else {
- return false;
- }
- }
- @Override
- public Chromosome next() {
- Chromosome next = population[index];
- index++;
- return next;
- }
+ offspring = new Chromosome[Parameters.getOffspringCount()];
+ for (int c = 0; c < offspring.length; c++) {
+ offspring[c] = new Chromosome();
+ }
+ }
- @Override
- public void remove() {
- // not allowed
- throw new UnsupportedOperationException("Removing chromosomes from the population is not allowed. Instead, re-instantiate the chromosome.");
- }
- };
+ public Chromosome getOffspring(int index) {
+ return offspring[index];
+ }
+
+ public Chromosome getParent(int index) {
+ return parents[index];
+ }
+
+ /**
+ * Returns all chromosomes, parents first, then offspring.
+ *
+ * @param index
+ * @return
+ */
+ public Chromosome getChromosome(int index) {
+ if (index < parents.length) {
+ return parents[index];
+ } else {
+ return offspring[index - parents.length];
+ }
+ }
+
+ public void setBestIndividual(int index) {
+ if (index < parents.length) {
+ bestIndividual = parents[index];
+ } else {
+ bestIndividual = offspring[index - parents.length];
+ }
+ }
+
+ public Chromosome getBestIndividual() {
+ return bestIndividual;
}
}
diff --git a/src/jcgp/tests/ChromosomeTests.java b/src/jcgp/tests/ChromosomeTests.java
index 8092d60..c943da8 100644
--- a/src/jcgp/tests/ChromosomeTests.java
+++ b/src/jcgp/tests/ChromosomeTests.java
@@ -31,8 +31,7 @@ import org.junit.Test;
* - 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 the inputs.
- * - It should feature a clone constructor, which creates a deep copy of a
- * specified Chromosome object.
+ * - It should feature a copy method, which creates a deep copy of a specified Chromosome object.
* - It should be able to return a list of active nodes.
* - It should contain a method to evaluate whether a given chromosome is identical
* to it.
@@ -65,11 +64,11 @@ public class ChromosomeTests {
@Before
public void setUp() throws Exception {
- Parameters.setColumns(10);
+ Parameters.setColumns(5);
Parameters.setRows(2);
Parameters.setInputs(2);
Parameters.setOutputs(4);
- Parameters.setLevelsBack(10);
+ Parameters.setLevelsBack(5);
chromosome = new Chromosome();
}
@@ -183,10 +182,9 @@ public class ChromosomeTests {
assertTrue("Connection is not an input.", connectionReturn);
}
- // get random connections with column 1
- // they should all be nodes, and their columns should be within range
+ // get random connections with the last column as reference, check that they're all within range
int connectionNodes = 0, connectionOutOfRange = 0, connectionInputs = 0, connectionPicks = 100000;
- int chosenColumn = 1;
+ int chosenColumn = Parameters.getColumns() - 1;
for (int i = 0; i < connectionPicks; i++) {
Connection c = chromosome.getRandomConnection(chosenColumn);
if (c instanceof Node) {
diff --git a/src/jcgp/tests/PopulationTests.java b/src/jcgp/tests/PopulationTests.java
index bb8fece..b8639bf 100644
--- a/src/jcgp/tests/PopulationTests.java
+++ b/src/jcgp/tests/PopulationTests.java
@@ -2,7 +2,6 @@ package jcgp.tests;
import static org.junit.Assert.*;
-import java.util.Iterator;
import java.util.Random;
import jcgp.Parameters;
@@ -11,8 +10,6 @@ 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.Population;
import org.junit.Before;
@@ -23,14 +20,13 @@ 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.
- * - Iterator.remove() should generate an UnsupportedOperationException
- * since chromosomes may not be removed.
+ * - A population should be able to return parents and offspring separately.
+ * - It should be possible to iterate through all the chromosomes in a population
+ * with one indexing system - parents then offspring.
* - When constructed with no arguments, it should generate populationSize
- * random chromosomes.
- * - If a chromosome is passed as an argument to the constructor, it should
- * create a population of copies of that chromosome.
+ * random chromosomes, distributed according to the EA parameters.
+ * - If one or more chromosomes are passed into the constructor, it should use them
+ * as parents to create the rest of the population.
*
*
* @author Eduardo Pedroni
@@ -57,7 +53,7 @@ public class PopulationTests {
Parameters.setMutationRate(10);
Parameters.setTotalGenerations(100);
Parameters.setTotalRuns(5);
- Parameters.setPopulationSize(5);
+ Parameters.setPopulationSize(1, 4);
Parameters.setMaxArity(functionSet.getMaxArity());
}
@@ -67,42 +63,43 @@ public class PopulationTests {
}
@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;
- boolean exceptionThrown = false;
-
- for (Chromosome chromosome : population) {
- iterationCount++;
- assertTrue("Same chromosome returned twice.", comparison != chromosome);
- comparison = chromosome;
-
+ public void defaultPopulationTest() {
+ // check that the constructor really generates populationSize chromosomes when none is given
+ int offspring = 0, parent = 0;
+ while (true) {
try {
- population.iterator().remove();
- } catch (UnsupportedOperationException e) {
- exceptionThrown = true;
+ population.getOffspring(offspring);
+ } catch (IndexOutOfBoundsException e) {
+ break;
}
- assertTrue("Chromosome removed.", exceptionThrown);
- exceptionThrown = false;
+ offspring++;
}
- // check that all chromosomes were iterated through
- assertTrue("Number of elements in population does not match specified parameter size.",
- iterationCount == Parameters.getPopulationSize());
+ while (true) {
+ try {
+ population.getParent(parent);
+ } catch (IndexOutOfBoundsException e) {
+ break;
+ }
+ parent++;
+ }
+ assertTrue("Incorrect number of chromosomes generated.", offspring + parent == Parameters.getPopulationSize());
}
-
+
@Test
- public void defaultPopulationTest() {
- // check that the constructor really generates populationSize chromosomes when none is given
- int populationCount = 0;
- for (Iterator<Chromosome> iterator = population.iterator(); iterator.hasNext();) {
- populationCount++;
- iterator.next();
+ public void offspringParentTest() {
+ // the first parent should not be the same as the first offspring
+ assertTrue("Same chromosome returned as parent and offspring", population.getOffspring(0) != population.getParent(0));
+ }
+
+ @Test
+ public void singleIndexTest() {
+ // assuming 1+4
+ // the first chromosome should be the first (and only) parent
+ assertTrue("Incorrect chromosome returned.", population.getChromosome(0) == population.getParent(0));
+ // the next 4 chromosomes should be the offspring, in order
+ for (int i = 0; i < Parameters.getOffspringCount(); i++) {
+ assertTrue("Incorrect chromosome returned.", population.getChromosome(i + 1) == population.getOffspring(i));
}
- assertTrue("Incorrect number of chromosomes generated.", populationCount == Parameters.getPopulationSize());
}
@Test
@@ -110,65 +107,9 @@ public class PopulationTests {
// the original chromosome that will be cloned
Chromosome oc = new Chromosome();
- // initialise a population with copies of it
+ // initialise a population with a copy of it
population = new Population(oc);
- // check that the chromosomes returned are identical to the one given
- int index = 0;
- for (Chromosome c : population) {
- assertTrue("Incorrect chromosome in population.", c != oc);
- index++;
- }
- // check that the right number of copies was made
- assertTrue("Wrong number of chromosomes in population.", index == Parameters.getPopulationSize());
-
- // check that the copies are exact copies
- for (Chromosome c : population) {
- // check outputs
- for (int o = 0; o < Parameters.getOutputs(); o++) {
- // check that no cross-references exist between chromosomes
- assertTrue("Cloned chromosome contained a reference to a member of the original chromosome.",
- c.getOutput(o) != oc.getOutput(o) &&
- c.getOutput(o).getSource() != oc.getOutput(o).getSource());
- // check that the connections are equivalent
- if (c.getOutput(o).getSource() instanceof Input && oc.getOutput(o).getSource() instanceof Input) {
- assertTrue("Outputs did not connect to equivalent inputs.",
- ((Input) c.getOutput(o).getSource()).getIndex() == ((Input) oc.getOutput(o).getSource()).getIndex());
- } else if (c.getOutput(o).getSource() instanceof Node && oc.getOutput(o).getSource() instanceof Node) {
- assertTrue("Outputs did not connect to equivalent nodes.",
- ((Node) c.getOutput(o).getSource()).getRow() == ((Node) oc.getOutput(o).getSource()).getRow() &&
- ((Node) c.getOutput(o).getSource()).getColumn() == ((Node) oc.getOutput(o).getSource()).getColumn());
- } else {
- fail("Output source types did not match.");
- }
- }
- // check nodes, rows first
- for (int row = 0; row < Parameters.getRows(); row++) {
- for (int column = 0; column < Parameters.getColumns(); column++) {
- // look at each connection
- for (int connection = 0; connection < Parameters.getMaxArity(); connection++) {
- if (c.getNode(row, column).getConnection(connection) instanceof Input &&
- oc.getNode(row, column).getConnection(connection) instanceof Input) {
-
- assertTrue("Nodes did not connect to equivalent inputs.",
- ((Input) c.getNode(row, column).getConnection(connection)).getIndex() ==
- ((Input) oc.getNode(row, column).getConnection(connection)).getIndex());
-
- } else if (c.getNode(row, column).getConnection(connection) instanceof Node &&
- oc.getNode(row, column).getConnection(connection) instanceof Node) {
-
- assertTrue("Nodes did not connect to equivalent nodes.",
- ((Node) c.getNode(row, column).getConnection(connection)).getRow() ==
- ((Node) oc.getNode(row, column).getConnection(connection)).getRow() &&
-
- ((Node) c.getNode(row, column).getConnection(connection)).getColumn() ==
- ((Node) oc.getNode(row, column).getConnection(connection)).getColumn());
-
- } else {
- fail("Connection types did not match.");
- }
- }
- }
- }
- }
+ // check that the first parent chromosome is identical to, but not the same instance as, the one given
+ assertTrue("Incorrect chromosome in population.", population.getParent(0).compareTo(oc) && population.getParent(0) != oc);
}
}