From aa9e74e7f67789f6353fc26e02ee8e68e40609a2 Mon Sep 17 00:00:00 2001 From: Eduardo Pedroni Date: Sun, 4 May 2014 19:23:52 +0100 Subject: Added more comments, minor refactorings --- src/jcgp/backend/population/Chromosome.java | 192 +++++++++++++++++++--- src/jcgp/backend/population/Connection.java | 23 +++ src/jcgp/backend/population/Gene.java | 5 - src/jcgp/backend/population/Input.java | 36 +++- src/jcgp/backend/population/MutableElement.java | 53 ++++-- src/jcgp/backend/population/Node.java | 125 +++++++++++--- src/jcgp/backend/population/Output.java | 49 +++++- src/jcgp/backend/population/Population.java | 67 +++++++- src/jcgp/backend/resources/Resources.java | 17 +- src/jcgp/backend/statistics/StatisticsLogger.java | 5 +- 10 files changed, 467 insertions(+), 105 deletions(-) delete mode 100644 src/jcgp/backend/population/Gene.java (limited to 'src/jcgp/backend') 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. + *

+ * 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. + *

+ * 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. + *

+ * To illustrate this, given two chromosomes, chr1 and chr2, the following code: + *

+ * + * chr1.copyGenes(chr2); + *

+ * will modify all of chr1's connections and functions to match those of chr2, without + * creating a new instance. In contrast, + *

+ * + * chr1 = new Chromosome(chr2); + *

+ * 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, + *

+ * population.copyChromosome(2, 1); + *

+ * 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. + *

