diff options
Diffstat (limited to 'src/jcgp/JCGP.java')
-rw-r--r-- | src/jcgp/JCGP.java | 400 |
1 files changed, 30 insertions, 370 deletions
diff --git a/src/jcgp/JCGP.java b/src/jcgp/JCGP.java index 962ddec..2c7023e 100644 --- a/src/jcgp/JCGP.java +++ b/src/jcgp/JCGP.java @@ -1,375 +1,36 @@ package jcgp; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map.Entry; -import java.util.Random; - -import javafx.beans.property.SimpleIntegerProperty; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import jcgp.backend.function.Arithmetic; -import jcgp.backend.function.BitwiseLogic; -import jcgp.backend.function.BooleanLogic; -import jcgp.backend.function.Function; -import jcgp.backend.function.FunctionSet; import jcgp.backend.modules.ea.EvolutionaryAlgorithm; import jcgp.backend.modules.ea.MuPlusLambda; import jcgp.backend.modules.ea.TournamentSelection; import jcgp.backend.modules.fitness.FitnessFunction; -import jcgp.backend.modules.fitness.TestCase; -import jcgp.backend.modules.fitness.TestCaseEvaluator; +import jcgp.backend.modules.fitness.testcase.TestCaseEvaluator.TestCase; import jcgp.backend.modules.mutator.Mutator; import jcgp.backend.modules.mutator.PointMutator; -import jcgp.backend.parameters.BooleanParameter; -import jcgp.backend.parameters.DoubleParameter; -import jcgp.backend.parameters.IntegerParameter; -import jcgp.backend.parameters.Parameter; -import jcgp.backend.parameters.ParameterStatus; import jcgp.backend.population.Population; -import jcgp.gui.console.Console; +import jcgp.backend.resources.Console; +import jcgp.backend.resources.ModifiableResources; +import jcgp.backend.resources.Resources; /** + * + * Top-level CGP class. This class is the entry point for a CGP experiment. + * <p> + * An instance of JCGP encapsulates the entire experiment. It contains a Resources + * object which can be retrieved via a getter. Modules can be selected using their + * respective setters and function sets can be selected through the resources. + * + * The flow of the experiment is controlled using start() and nextGeneration(). The + * experiment can be reset with reset(), + * + * * @author Eduardo Pedroni - * + * @see Resources, Module, FunctionSet */ public class JCGP { - - /** - * - * 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. - * - * @author Eduardo Pedroni - * - */ - public static class Resources { - private HashMap<String, Parameter> parameters = new HashMap<String, Parameter>(); - - private Random numberGenerator; - - private TestCase[] testCases; - - // function sets - private FunctionSet[] functionSets = new FunctionSet[] { - new Arithmetic(), - new BitwiseLogic(), - new BooleanLogic() }; - private FunctionSet functionSet = functionSets[0]; - - // GUI console - private Console console; - - public Resources() { - createBaseParameters(); - - numberGenerator = new Random(getInt("seed")); - set("arity", functionSet.getMaxArity()); - } - - public int getInt(String key) { - if (parameters.get(key) instanceof IntegerParameter) { - return ((IntegerParameter) parameters.get(key)).get(); - } else if (parameters.get(key) instanceof DoubleParameter) { - return (int) ((DoubleParameter) parameters.get(key)).get(); - } else { - throw new ClassCastException("Could not cast " + parameters.get(key).getClass() + " to int."); - } - } - - public double getDouble(String key) { - if (parameters.get(key) instanceof IntegerParameter) { - return (double) ((IntegerParameter) parameters.get(key)).get(); - } else if (parameters.get(key) instanceof DoubleParameter) { - return ((DoubleParameter) parameters.get(key)).get(); - } else { - throw new ClassCastException("Could not cast " + parameters.get(key).getClass() + " to double."); - } - } - - public boolean getBoolean(String key) { - if (parameters.get(key) instanceof BooleanParameter) { - return ((BooleanParameter) parameters.get(key)).get(); - } else { - throw new ClassCastException("Could not cast " + parameters.get(key).getClass() + " to int."); - } - } - - public void set(String key, Object value) { - if (parameters.get(key) instanceof IntegerParameter) { - ((IntegerParameter) parameters.get(key)).set(((Integer) value).intValue()); - } else if (parameters.get(key) instanceof DoubleParameter) { - ((DoubleParameter) parameters.get(key)).set(((Double) value).doubleValue()); - } else if (parameters.get(key) instanceof BooleanParameter) { - ((BooleanParameter) parameters.get(key)).set(((Boolean) value).booleanValue()); - } - } - - public Parameter getParameter(String key) { - return parameters.get(key); - } - - public boolean contains(String key) { - return parameters.containsKey(key); - } - - private void createBaseParameters() { - parameters.put("rows", new IntegerParameter(8, "Rows", false, true) { - @Override - public void validate(int newValue) { - if (newValue <= 0) { - status = ParameterStatus.INVALID; - status.setDetails("Chromosome must have at least 1 row."); - } else { - status = ParameterStatus.VALID; - } - } - }); - parameters.put("columns", new IntegerParameter(9, "Columns", false, true) { - @Override - public void validate(int newValue) { - if (newValue <= 0) { - status = ParameterStatus.INVALID; - status.setDetails("Chromosome must have at least 1 column."); - } else { - status = ParameterStatus.VALID; - } - } - }); - parameters.put("inputs", new IntegerParameter(3, "Inputs", false, true) { - @Override - public void validate(int newValue) { - if (newValue <= 0) { - status = ParameterStatus.INVALID; - status.setDetails("Chromosome must have at least 1 input."); - } else { - status = ParameterStatus.VALID; - } - } - }); - parameters.put("outputs", new IntegerParameter(3, "Outputs", false, true) { - @Override - public void validate(int newValue) { - if (newValue <= 0) { - status = ParameterStatus.INVALID; - status.setDetails("Chromosome must have at least 1 output."); - } else { - status = ParameterStatus.VALID; - } - } - }); - parameters.put("popSize", new IntegerParameter(5, "Population", false, true) { - @Override - public void validate(int newValue) { - if (newValue <= 0) { - status = ParameterStatus.INVALID; - status.setDetails("Population size must be at least 1."); - } else { - status = ParameterStatus.VALID; - } - } - }); - parameters.put("levelsBack", new IntegerParameter(2, "Levels back", false, true) { - @Override - public void validate(int newValue) { - if (newValue <= 0) { - status = ParameterStatus.INVALID; - status.setDetails("Levels back must be at least 1."); - } else if (newValue > getInt("columns")) { - status = ParameterStatus.INVALID; - status.setDetails("Levels back must be less than or equal to the number of columns."); - } else { - status = ParameterStatus.VALID; - } - } - }); - - IntegerParameter nodes = new IntegerParameter(1, "Nodes", true, false) { - @Override - public void validate(int newValue) { - // blank - } - }; - nodes.valueProperty().bind(((SimpleIntegerProperty) ((IntegerParameter) parameters.get("rows")).valueProperty()).multiply((SimpleIntegerProperty) ((IntegerParameter) parameters.get("columns")).valueProperty())); - parameters.put("nodes", nodes); - - parameters.put("generations", new IntegerParameter(1000000, "Generations") { - @Override - public void validate(int newValue) { - if (newValue <= 0) { - status = ParameterStatus.INVALID; - status.setDetails("Number of generations must be greater than 0."); - } else if (newValue < getInt("currentGen")) { - status = ParameterStatus.WARNING_RESET; - status.setDetails("Setting generations to less than the current generation will cause the experiment to restart."); - } else { - status = ParameterStatus.VALID; - } - } - }); - parameters.put("currentGen", new IntegerParameter(1, "Generation", true, false) { - @Override - public void validate(int newValue) { - // blank - } - }); - - parameters.put("runs", new IntegerParameter(5, "Runs") { - @Override - public void validate(int newValue) { - if (newValue <= 0) { - status = ParameterStatus.INVALID; - status.setDetails("Number of runs must be greater than 0."); - } else if (newValue < getInt("currentRun")) { - status = ParameterStatus.WARNING_RESET; - status.setDetails("Setting runs to less than the current run will cause the experiment to restart."); - } else { - status = ParameterStatus.VALID; - } - } - }); - parameters.put("currentRun", new IntegerParameter(1, "Run", true, false) { - @Override - public void validate(int newValue) { - // blank - } - }); - - parameters.put("arity", new IntegerParameter(0, "Max arity", true, false) { - @Override - public void validate(int newValue) { - // blank - } - }); - parameters.put("maxFitness", new IntegerParameter(3, "Max fitness", true, true) { - @Override - public void validate(int newValue) { - // blank - } - }); - - IntegerParameter seed = new IntegerParameter(123, "Seed", false, true) { - @Override - public void validate(int newValue) { - status = ParameterStatus.VALID; - } - }; - seed.valueProperty().addListener(new ChangeListener<Number>() { - @Override - public void changed( - ObservableValue<? extends Number> observable, - Number oldValue, Number newValue) { - numberGenerator.setSeed(newValue.longValue()); - } - }); - parameters.put("seed", seed); - - parameters.put("report", new IntegerParameter(1, "Report", false, false) { - @Override - public void validate(int newValue) { - if (newValue > getInt("generations")) { - status = ParameterStatus.WARNING; - status.setDetails("No reports will be printed."); - } else { - status = ParameterStatus.VALID; - } - } - }); - } - - /** - * - * - * @return the iterator for the set of base parameters - */ - public Iterator<Entry<String, Parameter>> iterator() { - return parameters.entrySet().iterator(); - } - - /* - * Utility functions - */ - public int getRandomInt(int limit) { - return numberGenerator.nextInt(limit); - } - - public double getRandomDouble(int limit) { - return numberGenerator.nextDouble() * limit; - } - - public double getRandomDouble() { - return numberGenerator.nextDouble(); - } - - /* - * FunctionSet functions - */ - public Function getRandomFunction() { - Function f = functionSet.getAllowedFunction(numberGenerator.nextInt(functionSet.getAllowedFunctionCount())); - return f; - } - - public Function getFunction(int index) { - return functionSet.getAllowedFunction(index); - } - - public void setFunctionSet(int index) { - functionSet = functionSets[index]; - } - - /** - * @return the functionSets - */ - public FunctionSet[] getFunctionSets() { - return functionSets; - } - - /** - * @return the functionSet - */ - public FunctionSet getFunctionSet() { - return functionSet; - } - - /* - * Test cases - */ - public void setTestCases(TestCase ... testCases) { - this.testCases = testCases; - } - - public TestCase getTestCase(int index) { - return testCases[index]; - } - - public int getTestCaseCount() { - return testCases.length; - } - /* - * Console functionality - */ - public void setConsole(Console console) { - this.console = console; - } - - public void println(String s) { - System.out.println(s); - if (console != null) { - console.println(s); - } - } - - public void print(String s) { - System.out.print(s); - if (console != null) { - console.print(s); - } - } - } - - private final Resources resources = new Resources(); + // make resources + private final ModifiableResources resources = new ModifiableResources(); /* * The following arrays contain all available modules. These collections are read by the GUI @@ -380,7 +41,7 @@ public class JCGP { */ // mutators private Mutator[] mutators = new Mutator[] { - new PointMutator() }; + new PointMutator(resources) }; private Mutator mutator; // evolutionary algorithms @@ -391,7 +52,7 @@ public class JCGP { // fitness evaluators private FitnessFunction[] fitnessFunctions = new FitnessFunction[] { - new TestCaseEvaluator() }; + /*new TestCaseEvaluator()*/ }; private FitnessFunction fitnessFunction; /* @@ -401,7 +62,6 @@ public class JCGP { private boolean finished = false; - public JCGP() { population = new Population(resources); @@ -411,20 +71,17 @@ public class JCGP { mutator = mutators[0]; fitnessFunction = fitnessFunctions[0]; - - resources.setTestCases(new TestCase(new Integer[]{1, 2, 3}, new Integer[]{-4, 5, 6})); } - public Resources getResources() { + public ModifiableResources getResources() { return resources; } - + public Population getPopulation() { return population; } - /** * @return the mutators */ @@ -498,7 +155,7 @@ public class JCGP { public void nextGeneration() { if (!finished) { - fitnessFunction.evaluate(population, resources); + fitnessFunction.evaluate(population, (Resources) resources); report(); @@ -506,7 +163,7 @@ public class JCGP { // we still have generations left to go if (population.getChromosome(evolutionaryAlgorithm.getFittestChromosome()).getFitness() >= resources.getInt("maxFitness")) { // solution has been found, start next run - resources.println("Solution found in generation " + resources.getInt("currentGen") + ", chromosome: " + evolutionaryAlgorithm.getFittestChromosome()); + resources.println("Solution found on generation " + resources.getInt("currentGen") + ", chromosome: " + evolutionaryAlgorithm.getFittestChromosome()); if (resources.getInt("currentRun") < resources.getInt("runs")) { // there are still runs left @@ -514,7 +171,7 @@ public class JCGP { resources.set("currentGen", 0); // start a new population - population = new Population(resources); + population = new Population((Resources) resources); } else { // no more generations and no more runs, we're done finished = true; @@ -543,7 +200,7 @@ public class JCGP { } } - evolutionaryAlgorithm.evolve(population, mutator, resources); + evolutionaryAlgorithm.evolve(population, mutator, (Resources) resources); } @@ -553,7 +210,6 @@ public class JCGP { resources.println("Generation: " + resources.getInt("currentGen") + ", fitness: " + population.getChromosome(evolutionaryAlgorithm.getFittestChromosome()).getFitness()); } } - } public void start() { @@ -581,4 +237,8 @@ public class JCGP { return finished; } + public void setConsole(Console console) { + resources.setConsole(console); + } + } |