diff options
author | Eduardo Pedroni <ep625@york.ac.uk> | 2014-02-15 21:43:35 +0000 |
---|---|---|
committer | Eduardo Pedroni <ep625@york.ac.uk> | 2014-02-15 21:45:21 +0000 |
commit | e9290a500b228e2561a8537adbc13e86f1356747 (patch) | |
tree | 5e76280ddefc5bf9dcf9cdb55e80ca4831998115 | |
parent | afa484021ba94d12e98da682a9ff69c3837d5dbb (diff) |
Population and Chromosome classes refactored so that EAs are easier to implement.
24 files changed, 251 insertions, 196 deletions
@@ -139,5 +139,10 @@ Tests have been refactored to deal with the new data system. The system uses Obj any class to be used (and also primitive types). +15/2 +The Population class will be refactored to contain two collections of chromosomes, one for parents and one for offpsring. This allows +for (1+λ) and (1,λ) EAs, for example. It no longer makes sense for Population to implement Iterable, so the tests will be changed to reflect +the specification change. Population can still return an addressed chromosome in general, which it does by returning parents followed by offspring. +The chromosome copyConnections method has been made public to facilitate the EA implementation. 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); } } |