From 7f89d81e6f8a5ce82d42c3b852b5219edaa4b86c Mon Sep 17 00:00:00 2001 From: Eduardo Pedroni Date: Wed, 7 May 2014 18:38:27 +0100 Subject: Removed reflection for now, added fitness orientation support --- src/jcgp/JCGP.java | 171 ++++----------------- src/jcgp/backend/modules/mutator/PointMutator.java | 6 +- src/jcgp/backend/modules/problem/BestFitness.java | 18 +++ .../modules/problem/DigitalCircuitProblem.java | 14 +- src/jcgp/backend/modules/problem/Problem.java | 2 +- .../modules/problem/SymbolicRegressionProblem.java | 16 +- .../backend/modules/problem/TestCaseProblem.java | 19 +++ src/jcgp/backend/parsers/ChromosomeParser.java | 1 - src/jcgp/backend/population/Chromosome.java | 4 +- src/jcgp/backend/population/Mutable.java | 53 +++++++ src/jcgp/backend/population/MutableElement.java | 53 ------- src/jcgp/backend/population/Node.java | 6 +- src/jcgp/backend/population/Output.java | 6 +- src/jcgp/backend/tests/ChromosomeTests.java | 6 +- 14 files changed, 138 insertions(+), 237 deletions(-) create mode 100644 src/jcgp/backend/modules/problem/BestFitness.java create mode 100644 src/jcgp/backend/population/Mutable.java delete mode 100644 src/jcgp/backend/population/MutableElement.java (limited to 'src/jcgp') 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 mutators; + private Mutator[] mutators = new Mutator[] { + new PercentPointMutator(resources), + new FixedPointMutator(resources), + new ProbabilisticMutator(resources) + }; private Mutator mutator; // evolutionary algorithms - private ArrayList evolutionaryStrategies; + private EvolutionaryStrategy[] evolutionaryStrategies = new EvolutionaryStrategy[] { + new MuPlusLambda(resources), + new TournamentSelection(resources) + }; private EvolutionaryStrategy evolutionaryStrategy; // problem types - private ArrayList 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> esList = reflections.getSubTypesOf(EvolutionaryStrategy.class); - evolutionaryStrategies = new ArrayList(); - - // go through all subclasses of EvolutionaryStrategy - for (Class esType : esList) { - Constructor 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> mutatorList = reflections.getSubTypesOf(Mutator.class); - mutators = new ArrayList(); - - // go through all subclasses of Mutator - for (Class mutatorType : mutatorList) { - Constructor 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> problemTypes = reflections.getSubTypesOf(Problem.class); - problems = new ArrayList(); - - // go through all subclasses of Problem - for (Class problemType : problemTypes) { - - Constructor 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 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 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 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. + *

+ * {@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 { } @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 { } 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 { } @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 { } 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 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 { /** * 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/Mutable.java b/src/jcgp/backend/population/Mutable.java new file mode 100644 index 0000000..3ce7065 --- /dev/null +++ b/src/jcgp/backend/population/Mutable.java @@ -0,0 +1,53 @@ +package jcgp.backend.population; + +/** + * {@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. + *

+ * 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 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. + */ + public void setConnection(int index, Connection newConnection); + + /** + * 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.
  • + *
+ * @param element the mutable element to compare to. + * @return true if {@code element} is a copy of this element. + */ + boolean copyOf(Mutable element); + +} diff --git a/src/jcgp/backend/population/MutableElement.java b/src/jcgp/backend/population/MutableElement.java deleted file mode 100644 index 5782a99..0000000 --- a/src/jcgp/backend/population/MutableElement.java +++ /dev/null @@ -1,53 +0,0 @@ -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 { - - /** - * 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. - */ - public void setConnection(int index, Connection newConnection); - - /** - * 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.
  • - *
- * @param element the mutable element to compare to. - * @return true if {@code element} is a copy of this element. - */ - boolean copyOf(MutableElement 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++; -- cgit v1.2.3