package jcgp; import java.util.Random; import jcgp.ea.EvolutionaryAlgorithm; import jcgp.ea.Mutator; import jcgp.ea.StandardEA; import jcgp.ea.StandardMutator; import jcgp.fitness.FitnessFunction; import jcgp.fitness.TestCase; import jcgp.fitness.TruthTableEvaluator; import jcgp.function.Addition; import jcgp.function.Function; import jcgp.function.FunctionSet; import jcgp.function.Subtraction; import jcgp.population.Chromosome; import jcgp.population.Connection; import jcgp.population.Input; import jcgp.population.MutableElement; import jcgp.population.Node; import jcgp.population.Population; public final class CGP { public static class Parameters { private static int rows, columns, inputs, outputs, mutationRate, generations, runs, populationSize, levelsBack, maxArity; /** * @return the number of nodes */ public static int getNodeNumber() { return rows * columns; } /** * @return the levelsBack */ public static int getLevelsBack() { return levelsBack; } /** * @param levelsBack the levelsBack to set */ private static void setLevelsBack(int levelsBack) { Parameters.levelsBack = levelsBack; } /** * @return the populationSize */ public static int getPopulationSize() { return populationSize; } /** * @param populationSize the populationSize to set */ private static void setPopulationSize(int populationSize) { Parameters.populationSize = populationSize; } /** * @return the rows */ public static int getRows() { return rows; } /** * @return the columns */ public static int getColumns() { return columns; } /** * @return the inputs */ public static int getInputs() { return inputs; } /** * @return the outputs */ public static int getOutputs() { return outputs; } /** * @return the mutationRate */ public static int getMutationRate() { return mutationRate; } /** * @return the generations */ public static int getGenerations() { return generations; } /** * @return the runs */ public static int getRuns() { return runs; } /** * @param rows the rows to set */ private static void setRows(int rows) { Parameters.rows = rows; } /** * @param columns the columns to set */ private static void setColumns(int columns) { Parameters.columns = columns; } /** * @param inputs the inputs to set */ private static void setInputs(int inputs) { Parameters.inputs = inputs; } /** * @param outputs the outputs to set */ private static void setOutputs(int outputs) { Parameters.outputs = outputs; } /** * @param mutationRate the mutationRate to set */ private static void setMutationRate(int mutationRate) { Parameters.mutationRate = mutationRate; } /** * @param generations the generations to set */ private static void setGenerations(int generations) { Parameters.generations = generations; } /** * @param runs the runs to set */ private static void setRuns(int runs) { Parameters.runs = runs; } /** * @return the maxArity */ public static int getMaxArity() { return maxArity; } /** * @param maxArity the maxArity to set */ private static void setMaxArity(int maxArity) { Parameters.maxArity = maxArity; } } public abstract static class Utilities { public static int getRandomInt(int limit){ return numberGenerator.nextInt(limit); } public static double getRandomDouble(int limit){ return numberGenerator.nextDouble() * limit; } /** * Returns a random allowed connection respecting levels back. * This method may always pick inputs, as they can be picked * regardless of the column. * * @param chromosome the chromosome to pick from * @param column the column to use as reference * @return a random connection */ public static Connection getRandomConnection(Chromosome chromosome, int column){ // work out the allowed range obeying levels back int allowedColumns = ((column >= Parameters.getLevelsBack()) ? Parameters.getLevelsBack() : column); int offset = column - allowedColumns; // choose input or node int connectionType = getRandomInt(Parameters.getInputs() + (Parameters.getRows() * allowedColumns)); if (connectionType < Parameters.getInputs()) { // input return chromosome.getInput(getRandomInt(Parameters.getInputs())); } else { // node return chromosome.getNode(getRandomInt(Parameters.getRows()), getRandomInt(allowedColumns) + offset); } } /** * Returns a random allowed connection. * * This method may always pick inputs, as they can be picked * regardless of the column. * * @param chromosome the chromosome to pick from * @param column the column to use as reference * @param levelsBack whether or not to respect levels back * @return a random connection */ public static Connection getRandomConnection(Chromosome chromosome, int column, boolean levelsBack){ if (levelsBack) { return getRandomConnection(chromosome, column); } else { // choose input or node int connectionType = getRandomInt(Parameters.getInputs() + (Parameters.getRows() * column)); if (connectionType < Parameters.getInputs()) { // input return chromosome.getInput(getRandomInt(Parameters.getInputs())); } else { // node return chromosome.getNode(getRandomInt(Parameters.getRows()), getRandomInt(column)); } } } /** * @param chromosome the chromosome to choose from * @return a random input */ public static Input getRandomInput(Chromosome chromosome){ return chromosome.getInput(getRandomInt(Parameters.getInputs())); } /** * Returns a random allowed node respecting levels back. * * This method will NOT pick inputs. * * @param chromosome the chromosome to pick from * @param column the column to use as reference * @return a random node */ public static Node getRandomNode(Chromosome chromosome, int column){ // work out the allowed range obeying levels back int allowedColumns = ((column >= Parameters.getLevelsBack()) ? Parameters.getLevelsBack() : column); int offset = column - allowedColumns; // pick a random allowed column and row int randomColumn = (getRandomInt(allowedColumns) + offset); int randomRow = (getRandomInt(Parameters.getRows())); return chromosome.getNode(randomRow, randomColumn); } /** * Returns a random allowed node. * * This method will NOT pick inputs. * * @param chromosome the chromosome to pick from * @param column the column to use as reference * @param levelsBack whether or not to respect levels back * @return a random node */ public static Node getRandomNode(Chromosome chromosome, int column, boolean levelsBack){ if (levelsBack) { return getRandomNode(chromosome, column); } else { // pick any random column before the given column int randomColumn = (getRandomInt(column)); // pick a random rowgetColumns int randomRow = (getRandomInt(Parameters.getRows())); return chromosome.getNode(randomRow, randomColumn); } } /** * This method picks a random mutable element from the given chromosome. * * It will pick outputs or nodes fairly. * * @param chromosome the chromosome to pick from * @return a random mutable element */ public static MutableElement getRandomMutable(Chromosome chromosome){ // choose output or node int connectionType = getRandomInt(Parameters.getOutputs() + Parameters.getNodeNumber()); if (connectionType < Parameters.getOutputs()) { // outputs return chromosome.getOutput(getRandomInt(Parameters.getOutputs())); } else { // node return chromosome.getNode(getRandomInt(Parameters.getRows()), getRandomInt(Parameters.getRows())); } } /** * pick from any column - use this for setting outputs * * @param chromosome * @return */ public static Node getRandomNode(Chromosome chromosome) { return chromosome.getNode(getRandomInt(Parameters.getRows()), getRandomInt(Parameters.getColumns())); } public static Function getRandomFunction() { return functionSet.getFunction(Utilities.getRandomInt(functionSet.getFunctionCount())); } public static Function getFunction(int index) { return functionSet.getFunction(index); } } public static class TruthTable { private static TestCase[] testCases; private static void setTestCases(TestCase ... testCases) { TruthTable.testCases = testCases; } public static TestCase getTestCase(int index) { return testCases[index]; } public static int getTestCaseCount() { return testCases.length; } } // system-wide resources private static FunctionSet functionSet; private static Random numberGenerator; // CGP components private EvolutionaryAlgorithm ea; private Mutator mutator; private Population population; private FitnessFunction fitnessFunction; public CGP() { initialise(); fitnessFunction.evaluate(population); ea.evolve(population, mutator); } /** * */ private void initialise() { // initialise random number generator numberGenerator = new Random(1234); // initialise function set functionSet = new FunctionSet(new Addition(), new Subtraction()); // initialise parameters Parameters.setInputs(3); Parameters.setColumns(3); Parameters.setRows(3); Parameters.setOutputs(3); Parameters.setGenerations(10); Parameters.setMutationRate(1); Parameters.setRuns(5); Parameters.setPopulationSize(5); Parameters.setLevelsBack(1); // compute and set maximum arity Parameters.setMaxArity(functionSet.getMaxArity()); // initialise EA ea = new StandardEA(); mutator = new StandardMutator(); // initialise fitness function and truth table TruthTable.setTestCases(new TestCase(new int[] {2, 5, 4}, new int[] {1, 10, 15})); fitnessFunction = new TruthTableEvaluator(); // initialise population population = new Population(); } }