aboutsummaryrefslogtreecommitdiffstats
path: root/src/jcgp/backend/population/Chromosome.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jcgp/backend/population/Chromosome.java')
-rw-r--r--src/jcgp/backend/population/Chromosome.java192
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;
}