aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/jcgp/JCGP.java171
-rw-r--r--src/jcgp/backend/modules/mutator/PointMutator.java6
-rw-r--r--src/jcgp/backend/modules/problem/BestFitness.java18
-rw-r--r--src/jcgp/backend/modules/problem/DigitalCircuitProblem.java14
-rw-r--r--src/jcgp/backend/modules/problem/Problem.java2
-rw-r--r--src/jcgp/backend/modules/problem/SymbolicRegressionProblem.java16
-rw-r--r--src/jcgp/backend/modules/problem/TestCaseProblem.java19
-rw-r--r--src/jcgp/backend/parsers/ChromosomeParser.java1
-rw-r--r--src/jcgp/backend/population/Chromosome.java4
-rw-r--r--src/jcgp/backend/population/Mutable.java (renamed from src/jcgp/backend/population/MutableElement.java)6
-rw-r--r--src/jcgp/backend/population/Node.java6
-rw-r--r--src/jcgp/backend/population/Output.java6
-rw-r--r--src/jcgp/backend/tests/ChromosomeTests.java6
13 files changed, 88 insertions, 187 deletions
diff --git a/src/jcgp/JCGP.java b/src/jcgp/JCGP.java
index 898f229..f60fc22 100644
--- a/src/jcgp/JCGP.java
+++ b/src/jcgp/JCGP.java
@@ -1,13 +1,17 @@
package jcgp;
import java.io.File;
-import java.lang.reflect.Constructor;
-import java.util.ArrayList;
-import java.util.Set;
import jcgp.backend.modules.es.EvolutionaryStrategy;
+import jcgp.backend.modules.es.MuPlusLambda;
+import jcgp.backend.modules.es.TournamentSelection;
+import jcgp.backend.modules.mutator.FixedPointMutator;
import jcgp.backend.modules.mutator.Mutator;
+import jcgp.backend.modules.mutator.PercentPointMutator;
+import jcgp.backend.modules.mutator.ProbabilisticMutator;
+import jcgp.backend.modules.problem.DigitalCircuitProblem;
import jcgp.backend.modules.problem.Problem;
+import jcgp.backend.modules.problem.SymbolicRegressionProblem;
import jcgp.backend.modules.problem.TestCaseProblem;
import jcgp.backend.parsers.ChromosomeParser;
import jcgp.backend.parsers.FunctionParser;
@@ -19,8 +23,6 @@ import jcgp.backend.resources.ModifiableResources;
import jcgp.backend.resources.Resources;
import jcgp.backend.statistics.StatisticsLogger;
-import org.reflections.Reflections;
-
/**
*
* Top-level JCGP class. This class is the entry point for a CGP experiment.
@@ -51,21 +53,30 @@ public class JCGP {
* module, 0 by default.
*/
// mutators
- private ArrayList<Mutator> mutators;
+ private Mutator[] mutators = new Mutator[] {
+ new PercentPointMutator(resources),
+ new FixedPointMutator(resources),
+ new ProbabilisticMutator(resources)
+ };
private Mutator mutator;
// evolutionary algorithms
- private ArrayList<EvolutionaryStrategy> evolutionaryStrategies;
+ private EvolutionaryStrategy[] evolutionaryStrategies = new EvolutionaryStrategy[] {
+ new MuPlusLambda(resources),
+ new TournamentSelection(resources)
+ };
private EvolutionaryStrategy evolutionaryStrategy;
// problem types
- private ArrayList<Problem> problems;
+ private Problem[] problems = new Problem[] {
+ new DigitalCircuitProblem(resources),
+ new SymbolicRegressionProblem(resources)
+ };
private Problem problem;
private Population population;
private StatisticsLogger statistics = new StatisticsLogger();
- private Reflections reflections;
// these record the best results found in the run, in case the runs ends before a perfect solution is found
private int lastImprovementGeneration = 0, activeNodes = 0;
@@ -104,135 +115,15 @@ public class JCGP {
* Creates a new instance of JCGP.
*/
public JCGP() {
- // prepare reflections instance
- reflections = new Reflections("jcgp");
-
- // generate module lists from all encountered valid modules
- createEvolutionaryStrategyList();
- createMutatorList();
- createProblemList();
+ // initialise modules
+ setEvolutionaryStrategy(0);
+ setMutator(0);
+ setProblem(0);
// create a new population
population = new Population(resources);
}
-
- /**
- * Iterates through all classes in the classpath and builds a list
- * of instances of all valid evolutionary strategies found. In order
- * to be included in this list, a class must implement {@code EvolutionaryStrategy}
- * and must contain a constructor with a {@code Resources} object as its only argument.
- */
- private void createEvolutionaryStrategyList() {
- Set<Class<? extends EvolutionaryStrategy>> esList = reflections.getSubTypesOf(EvolutionaryStrategy.class);
- evolutionaryStrategies = new ArrayList<EvolutionaryStrategy>();
-
- // go through all subclasses of EvolutionaryStrategy
- for (Class<? extends EvolutionaryStrategy> esType : esList) {
- Constructor<? extends EvolutionaryStrategy> constructor;
- try {
- constructor = esType.getConstructor(Resources.class);
- } catch (NoSuchMethodException | SecurityException e) {
- // constructor most likely doesnt exist, try next class
- System.out.println("Warning: could not find valid constructor for " + esType.getName() + ", skipping...");
- continue;
- }
-
- if (constructor != null) {
- EvolutionaryStrategy es;
- try {
- es = (EvolutionaryStrategy) constructor.newInstance(resources);
- } catch (Exception e) {
- // could not instantiate for some reason, keep going
- System.out.println("Warning: could not instantiate " + esType.getName() + ", skipping...");
- continue;
- }
- // add it to the list if it was instantiated properly
- evolutionaryStrategies.add(es);
- }
- }
- // choose the initial module
- evolutionaryStrategy = evolutionaryStrategies.get(0);
- }
- /**
- * Iterates through all classes in the classpath and builds a list
- * of instances of all valid mutators found. In order to be included
- * in this list, a class must implement {@code Mutator}
- * and must contain a constructor with a {@code Resources} object as its only argument.
- */
- private void createMutatorList() {
- Set<Class<? extends Mutator>> mutatorList = reflections.getSubTypesOf(Mutator.class);
- mutators = new ArrayList<Mutator>();
-
- // go through all subclasses of Mutator
- for (Class<? extends Mutator> mutatorType : mutatorList) {
- Constructor<? extends Mutator> constructor;
- try {
- constructor = mutatorType.getConstructor(Resources.class);
- } catch (NoSuchMethodException | SecurityException e) {
- // constructor most likely doesnt exist, try next class
- System.out.println("Warning: could not find valid constructor for "
- + mutatorType.getName() + ", skipping...");
- continue;
- }
-
- if (constructor != null) {
- Mutator mutator;
- try {
- mutator = (Mutator) constructor.newInstance(resources);
- } catch (Exception e) {
- // could not instantiate for some reason, keep going
- System.out.println("Warning: could not instantiate " + mutatorType.getName() + ", skipping...");
- continue;
- }
- // add it to the list if it was instantiated properly
- mutators.add(mutator);
- }
- }
- // choose the initial module
- mutator = mutators.get(0);
- }
-
- /**
- * Iterates through all classes in the classpath and builds a list
- * of instances of all valid problem types found. In order to be included
- * in this list, a class must implement {@code Problem}
- * and must contain a constructor with a {@code Resources} object as its only argument.
- */
- private void createProblemList() {
- Set<Class<? extends Problem>> problemTypes = reflections.getSubTypesOf(Problem.class);
- problems = new ArrayList<Problem>();
-
- // go through all subclasses of Problem
- for (Class<? extends Problem> problemType : problemTypes) {
-
- Constructor<? extends Problem> constructor;
- try {
- constructor = problemType.getConstructor(Resources.class);
- } catch (NoSuchMethodException | SecurityException e) {
- // constructor most likely doesnt exist, try next class
- System.out.println("Warning: could not find valid constructor for "
- + problemType.getName() + ", skipping...");
- continue;
- }
-
- if (constructor != null) {
- Problem problem;
- try {
- problem = (Problem) constructor.newInstance(resources);
- } catch (Exception e) {
- // could not instantiate for some reason, keep going
- System.out.println("Warning: could not instantiate " + problemType.getName() + ", skipping...");
- continue;
- }
- // add it to the list if it was instantiated properly
- problems.add(problem);
- }
- }
- // choose the initial module
- problem = problems.get(0);
- resources.setFunctionSet(problem.getFunctionSet());
- }
/**
* Returns a reference to the {@code ModifiableResources} used by the
@@ -256,7 +147,7 @@ public class JCGP {
/**
* @return a complete list of the experiment's mutators.
*/
- public ArrayList<Mutator> getMutators() {
+ public Mutator[] getMutators() {
return mutators;
}
@@ -272,7 +163,7 @@ public class JCGP {
/**
* @return a complete list of the experiment's evolutionary strategies.
*/
- public ArrayList<EvolutionaryStrategy> getEvolutionaryStrategies() {
+ public EvolutionaryStrategy[] getEvolutionaryStrategies() {
return evolutionaryStrategies;
}
@@ -288,7 +179,7 @@ public class JCGP {
/**
* @return a complete list of the experiment's problem types.
*/
- public ArrayList<Problem> getProblems() {
+ public Problem[] getProblems() {
return problems;
}
@@ -305,7 +196,7 @@ public class JCGP {
* @param index the index of the desired mutator.
*/
public void setMutator(int index) {
- this.mutator = mutators.get(index);
+ this.mutator = mutators[index];
resources.println("[CGP] Mutator selected: " + mutator.toString());
}
@@ -314,7 +205,7 @@ public class JCGP {
* @param index the index of the desired evolutionary strategy.
*/
public void setEvolutionaryStrategy(int index) {
- this.evolutionaryStrategy = evolutionaryStrategies.get(index);
+ this.evolutionaryStrategy = evolutionaryStrategies[index];
resources.println("[CGP] Evolutionary strategy selected: " + evolutionaryStrategy.toString());
}
@@ -323,7 +214,7 @@ public class JCGP {
* @param index the index of the desired problem type.
*/
public void setProblem(int index) {
- this.problem = problems.get(index);
+ this.problem = problems[index];
resources.setFunctionSet(problem.getFunctionSet());
resources.setFitnessOrientation(problem.getFitnessOrientation());
}
@@ -348,7 +239,7 @@ public class JCGP {
if (resources.currentGeneration() < resources.generations()) {
// we still have generations left to go
- int perfect = problem.perfectSolutionFound(population);
+ int perfect = problem.hasPerfectSolution(population);
if (perfect >= 0) {
// log results
statistics.logRun(resources.currentGeneration(), population.get(perfect).getFitness(), population.get(perfect).getActiveNodes().size(), true);
diff --git a/src/jcgp/backend/modules/mutator/PointMutator.java b/src/jcgp/backend/modules/mutator/PointMutator.java
index 9e421c2..5aba0d1 100644
--- a/src/jcgp/backend/modules/mutator/PointMutator.java
+++ b/src/jcgp/backend/modules/mutator/PointMutator.java
@@ -3,7 +3,7 @@ package jcgp.backend.modules.mutator;
import jcgp.backend.parameters.BooleanParameter;
import jcgp.backend.parameters.IntegerParameter;
import jcgp.backend.population.Chromosome;
-import jcgp.backend.population.MutableElement;
+import jcgp.backend.population.Mutable;
import jcgp.backend.population.Node;
import jcgp.backend.population.Output;
import jcgp.backend.resources.Resources;
@@ -41,7 +41,7 @@ public abstract class PointMutator extends Mutator {
// for however many genes must be mutated
for (int i = 0; i < genesMutated.get(); i++) {
- MutableElement m = chromosome.getRandomMutableElement();
+ Mutable m = chromosome.getRandomMutable();
if (report.get()) getResources().report("[Mutator] Mutation " + i + " selected " + m + ", ");
@@ -69,7 +69,7 @@ public abstract class PointMutator extends Mutator {
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 -= 1;
+ geneType--;
if (report.get()) getResources().report("changed connection " + geneType + " from " + ((Node) m).getConnection(geneType) + " ");
m.setConnection(geneType, chromosome.getRandomConnection(((Node) m).getColumn()));
diff --git a/src/jcgp/backend/modules/problem/BestFitness.java b/src/jcgp/backend/modules/problem/BestFitness.java
new file mode 100644
index 0000000..dce9ecd
--- /dev/null
+++ b/src/jcgp/backend/modules/problem/BestFitness.java
@@ -0,0 +1,18 @@
+package jcgp.backend.modules.problem;
+
+/**
+ * Enum type to allow problems to indicate their fitness
+ * orientation.
+ * <br><br>
+ * {@code BestFitness.HIGH} means high fitness values are
+ * better than low. Conversely, {@code BestFitness.LOW}
+ * signals that low fitness values indicate better fitness
+ * than high values.
+ *
+ *
+ * @author Eduardo Pedroni
+ *
+ */
+public enum BestFitness {
+ HIGH, LOW;
+}
diff --git a/src/jcgp/backend/modules/problem/DigitalCircuitProblem.java b/src/jcgp/backend/modules/problem/DigitalCircuitProblem.java
index 0071ed5..b615675 100644
--- a/src/jcgp/backend/modules/problem/DigitalCircuitProblem.java
+++ b/src/jcgp/backend/modules/problem/DigitalCircuitProblem.java
@@ -80,7 +80,7 @@ public class DigitalCircuitProblem extends TestCaseProblem<UnsignedInteger> {
}
@Override
- public int perfectSolutionFound(Population population) {
+ public int hasPerfectSolution(Population population) {
// higher fitness is better
for (int i = 0; i < getResources().populationSize(); i++) {
if (population.get(i).getFitness() >= maxFitness.get()) {
@@ -89,16 +89,4 @@ public class DigitalCircuitProblem extends TestCaseProblem<UnsignedInteger> {
}
return -1;
}
-
- @Override
- public int hasImprovement(Population population) {
- // higher fitness is better
- for (int i = 0; i < getResources().populationSize(); i++) {
- if (population.get(i).getFitness() > bestFitness.get()) {
- bestFitness.set(population.get(i).getFitness());
- return i;
- }
- }
- return -1;
- }
}
diff --git a/src/jcgp/backend/modules/problem/Problem.java b/src/jcgp/backend/modules/problem/Problem.java
index 5f194b5..2af2373 100644
--- a/src/jcgp/backend/modules/problem/Problem.java
+++ b/src/jcgp/backend/modules/problem/Problem.java
@@ -85,7 +85,7 @@ public abstract class Problem extends Module {
* @param population the population to search through for a perfect chromosome.
* @return the perfect solution index, if one exits, -1 if no perfect solution was found.
*/
- public abstract int perfectSolutionFound(Population population);
+ public abstract int hasPerfectSolution(Population population);
/**
* Used to assert whether a given population has a chromosome that is an improvement over
diff --git a/src/jcgp/backend/modules/problem/SymbolicRegressionProblem.java b/src/jcgp/backend/modules/problem/SymbolicRegressionProblem.java
index 24c61d6..3b5f539 100644
--- a/src/jcgp/backend/modules/problem/SymbolicRegressionProblem.java
+++ b/src/jcgp/backend/modules/problem/SymbolicRegressionProblem.java
@@ -126,7 +126,7 @@ public class SymbolicRegressionProblem extends TestCaseProblem<Double> {
}
@Override
- public int perfectSolutionFound(Population population) {
+ public int hasPerfectSolution(Population population) {
// higher fitness is better
for (int i = 0; i < getResources().populationSize(); i++) {
if (population.get(i).getFitness() >= maxFitness.get() - perfectionThreshold.get()) {
@@ -135,18 +135,4 @@ public class SymbolicRegressionProblem extends TestCaseProblem<Double> {
}
return -1;
}
-
- @Override
- public int hasImprovement(Population population) {
- // higher fitness is better
- for (int i = 0; i < getResources().populationSize(); i++) {
- System.out.println("checking for improvement");
- if (population.get(i).getFitness() > bestFitness.get()) {
- System.out.println("found a better chr, " + i);
- bestFitness.set(population.get(i).getFitness());
- return i;
- }
- }
- return -1;
- }
}
diff --git a/src/jcgp/backend/modules/problem/TestCaseProblem.java b/src/jcgp/backend/modules/problem/TestCaseProblem.java
index 69c078d..188e236 100644
--- a/src/jcgp/backend/modules/problem/TestCaseProblem.java
+++ b/src/jcgp/backend/modules/problem/TestCaseProblem.java
@@ -5,6 +5,7 @@ import java.io.File;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import jcgp.backend.parsers.TestCaseParser;
+import jcgp.backend.population.Population;
import jcgp.backend.resources.ModifiableResources;
import jcgp.backend.resources.Resources;
@@ -162,6 +163,24 @@ public abstract class TestCaseProblem<T> extends Problem {
// use standard test case parser for this
TestCaseParser.parse(file, this, resources);
}
+
+ @Override
+ public int hasImprovement(Population population) {
+ for (int i = 0; i < getResources().populationSize(); i++) {
+ if (getFitnessOrientation() == BestFitness.HIGH) {
+ if (population.get(i).getFitness() > bestFitness.get()) {
+ bestFitness.set(population.get(i).getFitness());
+ return i;
+ }
+ } else {
+ if (population.get(i).getFitness() < bestFitness.get()) {
+ bestFitness.set(population.get(i).getFitness());
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
}
diff --git a/src/jcgp/backend/parsers/ChromosomeParser.java b/src/jcgp/backend/parsers/ChromosomeParser.java
index f5f25ae..838ec48 100644
--- a/src/jcgp/backend/parsers/ChromosomeParser.java
+++ b/src/jcgp/backend/parsers/ChromosomeParser.java
@@ -10,7 +10,6 @@ import jcgp.backend.population.Chromosome;
import jcgp.backend.population.Connection;
import jcgp.backend.population.Input;
import jcgp.backend.population.Node;
-import jcgp.backend.resources.ModifiableResources;
import jcgp.backend.resources.Resources;
/**
diff --git a/src/jcgp/backend/population/Chromosome.java b/src/jcgp/backend/population/Chromosome.java
index 0dfa801..673bb26 100644
--- a/src/jcgp/backend/population/Chromosome.java
+++ b/src/jcgp/backend/population/Chromosome.java
@@ -283,12 +283,12 @@ public class Chromosome implements Comparable<Chromosome> {
/**
* This method is useful for mutating chromosomes. It returns any
- * random {@code MutableElement} out of the chromosome with equal
+ * random {@code Mutable} out of the chromosome with equal
* probability.
*
* @return a random element that can be mutated - node or output.
*/
- public MutableElement getRandomMutableElement() {
+ public Mutable getRandomMutable() {
// choose output or node
int index = resources.getRandomInt(outputs.length + (resources.rows() * resources.columns()));
diff --git a/src/jcgp/backend/population/MutableElement.java b/src/jcgp/backend/population/Mutable.java
index 5782a99..3ce7065 100644
--- a/src/jcgp/backend/population/MutableElement.java
+++ b/src/jcgp/backend/population/Mutable.java
@@ -1,7 +1,7 @@
package jcgp.backend.population;
/**
- * {@code MutableElement} declares the expected behaviour of any
+ * {@code Mutable} 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.
@@ -14,7 +14,7 @@ package jcgp.backend.population;
* @author Eduardo Pedroni
*
*/
-public interface MutableElement {
+public interface Mutable {
/**
* This method sets the indexed connection to the specified new connection.
@@ -48,6 +48,6 @@ public interface MutableElement {
* @param element the mutable element to compare to.
* @return true if {@code element} is a copy of this element.
*/
- boolean copyOf(MutableElement element);
+ boolean copyOf(Mutable element);
}
diff --git a/src/jcgp/backend/population/Node.java b/src/jcgp/backend/population/Node.java
index 704b24e..3bcf3da 100644
--- a/src/jcgp/backend/population/Node.java
+++ b/src/jcgp/backend/population/Node.java
@@ -10,7 +10,7 @@ import jcgp.backend.function.Function;
* 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}
+ * implement both {@code Mutable} 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)
@@ -20,7 +20,7 @@ import jcgp.backend.function.Function;
* @author Eduardo Pedroni
*
*/
-public class Node implements MutableElement, Connection {
+public class Node implements Mutable, Connection {
private Function function;
private Connection[] connections;
@@ -124,7 +124,7 @@ public class Node implements MutableElement, Connection {
}
@Override
- public boolean copyOf(MutableElement element) {
+ public boolean copyOf(Mutable element) {
// both cannot be the same instance
if (this != element) {
// element must be instance of node
diff --git a/src/jcgp/backend/population/Output.java b/src/jcgp/backend/population/Output.java
index ab693e2..938741b 100644
--- a/src/jcgp/backend/population/Output.java
+++ b/src/jcgp/backend/population/Output.java
@@ -12,7 +12,7 @@ import java.util.ArrayList;
* @author Eduardo Pedroni
*
*/
-public class Output implements MutableElement {
+public class Output implements Mutable {
private Connection source;
private Chromosome chromosome;
@@ -56,7 +56,7 @@ public class Output implements MutableElement {
* is simply ignored and the output source is
* set.
*
- * @see jcgp.backend.population.MutableElement#setConnection(int, jcgp.backend.population.Connection)
+ * @see jcgp.backend.population.Mutable#setConnection(int, jcgp.backend.population.Connection)
*/
@Override
public void setConnection(int index, Connection newConnection) {
@@ -66,7 +66,7 @@ public class Output implements MutableElement {
}
@Override
- public boolean copyOf(MutableElement m) {
+ public boolean copyOf(Mutable m) {
// both cannot be the same instance
if (this != m) {
// element must be instance of output
diff --git a/src/jcgp/backend/tests/ChromosomeTests.java b/src/jcgp/backend/tests/ChromosomeTests.java
index c326805..b5c1da7 100644
--- a/src/jcgp/backend/tests/ChromosomeTests.java
+++ b/src/jcgp/backend/tests/ChromosomeTests.java
@@ -5,7 +5,7 @@ import static org.junit.Assert.fail;
import jcgp.backend.population.Chromosome;
import jcgp.backend.population.Connection;
import jcgp.backend.population.Input;
-import jcgp.backend.population.MutableElement;
+import jcgp.backend.population.Mutable;
import jcgp.backend.population.Node;
import jcgp.backend.population.Output;
import jcgp.backend.resources.ModifiableResources;
@@ -19,7 +19,7 @@ import org.junit.Test;
* Tests which cover the behaviour specified for a chromosome.
*
* - The chromosome should be able to return a specified node, input or output.
- * - It should be able to return a random MutableElement.
+ * - It should be able to return a random Mutable.
* - It should be able to return a random allowed connection given a column.
* - It should be able to return a random connection.
* - It should contain a freely modifiable fitness value.
@@ -198,7 +198,7 @@ public class ChromosomeTests {
int mutablePicks = 100000;
int mutableNodes = 0, mutableOutputs = 0;
for (int i = 0; i < mutablePicks; i++) {
- MutableElement m = chromosome.getRandomMutableElement();
+ Mutable m = chromosome.getRandomMutable();
if (m instanceof Node) {
mutableNodes++;