From 9ac2848be66c39acdc291dc3b48b91178acc1a05 Mon Sep 17 00:00:00 2001 From: Eduardo Pedroni Date: Thu, 24 Apr 2014 10:34:30 +0100 Subject: Refactored parsers and parameters, had to install e(fx)clipse to deploy application. --- src/jcgp/JCGP.java | 61 ++++--- src/jcgp/backend/function/BitwiseLogic.java | 173 +++++++++++++++---- .../backend/modules/es/TournamentSelection.java | 10 +- .../modules/problem/DigitalCircuitProblem.java | 4 +- .../backend/modules/problem/TestCaseProblem.java | 43 +---- src/jcgp/backend/parsers/ChromosomeParser.java | 189 +++++++++++++++++++++ src/jcgp/backend/parsers/FunctionParser.java | 53 ++++++ src/jcgp/backend/parsers/ParameterParser.java | 77 +++++++++ src/jcgp/backend/parsers/TestCaseParser.java | 90 ++++++++++ src/jcgp/backend/population/Node.java | 3 + .../backend/resources/ModifiableResources.java | 3 +- src/jcgp/backend/resources/Resources.java | 2 +- .../settings/parameters/GUIDoubleParameter.java | 10 +- .../settings/parameters/GUIIntegerParameter.java | 4 +- src/jcgp/gui/settings/parameters/GUIParameter.java | 2 +- 15 files changed, 610 insertions(+), 114 deletions(-) create mode 100644 src/jcgp/backend/parsers/ChromosomeParser.java create mode 100644 src/jcgp/backend/parsers/FunctionParser.java create mode 100644 src/jcgp/backend/parsers/ParameterParser.java create mode 100644 src/jcgp/backend/parsers/TestCaseParser.java diff --git a/src/jcgp/JCGP.java b/src/jcgp/JCGP.java index 2a6552c..f980c00 100644 --- a/src/jcgp/JCGP.java +++ b/src/jcgp/JCGP.java @@ -11,10 +11,10 @@ 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.parser.ChromosomeParser; -import jcgp.backend.parser.FunctionParser; -import jcgp.backend.parser.ParameterParser; -import jcgp.backend.parser.TestCaseParser; +import jcgp.backend.parsers.ChromosomeParser; +import jcgp.backend.parsers.FunctionParser; +import jcgp.backend.parsers.ParameterParser; +import jcgp.backend.parsers.TestCaseParser; import jcgp.backend.population.Population; import jcgp.backend.resources.Console; import jcgp.backend.resources.ModifiableResources; @@ -50,19 +50,19 @@ public class JCGP { // mutators private Mutator[] mutators = new Mutator[] { new PointMutator(resources) }; - private Mutator mutator; + private Mutator mutator = mutators[0]; // evolutionary algorithms private EvolutionaryStrategy[] evolutionaryStrategies = new EvolutionaryStrategy[] { new MuPlusLambda(resources), - new TournamentSelection() }; - private EvolutionaryStrategy evolutionaryStrategy; + new TournamentSelection(resources) }; + private EvolutionaryStrategy evolutionaryStrategy = evolutionaryStrategies[0]; // problem types private Problem[] problems = new Problem[] { new SymbolicRegressionProblem(resources), new DigitalCircuitProblem(resources) }; - private Problem problem; + private Problem problem = problems[0]; /* * the population of chromosomes @@ -84,17 +84,14 @@ public class JCGP { jcgp.loadParameters(new File(args[0])); if (jcgp.getProblem() instanceof TestCaseProblem) { - ((TestCaseProblem) jcgp.getProblem()).parse(new File(args[2])); + TestCaseParser.parse(new File(args[2]), (TestCaseProblem) jcgp.getProblem(), jcgp.getResources()); } jcgp.start(); } public JCGP() { - setEvolutionaryStrategy(0); - setMutator(0); - setProblem(0); - + resources.setFunctionSet(problem.getFunctionSet()); population = new Population(resources); } @@ -159,14 +156,16 @@ public class JCGP { */ public void setMutator(int index) { this.mutator = mutators[index]; + resources.println("[CGP] Mutator selected: " + mutator.toString()); } /** * @param evolutionaryStrategy the evolutionaryAlgorithm to set */ - public void setEvolutionaryStrategy(int index) { + public void setEvolutionaryStrategy(int index) { this.evolutionaryStrategy = evolutionaryStrategies[index]; + resources.println("[CGP] Evolutionary strategy selected: " + evolutionaryStrategy.toString()); } @@ -179,6 +178,7 @@ public class JCGP { } public void nextGeneration() { + System.out.println("service: doing next gen"); if (!finished) { problem.evaluate(population, (Resources) resources); reportGeneration(); @@ -188,7 +188,6 @@ public class JCGP { if (problem.isPerfectSolution(population.getFittest())) { // solution has been found, start next run resources.println("[CGP] Solution found, generation " + resources.currentGeneration() + ", chromosome " + population.getFittestIndex()); - if (resources.currentRun() < resources.runs()) { // there are still runs left resources.setCurrentRun(resources.currentRun() + 1); @@ -202,6 +201,8 @@ public class JCGP { } } else { resources.setCurrentGeneration(resources.currentGeneration() + 1); + // solution isn't perfect and we still have generations left, evolve more! + evolutionaryStrategy.evolve(population, mutator, (Resources) resources); } } else { // the run has ended, check if any more runs must be done @@ -222,18 +223,11 @@ public class JCGP { } } } - - evolutionaryStrategy.evolve(population, mutator, (Resources) resources); - } private void reportGeneration() { - if (resources.reportInterval() > 0) { - if (resources.currentGeneration() % resources.reportInterval() == 0) { - resources.println("[CGP] Generation: " + resources.currentGeneration() + ", fittest chromosome (" - + population.getFittestIndex() + ") has fitness: " + population.getFittest().getFitness()); - } - } + resources.reportln("[CGP] Generation: " + resources.currentGeneration() + ", fittest chromosome (" + + population.getFittestIndex() + ") has fitness: " + population.getFittest().getFitness()); } public void start() { @@ -249,13 +243,24 @@ public class JCGP { population = new Population(resources); resources.setCurrentGeneration(1); resources.setCurrentRun(1); - resources.println("-----------------------------"); - resources.println("New experiment: " + problem.toString()); + resources.println("*********************************************************"); + resources.println("[CGP] New experiment: " + problem.toString()); + resources.println("[CGP] Rows: " + resources.rows()); + resources.println("[CGP] Columns: " + resources.columns()); + resources.println("[CGP] Levels back: " + resources.levelsBack()); + resources.println("[CGP] Population size: " + resources.populationSize()); + resources.println("[CGP] Total generations: " + resources.generations()); + resources.println("[CGP] Total runs: " + resources.runs()); + resources.println("[CGP] Report interval: " + resources.reportInterval()); + resources.println("[CGP] Seed: " + resources.seed()); + resources.println(""); + resources.println("[CGP] Evolutionary strategy: " + evolutionaryStrategy.toString()); + resources.println("[CGP] Mutator: " + mutator.toString()); } public void loadParameters(File file) { ParameterParser.parseParameters(file, resources); - FunctionParser.parseFunctions(file, problem); + FunctionParser.parseFunctions(file, problem, resources); reset(); } @@ -263,7 +268,7 @@ public class JCGP { if (problem instanceof TestCaseProblem) { TestCaseParser.parseParameters(file, resources); reset(); - ((TestCaseProblem) problem).parse(file); + TestCaseParser.parse(file, (TestCaseProblem) problem, resources); } } diff --git a/src/jcgp/backend/function/BitwiseLogic.java b/src/jcgp/backend/function/BitwiseLogic.java index a4c2737..2466f36 100644 --- a/src/jcgp/backend/function/BitwiseLogic.java +++ b/src/jcgp/backend/function/BitwiseLogic.java @@ -22,9 +22,12 @@ public class BitwiseLogic extends FunctionSet { new Or(), new OrNotA(), new OrNotB(), - new Nand()}; - - // TODO muxes + new Nand() +// new Mux1(), +// new Mux2(), +// new Mux3(), +// new Mux4() + }; enableAll(); } @@ -153,9 +156,9 @@ public class BitwiseLogic extends FunctionSet { if (connections.length < getArity()) { throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); } else { - UnsignedInteger arg1 = ((UnsignedInteger) connections[0].getValue()); - UnsignedInteger arg2 = ((UnsignedInteger) connections[1].getValue()); - Integer result = arg1.get() & arg2.get(); + UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); + Integer result = in0.get() & in1.get(); return new UnsignedInteger(result); } @@ -178,9 +181,9 @@ public class BitwiseLogic extends FunctionSet { if (connections.length < getArity()) { throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); } else { - UnsignedInteger arg1 = ((UnsignedInteger) connections[0].getValue()); - UnsignedInteger arg2 = ((UnsignedInteger) connections[1].getValue()); - Integer result = ~(arg1.get()) & arg2.get(); + UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); + Integer result = ~(in0.get()) & in1.get(); return new UnsignedInteger(result); } @@ -203,9 +206,9 @@ public class BitwiseLogic extends FunctionSet { if (connections.length < getArity()) { throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); } else { - UnsignedInteger arg1 = ((UnsignedInteger) connections[0].getValue()); - UnsignedInteger arg2 = ((UnsignedInteger) connections[1].getValue()); - Integer result = arg1.get() & ~(arg2.get()); + UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); + Integer result = in0.get() & ~(in1.get()); return new UnsignedInteger(result); } @@ -228,9 +231,9 @@ public class BitwiseLogic extends FunctionSet { if (connections.length < getArity()) { throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); } else { - UnsignedInteger arg1 = ((UnsignedInteger) connections[0].getValue()); - UnsignedInteger arg2 = ((UnsignedInteger) connections[1].getValue()); - Integer result = arg1.get() | arg2.get(); + UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); + Integer result = in0.get() | in1.get(); return new UnsignedInteger(~result); } @@ -253,9 +256,9 @@ public class BitwiseLogic extends FunctionSet { if (connections.length < getArity()) { throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); } else { - UnsignedInteger arg1 = ((UnsignedInteger) connections[0].getValue()); - UnsignedInteger arg2 = ((UnsignedInteger) connections[1].getValue()); - Integer result = arg1.get() ^ arg2.get(); + UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); + Integer result = in0.get() ^ in1.get(); return new UnsignedInteger(result); } @@ -278,9 +281,9 @@ public class BitwiseLogic extends FunctionSet { if (connections.length < getArity()) { throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); } else { - UnsignedInteger arg1 = ((UnsignedInteger) connections[0].getValue()); - UnsignedInteger arg2 = ((UnsignedInteger) connections[1].getValue()); - Integer result = arg1.get() ^ arg2.get(); + UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); + Integer result = in0.get() ^ in1.get(); return new UnsignedInteger(~result); } @@ -303,9 +306,9 @@ public class BitwiseLogic extends FunctionSet { if (connections.length < getArity()) { throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); } else { - UnsignedInteger arg1 = ((UnsignedInteger) connections[0].getValue()); - UnsignedInteger arg2 = ((UnsignedInteger) connections[1].getValue()); - Integer result = arg1.get() | arg2.get(); + UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); + Integer result = in0.get() | in1.get(); return new UnsignedInteger(result); } @@ -328,9 +331,9 @@ public class BitwiseLogic extends FunctionSet { if (connections.length < getArity()) { throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); } else { - UnsignedInteger arg1 = ((UnsignedInteger) connections[0].getValue()); - UnsignedInteger arg2 = ((UnsignedInteger) connections[1].getValue()); - Integer result = ~arg1.get() | arg2.get(); + UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); + Integer result = ~in0.get() | in1.get(); return new UnsignedInteger(result); } @@ -353,9 +356,9 @@ public class BitwiseLogic extends FunctionSet { if (connections.length < getArity()) { throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); } else { - UnsignedInteger arg1 = ((UnsignedInteger) connections[0].getValue()); - UnsignedInteger arg2 = ((UnsignedInteger) connections[1].getValue()); - Integer result = arg1.get() | ~arg2.get(); + UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); + Integer result = in0.get() | ~in1.get(); return new UnsignedInteger(result); } @@ -378,9 +381,9 @@ public class BitwiseLogic extends FunctionSet { if (connections.length < getArity()) { throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); } else { - UnsignedInteger arg1 = ((UnsignedInteger) connections[0].getValue()); - UnsignedInteger arg2 = ((UnsignedInteger) connections[1].getValue()); - Integer result = arg1.get() & arg2.get(); + UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); + Integer result = in0.get() & in1.get(); return new UnsignedInteger(~result); } @@ -396,4 +399,108 @@ public class BitwiseLogic extends FunctionSet { return "Nand"; } } + + public static class Mux1 extends Function { + @Override + public UnsignedInteger run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); + UnsignedInteger in2 = ((UnsignedInteger) connections[2].getValue()); + Integer result = ((in0.get() & ~in2.get()) | (in1.get() & in2.get())); + + return new UnsignedInteger(result); + } + } + + @Override + public int getArity() { + return 3; + } + + @Override + public String getName() { + return "Mux1"; + } + } + + public static class Mux2 extends Function { + @Override + public UnsignedInteger run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); + UnsignedInteger in2 = ((UnsignedInteger) connections[2].getValue()); + Integer result = ((in0.get() & ~in2.get()) | (~in1.get() & in2.get())); + + return new UnsignedInteger(result); + } + } + + @Override + public int getArity() { + return 3; + } + + @Override + public String getName() { + return "Mux2"; + } + } + + public static class Mux3 extends Function { + @Override + public UnsignedInteger run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); + UnsignedInteger in2 = ((UnsignedInteger) connections[2].getValue()); + Integer result = ((~in0.get() & ~in2.get()) | (in1.get() & in2.get())); + + return new UnsignedInteger(result); + } + } + + @Override + public int getArity() { + return 3; + } + + @Override + public String getName() { + return "Mux3"; + } + } + + public static class Mux4 extends Function { + @Override + public UnsignedInteger run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); + UnsignedInteger in2 = ((UnsignedInteger) connections[2].getValue()); + Integer result = ((~in0.get() & ~in2.get()) | (~in1.get() & in2.get())); + + return new UnsignedInteger(result); + } + } + + @Override + public int getArity() { + return 3; + } + + @Override + public String getName() { + return "Mux4"; + } + } } diff --git a/src/jcgp/backend/modules/es/TournamentSelection.java b/src/jcgp/backend/modules/es/TournamentSelection.java index 4070468..7cc9706 100644 --- a/src/jcgp/backend/modules/es/TournamentSelection.java +++ b/src/jcgp/backend/modules/es/TournamentSelection.java @@ -8,10 +8,10 @@ import jcgp.backend.resources.parameters.Parameter; public class TournamentSelection implements EvolutionaryStrategy { - private IntegerParameter tournament; + private IntegerParameter tournamentSize; - public TournamentSelection() { - tournament = new IntegerParameter(1, "Tournament size") { + public TournamentSelection(Resources resources) { + tournamentSize = new IntegerParameter(1, "Tournament size") { @Override public void validate(Number newValue) { // TODO this @@ -21,13 +21,13 @@ public class TournamentSelection implements EvolutionaryStrategy { @Override public Parameter[] getLocalParameters() { - return new Parameter[] {tournament}; + return new Parameter[] {tournamentSize}; } @Override public void evolve(Population population, Mutator mutator, Resources parameters) { - tournament.set(tournament.get() + 1); + tournamentSize.set(tournamentSize.get() + 1); // TODO implement this } diff --git a/src/jcgp/backend/modules/problem/DigitalCircuitProblem.java b/src/jcgp/backend/modules/problem/DigitalCircuitProblem.java index e92989e..3c30e4c 100644 --- a/src/jcgp/backend/modules/problem/DigitalCircuitProblem.java +++ b/src/jcgp/backend/modules/problem/DigitalCircuitProblem.java @@ -49,8 +49,8 @@ public class DigitalCircuitProblem extends TestCaseProblem { } @Override - protected int getMaxFitness() { - int maxFitness = (int) Math.pow(2.0, (double) resources.inputs()) * resources.outputs(); + protected double getMaxFitness() { + double maxFitness = Math.pow(2.0, (double) resources.inputs()) * resources.outputs(); return maxFitness; } diff --git a/src/jcgp/backend/modules/problem/TestCaseProblem.java b/src/jcgp/backend/modules/problem/TestCaseProblem.java index ff13c2e..d8dd32b 100644 --- a/src/jcgp/backend/modules/problem/TestCaseProblem.java +++ b/src/jcgp/backend/modules/problem/TestCaseProblem.java @@ -1,13 +1,11 @@ package jcgp.backend.modules.problem; -import java.io.File; import java.util.List; import javafx.collections.FXCollections; import javafx.collections.ObservableList; -import jcgp.backend.parser.TestCaseParser; import jcgp.backend.resources.Resources; -import jcgp.backend.resources.parameters.IntegerParameter; +import jcgp.backend.resources.parameters.DoubleParameter; import jcgp.backend.resources.parameters.Parameter; /** @@ -49,43 +47,21 @@ public abstract class TestCaseProblem extends Problem { } protected ObservableList> testCases; - protected IntegerParameter maxFitness; + protected DoubleParameter maxFitness; protected Resources resources; - protected TestCaseParser parser; - public TestCaseProblem(Resources resources) { super(); this.resources = resources; - maxFitness = new IntegerParameter(0, "Max fitness", true, false) { + maxFitness = new DoubleParameter(0, "Max fitness", true, false) { @Override public void validate(Number newValue) { // blank } }; testCases = FXCollections.observableArrayList(); - - parser = new TestCaseParser(this); - } - - public TestCaseProblem(Resources resources, File testCase) { - super(); - - this.resources = resources; - - maxFitness = new IntegerParameter(0, "Max fitness", true, false) { - @Override - public void validate(Number newValue) { - // blank - } - }; - testCases = FXCollections.observableArrayList(); - - parser = new TestCaseParser(this); - - parser.parse(testCase); } @Override @@ -93,7 +69,7 @@ public abstract class TestCaseProblem extends Problem { return new Parameter[]{maxFitness}; } - protected int getMaxFitness() { + protected double getMaxFitness() { int fitness = 0; for (TestCase tc : testCases) { @@ -115,7 +91,7 @@ public abstract class TestCaseProblem extends Problem { public abstract void addTestCase(String[] inputs, String[] outputs); - public void addTestCase(TestCase testCase) { + protected final void addTestCase(TestCase testCase) { if (testCase.getInputs().length != resources.inputs()) { throw new IllegalArgumentException("Received test case with " + testCase.getInputs().length + " inputs but need exactly " + resources.inputs()); @@ -128,11 +104,6 @@ public abstract class TestCaseProblem extends Problem { } } - public void removeTestCase(TestCase testCase) { - testCases.remove(testCase); - maxFitness.set(getMaxFitness()); - } - public int getInputCount() { return resources.inputs(); } @@ -141,10 +112,6 @@ public abstract class TestCaseProblem extends Problem { return resources.outputs(); } - public void parse(File file) { - parser.parse(file); - } - public void clearTestCases() { testCases.clear(); } diff --git a/src/jcgp/backend/parsers/ChromosomeParser.java b/src/jcgp/backend/parsers/ChromosomeParser.java new file mode 100644 index 0000000..fe58ff8 --- /dev/null +++ b/src/jcgp/backend/parsers/ChromosomeParser.java @@ -0,0 +1,189 @@ +package jcgp.backend.parsers; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.PrintWriter; +import java.util.Scanner; + +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; + +/** + * This class includes a method for parsing .chr files and another + * for writing .chr files from given chromosomes. + * + * @author Eduardo Pedroni + * + */ +public abstract class ChromosomeParser { + + /** + * Use this method to parse .chr files into a given chromosome. + *

+ * This is not fully defensive as it doesn't check for number of inputs, + * doesn't compare rows and columns individually and doesn't account for levels back. It + * is not viable to implement these defensive measures with the chromosome format used + * by CGP. + * + * @param file the .chr file to parse from + * @param chromosome the chromosome to configure + * @param resources the experiment resources + */ + public static void parse(File file, Chromosome chromosome, ModifiableResources resources) { + /* + * Count the nodes to make sure the size of the .chr file matches the experiment parameters. + * + * We do this by using the scanner to get the node and output portions of the file as they + * are separated by 3 tab characters. Every number is replaced by a single known character, + * and the length of the string with the new characters is compared with that of a string + * where the new known character has been removed, yielding the total number of values. + * + * TODO this is NOT ideal and should be refactored + * + */ + FileReader fr; + try { + fr = new FileReader(file); + } catch (FileNotFoundException e) { + resources.println("[Parser] Error: could not find " + file.getAbsolutePath() + "."); + return; + } + Scanner in = new Scanner(fr); + + in.useDelimiter("\\t\\t\\t"); + String geneString = in.next().replaceAll("[0-9]+", "g"); + String outString = in.next().replaceAll("[0-9]+", "o"); + int geneCount = geneString.length() - geneString.replace("g", "").length(); + int outCount = outString.length() - outString.replace("o", "").length(); + in.close(); + + + // if the acquired values match the current parameters, apply them to the chromosome + if ((geneCount == resources.nodes() * (resources.arity() + 1)) + && outCount == resources.outputs()) { + // prepare a new scanner + try { + fr = new FileReader(file); + } catch (FileNotFoundException e) { + resources.println("[Parser] Error: could not find " + file.getAbsolutePath() + "."); + return; + } + in = new Scanner(fr); + + resources.println("[Parser] Parsing file: " + file.getAbsolutePath() + "..."); + + int gene; + Connection newConnection; + Node changingNode; + // for all nodes, columns first + for (int c = 0; c < resources.columns(); c++) { + for (int r = 0; r < resources.rows(); r++) { + // store the changing node + changingNode = chromosome.getNode(r, c); + + // for every connection + for (int i = 0; i < resources.arity(); i++) { + // get connection number from the .chr file + gene = in.nextInt(); + if (gene < resources.inputs()) { + // connection was an input + newConnection = chromosome.getInput(gene); + } else { + // connection was another node, calculate which from its number + newConnection = chromosome.getNode((gene - resources.inputs()) % resources.rows(), + (gene - resources.inputs()) / resources.rows()); + } + changingNode.setConnection(i, newConnection); + } + + // set the function, straight indexing should work - this is not entirely + // safe, but it is not viable to check for functionset compatibility + changingNode.setFunction(resources.getFunction(in.nextInt())); + } + } + + // outputs + for (int o = 0; o < resources.outputs(); o ++) { + gene = in.nextInt(); + if (gene < resources.inputs()) { + // connection was an input + newConnection = chromosome.getInput(gene); + } else { + // connection was another node, calculate which from its number + newConnection = chromosome.getNode((gene - resources.inputs()) % resources.rows(), + (gene - resources.inputs()) / resources.rows()); + } + chromosome.getOutput(o).setConnection(0, newConnection); + } + in.close(); + + resources.println("[Parser] File parsed successfully."); + + } else { + resources.println("[Parser] Error: the topology of the chromosome in " + file.getName() + " does not match that of the experiment."); + } + } + + /** + * Writes a chromosome into the specified .chr file. + *

+ * The file is written in the standard .chr format and can + * be read by the original CGP implementation. + * + * @param file the file to write to + * @param chromosome the chromosome to save + */ + public static void save(File file, Chromosome chromosome, ModifiableResources resources) { + PrintWriter writer; + try { + writer = new PrintWriter(file); + } catch (FileNotFoundException e) { + resources.println("[Parser] Error: could not find " + file.getAbsolutePath() + "."); + return; + } + + resources.println("[Parser] Saving to " + file.getAbsolutePath() + "..."); + + // for all nodes, columns first + for (int c = 0; c < resources.columns(); c++) { + for (int r = 0; r < resources.rows(); r++) { + for (int i = 0; i < resources.arity(); i++) { + // print the connections, separated by spaces + Connection conn = chromosome.getNode(r, c).getConnection(i); + if (conn instanceof Input) { + writer.print(" " + ((Input) conn).getIndex()); + } else if (conn instanceof Node) { + writer.print(" " + (((((Node) conn).getColumn() + 1) * resources.inputs()) + ((Node) conn).getRow())); + } else { + resources.println("[Parser] Error: could not handle " + conn.getClass() + " as a subclass of Connection"); + } + } + // print the function numbers + writer.print(" " + resources.getFunctionIndex(chromosome.getNode(r, c).getFunction())); + // node is done, print tab + writer.print("\t"); + } + } + // nodes are done, print two tabs to separate from output + writer.print("\t\t"); + for (int o = 0; o < resources.outputs(); o ++) { + Connection source = chromosome.getOutput(o).getSource(); + if (source instanceof Input) { + writer.print(" " + ((Input) source).getIndex()); + } else if (source instanceof Node) { + writer.print(" " + (((((Node) source).getColumn() + 1) * resources.inputs()) + ((Node) source).getRow())); + } else { + resources.println("[Parser] Error: could not handle " + source.getClass() + " as a subclass of Connection"); + } + } + + writer.close(); + + resources.println("[Parser] Chromosome saved successfully."); + } + +} diff --git a/src/jcgp/backend/parsers/FunctionParser.java b/src/jcgp/backend/parsers/FunctionParser.java new file mode 100644 index 0000000..6d6c73b --- /dev/null +++ b/src/jcgp/backend/parsers/FunctionParser.java @@ -0,0 +1,53 @@ +package jcgp.backend.parsers; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.util.Scanner; + +import jcgp.backend.function.FunctionSet; +import jcgp.backend.modules.problem.Problem; +import jcgp.backend.resources.ModifiableResources; + +/** + * Parses the functions from a .par file. + * Functions marked with a 1 will be enabled, + * and those marked with 0 are disabled. + * + * @author Eduardo Pedroni + * + */ +public abstract class FunctionParser { + + public static void parseFunctions(File file, Problem problem, ModifiableResources resources) { + + FileReader fr; + try { + fr = new FileReader(file); + } catch (FileNotFoundException e) { + resources.println("[Parser] Error: could not find " + file.getAbsolutePath() + "."); + return; + } + + Scanner in = new Scanner(fr); + FunctionSet functionSet = problem.getFunctionSet(); + resources.println("[Parser] Parsing file: " + file.getAbsolutePath() + "..."); + + while (in.hasNextLine()) { + String line = in.nextLine(); + if (line.substring(line.length() - 1).matches("[0-9]")) { + String[] splitString = line.split("[^0-9]+"); + int functionIndex = Integer.parseInt(splitString[splitString.length - 1]); + if (Integer.parseInt(splitString[0]) != 0 && !functionSet.isEnabled(functionSet.getFunction(functionIndex))) { + functionSet.enableFunction(functionIndex); + resources.println("[Parser] Enabled function: " + functionSet.getFunction(functionIndex).getName() + "."); + } else if (Integer.parseInt(splitString[0]) == 0 && functionSet.isEnabled(functionSet.getFunction(functionIndex))) { + functionSet.disableFunction(functionIndex); + resources.println("[Parser] Disabled function: " + functionSet.getFunction(functionIndex).getName() + "."); + } + } + } + in.close(); + resources.println("[Parser] Finished parsing functions."); + } +} diff --git a/src/jcgp/backend/parsers/ParameterParser.java b/src/jcgp/backend/parsers/ParameterParser.java new file mode 100644 index 0000000..ae72126 --- /dev/null +++ b/src/jcgp/backend/parsers/ParameterParser.java @@ -0,0 +1,77 @@ +package jcgp.backend.parsers; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.util.Scanner; + +import jcgp.backend.resources.ModifiableResources; + +public abstract class ParameterParser { + + public static void parseParameters(File file, ModifiableResources resources) { + + FileReader fr; + try { + fr = new FileReader(file); + } catch (FileNotFoundException e) { + resources.println("[Parser] Error: could not find " + file.getAbsolutePath() + "."); + return; + } + + Scanner in = new Scanner(fr); + resources.println("[Parser] Parsing file: " + file.getAbsolutePath() + "..."); + + while (in.hasNextLine()) { + String[] splitString = in.nextLine().split("( |\t)+"); + + switch (splitString[1]) { + case "population_size": + resources.setPopulationSize(Integer.parseInt(splitString[0])); + resources.println("[Parser] Population size is now " + resources.populationSize() + "."); + break; + + case "num_generations": + resources.setGenerations(Integer.parseInt(splitString[0])); + resources.println("[Parser] Total generations is now " + resources.generations() + "."); + break; + + case "num_runs_total": + resources.setRuns(Integer.parseInt(splitString[0])); + resources.println("[Parser] Total runs is now " + resources.runs() + "."); + break; + + case "num_rows": + resources.setRows(Integer.parseInt(splitString[0])); + resources.println("[Parser] Row number is now " + resources.rows() + "."); + break; + + case "num_cols": + resources.setColumns(Integer.parseInt(splitString[0])); + resources.println("[Parser] Column number is now " + resources.columns() + "."); + break; + + case "levels_back": + resources.setLevelsBack(Integer.parseInt(splitString[0])); + resources.println("[Parser] Levels back is now " + resources.levelsBack() + "."); + break; + + case "report_interval": + resources.setReportInterval(Integer.parseInt(splitString[0])); + resources.println("[Parser] Report interval is now " + resources.levelsBack() + "."); + break; + + case "global_seed": + resources.setSeed(Integer.parseInt(splitString[0])); + resources.println("[Parser] Seed is now " + resources.seed() + "."); + break; + + default: + break; + } + } + + in.close(); + resources.println("[Parser] Finished parsing parameters."); + } +} diff --git a/src/jcgp/backend/parsers/TestCaseParser.java b/src/jcgp/backend/parsers/TestCaseParser.java new file mode 100644 index 0000000..cef018e --- /dev/null +++ b/src/jcgp/backend/parsers/TestCaseParser.java @@ -0,0 +1,90 @@ +package jcgp.backend.parsers; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.util.Scanner; + +import jcgp.backend.modules.problem.TestCaseProblem; +import jcgp.backend.resources.ModifiableResources; + +public abstract class TestCaseParser { + + public static void parse(File file, TestCaseProblem problem, ModifiableResources resources) { + FileReader fr; + try { + fr = new FileReader(file); + } catch (FileNotFoundException e) { + resources.println("[Parser] Error: could not find " + file.getAbsolutePath() + "."); + return; + } + resources.println("[Parser] Parsing file: " + file.getAbsolutePath() + "..."); + Scanner in = new Scanner(fr); + boolean readingTestCases = false; + int inputs = 0, outputs = 0; + int cases = 0; + + problem.clearTestCases(); + + while (in.hasNextLine()) { + String nextLine = in.nextLine(); + + if (nextLine.startsWith(".i")) { + String[] split = nextLine.split(" +"); + inputs = Integer.parseInt(split[1]); + } else if (nextLine.startsWith(".o")) { + String[] split = nextLine.split(" +"); + outputs = Integer.parseInt(split[1]); + } else if (nextLine.startsWith(".p") || nextLine.startsWith(".t")) { + readingTestCases = true; + } else if (nextLine.startsWith(".e")) { + readingTestCases = false; + } else if (readingTestCases) { + String[] split = nextLine.split("( |\t)+"); + String[] inputCases = new String[inputs]; + String[] outputCases = new String[outputs]; + for (int i = 0; i < inputs; i++) { + inputCases[i] = split[i]; + } + for (int o = 0; o < outputs; o++) { + outputCases[o] = split[o + inputs]; + } + + problem.addTestCase(inputCases, outputCases); + cases++; + } + } + resources.println("[Parser] Finished, added " + cases + " test cases."); + in.close(); + } + + public static void parseParameters(File file, ModifiableResources resources) { + + FileReader fr; + try { + fr = new FileReader(file); + } catch (FileNotFoundException e) { + resources.println("[Parser] Error: could not find " + file.getAbsolutePath() + "."); + return; + } + + resources.println("[Parser] Parsing parameters..."); + Scanner in = new Scanner(fr); + + while (in.hasNextLine()) { + String nextLine = in.nextLine(); + if (nextLine.startsWith(".i")) { + String[] split = nextLine.split(" +"); + resources.setInputs(Integer.parseInt(split[1])); + resources.println("[Parser] Number of inputs set to " + resources.inputs()); + } else if (nextLine.startsWith(".o")) { + String[] split = nextLine.split(" +"); + resources.setOutputs(Integer.parseInt(split[1])); + resources.println("[Parser] Number of outputs set to " + resources.outputs()); + } + } + in.close(); + + resources.println("[Parser] Finished parsing parameters."); + } +} diff --git a/src/jcgp/backend/population/Node.java b/src/jcgp/backend/population/Node.java index b716ff8..1ac5b10 100644 --- a/src/jcgp/backend/population/Node.java +++ b/src/jcgp/backend/population/Node.java @@ -36,6 +36,9 @@ public class Node extends Gene implements MutableElement, Connection { connections[index] = newConnection; chromosome.recomputeActiveNodes(); } + } else if (newConnection instanceof Input) { + connections[index] = newConnection; + chromosome.recomputeActiveNodes(); } } diff --git a/src/jcgp/backend/resources/ModifiableResources.java b/src/jcgp/backend/resources/ModifiableResources.java index 3841963..048e460 100644 --- a/src/jcgp/backend/resources/ModifiableResources.java +++ b/src/jcgp/backend/resources/ModifiableResources.java @@ -216,6 +216,7 @@ public class ModifiableResources extends Resources { /* * Console functionality + * These are not affected by parameter report interval */ public void println(String s) { System.out.println(s); @@ -223,7 +224,7 @@ public class ModifiableResources extends Resources { console.println(s); } } - + public void print(String s) { System.out.print(s); if (console != null) { diff --git a/src/jcgp/backend/resources/Resources.java b/src/jcgp/backend/resources/Resources.java index 6eb75cd..e83680f 100644 --- a/src/jcgp/backend/resources/Resources.java +++ b/src/jcgp/backend/resources/Resources.java @@ -332,7 +332,7 @@ public class Resources { /* * Console functionality - * These are affected by parameter report + * These are affected by parameter report interval */ public void reportln(String s) { if (reportInterval.get() > 0) { diff --git a/src/jcgp/gui/settings/parameters/GUIDoubleParameter.java b/src/jcgp/gui/settings/parameters/GUIDoubleParameter.java index 5331364..f177ffa 100644 --- a/src/jcgp/gui/settings/parameters/GUIDoubleParameter.java +++ b/src/jcgp/gui/settings/parameters/GUIDoubleParameter.java @@ -32,13 +32,13 @@ public class GUIDoubleParameter extends GUIParameter { */ GUIDoubleParameter(Parameter parameter, SettingsPane sp) { super(parameter, sp); - decimalFormat = new DecimalFormat(); - decimalFormat.setMaximumFractionDigits(10); } @Override protected Control makeControl() { - textField = new TextField(String.valueOf(parameter.get())); + decimalFormat = new DecimalFormat(); + decimalFormat.setMaximumFractionDigits(10); + textField = new TextField(decimalFormat.format(parameter.get().doubleValue())); textField.setStyle(VALID_PARAMETER_STYLE); textField.setAlignment(Pos.CENTER_RIGHT); textField.prefWidthProperty().bind(widthProperty().divide(2)); @@ -100,6 +100,8 @@ public class GUIDoubleParameter extends GUIParameter { @Override public void refreshValue() { - textField.setText(decimalFormat.format(parameter.get().doubleValue())); + if (!textField.isFocused()) { + textField.setText(decimalFormat.format(parameter.get().doubleValue())); + } } } diff --git a/src/jcgp/gui/settings/parameters/GUIIntegerParameter.java b/src/jcgp/gui/settings/parameters/GUIIntegerParameter.java index ee266f3..e1b0b75 100644 --- a/src/jcgp/gui/settings/parameters/GUIIntegerParameter.java +++ b/src/jcgp/gui/settings/parameters/GUIIntegerParameter.java @@ -97,6 +97,8 @@ public class GUIIntegerParameter extends GUIParameter { @Override public void refreshValue() { - textField.setText(String.valueOf(parameter.get())); + if (!textField.isFocused()) { + textField.setText(String.valueOf(parameter.get())); + } } } diff --git a/src/jcgp/gui/settings/parameters/GUIParameter.java b/src/jcgp/gui/settings/parameters/GUIParameter.java index c6ac2e6..79762ff 100644 --- a/src/jcgp/gui/settings/parameters/GUIParameter.java +++ b/src/jcgp/gui/settings/parameters/GUIParameter.java @@ -141,7 +141,7 @@ public abstract class GUIParameter extends HBox { ObservableValue observable, Object oldValue, Object newValue) { // only do this if the experiment is running - if (settingsPane.isExperimentRunning()) { + if (settingsPane.isExperimentRunning() || !isFocused()) { /* here's the catch - atomically get the lock state and set it to true * the lock will only be false again when the runnable is finished executing, * preventing multiple runnables to concurrently update the same GUIParameter -- cgit v1.2.3