aboutsummaryrefslogtreecommitdiffstats
path: root/src/jcgp/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/jcgp/backend')
-rw-r--r--src/jcgp/backend/modules/mutator/PointMutator.java42
-rw-r--r--src/jcgp/backend/modules/mutator/ProbabilisticMutator.java4
-rw-r--r--src/jcgp/backend/parsers/ChromosomeParser.java2
-rw-r--r--src/jcgp/backend/population/Chromosome.java26
-rw-r--r--src/jcgp/backend/population/Mutable.java22
-rw-r--r--src/jcgp/backend/population/Node.java41
-rw-r--r--src/jcgp/backend/population/Output.java51
-rw-r--r--src/jcgp/backend/tests/ChromosomeTests.java6
-rw-r--r--src/jcgp/backend/tests/OutputTests.java4
9 files changed, 111 insertions, 87 deletions
diff --git a/src/jcgp/backend/modules/mutator/PointMutator.java b/src/jcgp/backend/modules/mutator/PointMutator.java
index 5aba0d1..6ba3e10 100644
--- a/src/jcgp/backend/modules/mutator/PointMutator.java
+++ b/src/jcgp/backend/modules/mutator/PointMutator.java
@@ -4,8 +4,6 @@ import jcgp.backend.parameters.BooleanParameter;
import jcgp.backend.parameters.IntegerParameter;
import jcgp.backend.population.Chromosome;
import jcgp.backend.population.Mutable;
-import jcgp.backend.population.Node;
-import jcgp.backend.population.Output;
import jcgp.backend.resources.Resources;
/**
@@ -40,43 +38,13 @@ public abstract class PointMutator extends Mutator {
// for however many genes must be mutated
for (int i = 0; i < genesMutated.get(); i++) {
+ // choose a random mutable
+ Mutable mutable = chromosome.getRandomMutable();
- Mutable m = chromosome.getRandomMutable();
+ if (report.get()) getResources().report("[Mutator] Mutation " + i + " selected " + mutable);
- if (report.get()) getResources().report("[Mutator] Mutation " + i + " selected " + m + ", ");
-
- // outputs and nodes are mutated differently
- if (m instanceof Output) {
- if (report.get()) getResources().report("changed source from " + ((Output) m).getSource() + " ");
-
- // outputs are easy, simply set to a different random connection, any will do
- m.setConnection(0, chromosome.getRandomConnection());
-
- if (report.get()) getResources().reportln("to " + ((Output) m).getSource());
- } else if (m instanceof Node) {
- /* nodes are more complicated, first we must decide whether to mutate the function
- * or a connection
- * we do this by generating a random int between 0 and 1 + arity
- */
- int geneType = getResources().getRandomInt(1 + getResources().arity());
-
- // if the int is less than 1, mutate function, else mutate connections
- if (geneType < 1) {
- if (report.get()) getResources().report("changed function from " + ((Node) m).getFunction() + " ");
-
- ((Node) m).setFunction(getResources().getRandomFunction());
-
- if (report.get()) getResources().reportln("to " + ((Node) m).getFunction());
- } else {
- // if we decided to mutate connection, subtract 1 from geneType so it fits into the arity range
- geneType--;
- if (report.get()) getResources().report("changed connection " + geneType + " from " + ((Node) m).getConnection(geneType) + " ");
-
- m.setConnection(geneType, chromosome.getRandomConnection(((Node) m).getColumn()));
-
- if (report.get()) getResources().reportln("to " + ((Node) m).getConnection(geneType));
- }
- }
+ // mutate a random gene
+ mutable.mutate();
}
}
diff --git a/src/jcgp/backend/modules/mutator/ProbabilisticMutator.java b/src/jcgp/backend/modules/mutator/ProbabilisticMutator.java
index 9273558..1ea1373 100644
--- a/src/jcgp/backend/modules/mutator/ProbabilisticMutator.java
+++ b/src/jcgp/backend/modules/mutator/ProbabilisticMutator.java
@@ -93,13 +93,13 @@ public class ProbabilisticMutator extends Mutator {
if (report.get()) getResources().report("[Mutator] Mutating " + out +
", changed source from " + out.getSource());
- out.setConnection(0, chromosome.getRandomConnection());
+ out.setSource(chromosome.getRandomConnection());
if (report.get()) getResources().reportln("to " + out.getSource());
}
}
- if (report.get()) getResources().reportln("[Mutator] Mutation finished ");
+ if (report.get()) getResources().reportln("[Mutator] Mutation finished");
}
diff --git a/src/jcgp/backend/parsers/ChromosomeParser.java b/src/jcgp/backend/parsers/ChromosomeParser.java
index 6106dbd..b892182 100644
--- a/src/jcgp/backend/parsers/ChromosomeParser.java
+++ b/src/jcgp/backend/parsers/ChromosomeParser.java
@@ -117,7 +117,7 @@ public abstract class ChromosomeParser {
newConnection = chromosome.getNode((gene - resources.inputs()) % resources.rows(),
(gene - resources.inputs()) / resources.rows());
}
- chromosome.getOutput(o).setConnection(0, newConnection);
+ chromosome.getOutput(o).setSource(newConnection);
}
in.close();
diff --git a/src/jcgp/backend/population/Chromosome.java b/src/jcgp/backend/population/Chromosome.java
index 673bb26..e28032c 100644
--- a/src/jcgp/backend/population/Chromosome.java
+++ b/src/jcgp/backend/population/Chromosome.java
@@ -149,7 +149,7 @@ public class Chromosome implements Comparable<Chromosome> {
// set random outputs
for (Output output : outputs) {
- output.setConnection(0, getRandomConnection());
+ output.setSource(getRandomConnection());
}
}
@@ -198,9 +198,9 @@ public class Chromosome implements Comparable<Chromosome> {
for (int o = 0; o < outputs.length; o++) {
copyOutput = clone.getOutput(o).getSource();
if (copyOutput instanceof Input) {
- outputs[o].setConnection(0, inputs[((Input) copyOutput).getIndex()]);
+ outputs[o].setSource(inputs[((Input) copyOutput).getIndex()]);
} else if (copyOutput instanceof Node) {
- outputs[o].setConnection(0, nodes[((Node) copyOutput).getRow()][((Node) copyOutput).getColumn()]);
+ outputs[o].setSource(nodes[((Node) copyOutput).getRow()][((Node) copyOutput).getColumn()]);
} else {
// something bad happened
System.out.println("Warning: Connection of subtype " + copyOutput.getClass().toString() + " is not explicitly handled by copy constructor.");
@@ -212,6 +212,16 @@ public class Chromosome implements Comparable<Chromosome> {
}
/**
+ * Returns a reference to the indexed input.
+ *
+ * @param index the input index.
+ * @return the input reference.
+ */
+ public Input getInput(int index) {
+ return inputs[index];
+ }
+
+ /**
* Returns a reference to any node, addressed by row and column.
*
* @param row the row of the node.
@@ -233,16 +243,6 @@ public class Chromosome implements Comparable<Chromosome> {
}
/**
- * 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() {
diff --git a/src/jcgp/backend/population/Mutable.java b/src/jcgp/backend/population/Mutable.java
index 3ce7065..a5cbe37 100644
--- a/src/jcgp/backend/population/Mutable.java
+++ b/src/jcgp/backend/population/Mutable.java
@@ -8,8 +8,8 @@ package jcgp.backend.population;
* <br><br>
* 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.
+ * or outputs. When mutating a mutable, {@code mutate()} is guaranteed
+ * to perform a fair mutation.
*
* @author Eduardo Pedroni
*
@@ -17,14 +17,16 @@ package jcgp.backend.population;
public interface Mutable {
/**
- * This method sets the indexed connection to the specified new connection.
- * Implementing classes may choose to ignore the given index (such as in the
- * case of outputs, which only have one connection).
- *
- * @param index the connection index to set.
- * @param newConnection the chromosome element to connect to.
+ * This method performs an arbitrary mutation on the {@code Mutable}.
+ * <br><br>
+ * In the case of nodes, this chooses to mutate a function or connection
+ * fairly, and carries out the required mutation by using the node's own
+ * reference to chromosome.
+ * <br><br>
+ * In the case of outputs, this simply picks a random connection to serve
+ * as the source - any connection is allowed.
*/
- public void setConnection(int index, Connection newConnection);
+ public void mutate();
/**
* Asserts if the specified element is a copy of the elements
@@ -48,6 +50,6 @@ public interface Mutable {
* @param element the mutable element to compare to.
* @return true if {@code element} is a copy of this element.
*/
- boolean copyOf(Mutable element);
+ public boolean copyOf(Mutable element);
}
diff --git a/src/jcgp/backend/population/Node.java b/src/jcgp/backend/population/Node.java
index 3bcf3da..7712c50 100644
--- a/src/jcgp/backend/population/Node.java
+++ b/src/jcgp/backend/population/Node.java
@@ -3,6 +3,7 @@ package jcgp.backend.population;
import java.util.ArrayList;
import jcgp.backend.function.Function;
+import jcgp.backend.resources.Resources;
/**
* Nodes make up the main part of the chromosome,
@@ -16,6 +17,10 @@ import jcgp.backend.function.Function;
* (determined by the maximum arity of the function set)
* and must be reinstantiated if the experiment arity
* changes.
+ * <br><br>
+ * When mutating a node, it is easiest to use {@code mutate()}.
+ * Alternatively, you may also perform a specific mutation using
+ * {@code setConnection(...)} and {@code setFunction(...)}.
*
* @author Eduardo Pedroni
*
@@ -122,6 +127,24 @@ public class Node implements Mutable, Connection {
}
}
}
+
+ /**
+ * This method sets the indexed connection to the specified new connection.
+ * If the given connection is null or disrespects levels back, it is discarded
+ * and no connections are changed.
+ *
+ * @param index the connection index to set.
+ * @param newConnection the {@code Connection} to connect to.
+ */
+ public void setConnection(int index, Connection newConnection) {
+ // connection must not be null
+ if (newConnection != null) {
+ //if () {
+ connections[index] = newConnection;
+ chromosome.recomputeActiveNodes();
+ //}
+ }
+ }
@Override
public boolean copyOf(Mutable element) {
@@ -174,11 +197,19 @@ public class Node implements Mutable, Connection {
}
@Override
- public void setConnection(int index, Connection newConnection) {
- // connection must not be null
- if (newConnection != null) {
- connections[index] = newConnection;
- chromosome.recomputeActiveNodes();
+ public void mutate() {
+ Resources resources = chromosome.getResources();
+
+ // choose to mutate the function or a connection
+ int geneType = resources.getRandomInt(1 + resources.arity());
+
+ // if the int is less than 1, mutate function, else mutate connections
+ if (geneType < 1) {
+ setFunction(resources.getRandomFunction());
+ } else {
+ // if we decided to mutate connection, subtract 1 from geneType so it fits into the arity range
+ geneType--;
+ setConnection(geneType, chromosome.getRandomConnection(column));
}
}
diff --git a/src/jcgp/backend/population/Output.java b/src/jcgp/backend/population/Output.java
index 938741b..a346d4a 100644
--- a/src/jcgp/backend/population/Output.java
+++ b/src/jcgp/backend/population/Output.java
@@ -8,6 +8,10 @@ import java.util.ArrayList;
* returns the value of its single connection, but it
* may not be connected to - it terminates a chromosome
* active connection path.
+ * <br><br>
+ * When mutating an output, it is easiest to use {@code mutate()}.
+ * Alternatively, you may also perform a specific mutation using
+ * {@code setSource(...)}.
*
* @author Eduardo Pedroni
*
@@ -37,34 +41,47 @@ public class Output implements Mutable {
return source.getValue();
}
+ /**
+ * @return this output's index.
+ */
public int getIndex() {
return index;
}
+
+ /**
+ * This method sets the output source to the specified connection.
+ *
+ * @param newConnection the {@code Connection} to connect to.
+ */
+ public void setSource(Connection newConnection) {
+ source = newConnection;
+ // trigger active path recomputation
+ chromosome.recomputeActiveNodes();
+ }
+ /**
+ * @return the source of this output's value.
+ */
public Connection getSource() {
return source;
}
+ /**
+ * Calls {@code getActive(...)} on this output's
+ * source. This kicks off a recursive process whereby
+ * all nodes connected to this output are added to the
+ * specified list of nodes. This is used to create a
+ * list of all active nodes.
+ *
+ * @param activeNodes the list to add all active nodes to.
+ */
public void getActiveNodes(ArrayList<Node> activeNodes) {
+ // do not add if the source is an input
if (source instanceof Node) {
((Node) source).getActive(activeNodes);
}
}
- /**
- * When mutating an output, the index parameter
- * is simply ignored and the output source is
- * set.
- *
- * @see jcgp.backend.population.Mutable#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(Mutable m) {
// both cannot be the same instance
@@ -94,6 +111,12 @@ public class Output implements Mutable {
}
@Override
+ public void mutate() {
+ // simply change output to a new, random connection
+ setSource(chromosome.getRandomConnection());
+ }
+
+ @Override
public String toString() {
return "Output " + index;
}
diff --git a/src/jcgp/backend/tests/ChromosomeTests.java b/src/jcgp/backend/tests/ChromosomeTests.java
index b5c1da7..7cbf2e2 100644
--- a/src/jcgp/backend/tests/ChromosomeTests.java
+++ b/src/jcgp/backend/tests/ChromosomeTests.java
@@ -136,7 +136,7 @@ public class ChromosomeTests {
}
// mutate an output in clone, check that the same node in chromosome produces a different output
- clone.getOutput(1).setConnection(resources.getRandomInt(resources.arity()), clone.getInput(2));
+ clone.getOutput(1).setSource(clone.getInput(2));
assertTrue("Mutation affected nodes in both chromosomes.",
clone.getOutput(1).calculate() != chromosome.getOutput(1).calculate());
@@ -332,8 +332,8 @@ public class ChromosomeTests {
c.getNode(1, 1).initialise(resources.getFunction(0), c.getNode(0, 0), c.getInput(1));
c.getNode(1, 2).initialise(resources.getFunction(0), c.getNode(1, 1), c.getInput(2));
- c.getOutput(0).setConnection(0, c.getNode(0, 0));
- c.getOutput(1).setConnection(0, c.getNode(1, 2));
+ c.getOutput(0).setSource(c.getNode(0, 0));
+ c.getOutput(1).setSource(c.getNode(1, 2));
return c;
}
diff --git a/src/jcgp/backend/tests/OutputTests.java b/src/jcgp/backend/tests/OutputTests.java
index 8cc10a8..c5aa6b4 100644
--- a/src/jcgp/backend/tests/OutputTests.java
+++ b/src/jcgp/backend/tests/OutputTests.java
@@ -47,7 +47,7 @@ public class OutputTests {
@Test
public void evaluationsTest() {
// set source connection, check that the appropriate value is returned
- output.setConnection(0, new Connection() {
+ output.setSource(new Connection() {
@Override
public Object getValue() {
@@ -70,7 +70,7 @@ public class OutputTests {
return 0;
}
};
- output.setConnection(0, newConn);
+ output.setSource(newConn);
assertTrue("Incorrect connection returned.", output.getSource() == newConn);
}