diff options
author | Eduardo Pedroni <ep625@york.ac.uk> | 2014-05-04 19:23:52 +0100 |
---|---|---|
committer | Eduardo Pedroni <ep625@york.ac.uk> | 2014-05-04 19:23:52 +0100 |
commit | aa9e74e7f67789f6353fc26e02ee8e68e40609a2 (patch) | |
tree | 3ad4ed8a0717a9983775a38b0cc8d9a10c01302a /src/jcgp/backend/population/Chromosome.java | |
parent | c4fc7e307caf03c93c4203aff8960ffcb3ca8737 (diff) |
Added more comments, minor refactorings
Diffstat (limited to 'src/jcgp/backend/population/Chromosome.java')
-rw-r--r-- | src/jcgp/backend/population/Chromosome.java | 192 |
1 files changed, 166 insertions, 26 deletions
diff --git a/src/jcgp/backend/population/Chromosome.java b/src/jcgp/backend/population/Chromosome.java index d23f43c..b99b817 100644 --- a/src/jcgp/backend/population/Chromosome.java +++ b/src/jcgp/backend/population/Chromosome.java @@ -4,6 +4,54 @@ import java.util.ArrayList; import jcgp.backend.resources.Resources; +/** + * This class encapsulates a CGP chromosome. + * <br><br> + * A chromosome contains a matrix of nodes and arrays of inputs and outputs. + * These elements are all interconnected, and actually form the chromosome + * network itself. Individual nodes can be retrieved using {@code getNode()} + * which requires the row and column to be specified. The same works for + * inputs and outputs using the associated getters, in which case only the + * index is necessary. + * <br><br> + * In evolutionary computation it is often necessary to make copies of + * chromosomes; this can be accomplished in JCGP in two ways. The recommended + * way to do this is using {@code copyChromosome()} in {@code Population}, but alternatively + * it can be done by using the {@code Chromosome} copy constructor and specifying the + * object to copy from, or by using the {@code copyGenes()} method. + * <br><br> + * To illustrate this, given two chromosomes, chr1 and chr2, the following code: + * <br><br> + * <code> + * chr1.copyGenes(chr2); + * </code><br><br> + * will modify all of chr1's connections and functions to match those of chr2, without + * creating a new instance. In contrast, + * <br><br> + * <code> + * chr1 = new Chromosome(chr2); + * </code><br><br> + * creates a new instance of chromosome which is identical to chr2 and assigns it to chr1, + * meaning any old references to chr1 that are not updated will still refer to a chromosome + * that is not identical to chr2. In practice, the most reliable way is to use the copy method + * in {@code Population}. Assuming chr1 and chr2 are indexed 1 and 2 in {@code population} respectively, + * <br><br> + * population.copyChromosome(2, 1); + * <br><br> + * will copy chr2 into chr1 without creating new instances or requiring access to the underlying + * chromosome array. {@code Chromosome} offers a variety of methods to compare chromosomes as well, + * such as {@code compareGenesTo()} and {@code compareActiveGenesTo()}. {@code Comparable} is implemented + * to compare fitness value, meaning {@code compareTo()} returns a value depending the relative fitness + * of the compared chromosomes. + * <br><br> + * In order to set the chromosome's input values for decoding, {@code setInputs()} should be used. A few + * utility methods are provided in order to retrieve random elements from the chromosome, which are used + * internally to initialise with random connections but also externally by mutators when performing + * mutations. + * + * @author Eduardo Pedroni + * + */ public class Chromosome implements Comparable<Chromosome> { private Resources resources; @@ -19,14 +67,13 @@ public class Chromosome implements Comparable<Chromosome> { /** * Initialise a chromosome with the specified parameters. Random valid connections - * are created. - * - * + * are created upon initialisation. + * + * @param resources the experiment's resources. */ public Chromosome(Resources resources) { // store a reference to the parameters this.resources = resources; - // allocate memory for all elements of the chromosome instantiateElements(); // set random connections so that the chromosome can be evaluated @@ -38,12 +85,11 @@ public class Chromosome implements Comparable<Chromosome> { * * Initialise a new chromosome with the exact same connections as a given instance of Chromosome. * - * @param clone the chromosome to be copied + * @param clone the chromosome to be copied. */ public Chromosome(Chromosome clone) { // store a reference to the parameters this.resources = clone.getResources(); - // allocate memory for all elements of the chromosome instantiateElements(); // initialise all connections based on argument @@ -51,7 +97,14 @@ public class Chromosome implements Comparable<Chromosome> { } /** - * + * Allocates the necessary memory for all of the nodes, inputs + * and outputs in the chromosome according to the experiment + * resources. + * <br> + * Note that this does not actually initialise the genes, as it + * is not possible to do so until they have all been initialised; + * to initialise the genes, {@code reinitialiseConnections()} should + * be used. */ private void instantiateElements() { inputs = new Input[(resources.inputs())]; @@ -75,7 +128,9 @@ public class Chromosome implements Comparable<Chromosome> { } /** - * + * Sets random connections and functions across the entire + * chromosome. This method can be used more than once for + * each instance, if entirely random chromosomes are desired. */ public void reinitialiseConnections() { @@ -92,6 +147,7 @@ public class Chromosome implements Comparable<Chromosome> { } } + // set random outputs for (Output output : outputs) { output.setConnection(0, getRandomConnection()); } @@ -99,11 +155,21 @@ public class Chromosome implements Comparable<Chromosome> { } /** - * @param clone + * Creates a deep copy of the specified chromosome in the + * this instance. In practice, this iterates through the + * entire chromosome making equivalent connections and + * setting functions to the same values as those in the + * specified chromosome. + * <br> + * It is assumed that both chromosomes have the same + * topology; while this method will still run if that is not + * the case, the effects might be undesirable and null pointer + * access might occur. + * + * @param clone the chromosome to clone. */ public void copyGenes(Chromosome clone) { int arity = resources.arity(); - // copy nodes - [rows][columns] for (int r = 0; r < nodes.length; r++) { for (int c = 0; c < nodes[r].length; c++) { @@ -141,31 +207,64 @@ public class Chromosome implements Comparable<Chromosome> { } } + /** + * Returns a reference to any node, addressed by row and column. + * + * @param row the row of the node. + * @param column the column of the node. + * @return the addressed node. + */ public Node getNode(int row, int column) { return nodes[row][column]; } + /** + * Returns a reference to the indexed output. + * + * @param index the output index. + * @return the output reference. + */ public Output getOutput(int index) { return outputs[index]; } + /** + * Returns a reference to the indexed input. + * + * @param index the input index. + * @return the input reference. + */ public Input getInput(int index) { return inputs[index]; } + /** + * @return the fitness of the chromosome. + */ public double getFitness() { return fitness; } + /** + * Sets the fitness of the chromosome. This method + * should be used by the experiment problem when the + * population is evaluated in order to assign a fitness + * to each individual. + * + * @param newFitness the fitness to assign. + */ public void setFitness(double newFitness) { fitness = newFitness; } /** + * Loops through the inputs and sets the specified values, + * so that evaluations can be performed. If the number of + * elements in the array of values does not match the + * number of inputs exactly, an exception is thrown. * - * - * @param values - * @throws ParameterMismatchException + * @param values the values the input should take. + * @throws ParameterMismatchException if the wrong number of values is received. */ public void setInputs(Object ... values) { // if the values provided don't match the specified number of inputs, the user should be warned @@ -180,9 +279,11 @@ public class Chromosome implements Comparable<Chromosome> { } /** - * This method is useful for mutating chromosomes. + * This method is useful for mutating chromosomes. It returns any + * random {@code MutableElement} out of the chromosome with equal + * probability. * - * @return a random element that can be mutated - Node or Output + * @return a random element that can be mutated - node or output. */ public MutableElement getRandomMutableElement() { // choose output or node @@ -199,12 +300,12 @@ public class Chromosome implements Comparable<Chromosome> { } /** - * Returns a random allowed connection respecting levels back.</br> + * Returns a random allowed connection respecting levels back.<br> * This method may always pick inputs, as they can be picked * regardless of the column. * - * @param column the column to use as reference - * @return a random connection + * @param column the column to use as reference. + * @return a random connection. */ public Connection getRandomConnection(int column) { // work out the allowed range obeying levels back @@ -226,12 +327,9 @@ public class Chromosome implements Comparable<Chromosome> { /** * This method will pick a completely random connection, independently - * of levels back, including inputs. - * - * Useful for setting outputs. + * of levels back, including inputs. It is useful for setting outputs. * - * - * @return a random connection + * @return a random connection regardless of levels back. */ public Connection getRandomConnection() { // choose output or node @@ -254,27 +352,54 @@ public class Chromosome implements Comparable<Chromosome> { } /** - * This method computes a list of active connections (if necessary) and returns it. + * This method computes a list of active nodes (if necessary) and returns it. * - * @return + * @return the list of active nodes. */ public ArrayList<Node> getActiveNodes() { computeActiveNodes(); return activeNodes; } + /** + * For internal use only, this method actually computes the list of active nodes + * from the chromosome. This is done recursively by calling {@code getActive()} + * on the nodes until the first node returns. + */ private void computeActiveNodes() { // lazy recomputation has been triggered, do it if (recomputeActiveNodes) { recomputeActiveNodes = false; activeNodes = new ArrayList<Node>(); - + // recursive operation for (Output output : outputs) { output.getActiveNodes(activeNodes); } } } + /** + * Performs a deep comparison between this chromosome and the provided one. + * This is done on a gene-by-gene basis. + * + * This method returns true if and only if: + * <ul> + * <li>the chromosomes being compared are not the same instance;</li> + * <li>the connections of the compared chromosomes are not the same instance;</li> + * <li>the grid position of the chromosome's elements are the same;</li> + * </ul> + * <br><br> + * The relationship computed by this method is: + * <ul> + * <li>symmetric: a.copyOf(b) == b.copyOf(a);</li> + * <li>not reflexive: a.copyOf(a) returns false;</li> + * <li>not transitive: if a.copyOf(b) is true and b.copyOf(c) is true, a.copyOf(c) is + * not necessarily true since it is possible that a == c.</li> + * </ul> + * @param chromosome the chromosome to compare to. + * @return true if it is a copy of this chromosome, but not the same chromosome. + * + */ public boolean compareGenesTo(Chromosome chromosome) { for (int r = 0; r < resources.rows(); r++) { for (int c = 0; c < resources.columns(); c++) { @@ -293,6 +418,13 @@ public class Chromosome implements Comparable<Chromosome> { return true; } + /** + * Does the same as {@code compareGenesto()} but only looks + * at the active portion of the chromosome. + * + * @param chromosome the chromosome to compare to. + * @return true if the two active portions are identical. + */ public boolean compareActiveGenesTo(Chromosome chromosome) { // update list if it is out of date computeActiveNodes(); @@ -308,6 +440,11 @@ public class Chromosome implements Comparable<Chromosome> { return false; } + /** + * Iterates through the nodes and prints all connections and functions. + * This is intended for debugging purposes only and does not print to the + * GUI console. + */ public void printNodes() { int arity = resources.arity(); @@ -330,6 +467,9 @@ public class Chromosome implements Comparable<Chromosome> { System.out.println(); } + /** + * @return a reference to the resources based on which the chromosome was built. + */ public Resources getResources() { return resources; } |