From 88314e71f908efcfc38da3b800319c171a6ccceb Mon Sep 17 00:00:00 2001 From: Eduardo Pedroni Date: Fri, 18 Apr 2014 09:08:41 +0100 Subject: Added parsers, did a bit of testing, switched to java8 --- src/cgp0.chr | 1 + src/jcgp/JCGP.java | 70 ++- src/jcgp/backend/function/BitwiseLogic.java | 337 +++++++++--- src/jcgp/backend/function/DoubleArithmetic.java | 589 +++++++++++++++++++++ src/jcgp/backend/function/FunctionSet.java | 1 + src/jcgp/backend/function/IntegerArithmetic.java | 122 ----- .../modules/problem/SymbolicRegression.java | 12 +- src/jcgp/backend/parser/ChromosomeParser.java | 131 +++++ src/jcgp/backend/parser/FunctionParser.java | 58 ++ src/jcgp/backend/parser/ParameterParser.java | 76 +++ src/jcgp/backend/parser/TestCaseParser.java | 13 + src/jcgp/backend/population/Population.java | 1 - .../backend/resources/ModifiableResources.java | 14 +- src/jcgp/backend/resources/Resources.java | 18 +- src/jcgp/backend/tests/ChromosomeTests.java | 4 +- src/jcgp/backend/tests/NodeTests.java | 8 +- src/jcgp/backend/tests/OutputTests.java | 4 +- src/jcgp/backend/tests/PopulationTests.java | 4 +- src/jcgp/gui/GUI.java | 21 +- src/jcgp/gui/population/PopulationPane.java | 6 +- src/jcgp/gui/settings/SettingsPane.java | 59 ++- src/jcgp/gui/settings/parameters/GUIParameter.java | 2 +- src/parameters.par | 32 ++ 23 files changed, 1321 insertions(+), 262 deletions(-) create mode 100644 src/cgp0.chr create mode 100644 src/jcgp/backend/function/DoubleArithmetic.java delete mode 100644 src/jcgp/backend/function/IntegerArithmetic.java create mode 100644 src/jcgp/backend/parser/ChromosomeParser.java create mode 100644 src/jcgp/backend/parser/FunctionParser.java create mode 100644 src/jcgp/backend/parser/ParameterParser.java create mode 100644 src/jcgp/backend/parser/TestCaseParser.java create mode 100644 src/parameters.par diff --git a/src/cgp0.chr b/src/cgp0.chr new file mode 100644 index 0000000..3157c03 --- /dev/null +++ b/src/cgp0.chr @@ -0,0 +1 @@ + 1 2 7 1 2 6 2 2 7 3 2 7 2 0 7 3 0 7 0 1 7 7 1 10 6 0 7 10 11 7 2 11 7 0 11 6 13 0 7 13 12 10 14 1 7 16 \ No newline at end of file diff --git a/src/jcgp/JCGP.java b/src/jcgp/JCGP.java index e124dbf..1e847fb 100644 --- a/src/jcgp/JCGP.java +++ b/src/jcgp/JCGP.java @@ -1,5 +1,7 @@ package jcgp; +import java.io.File; + import jcgp.backend.modules.es.EvolutionaryStrategy; import jcgp.backend.modules.es.MuPlusLambda; import jcgp.backend.modules.es.TournamentSelection; @@ -8,6 +10,11 @@ import jcgp.backend.modules.mutator.PointMutator; import jcgp.backend.modules.problem.DigitalCircuit; import jcgp.backend.modules.problem.Problem; import jcgp.backend.modules.problem.SymbolicRegression; +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.population.Population; import jcgp.backend.resources.Console; import jcgp.backend.resources.ModifiableResources; @@ -16,13 +23,13 @@ import jcgp.backend.resources.Resources; /** * * Top-level CGP class. This class is the entry point for a CGP experiment. - *

+ *
* 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(), + * experiment can be reset with reset(), TODO comment * * * @author Eduardo Pedroni @@ -48,7 +55,7 @@ public class JCGP { // evolutionary algorithms private EvolutionaryStrategy[] evolutionaryStrategies = new EvolutionaryStrategy[] { new MuPlusLambda(resources), - new TournamentSelection()}; + new TournamentSelection() }; private EvolutionaryStrategy evolutionaryStrategy; // problem types @@ -63,6 +70,26 @@ public class JCGP { private Population population; private boolean finished = false; + /** + * TODO comment this! + * + * @param args + */ + public static void main(String... args) { + if (args.length < 1) { + System.err.println("JCGP requires at least a .par file."); + System.exit(1); + } + JCGP jcgp = new JCGP(); + jcgp.loadParameters(new File(args[0])); + + if (jcgp.getProblem() instanceof TestCaseProblem) { + TestCaseParser.parse(new File(args[2]), (TestCaseProblem) jcgp.getProblem()); + } + + jcgp.start(); + } + public JCGP() { setEvolutionaryStrategy(0); setMutator(0); @@ -154,7 +181,7 @@ public class JCGP { public void nextGeneration() { if (!finished) { problem.evaluate(population, (Resources) resources); - report(); + reportGeneration(); if (resources.currentGeneration() < resources.generations()) { // we still have generations left to go @@ -200,24 +227,20 @@ public class JCGP { } - private void report() { - if (resources.report() > 0) { - if (resources.currentGeneration() % resources.report() == 0) { - resources.println("[CGP] Generation: " + resources.currentGeneration() + ", fitness: " + population.getFittest().getFitness()); + private void reportGeneration() { + if (resources.reportInterval() > 0) { + if (resources.currentGeneration() % resources.reportInterval() == 0) { + resources.println("[CGP] Generation: " + resources.currentGeneration()); } } } public void start() { if (!finished) { - while (resources.currentGeneration() <= resources.generations()) { + while (!finished) { nextGeneration(); - if (finished) { - break; - } } } - } public void reset() { @@ -228,6 +251,26 @@ public class JCGP { resources.println("-----------------------------"); resources.println("New experiment: " + problem.toString()); } + + public void loadParameters(File file) { + ParameterParser.parseParameters(file, resources); + FunctionParser.parseFunctions(file, problem); + reset(); + } + + public void loadTestCases(File file) { + if (problem instanceof TestCaseProblem) { + TestCaseParser.parse(file, (TestCaseProblem) problem); + } + } + + public void loadChromosome(File file) { + ChromosomeParser.parse(file, population.getChromosome(0), resources); + } + + public void saveChromosome(File file, int chromosomeIndex) { + ChromosomeParser.save(file, population.getChromosome(chromosomeIndex)); + } public boolean isFinished() { return finished; @@ -236,5 +279,4 @@ public class JCGP { public void setConsole(Console console) { resources.setConsole(console); } - } diff --git a/src/jcgp/backend/function/BitwiseLogic.java b/src/jcgp/backend/function/BitwiseLogic.java index 5d47ff7..14f4488 100644 --- a/src/jcgp/backend/function/BitwiseLogic.java +++ b/src/jcgp/backend/function/BitwiseLogic.java @@ -1,6 +1,5 @@ package jcgp.backend.function; -import jcgp.backend.exceptions.InvalidArgumentsException; import jcgp.backend.population.Connection; public class BitwiseLogic extends FunctionSet { @@ -8,26 +7,155 @@ public class BitwiseLogic extends FunctionSet { public BitwiseLogic() { name = "32-bit Logic"; functionList = new Function[]{ + new ConstantZero(), + new ConstantOne(), + new WireA(), + new WireB(), + new NotA(), + new NotB(), new And(), - new Or(), - new Not(), - new Xor(), - new Nand(), + new AndNotA(), + new AndNotB(), new Nor(), - new Xnor()}; + new Xor(), + new Xnor(), + new Or(), + new OrNotA(), + new OrNotB(), + new Nand()}; + + // TODO muxes enableAll(); } + + public static class ConstantZero extends Function { + @Override + public Long run(Connection... connections) { + return new Long(0); + } + + @Override + public int getArity() { + return 0; + } + + @Override + public String getName() { + return "0"; + } + } + + public static class ConstantOne extends Function { + @Override + public Long run(Connection... connections) { + return new Long(Long.MAX_VALUE); + } + + @Override + public int getArity() { + return 0; + } + + @Override + public String getName() { + return "1"; + } + } + + public static class WireA extends Function { + @Override + public Long run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + return ((Long) connections[0].getValue()).longValue(); + } + } + + @Override + public int getArity() { + return 2; + } + + @Override + public String getName() { + return "Wire A"; + } + } + + public static class WireB extends Function { + @Override + public Long run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + return ((Long) connections[1].getValue()).longValue(); + } + } + + @Override + public int getArity() { + return 2; + } + + @Override + public String getName() { + return "Wire B"; + } + } + + public static class NotA extends Function { + @Override + public Long run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + return ~((Long) connections[0].getValue()).longValue(); + } + } + + @Override + public int getArity() { + return 2; + } + + @Override + public String getName() { + return "Not A"; + } + } + + public static class NotB extends Function { + @Override + public Long run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + return ~((Long) connections[1].getValue()).longValue(); + } + } + + @Override + public int getArity() { + return 2; + } + @Override + public String getName() { + return "Not B"; + } + } + public static class And extends Function { @Override - public Object run(Connection... connections) { - if (connections.length < 2) { - throw new InvalidArgumentsException("Not enough connections were given."); + public Long run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); } else { - int arg1 = ((int) connections[0].getValue()); - int arg2 = ((int) connections[1].getValue()); - int result = arg1 & arg2; + Long arg1 = ((Long) connections[0].getValue()); + Long arg2 = ((Long) connections[1].getValue()); + Long result = arg1 & arg2; return result; } @@ -40,20 +168,20 @@ public class BitwiseLogic extends FunctionSet { @Override public String getName() { - return "AND"; + return "And"; } } - public static class Or extends Function { + public static class AndNotA extends Function { @Override - public Object run(Connection... connections) { - if (connections.length < 2) { - throw new InvalidArgumentsException("Not enough connections were given."); + public Long run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); } else { - int arg1 = ((int) connections[0].getValue()); - int arg2 = ((int) connections[1].getValue()); - int result = arg1 | arg2; - + Long arg1 = ((Long) connections[0].getValue()); + Long arg2 = ((Long) connections[1].getValue()); + Long result = ~arg1 & arg2; + return result; } } @@ -65,43 +193,69 @@ public class BitwiseLogic extends FunctionSet { @Override public String getName() { - return "OR"; + return "And !A"; } } - - public static class Not extends Function { + + public static class AndNotB extends Function { @Override - public Object run(Connection... connections) { - if (connections.length < 1) { - throw new InvalidArgumentsException("Not enough connections were given."); + public Long run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); } else { - int arg1 = ((int) connections[0].getValue()); - int result = ~arg1; - + Long arg1 = ((Long) connections[0].getValue()); + Long arg2 = ((Long) connections[1].getValue()); + Long result = arg1 & ~arg2; + return result; } } @Override public int getArity() { - return 1; + return 2; } @Override public String getName() { - return "NOT"; + return "And !B"; } } + + public static class Nor extends Function { + @Override + public Long run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + Long arg1 = ((Long) connections[0].getValue()); + Long arg2 = ((Long) connections[1].getValue()); + Long result = arg1 | arg2; + return ~result; + } + } + + @Override + public int getArity() { + return 2; + } + + @Override + public String getName() { + return "Nor"; + } + } + public static class Xor extends Function { @Override - public Object run(Connection... connections) { - if (connections.length < 2) { - throw new InvalidArgumentsException("Not enough connections were given."); + public Long run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); } else { - int arg1 = ((int) connections[0].getValue()); - int arg2 = ((int) connections[1].getValue()); - int result = arg1 ^ arg2; + Long arg1 = ((Long) connections[0].getValue()); + Long arg2 = ((Long) connections[1].getValue()); + Long result = arg1 ^ arg2; return result; } @@ -114,19 +268,19 @@ public class BitwiseLogic extends FunctionSet { @Override public String getName() { - return "XOR"; + return "Xor"; } } - - public static class Nand extends Function { + + public static class Xnor extends Function { @Override - public Object run(Connection... connections) { - if (connections.length < 2) { - throw new InvalidArgumentsException("Not enough connections were given."); + public Long run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); } else { - int arg1 = ((int) connections[0].getValue()); - int arg2 = ((int) connections[1].getValue()); - int result = arg1 & arg2; + Long arg1 = ((Long) connections[0].getValue()); + Long arg2 = ((Long) connections[1].getValue()); + Long result = arg1 ^ arg2; return ~result; } @@ -139,21 +293,71 @@ public class BitwiseLogic extends FunctionSet { @Override public String getName() { - return "NAND"; + return "Xnor"; } } + + public static class Or extends Function { + @Override + public Long run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + Long arg1 = ((Long) connections[0].getValue()); + Long arg2 = ((Long) connections[1].getValue()); + Long result = arg1 | arg2; - public static class Nor extends Function { + return result; + } + } + + @Override + public int getArity() { + return 2; + } + + @Override + public String getName() { + return "Or"; + } + } + + public static class OrNotA extends Function { @Override - public Object run(Connection... connections) { - if (connections.length < 2) { - throw new InvalidArgumentsException("Not enough connections were given."); + public Long run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); } else { - int arg1 = ((int) connections[0].getValue()); - int arg2 = ((int) connections[1].getValue()); - int result = arg1 | arg2; + Long arg1 = ((Long) connections[0].getValue()); + Long arg2 = ((Long) connections[1].getValue()); + Long result = ~arg1 | arg2; - return ~result; + return result; + } + } + + @Override + public int getArity() { + return 2; + } + + @Override + public String getName() { + return "Or !A"; + } + } + + public static class OrNotB extends Function { + @Override + public Long run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + Long arg1 = ((Long) connections[0].getValue()); + Long arg2 = ((Long) connections[1].getValue()); + Long result = arg1 | ~arg2; + + return result; } } @@ -164,19 +368,19 @@ public class BitwiseLogic extends FunctionSet { @Override public String getName() { - return "NOR"; + return "Or !B"; } } - public static class Xnor extends Function { + public static class Nand extends Function { @Override - public Object run(Connection... connections) { - if (connections.length < 2) { - throw new InvalidArgumentsException("Not enough connections were given."); + public Long run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); } else { - int arg1 = ((int) connections[0].getValue()); - int arg2 = ((int) connections[1].getValue()); - int result = arg1 ^ arg2; + Long arg1 = ((Long) connections[0].getValue()); + Long arg2 = ((Long) connections[1].getValue()); + Long result = arg1 & arg2; return ~result; } @@ -189,10 +393,7 @@ public class BitwiseLogic extends FunctionSet { @Override public String getName() { - return "XNOR"; + return "Nand"; } } - - - } diff --git a/src/jcgp/backend/function/DoubleArithmetic.java b/src/jcgp/backend/function/DoubleArithmetic.java new file mode 100644 index 0000000..ce4826f --- /dev/null +++ b/src/jcgp/backend/function/DoubleArithmetic.java @@ -0,0 +1,589 @@ +package jcgp.backend.function; + +import jcgp.backend.population.Connection; + +public class DoubleArithmetic extends FunctionSet { + + public final static double DIVISION_LIMIT = 0.0001; + + public DoubleArithmetic() { + name = "Double Arithmetic"; + functionList = new Function[]{ + new Absolute(), + new SquareRoot(), + new Reciprocal(), + new Sine(), + new Cosine(), + new Tangent(), + new Exponential(), + new HyperbolicSine(), + new HyperbolicCosine(), + new HyperbolicTangent(), + new NaturalLog(), + new LogBaseTen(), + new SineAB(), + new CosineAB(), + new Hypotenuse(), + new Power(), + new Addition(), + new Subtraction(), + new Multiplication(), + new Division()}; + + enableAll(); + } + + /** + * Absolute returns the positive value of input 0. + * + * @see Math.abs() + */ + public static class Absolute extends Function { + @Override + public Double run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + Double in0 = ((Double) connections[0].getValue()); + return Math.abs(in0); + } + } + + @Override + public int getArity() { + return 1; + } + + @Override + public String getName() { + return "Absolute"; + } + } + + /** + * Protected square root function, returns the square root of the absolute + * value of input 0. + * + * @see Math.abs(), Math.sqrt() + */ + public static class SquareRoot extends Function { + @Override + public Double run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + Double in0 = ((Double) connections[0].getValue()); + return Math.sqrt(Math.abs(in0)); + } + } + + @Override + public int getArity() { + return 1; + } + + @Override + public String getName() { + return "Square root"; + } + } + + /** + * Protected reciprocal function, returns (1 / input 0). If input 0 is less than + * {@link DoubleArithmetic.}DIVISION_LIMIT, this returns it unchanged. + * + */ + public static class Reciprocal extends Function { + @Override + public Double run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + Double in0 = ((Double) connections[0].getValue()); + return in0 < DIVISION_LIMIT ? in0 : (1 / in0); + } + } + + @Override + public int getArity() { + return 1; + } + + @Override + public String getName() { + return "Reciprocal"; + } + } + + /** + * Sine function, in radians. + * + * @see Math.sin() + */ + public static class Sine extends Function { + @Override + public Double run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + Double in0 = ((Double) connections[0].getValue()); + return Math.sin(in0); + } + } + + @Override + public int getArity() { + return 1; + } + + @Override + public String getName() { + return "Sin"; + } + } + + /** + * Cosine function, in radians. + * + * @see Math.cos() + */ + public static class Cosine extends Function { + @Override + public Double run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + Double in0 = ((Double) connections[0].getValue()); + return Math.cos(in0); + } + } + + @Override + public int getArity() { + return 1; + } + + @Override + public String getName() { + return "Cos"; + } + } + + /** + * Protected tangent function, in radians. Returns the tangent of input 0. + * If input 0 is less than {@link DoubleArithmetic.}DIVISION_LIMIT, + * this returns it unchanged. + * + * @see Math.tan() + */ + public static class Tangent extends Function { + @Override + public Double run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + Double in0 = ((Double) connections[0].getValue()); + return in0 < DIVISION_LIMIT ? in0 : Math.tan(in0); + } + } + + @Override + public int getArity() { + return 1; + } + + @Override + public String getName() { + return "Tan"; + } + } + + /** + * Exponential function. Returns the exponential of input 0. + * + * @see Math.exp() + */ + public static class Exponential extends Function { + @Override + public Double run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + Double in0 = ((Double) connections[0].getValue()); + return Math.exp(in0); + } + } + + @Override + public int getArity() { + return 1; + } + + @Override + public String getName() { + return "Exp"; + } + } + + /** + * Returns the hyperbolic sine of input 0. + * + * @see Math.sinh() + */ + public static class HyperbolicSine extends Function { + @Override + public Double run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + Double in0 = ((Double) connections[0].getValue()); + return Math.sinh(in0); + } + } + + @Override + public int getArity() { + return 1; + } + + @Override + public String getName() { + return "Sinh"; + } + } + + /** + * Returns the hyperbolic cosine of input 0. + * + * @see Math.cosh() + */ + public static class HyperbolicCosine extends Function { + @Override + public Double run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + Double in0 = ((Double) connections[0].getValue()); + return Math.cosh(in0); + } + } + + @Override + public int getArity() { + return 1; + } + + @Override + public String getName() { + return "Cosh"; + } + } + + /** + * Returns the hyperbolic tangent of input 0. + * + * @see Math.tanh() + */ + public static class HyperbolicTangent extends Function { + @Override + public Double run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + Double in0 = ((Double) connections[0].getValue()); + return Math.tanh(in0); + } + } + + @Override + public int getArity() { + return 1; + } + + @Override + public String getName() { + return "Tanh"; + } + } + + /** + * Protected natural log function. Returns the natural log of the absolute + * value of input 0. If input 0 is less than {@link DoubleArithmetic.}DIVISION_LIMIT, + * this returns it unchanged. + * + * @see Math.log(), Math.abs() + */ + public static class NaturalLog extends Function { + @Override + public Double run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + Double in0 = ((Double) connections[0].getValue()); + return in0 < DIVISION_LIMIT ? in0 : Math.log(Math.abs(in0)); + } + } + + @Override + public int getArity() { + return 1; + } + + @Override + public String getName() { + return "Ln"; + } + } + + /** + * Protected log base 10 function. Returns the log to base 10 the absolute + * value of input 0. If input 0 is less than {@link DoubleArithmetic.}DIVISION_LIMIT, + * this returns it unchanged. + * + * @see Math.log10(), Math.abs() + */ + public static class LogBaseTen extends Function { + @Override + public Double run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + Double in0 = ((Double) connections[0].getValue()); + return in0 < DIVISION_LIMIT ? in0 : Math.log10(Math.abs(in0)); + } + } + + @Override + public int getArity() { + return 1; + } + + @Override + public String getName() { + return "Log"; + } + } + + /** + * Sine of sum. Returns the sine of the sum of inputs 0 and 1. + * + * @see Math.sin() + */ + public static class SineAB extends Function { + @Override + public Double run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + Double in0 = ((Double) connections[0].getValue()); + Double in1 = ((Double) connections[1].getValue()); + return Math.sin(in0 + in1); + } + } + + @Override + public int getArity() { + return 2; + } + + @Override + public String getName() { + return "Sin(a+b)"; + } + } + + /** + * Cosine of sum. Returns the cosine of the sum of inputs 0 and 1. + * + * @see Math.cos() + */ + public static class CosineAB extends Function { + @Override + public Double run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + Double in0 = ((Double) connections[0].getValue()); + Double in1 = ((Double) connections[1].getValue()); + return Math.cos(in0 + in1); + } + } + + @Override + public int getArity() { + return 2; + } + + @Override + public String getName() { + return "Cos(a+b)"; + } + } + + /** + * Hypotenuse function. Returns the square root of input 0 squared + * plus input 1 squared. + * + * @see Math.hypot() + */ + public static class Hypotenuse extends Function { + @Override + public Double run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + Double in0 = ((Double) connections[0].getValue()); + Double in1 = ((Double) connections[1].getValue()); + return Math.hypot(in0, in1); + } + } + + @Override + public int getArity() { + return 2; + } + + @Override + public String getName() { + return "Hypotenuse"; + } + } + + /** + * Power function. Returns the absolute value of input 0 to the power of input 1. + * + * @see Math.abs(), Math.pow + */ + public static class Power extends Function { + @Override + public Double run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + Double in0 = ((Double) connections[0].getValue()); + Double in1 = ((Double) connections[1].getValue()); + return Math.pow(Math.abs(in0), in1); + } + } + + @Override + public int getArity() { + return 2; + } + + @Override + public String getName() { + return "Power"; + } + } + + /** + * Addition returns the sum of inputs 0 and 1. + * + */ + public static class Addition extends Function { + @Override + public Double run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + Double in0 = ((Double) connections[0].getValue()); + Double in1 = ((Double) connections[1].getValue()); + return in0 + in1; + } + } + + @Override + public int getArity() { + return 2; + } + + @Override + public String getName() { + return "Addition"; + } + } + + /** + * Subtraction returns the difference between inputs 0 and 1. + * + */ + public static class Subtraction extends Function { + @Override + public Double run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + Double in0 = ((Double) connections[0].getValue()); + Double in1 = ((Double) connections[1].getValue()); + return in0 - in1; + } + } + + @Override + public int getArity() { + return 2; + } + + @Override + public String getName() { + return "Subtraction"; + } + } + + /** + * Multiplication returns the product of inputs 0 and 1. + * + */ + public static class Multiplication extends Function { + @Override + public Double run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + Double in0 = ((Double) connections[0].getValue()); + Double in1 = ((Double) connections[1].getValue()); + return in0 * in1; + } + } + + @Override + public int getArity() { + return 2; + } + + @Override + public String getName() { + return "Multiplication"; + } + } + + /** + * Protected division, returns the quotient of input 0 (the dividend) and input 1 (the divisor). + * If the divisor is less than {@link DoubleArithmetic.}DIVISION_LIMIT, this returns the it unchanged. + * + */ + public static class Division extends Function { + @Override + public Double run(Connection... connections) { + if (connections.length < getArity()) { + throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); + } else { + Double in0 = ((Double) connections[0].getValue()); + Double in1 = ((Double) connections[1].getValue()); + + return in1 < DIVISION_LIMIT ? in0 : (in0 / in1); + } + } + + @Override + public int getArity() { + return 2; + } + + @Override + public String getName() { + return "Division"; + } + } +} diff --git a/src/jcgp/backend/function/FunctionSet.java b/src/jcgp/backend/function/FunctionSet.java index 78801fc..1712b51 100644 --- a/src/jcgp/backend/function/FunctionSet.java +++ b/src/jcgp/backend/function/FunctionSet.java @@ -51,6 +51,7 @@ public abstract class FunctionSet { int function = iterator.next(); if (function == index) { iterator.remove(); + break; } } } else { diff --git a/src/jcgp/backend/function/IntegerArithmetic.java b/src/jcgp/backend/function/IntegerArithmetic.java deleted file mode 100644 index 9bb02b5..0000000 --- a/src/jcgp/backend/function/IntegerArithmetic.java +++ /dev/null @@ -1,122 +0,0 @@ -package jcgp.backend.function; - -import jcgp.backend.population.Connection; - -public class IntegerArithmetic extends FunctionSet { - - public IntegerArithmetic() { - name = "Integer Arithmetic"; - functionList = new Function[]{ - new Addition(), - new Subtraction(), - new Multiplication(), - new Division()}; - - enableAll(); - } - - public static class Addition extends Function { - @Override - public Integer run(Connection... connections) { - if (connections.length < 2) { - throw new IllegalArgumentException("Not enough connections were given."); - } else { - Integer arg1 = ((Integer) connections[0].getValue()); - Integer arg2 = ((Integer) connections[1].getValue()); - Integer result = arg1 + arg2; - - return result; - } - } - - @Override - public int getArity() { - return 2; - } - - @Override - public String getName() { - return "Addition"; - } - } - - public static class Subtraction extends Function { - @Override - public Integer run(Connection... connections) { - if (connections.length < 2) { - throw new IllegalArgumentException("Not enough connections were given."); - } else { - Integer arg1 = ((Integer) connections[0].getValue()); - Integer arg2 = ((Integer) connections[1].getValue()); - Integer result = arg1 - arg2; - - return result; - } - } - - @Override - public int getArity() { - return 2; - } - - @Override - public String getName() { - return "Subtraction"; - } - } - - public static class Multiplication extends Function { - @Override - public Integer run(Connection... connections) { - if (connections.length < 2) { - throw new IllegalArgumentException("Not enough connections were given."); - } else { - Integer arg1 = ((Integer) connections[0].getValue()); - Integer arg2 = ((Integer) connections[1].getValue()); - Integer result = arg1 * arg2; - return result; - } - } - - @Override - public int getArity() { - return 2; - } - - @Override - public String getName() { - return "Multiplication"; - } - } - - public static class Division extends Function { - @Override - public Integer run(Connection... connections) { - if (connections.length < 2) { - throw new IllegalArgumentException("Not enough connections were given."); - } else { - Integer arg1 = ((Integer) connections[0].getValue()); - Integer arg2 = ((Integer) connections[1].getValue()); - Integer result; - if (arg2 == 0) { - result = 0; - } else { - result = arg1 / arg2; - } - - return result; - } - } - - @Override - public int getArity() { - return 2; - } - - @Override - public String getName() { - return "Division"; - } - } - -} diff --git a/src/jcgp/backend/modules/problem/SymbolicRegression.java b/src/jcgp/backend/modules/problem/SymbolicRegression.java index c92d183..46b8e09 100644 --- a/src/jcgp/backend/modules/problem/SymbolicRegression.java +++ b/src/jcgp/backend/modules/problem/SymbolicRegression.java @@ -2,18 +2,18 @@ package jcgp.backend.modules.problem; import java.util.ArrayList; -import jcgp.backend.function.IntegerArithmetic; +import jcgp.backend.function.DoubleArithmetic; import jcgp.backend.resources.Resources; -public class SymbolicRegression extends TestCaseProblem { +public class SymbolicRegression extends TestCaseProblem { public SymbolicRegression(Resources resources) { super(resources); - functionSet = new IntegerArithmetic(); + functionSet = new DoubleArithmetic(); - ArrayList> tc = new ArrayList>(); - tc.add(new TestCase(new Integer[]{1, 2, 3}, new Integer[]{-4, 5, 6})); - tc.add(new TestCase(new Integer[]{3, 2, 5}, new Integer[]{2, 5, 9})); + ArrayList> tc = new ArrayList>(); + tc.add(new TestCase(new Double[]{1.0, 2.0, 3.0}, new Double[]{-4.0, 5.0, 6.0})); + tc.add(new TestCase(new Double[]{3.0, 2.0, 5.0}, new Double[]{2.0, 5.0, 9.0})); setTestCases(tc); } diff --git a/src/jcgp/backend/parser/ChromosomeParser.java b/src/jcgp/backend/parser/ChromosomeParser.java new file mode 100644 index 0000000..74f638c --- /dev/null +++ b/src/jcgp/backend/parser/ChromosomeParser.java @@ -0,0 +1,131 @@ +package jcgp.backend.parser; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.util.Scanner; + +import jcgp.backend.population.Chromosome; +import jcgp.backend.population.Connection; +import jcgp.backend.population.Node; +import jcgp.backend.resources.Resources; + +/** + * This class includes a method for parsing .chr files and another + * for writing .chr files from given chromosomes. + * + * @author Eduardo Pedroni + * + */ +public 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, Resources 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. + * + */ + FileReader fr; + try { + fr = new FileReader(file); + } catch (FileNotFoundException e) { + e.printStackTrace(); + 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) { + e.printStackTrace(); + return; + } + in = new Scanner(fr); + + 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(); + } + } + + /** + * Writes a chromosome into the specified .chr file. + * + * + * + * @param file + * @param chromosome + */ + public static void save(File file, Chromosome chromosome) { + + } + +} diff --git a/src/jcgp/backend/parser/FunctionParser.java b/src/jcgp/backend/parser/FunctionParser.java new file mode 100644 index 0000000..64a095c --- /dev/null +++ b/src/jcgp/backend/parser/FunctionParser.java @@ -0,0 +1,58 @@ +package jcgp.backend.parser; + +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; + +public class FunctionParser { + +private FunctionSet functionSet; + + private FunctionParser(Problem problem) { + this.functionSet = problem.getFunctionSet(); + } + + public static void parseFunctions(File file, Problem problem) { + FunctionParser pp = new FunctionParser(problem); + + FileReader fr; + try { + fr = new FileReader(file); + } catch (FileNotFoundException e) { + e.printStackTrace(); + return; + } + + Scanner in = new Scanner(fr); + + while (in.hasNextLine()) { + String line = in.nextLine(); + if (line.substring(line.length() - 1).matches("[0-9]")) { + pp.parseAndSet(line.split("[^0-9]+")); + } + } + + in.close(); + } + + private void parseAndSet(String[] splitString) { +// System.out.println("new line"); +// for (int i= 0; i < splitString.length; i++) { +// System.out.println(i + ": " + splitString[i]); +// } + int functionIndex = Integer.parseInt(splitString[splitString.length - 1]); + System.out.println("index: " + functionIndex); + if (Integer.parseInt(splitString[0]) != 0) { + System.out.println("enabling: " + functionSet.getFunction(functionIndex).getName()); + functionSet.enableFunction(functionIndex); + } else { + System.out.println("disabling: " + functionSet.getFunction(functionIndex).getName()); + functionSet.disableFunction(functionIndex); + } + + } +} diff --git a/src/jcgp/backend/parser/ParameterParser.java b/src/jcgp/backend/parser/ParameterParser.java new file mode 100644 index 0000000..473b632 --- /dev/null +++ b/src/jcgp/backend/parser/ParameterParser.java @@ -0,0 +1,76 @@ +package jcgp.backend.parser; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.util.Scanner; +import jcgp.backend.resources.ModifiableResources; + +public class ParameterParser { + + private ModifiableResources resources; + + private ParameterParser(ModifiableResources resources) { + this.resources = resources; + } + + public static void parseParameters(File file, ModifiableResources resources) { + ParameterParser pp = new ParameterParser(resources); + + FileReader fr; + try { + fr = new FileReader(file); + } catch (FileNotFoundException e) { + e.printStackTrace(); + return; + } + + Scanner in = new Scanner(fr); + + while (in.hasNextLine()) { + pp.parseAndSet(in.nextLine().split("( |\t)+")); + } + + in.close(); + } + + private void parseAndSet(String[] splitString) { + switch (splitString[1]) { + + case "population_size": + resources.setPopulationSize(Integer.parseInt(splitString[0])); + break; + + case "num_generations": + resources.setGenerations(Integer.parseInt(splitString[0])); + break; + + case "num_runs_total": + resources.setRuns(Integer.parseInt(splitString[0])); + break; + + case "num_rows": + resources.setRows(Integer.parseInt(splitString[0])); + break; + + case "num_cols": + resources.setColumns(Integer.parseInt(splitString[0])); + break; + + case "levels_back": + resources.setLevelsBack(Integer.parseInt(splitString[0])); + break; + + case "report_interval": + resources.setReportInterval(Integer.parseInt(splitString[0])); + break; + + case "global_seed": + resources.setSeed(Integer.parseInt(splitString[0])); + break; + + default: + break; + } + } +} diff --git a/src/jcgp/backend/parser/TestCaseParser.java b/src/jcgp/backend/parser/TestCaseParser.java new file mode 100644 index 0000000..c997177 --- /dev/null +++ b/src/jcgp/backend/parser/TestCaseParser.java @@ -0,0 +1,13 @@ +package jcgp.backend.parser; + +import java.io.File; + +import jcgp.backend.modules.problem.TestCaseProblem; + +public class TestCaseParser { + + public static void parse(File file, TestCaseProblem problem) { + + } + +} diff --git a/src/jcgp/backend/population/Population.java b/src/jcgp/backend/population/Population.java index a850595..1bbdc54 100644 --- a/src/jcgp/backend/population/Population.java +++ b/src/jcgp/backend/population/Population.java @@ -98,5 +98,4 @@ public class Population { public int getFittestIndex() { return fittest; } - } diff --git a/src/jcgp/backend/resources/ModifiableResources.java b/src/jcgp/backend/resources/ModifiableResources.java index 689f846..3841963 100644 --- a/src/jcgp/backend/resources/ModifiableResources.java +++ b/src/jcgp/backend/resources/ModifiableResources.java @@ -19,6 +19,10 @@ public class ModifiableResources extends Resources { super(); } + public void setValues(String filePath) { + + } + /** * @param rows the rows to set */ @@ -106,8 +110,8 @@ public class ModifiableResources extends Resources { /** * @param report the report to set */ - public void setReport(int report) { - this.report.set(report); + public void setReportInterval(int report) { + this.reportInterval.set(report); } /** @@ -197,10 +201,10 @@ public class ModifiableResources extends Resources { /** * @return the report */ - public IntegerParameter getReportParameter() { - return report; + public IntegerParameter getReportIntervalParameter() { + return reportInterval; } - + public void setFunctionSet(FunctionSet functionSet) { this.functionSet = functionSet; setArity(functionSet.getMaxArity()); diff --git a/src/jcgp/backend/resources/Resources.java b/src/jcgp/backend/resources/Resources.java index c83fa35..0bf1ee1 100644 --- a/src/jcgp/backend/resources/Resources.java +++ b/src/jcgp/backend/resources/Resources.java @@ -21,7 +21,7 @@ import jcgp.backend.resources.parameters.ParameterStatus; public class Resources { protected IntegerParameter rows, columns, inputs, outputs, populationSize, levelsBack, currentGeneration, generations, currentRun, runs, - arity, seed, report; + arity, seed, reportInterval; protected Random numberGenerator = new Random(); protected FunctionSet functionSet; @@ -124,10 +124,10 @@ public class Resources { } /** - * @return the report + * @return the report interval */ - public int report() { - return report.get(); + public int reportInterval() { + return reportInterval.get(); } private void createBaseParameters() { @@ -273,7 +273,7 @@ public class Resources { }); numberGenerator.setSeed(seed.get()); - report = new IntegerParameter(1, "Report", false, false) { + reportInterval = new IntegerParameter(1, "Report interval", false, false) { @Override public void validate(Number newValue) { if (newValue.intValue() > generations.get()) { @@ -325,8 +325,8 @@ public class Resources { * These are affected by parameter report */ public void reportln(String s) { - if (report.get() > 0) { - if (currentGeneration.get() % report.get() == 0) { + if (reportInterval.get() > 0) { + if (currentGeneration.get() % reportInterval.get() == 0) { System.out.println(s); if (console != null) { console.println(s); @@ -336,8 +336,8 @@ public class Resources { } public void report(String s) { - if (report.get() > 0) { - if (currentGeneration.get() % report.get() == 0) { + if (reportInterval.get() > 0) { + if (currentGeneration.get() % reportInterval.get() == 0) { System.out.print(s); if (console != null) { console.print(s); diff --git a/src/jcgp/backend/tests/ChromosomeTests.java b/src/jcgp/backend/tests/ChromosomeTests.java index 07326a7..36278ba 100644 --- a/src/jcgp/backend/tests/ChromosomeTests.java +++ b/src/jcgp/backend/tests/ChromosomeTests.java @@ -2,7 +2,7 @@ package jcgp.backend.tests; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import jcgp.backend.function.IntegerArithmetic; +import jcgp.backend.function.DoubleArithmetic; import jcgp.backend.population.Chromosome; import jcgp.backend.population.Connection; import jcgp.backend.population.Input; @@ -46,7 +46,7 @@ public class ChromosomeTests { @BeforeClass public static void setUpBeforeClass() { resources = new ModifiableResources(); - resources.setFunctionSet(new IntegerArithmetic()); + resources.setFunctionSet(new DoubleArithmetic()); } @Before diff --git a/src/jcgp/backend/tests/NodeTests.java b/src/jcgp/backend/tests/NodeTests.java index 0e08d92..c9f247a 100644 --- a/src/jcgp/backend/tests/NodeTests.java +++ b/src/jcgp/backend/tests/NodeTests.java @@ -3,7 +3,7 @@ package jcgp.backend.tests; import static org.junit.Assert.assertTrue; import jcgp.backend.exceptions.InvalidArgumentsException; import jcgp.backend.function.Function; -import jcgp.backend.function.IntegerArithmetic; +import jcgp.backend.function.DoubleArithmetic; import jcgp.backend.population.Chromosome; import jcgp.backend.population.Connection; import jcgp.backend.population.Node; @@ -41,7 +41,7 @@ public class NodeTests { public static void setUpBeforeClass() { resources = new ModifiableResources(); - resources.setFunctionSet(new IntegerArithmetic()); + resources.setFunctionSet(new DoubleArithmetic()); chromosome = new Chromosome(resources); } @@ -49,7 +49,7 @@ public class NodeTests { public void setUp() throws Exception { node = new Node(chromosome, 0, 0, resources.arity()); // make node with anonymous addition function and hard-coded value connections - node.initialise(new IntegerArithmetic.Addition(), + node.initialise(new DoubleArithmetic.Addition(), new Connection[]{new Connection() { @Override @@ -113,7 +113,7 @@ public class NodeTests { ((int) node.getValue()) == arg1 + arg2); // put in a different function, check the output has changed appropriately - node.setFunction(new IntegerArithmetic.Subtraction()); + node.setFunction(new DoubleArithmetic.Subtraction()); assertTrue("Node did not return expected value (difference of arguments).", ((Integer) node.getValue()) == arg1 - arg2); diff --git a/src/jcgp/backend/tests/OutputTests.java b/src/jcgp/backend/tests/OutputTests.java index a331f2d..95b7fc7 100644 --- a/src/jcgp/backend/tests/OutputTests.java +++ b/src/jcgp/backend/tests/OutputTests.java @@ -1,7 +1,7 @@ package jcgp.backend.tests; import static org.junit.Assert.assertTrue; -import jcgp.backend.function.IntegerArithmetic; +import jcgp.backend.function.DoubleArithmetic; import jcgp.backend.population.Chromosome; import jcgp.backend.population.Connection; import jcgp.backend.population.Output; @@ -35,7 +35,7 @@ public class OutputTests { @BeforeClass public static void setUpBeforeClass() { resources = new ModifiableResources(); - resources.setFunctionSet(new IntegerArithmetic()); + resources.setFunctionSet(new DoubleArithmetic()); chromosome = new Chromosome(resources); } diff --git a/src/jcgp/backend/tests/PopulationTests.java b/src/jcgp/backend/tests/PopulationTests.java index fb8ced4..fca9c4f 100644 --- a/src/jcgp/backend/tests/PopulationTests.java +++ b/src/jcgp/backend/tests/PopulationTests.java @@ -1,7 +1,7 @@ package jcgp.backend.tests; import static org.junit.Assert.assertTrue; -import jcgp.backend.function.IntegerArithmetic; +import jcgp.backend.function.DoubleArithmetic; import jcgp.backend.population.Chromosome; import jcgp.backend.population.Population; import jcgp.backend.resources.ModifiableResources; @@ -32,7 +32,7 @@ public class PopulationTests { @BeforeClass public static void setUpBeforeClass() throws Exception { resources = new ModifiableResources(); - resources.setFunctionSet(new IntegerArithmetic()); + resources.setFunctionSet(new DoubleArithmetic()); } @Before diff --git a/src/jcgp/gui/GUI.java b/src/jcgp/gui/GUI.java index e7a4a23..91c72e6 100644 --- a/src/jcgp/gui/GUI.java +++ b/src/jcgp/gui/GUI.java @@ -40,6 +40,8 @@ public class GUI extends Application { private final JCGP jcgp; + private Stage stage; + private final FunctionSelector functionSelector; private PopulationPane populationPane; @@ -108,7 +110,7 @@ public class GUI extends Application { public void start(Stage primaryStage) throws Exception { console = new GUIConsole(); jcgp.setConsole(console); - + stage = primaryStage; /* * Instantiate the various GUI elements here. * @@ -181,15 +183,20 @@ public class GUI extends Application { public void reset() { if (!running && settingsPane.areParametersValid()) { + setEvaluating(false); settingsPane.applyParameters(); jcgp.reset(); - populationPane.remakeTabs(); - settingsPane.revalidateParameters(); - settingsPane.updateControls(false, jcgp.isFinished()); - console.flush(); + reDraw(); } } + public void reDraw() { + populationPane.remakeTabs(); + settingsPane.revalidateParameters(); + settingsPane.updateControls(false, jcgp.isFinished()); + console.flush(); + } + private void runningMode(boolean value) { if (value) { populationPane.unlockOutputs(); @@ -234,4 +241,8 @@ public class GUI extends Application { public void setEvaluating(boolean value) { populationPane.setEvaluating(value); } + + public Stage getStage() { + return stage; + } } diff --git a/src/jcgp/gui/population/PopulationPane.java b/src/jcgp/gui/population/PopulationPane.java index 28b0ad9..5fa6067 100644 --- a/src/jcgp/gui/population/PopulationPane.java +++ b/src/jcgp/gui/population/PopulationPane.java @@ -38,19 +38,19 @@ public class PopulationPane extends TabPane { if (evaluating) { evaluateTestCase(currentTestCase); } - for (int i = 0; i < getChildrenUnmodifiable().size(); i++) { + for (int i = 0; i < getTabs().size(); i++) { ((ChromosomePane) getTabs().get(i).getContent()).updateGenes(); } } public void unlockOutputs() { - for (int i = 0; i < getChildrenUnmodifiable().size(); i++) { + for (int i = 0; i < getTabs().size(); i++) { ((ChromosomePane) getTabs().get(i).getContent()).unlockOutputs(); } } public void relockOutputs() { - for (int i = 0; i < getChildrenUnmodifiable().size(); i++) { + for (int i = 0; i < getTabs().size(); i++) { ((ChromosomePane) getTabs().get(i).getContent()).relockOutputs(); } } diff --git a/src/jcgp/gui/settings/SettingsPane.java b/src/jcgp/gui/settings/SettingsPane.java index 2ab9650..4e8c342 100644 --- a/src/jcgp/gui/settings/SettingsPane.java +++ b/src/jcgp/gui/settings/SettingsPane.java @@ -1,5 +1,6 @@ package jcgp.gui.settings; +import java.io.File; import java.util.ArrayList; import javafx.event.ActionEvent; @@ -16,6 +17,8 @@ import javafx.scene.layout.Priority; import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.scene.text.Text; +import javafx.stage.FileChooser; +import javafx.stage.FileChooser.ExtensionFilter; import jcgp.JCGP; import jcgp.backend.function.FunctionSet; import jcgp.backend.modules.es.EvolutionaryStrategy; @@ -31,6 +34,7 @@ public class SettingsPane extends AnchorPane { private VBox mainContainer; private VBox baseParameterPane, eaPane, mutatorPane, problemPane; + private VBox nodeFunctions; private Button runPause = new Button("Run"), step = new Button("Step"), reset = new Button("Reset"); private Button loadParameters = new Button("Load parameters"), loadChromosome = new Button("Load chromosome"), saveChromosome = new Button("Save chromosome"); @@ -103,7 +107,7 @@ public class SettingsPane extends AnchorPane { parameters.add(gp); parameters.add(GUIParameter.create(jcgp.getResources().getSeedParameter(), this)); - parameters.add(GUIParameter.create(jcgp.getResources().getReportParameter(), this)); + parameters.add(GUIParameter.create(jcgp.getResources().getReportIntervalParameter(), this)); baseParameterPane.getChildren().addAll(parameters); mainContainer.getChildren().add(baseParameterPane); @@ -201,10 +205,10 @@ public class SettingsPane extends AnchorPane { testCaseTable = new TestCaseTable((TestCaseProblem) jcgp.getProblem(), gui); } - final VBox nodeFunctions = new VBox(); + nodeFunctions = new VBox(); nodeFunctions.setSpacing(2); nodeFunctions.setPadding(new Insets(0, 0, 4, 0)); - refreshFunctions(jcgp.getResources().getFunctionSet(), nodeFunctions, gui); + refreshFunctions(); problemCBox.setOnAction(new EventHandler() { @Override @@ -215,7 +219,7 @@ public class SettingsPane extends AnchorPane { } testCaseTable.close(); gui.setEvaluating(false); - refreshFunctions(jcgp.getProblem().getFunctionSet(), nodeFunctions, gui); + refreshFunctions(); showTestCaseContainer.getChildren().clear(); if (jcgp.getProblem() instanceof TestCaseProblem) { showTestCaseContainer.getChildren().add(showTestCaseButton); @@ -284,14 +288,31 @@ public class SettingsPane extends AnchorPane { loadParameters.setOnAction(new EventHandler() { @Override public void handle(ActionEvent event) { - //gui.runPause(); + FileChooser fc = new FileChooser(); + fc.setTitle("Open .par file..."); + fc.getExtensionFilters().add(new ExtensionFilter("CGP parameter files", "*.par")); + fc.getExtensionFilters().add(new ExtensionFilter("All files", "*.*")); + File parFile = fc.showOpenDialog(gui.getStage()); + if (parFile != null) { + gui.getExperiment().loadParameters(parFile); + } + gui.reDraw(); + refreshFunctions(); } }); loadChromosome.setOnAction(new EventHandler() { @Override public void handle(ActionEvent event) { - //gui.step(); + FileChooser fc = new FileChooser(); + fc.setTitle("Open .chr file..."); + fc.getExtensionFilters().add(new ExtensionFilter("CGP chromosome files", "*.chr")); + fc.getExtensionFilters().add(new ExtensionFilter("All files", "*.*")); + File chrFile = fc.showOpenDialog(gui.getStage()); + if (chrFile != null) { + gui.getExperiment().loadChromosome(chrFile); + } + gui.reDraw(); } }); saveChromosome.setOnAction(new EventHandler() { @@ -331,31 +352,28 @@ public class SettingsPane extends AnchorPane { /** * This method handles a problem type change by updating the list of allowed * node functions. - * - * @param functionSet - * @param container - * @param gui */ - private void refreshFunctions(final FunctionSet functionSet, VBox container, final GUI gui) { - container.getChildren().clear(); + private void refreshFunctions() { + nodeFunctions.getChildren().clear(); CheckBox cb; - for (int i = 0; i < functionSet.getTotalFunctionCount(); i++) { - cb = new CheckBox(functionSet.getFunction(i).getName()); + final FunctionSet fs = gui.getExperiment().getResources().getFunctionSet(); + for (int i = 0; i < fs.getTotalFunctionCount(); i++) { + cb = new CheckBox(fs.getFunction(i).getName()); cb.setId(String.valueOf(i)); - cb.setSelected(functionSet.isEnabled(functionSet.getFunction(i))); + cb.setSelected(fs.isEnabled(fs.getFunction(i))); final int index = i; cb.setOnAction(new EventHandler() { @Override public void handle(ActionEvent event) { if (((CheckBox) event.getSource()).isSelected()) { - functionSet.enableFunction(index); + fs.enableFunction(index); } else { - functionSet.disableFunction(index); + fs.disableFunction(index); } gui.updateFunctionSelector(); } }); - container.getChildren().add(cb); + nodeFunctions.getChildren().add(cb); gui.updateFunctionSelector(); } @@ -436,6 +454,11 @@ public class SettingsPane extends AnchorPane { step.setDisable(running || finished); reset.setDisable(running); + loadParameters.setDisable(running); + loadChromosome.setDisable(running); + saveChromosome.setDisable(running); + + testCaseTable.getTable().setDisable(running); } diff --git a/src/jcgp/gui/settings/parameters/GUIParameter.java b/src/jcgp/gui/settings/parameters/GUIParameter.java index a8a8c4a..159e709 100644 --- a/src/jcgp/gui/settings/parameters/GUIParameter.java +++ b/src/jcgp/gui/settings/parameters/GUIParameter.java @@ -86,7 +86,7 @@ public abstract class GUIParameter extends HBox { // the tooltip is the hover-over label containing status information, when appropriate tooltip = new Tooltip(); - tooltip.setStyle("-fx-background-color: white; -fx-border-color: black; .page-corner {-fx-background-color: transparent;}"); + tooltip.setStyle("-fx-background-color: white; -fx-border-color: black;"); tooltip.setSkin(null); valueControl = makeControl(); diff --git a/src/parameters.par b/src/parameters.par new file mode 100644 index 0000000..bf38c11 --- /dev/null +++ b/src/parameters.par @@ -0,0 +1,32 @@ +5 population_size +1.0 per_cent_mutate +10000 num_generations +10 num_runs_total +1 num_rows +100 num_cols +100 levels_back +1 progress_report +1000 report_interval +173156789 global_seed +0 run_from_chrom +0 shrink_phenotype +0 1 modulus-0 +0 1 sqrt-1 +0 1 reciprocal-2 +0 1 sin-3 +0 1 cos-4 +0 1 tan-5 +0 1 exp-6 +0 1 sinh-7 +0 1 cosh-8 +0 1 tanh-9 +0 1 nat-log-10 +0 1 logbase10-11 +0 2 sin(a+b)-12 +0 2 cos(a+b)-13 +0 2 hypoteneuse-14 +0 2 power-15 +1 2 addition-16 +1 2 subtraction-17 +1 2 multiplication-18 +1 2 division-19 \ No newline at end of file -- cgit v1.2.3