+ * 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 { private Resources resources; @@ -19,14 +67,13 @@ public class Chromosome implements Comparable { /** * 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 { * * 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 { } /** - * + * Allocates the necessary memory for all of the nodes, inputs + * and outputs in the chromosome according to the experiment + * resources. + *
+ * 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 { } /** - * + * 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 { } } + // set random outputs for (Output output : outputs) { output.setConnection(0, getRandomConnection()); } @@ -99,11 +155,21 @@ public class Chromosome implements Comparable { } /** - * @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. + *
+ * 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 { } } + /** + * 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 { } /** - * 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 { } /** - * Returns a random allowed connection respecting levels back.
+ * Returns a random allowed connection respecting levels back.
* 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 { /** * 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 { } /** - * 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 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(); - + // 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: + *
    + *
  • the chromosomes being compared are not the same instance;
  • + *
  • the connections of the compared chromosomes are not the same instance;
  • + *
  • the grid position of the chromosome's elements are the same;
  • + *
+ *

+ * The relationship computed by this method is: + *
    + *
  • symmetric: a.copyOf(b) == b.copyOf(a);
  • + *
  • not reflexive: a.copyOf(a) returns false;
  • + *
  • 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.
  • + *
+ * @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 { 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 { 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 { System.out.println(); } + /** + * @return a reference to the resources based on which the chromosome was built. + */ public Resources getResources() { return resources; } diff --git a/src/jcgp/backend/population/Connection.java b/src/jcgp/backend/population/Connection.java index cd0f5ce..f0be590 100644 --- a/src/jcgp/backend/population/Connection.java +++ b/src/jcgp/backend/population/Connection.java @@ -1,7 +1,30 @@ package jcgp.backend.population; +/** + * {@code Connection} declares the expected behaviour of any + * part of a chromosome that can be connected to, specifically + * nodes or inputs. Outputs are not connections since they + * mark the end of chromosome paths. + *

+ * This interface provides a way to deal with connections + * generically without having to specify whether they are nodes + * or inputs. In this way a random connection can be picked and + * dealt with more easily, facilitating mutations. + * + * @author Eduardo Pedroni + * + */ public interface Connection { + /** + * Compute and return the value of this connection. In + * the case of inputs no computation is necessary, this + * simply returns the value the input is set to. In the + * case of nodes, the value is computed based on the + * node's function and the value of its own connections. + * + * @return the connection's value. + */ public Object getValue(); } diff --git a/src/jcgp/backend/population/Gene.java b/src/jcgp/backend/population/Gene.java deleted file mode 100644 index 6b90949..0000000 --- a/src/jcgp/backend/population/Gene.java +++ /dev/null @@ -1,5 +0,0 @@ -package jcgp.backend.population; - -public abstract class Gene { - -} diff --git a/src/jcgp/backend/population/Input.java b/src/jcgp/backend/population/Input.java index 2661f8c..97fe82b 100644 --- a/src/jcgp/backend/population/Input.java +++ b/src/jcgp/backend/population/Input.java @@ -1,27 +1,51 @@ package jcgp.backend.population; -public class Input extends Gene implements Connection { +/** + * This is a chromosome input. Inputs are a special + * type of connection which simply return a set value. + * They do not have connections and instead provide a + * starting point for the chromosome's active paths. + * + * @author Eduardo Pedroni + * + */ +public class Input implements Connection { - private Object value = 0; + private Object value; private int index; + /** + * Initialises a new input with the current index. + * + * @param index the index of the new input. + */ public Input(int index) { this.index = index; } + /** + * Sets this input's value. The new value + * will now be returned by this input's + * {@code getValue()} method. + * + * @param newValue the value to set. + */ public void setValue(Object newValue) { value = newValue; } + /** + * @return the input's index. + */ + public int getIndex() { + return index; + } + @Override public Object getValue() { return value; } - public int getIndex() { - return index; - } - @Override public String toString() { return "Input " + index; diff --git a/src/jcgp/backend/population/MutableElement.java b/src/jcgp/backend/population/MutableElement.java index 8548e63..33f3890 100644 --- a/src/jcgp/backend/population/MutableElement.java +++ b/src/jcgp/backend/population/MutableElement.java @@ -1,5 +1,19 @@ package jcgp.backend.population; +/** + * {@code MutableElement} declares the expected behaviour of any + * part of a chromosome that is mutable, more specifically + * nodes or outputs. Inputs are not mutable since they don't have + * connections or functions. + *

+ * This interface provides a way to deal with mutable elements + * generically without having to specify whether they are nodes + * or outputs. In this way a random mutable element can be picked and + * dealt with more easily, facilitating mutations. + * + * @author Eduardo Pedroni + * + */ public interface MutableElement { /** @@ -7,28 +21,33 @@ public interface MutableElement { * Implementing classes may choose to ignore the given index (such as in the * case of outputs, which only have one connection). * - * @param index - * @param newConnection + * @param index the connection index to set. + * @param newConnection the chromosome element to connect to. */ public void setConnection(int index, Connection newConnection); /** - * This method returns true if and only if:
- * - the elements being compared are not the same instance;
- * - the connections of the compared elements are not the same instance;
- * - the elements have the same function (in the case of Node);
- * - the grid position of the elements themselves are the same;
- * - the grid position of all equivalent connections are the same;

+ * Asserts if the specified element is a copy of the elements + * this is called on.
+ * This method returns true if and only if: + *
    + *
  • the elements being compared are not the same instance;
  • + *
  • the connections of the compared elements are not the same instance;
  • + *
  • the elements have the same function (in the case of Node);
  • + *
  • the grid position of the elements themselves are the same;
  • + *
  • the grid position of all equivalent connections are the same;
  • + *
+ *

+ * The relationship computed by this method is: + *
    + *
  • symmetric: a.copyOf(b) == b.copyOf(a);
  • + *
  • not reflexive: a.copyOf(a) returns false;
  • + *
  • 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.
  • * - * The relationship computed by this method is:
    - * - symmetric: a.copyOf(b) == b.copyOf(a);
    - * - not reflexive: a.copyOf(a) returns false;
    - * - 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.
    - * - * @param m - * @return + * @param element the mutable element to compare to. + * @return true if {@code element} is a copy of this element. */ - boolean copyOf(MutableElement m); + boolean copyOf(MutableElement element); } diff --git a/src/jcgp/backend/population/Node.java b/src/jcgp/backend/population/Node.java index 74f6b54..704b24e 100644 --- a/src/jcgp/backend/population/Node.java +++ b/src/jcgp/backend/population/Node.java @@ -4,41 +4,63 @@ import java.util.ArrayList; import jcgp.backend.function.Function; - -public class Node extends Gene implements MutableElement, Connection { +/** + * Nodes make up the main part of the chromosome, + * where the actual functions are evolved. Each node + * contains a function and a number of connections. + * The node outputs the result of performing its function + * on the values of its connections. Nodes therefore + * implement both {@code MutableElement} and {@code Connection} + * since they can be mutated but also connected to. + * Nodes are constructed with a fixed number of connections + * (determined by the maximum arity of the function set) + * and must be reinstantiated if the experiment arity + * changes. + * + * @author Eduardo Pedroni + * + */ +public class Node implements MutableElement, Connection { private Function function; private Connection[] connections; private int column, row; private Chromosome chromosome; + /** + * Constructs a new instance of {@code Node} with the + * specified parameters. Nodes must contain their + * own row and column for ease of copying. + * + * @param chromosome the chromosome this node belongs to. + * @param row the node's row. + * @param column the node's column. + * @param arity the maximum arity of the experiment. + */ public Node(Chromosome chromosome, int row, int column, int arity) { this.chromosome = chromosome; this.column = column; this.row = row; } - - @Override - public Object getValue() { - Object[] args = new Object[function.getArity()]; - for (int i = 0; i < function.getArity(); i++) { - args[i] = connections[i].getValue(); - } - return function.run(args); - } - + + /** + * Sets the node function. + * + * @param newFunction the new function to set. + */ public void setFunction(Function newFunction) { function = newFunction; } - @Override - public void setConnection(int index, Connection newConnection) { - if (newConnection != null) { - connections[index] = newConnection; - chromosome.recomputeActiveNodes(); - } - } - + /** + * Initialises the node with the specified values. + * The number of connections passed as argument must + * be exactly the same as the experiment arity, or + * an {@code IllegalArgumentException} will be thrown. + * + * @param newFunction the node function to set. + * @param newConnections the node connections to set. + */ public void initialise(Function newFunction, Connection ... newConnections) { function = newFunction; if (newConnections.length == chromosome.getResources().arity()) { @@ -48,41 +70,71 @@ public class Node extends Gene implements MutableElement, Connection { } } + /** + * @return this node's column. + */ public int getColumn() { return column; } + /** + * @return this node's row. + */ public int getRow() { return row; } + /** + * @return this node's function. + */ public Function getFunction() { return function; } + /** + * @param index the connection to return. + * @return the indexed connection. + */ public Connection getConnection(int index) { return connections[index]; } - public void getActive(ArrayList activeNodes) { + /** + * For package use, this is a recursive method + * used to create a collection of active nodes + * in the chromosome. If this node is not already + * in the active node list, this method adds it. + * It then calls {@code getActive()} on each of its + * connections, therefore recursively adding every + * single active node to the given list. + * + * @param activeNodes the list of active nodes being built. + */ + protected void getActive(ArrayList activeNodes) { + // don't add the same node twice if (!activeNodes.contains(this)) { activeNodes.add(this); } + // call getActive on all connections - they are all active for (int i = 0; i < function.getArity(); i++) { if (connections[i] instanceof Node) { ((Node) connections[i]).getActive(activeNodes); } - } } @Override - public boolean copyOf(MutableElement m) { - if (this != m) { - if (m instanceof Node) { - Node n = (Node) m; + public boolean copyOf(MutableElement element) { + // both cannot be the same instance + if (this != element) { + // element must be instance of node + if (element instanceof Node) { + Node n = (Node) element; + // must have the same function if (function == n.getFunction()) { + // row and column must be the same if (column == n.getColumn() && row == n.getRow()) { + // connections must be the equivalent, but not the same instance for (int i = 0; i < connections.length; i++) { if (connections[i] != n.getConnection(i)) { if (connections[i] instanceof Input && n.getConnection(i) instanceof Input) { @@ -101,6 +153,7 @@ public class Node extends Gene implements MutableElement, Connection { return false; } } + // all connections checked, this really is a copy return true; } } @@ -108,6 +161,26 @@ public class Node extends Gene implements MutableElement, Connection { } return false; } + + @Override + public Object getValue() { + // build list of arguments recursively + Object[] args = new Object[function.getArity()]; + for (int i = 0; i < function.getArity(); i++) { + args[i] = connections[i].getValue(); + } + // return function result + return function.run(args); + } + + @Override + public void setConnection(int index, Connection newConnection) { + // connection must not be null + if (newConnection != null) { + connections[index] = newConnection; + chromosome.recomputeActiveNodes(); + } + } @Override public String toString() { diff --git a/src/jcgp/backend/population/Output.java b/src/jcgp/backend/population/Output.java index d876951..ab693e2 100644 --- a/src/jcgp/backend/population/Output.java +++ b/src/jcgp/backend/population/Output.java @@ -2,26 +2,39 @@ package jcgp.backend.population; import java.util.ArrayList; -public class Output extends Gene implements MutableElement { +/** + * This is a chromosome output. Outputs are a special + * type of mutable element with a single connection. It + * returns the value of its single connection, but it + * may not be connected to - it terminates a chromosome + * active connection path. + * + * @author Eduardo Pedroni + * + */ +public class Output implements MutableElement { private Connection source; private Chromosome chromosome; private int index; + /** + * Makes a new instance of {@code Output} with the + * specified arguments. + * + * @param chromosome the chromosome this output belongs to. + * @param index the output index. + */ public Output(Chromosome chromosome, int index) { this.chromosome = chromosome; this.index = index; } + /** + * @return the value of the output's source. + */ public Object calculate() { - Object result = source.getValue(); - return result; - } - - @Override - public void setConnection(int index, Connection newConnection) { - source = newConnection; - chromosome.recomputeActiveNodes(); + return source.getValue(); } public int getIndex() { @@ -38,12 +51,30 @@ public class Output extends Gene implements MutableElement { } } + /** + * When mutating an output, the index parameter + * is simply ignored and the output source is + * set. + * + * @see jcgp.backend.population.MutableElement#setConnection(int, jcgp.backend.population.Connection) + */ + @Override + public void setConnection(int index, Connection newConnection) { + source = newConnection; + // trigger active path recomputation + chromosome.recomputeActiveNodes(); + } + @Override public boolean copyOf(MutableElement m) { + // both cannot be the same instance if (this != m) { + // element must be instance of output if (m instanceof Output) { Output o = (Output) m; + // index must be the same if (index == o.getIndex()) { + // source must be the same if (source != o.getSource()) { if (source instanceof Input && o.getSource() instanceof Input) { if (((Input) source).getIndex() == ((Input) o.getSource()).getIndex()) { diff --git a/src/jcgp/backend/population/Population.java b/src/jcgp/backend/population/Population.java index d99c64e..5d549e9 100644 --- a/src/jcgp/backend/population/Population.java +++ b/src/jcgp/backend/population/Population.java @@ -5,6 +5,35 @@ import java.util.Collections; import jcgp.backend.resources.Resources; +/** + * This class primarily holds a collection of chromosomes. In addition, + * it provides a few utility methods for manipulating and copying + * chromosomes, useful for evolutionary strategies. + *

    + * {@code copyChromosome()} is used to create copies of chromosomes, + * though it is also possible to create a new instance of population + * directly from a seed chromosome using the right constructor. + *

    + * For convenience, a random chromosome can be retrieved using + * {@code getRandomChromosome()}, which is guaranteed to use the + * experiment's specified seed. If an entirely random population + * is needed, {@code reinitialise()} should be used to randomise + * all chromosomes without creating a new instance of {@code Population}. + *

    + * By convention the population's chromosomes should always be sorted in + * order of fitness, from worst to best. This cannot be done automatically + * since a higher fitness value does not necessarily mean better fitness; + * some problem types might instead interpret fitness 0 as a perfect solution. + * Sorting the population is done easily using {@code sortAscending()} and + * {@code sortDescending()}, and should be done by the problem type as appropriate. + * It is critical to sort the population after it is evaluated as + * evolutionary strategies will obey the convention and assume the population + * is sorted in order of fitness. + * + * + * @author Eduardo Pedroni + * + */ public class Population { private final Chromosome[] chromosomes; @@ -14,7 +43,7 @@ public class Population { * Initialise a random population according to the parameters specified * in the resources. * - * @param resources the CGP resources + * @param resources the experiment's resources. */ public Population(Resources resources) { this.resources = resources; @@ -28,8 +57,8 @@ public class Population { /** * Initialise a population of copies of the given chromosome. * - * @param parent - * @param resources + * @param parent the chromosome to use as a model. + * @param resources a reference to the experiment's resources. */ public Population(Chromosome parent, Resources resources) { this.resources = resources; @@ -43,8 +72,8 @@ public class Population { /** * Returns the indexed chromosome. * - * @param index - * @return + * @param index the chromosome to return. + * @return the indexed chromosome. */ public Chromosome getChromosome(int index) { return chromosomes[index]; @@ -65,8 +94,8 @@ public class Population { * * This method does nothing if source == target. * - * @param source - * @param target + * @param source the chromosome to copy from. + * @param target the chromosome to copy to. */ public void copyChromosome(int source, int target) { if (source != target) { @@ -74,16 +103,40 @@ public class Population { } } + /** + * Loop through all chromosomes and randomise all connections + * and functions. + */ public void reinitialise() { for (int c = 0; c < chromosomes.length; c++) { chromosomes[c].reinitialiseConnections(); } } + /** + * The fittest chromosome, by convention, is the last one + * in the array. Problem evaluation methods are expected to + * sort the population into ascending order of fitness, such + * that the best chromosome is in the last position (size - 1). + * This method assumes that the population is sorted as such + * and returns the last chromosome in the array. + * + * @return the fittest chromosome in the population. + */ public Chromosome getFittest() { return chromosomes[chromosomes.length - 1]; } + /** + * The fittest chromosome, by convention, is the last one + * in the array. Problem evaluation methods are expected to + * sort the population into ascending order of fitness, such + * that the best chromosome is in the last position (size - 1). + * This method assumes that the population is sorted as such + * and returns the last index in the array. + * + * @return the index of the fittest chromosome. + */ public int getFittestIndex() { return chromosomes.length - 1; } diff --git a/src/jcgp/backend/resources/Resources.java b/src/jcgp/backend/resources/Resources.java index 1f79627..ebd6fb2 100644 --- a/src/jcgp/backend/resources/Resources.java +++ b/src/jcgp/backend/resources/Resources.java @@ -8,21 +8,22 @@ import jcgp.backend.parameters.IntegerParameter; /** * - * The resources class encapsulates all of the resources based on which the program operates. - * Each instance of JCGP contains a single instance of Resources, which gets passed to the selected - * modules as the program executes. + * Encapsulates all of the resources based on which the program operates. + * Each instance of JCGP contains a single instance of {@code Resources}. *

    * The experiment's {@code Resources} object is passed to modules as the program operates, and * the actual parameter values can be obtained using getter methods. Note that, for code brevity, * this class's getters do not start with the word "get". For instance, to get the number of rows, - * one would use {@code rows()} instead of {@code getRows()}. + * one would use {@code rows()} instead of {@code getRows()} which doesn't exist. *

    * In addition to parameters, this class also offers utility methods. Any necessary random numbers - * should be obtained using {@code getRandomInt()} and {@code getRandomDouble()}. Functions from the - * selected function set can be obtained through this class as well. Finally, printing to the console - * should be done via the resources using the report and print methods, so that these prints also - * get sent to the GUI console (if one is present). + * should be obtained using {@code getRandomInt()} and {@code getRandomDouble()} as these methods + * use a particular {@code Random} object guaranteed to generate random numbers based on the seed + * parameter. Functions from the selected function set can be obtained through this class as well. + * Finally, printing to the console should be done via the resources using the report and print + * methods, so that these prints also get sent to the GUI console (if one is present). * + * @see Parameter, Console, FunctionSet * @author Eduardo Pedroni * */ diff --git a/src/jcgp/backend/statistics/StatisticsLogger.java b/src/jcgp/backend/statistics/StatisticsLogger.java index dfbcdbe..7165a11 100644 --- a/src/jcgp/backend/statistics/StatisticsLogger.java +++ b/src/jcgp/backend/statistics/StatisticsLogger.java @@ -173,6 +173,7 @@ public class StatisticsLogger { public int getSuccessfulRuns() { int count = 0; for (RunEntry runEntry : runEntries) { + // only increment if solution was perfect if (runEntry.isSuccessful()) { count++; } @@ -189,7 +190,7 @@ public class StatisticsLogger { * @return the success rate across all runs. */ public double getSuccessRate() { - return getSuccessfulRuns() / runEntries.size(); + return getSuccessfulRuns() / (double) runEntries.size(); } /** @@ -203,6 +204,7 @@ public class StatisticsLogger { double average = 0; int successfulRuns = getSuccessfulRuns(); for (RunEntry runEntry : runEntries) { + // only if solution was perfect if (runEntry.isSuccessful()) { average += runEntry.getGeneration() / successfulRuns; } @@ -221,6 +223,7 @@ public class StatisticsLogger { double average = getAverageSuccessfulGenerations(); double temp, stdDev = 0; for (RunEntry runEntry : runEntries) { + // only if solution was perfect if (runEntry.isSuccessful()) { temp = runEntry.getGeneration() - average; temp = temp * temp; -- cgit v1.2.3