diff options
Diffstat (limited to 'src/jcgp/backend')
-rw-r--r-- | src/jcgp/backend/function/BitwiseLogic.java | 124 | ||||
-rw-r--r-- | src/jcgp/backend/function/BooleanLogic.java | 199 | ||||
-rw-r--r-- | src/jcgp/backend/function/UnsignedInteger.java | 66 | ||||
-rw-r--r-- | src/jcgp/backend/modules/mutator/PointMutator.java | 17 | ||||
-rw-r--r-- | src/jcgp/backend/modules/problem/DigitalCircuit.java | 25 | ||||
-rw-r--r-- | src/jcgp/backend/modules/problem/DigitalCircuitProblem.java | 85 | ||||
-rw-r--r-- | src/jcgp/backend/modules/problem/SymbolicRegression.java | 26 | ||||
-rw-r--r-- | src/jcgp/backend/modules/problem/SymbolicRegressionProblem.java | 124 | ||||
-rw-r--r-- | src/jcgp/backend/modules/problem/TestCaseProblem.java | 86 | ||||
-rw-r--r-- | src/jcgp/backend/parser/ChromosomeParser.java | 2 | ||||
-rw-r--r-- | src/jcgp/backend/parser/FunctionParser.java | 7 | ||||
-rw-r--r-- | src/jcgp/backend/parser/ParameterParser.java | 1 | ||||
-rw-r--r-- | src/jcgp/backend/parser/TestCaseParser.java | 79 | ||||
-rw-r--r-- | src/jcgp/backend/population/Chromosome.java | 6 | ||||
-rw-r--r-- | src/jcgp/backend/resources/Resources.java | 4 | ||||
-rw-r--r-- | src/jcgp/backend/tests/NodeTests.java | 2 |
16 files changed, 478 insertions, 375 deletions
diff --git a/src/jcgp/backend/function/BitwiseLogic.java b/src/jcgp/backend/function/BitwiseLogic.java index 14f4488..a4c2737 100644 --- a/src/jcgp/backend/function/BitwiseLogic.java +++ b/src/jcgp/backend/function/BitwiseLogic.java @@ -31,8 +31,8 @@ public class BitwiseLogic extends FunctionSet { public static class ConstantZero extends Function { @Override - public Long run(Connection... connections) { - return new Long(0); + public UnsignedInteger run(Connection... connections) { + return new UnsignedInteger(0); } @Override @@ -48,8 +48,8 @@ public class BitwiseLogic extends FunctionSet { public static class ConstantOne extends Function { @Override - public Long run(Connection... connections) { - return new Long(Long.MAX_VALUE); + public UnsignedInteger run(Connection... connections) { + return new UnsignedInteger(0xFFFF); } @Override @@ -65,11 +65,11 @@ public class BitwiseLogic extends FunctionSet { public static class WireA extends Function { @Override - public Long run(Connection... connections) { + public UnsignedInteger 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(); + return ((UnsignedInteger) connections[0].getValue()); } } @@ -86,11 +86,11 @@ public class BitwiseLogic extends FunctionSet { public static class WireB extends Function { @Override - public Long run(Connection... connections) { + public UnsignedInteger 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(); + return ((UnsignedInteger) connections[1].getValue()); } } @@ -107,11 +107,11 @@ public class BitwiseLogic extends FunctionSet { public static class NotA extends Function { @Override - public Long run(Connection... connections) { + public UnsignedInteger 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(); + return new UnsignedInteger(~((UnsignedInteger) connections[0].getValue()).get()); } } @@ -128,11 +128,11 @@ public class BitwiseLogic extends FunctionSet { public static class NotB extends Function { @Override - public Long run(Connection... connections) { + public UnsignedInteger 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(); + return new UnsignedInteger(~((UnsignedInteger) connections[1].getValue()).get()); } } @@ -149,15 +149,15 @@ public class BitwiseLogic extends FunctionSet { public static class And extends Function { @Override - public Long run(Connection... connections) { + public UnsignedInteger 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; + UnsignedInteger arg1 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger arg2 = ((UnsignedInteger) connections[1].getValue()); + Integer result = arg1.get() & arg2.get(); - return result; + return new UnsignedInteger(result); } } @@ -174,15 +174,15 @@ public class BitwiseLogic extends FunctionSet { public static class AndNotA extends Function { @Override - public Long run(Connection... connections) { + public UnsignedInteger 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; + UnsignedInteger arg1 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger arg2 = ((UnsignedInteger) connections[1].getValue()); + Integer result = ~(arg1.get()) & arg2.get(); - return result; + return new UnsignedInteger(result); } } @@ -199,15 +199,15 @@ public class BitwiseLogic extends FunctionSet { public static class AndNotB extends Function { @Override - public Long run(Connection... connections) { + public UnsignedInteger 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; + UnsignedInteger arg1 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger arg2 = ((UnsignedInteger) connections[1].getValue()); + Integer result = arg1.get() & ~(arg2.get()); - return result; + return new UnsignedInteger(result); } } @@ -224,15 +224,15 @@ public class BitwiseLogic extends FunctionSet { public static class Nor extends Function { @Override - public Long run(Connection... connections) { + public UnsignedInteger 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; + UnsignedInteger arg1 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger arg2 = ((UnsignedInteger) connections[1].getValue()); + Integer result = arg1.get() | arg2.get(); - return ~result; + return new UnsignedInteger(~result); } } @@ -249,15 +249,15 @@ public class BitwiseLogic extends FunctionSet { public static class Xor extends Function { @Override - public Long run(Connection... connections) { + public UnsignedInteger 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; + UnsignedInteger arg1 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger arg2 = ((UnsignedInteger) connections[1].getValue()); + Integer result = arg1.get() ^ arg2.get(); - return result; + return new UnsignedInteger(result); } } @@ -274,15 +274,15 @@ public class BitwiseLogic extends FunctionSet { public static class Xnor extends Function { @Override - public Long run(Connection... connections) { + public UnsignedInteger 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; + UnsignedInteger arg1 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger arg2 = ((UnsignedInteger) connections[1].getValue()); + Integer result = arg1.get() ^ arg2.get(); - return ~result; + return new UnsignedInteger(~result); } } @@ -299,15 +299,15 @@ public class BitwiseLogic extends FunctionSet { public static class Or extends Function { @Override - public Long run(Connection... connections) { + public UnsignedInteger 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; + UnsignedInteger arg1 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger arg2 = ((UnsignedInteger) connections[1].getValue()); + Integer result = arg1.get() | arg2.get(); - return result; + return new UnsignedInteger(result); } } @@ -324,15 +324,15 @@ public class BitwiseLogic extends FunctionSet { public static class OrNotA extends Function { @Override - public Long run(Connection... connections) { + public UnsignedInteger 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; + UnsignedInteger arg1 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger arg2 = ((UnsignedInteger) connections[1].getValue()); + Integer result = ~arg1.get() | arg2.get(); - return result; + return new UnsignedInteger(result); } } @@ -349,15 +349,15 @@ public class BitwiseLogic extends FunctionSet { public static class OrNotB extends Function { @Override - public Long run(Connection... connections) { + public UnsignedInteger 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; + UnsignedInteger arg1 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger arg2 = ((UnsignedInteger) connections[1].getValue()); + Integer result = arg1.get() | ~arg2.get(); - return result; + return new UnsignedInteger(result); } } @@ -374,15 +374,15 @@ public class BitwiseLogic extends FunctionSet { public static class Nand extends Function { @Override - public Long run(Connection... connections) { + public UnsignedInteger 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; + UnsignedInteger arg1 = ((UnsignedInteger) connections[0].getValue()); + UnsignedInteger arg2 = ((UnsignedInteger) connections[1].getValue()); + Integer result = arg1.get() & arg2.get(); - return ~result; + return new UnsignedInteger(~result); } } diff --git a/src/jcgp/backend/function/BooleanLogic.java b/src/jcgp/backend/function/BooleanLogic.java deleted file mode 100644 index 9e7d1ff..0000000 --- a/src/jcgp/backend/function/BooleanLogic.java +++ /dev/null @@ -1,199 +0,0 @@ -package jcgp.backend.function; - - -import jcgp.backend.exceptions.InvalidArgumentsException; -import jcgp.backend.population.Connection; - -public class BooleanLogic extends FunctionSet { - - public BooleanLogic() { - name = "1-bit Logic"; - functionList = new Function[]{ - new And(), - new Or(), - new Not(), - new Xor(), - new Nand(), - new Nor(), - new Xnor()}; - - enableAll(); - } - - public static class And extends Function { - @Override - public Boolean run(Connection... connections) { - if (connections.length < 2) { - throw new InvalidArgumentsException("Not enough connections were given."); - } else { - Boolean arg1 = ((Boolean) connections[0].getValue()); - Boolean arg2 = ((Boolean) connections[1].getValue()); - Boolean result = arg1 && arg2; - - return result; - } - } - - @Override - public int getArity() { - return 2; - } - - @Override - public String getName() { - return "AND"; - } - } - - public static class Or extends Function { - @Override - public Boolean run(Connection... connections) { - if (connections.length < 2) { - throw new InvalidArgumentsException("Not enough connections were given."); - } else { - Boolean arg1 = ((Boolean) connections[0].getValue()); - Boolean arg2 = ((Boolean) connections[1].getValue()); - Boolean result = arg1 || arg2; - - return result; - } - } - - @Override - public int getArity() { - return 2; - } - - @Override - public String getName() { - return "OR"; - } - } - - public static class Not extends Function { - @Override - public Boolean run(Connection... connections) { - if (connections.length < 1) { - throw new InvalidArgumentsException("Not enough connections were given."); - } else { - Boolean arg1 = ((Boolean) connections[0].getValue()); - Boolean result = !arg1; - - return result; - } - } - - @Override - public int getArity() { - return 1; - } - - @Override - public String getName() { - return "NOT"; - } - } - - public static class Xor extends Function { - @Override - public Boolean run(Connection... connections) { - if (connections.length < 2) { - throw new InvalidArgumentsException("Not enough connections were given."); - } else { - Boolean arg1 = ((Boolean) connections[0].getValue()); - Boolean arg2 = ((Boolean) connections[1].getValue()); - Boolean result = arg1 ^ arg2; - - return result; - } - } - - @Override - public int getArity() { - return 2; - } - - @Override - public String getName() { - return "XOR"; - } - } - - public static class Nand extends Function { - @Override - public Boolean run(Connection... connections) { - if (connections.length < 2) { - throw new InvalidArgumentsException("Not enough connections were given."); - } else { - Boolean arg1 = ((Boolean) connections[0].getValue()); - Boolean arg2 = ((Boolean) connections[1].getValue()); - Boolean result = arg1 && arg2; - - return !result; - } - } - - @Override - public int getArity() { - return 2; - } - - @Override - public String getName() { - return "NAND"; - } - } - - public static class Nor extends Function { - @Override - public Boolean run(Connection... connections) { - if (connections.length < 2) { - throw new InvalidArgumentsException("Not enough connections were given."); - } else { - Boolean arg1 = ((Boolean) connections[0].getValue()); - Boolean arg2 = ((Boolean) connections[1].getValue()); - Boolean result = arg1 || arg2; - - return !result; - } - } - - @Override - public int getArity() { - return 2; - } - - @Override - public String getName() { - return "NOR"; - } - } - - public static class Xnor extends Function { - @Override - public Boolean run(Connection... connections) { - if (connections.length < 2) { - throw new InvalidArgumentsException("Not enough connections were given."); - } else { - Boolean arg1 = ((Boolean) connections[0].getValue()); - Boolean arg2 = ((Boolean) connections[1].getValue()); - Boolean result = arg1 ^ arg2; - - return !result; - } - } - - @Override - public int getArity() { - return 2; - } - - @Override - public String getName() { - return "XNOR"; - } - } - - - -} diff --git a/src/jcgp/backend/function/UnsignedInteger.java b/src/jcgp/backend/function/UnsignedInteger.java new file mode 100644 index 0000000..7feb33f --- /dev/null +++ b/src/jcgp/backend/function/UnsignedInteger.java @@ -0,0 +1,66 @@ +package jcgp.backend.function; + +/** + * Integer wrapper type for unsigned integer values. + * <br><br> + * Java offers no support for unsigned types save from + * unsigned conversion methods. This class uses those methods + * to simulate the unsigned int data type, useful for circuit + * truth table encodings. + * <br><br> + * When a string representation of an unsigned integer is parsed + * using Integer.parseUnsignedInt(), an Integer is created using + * all 32 bits for unsigned magnitude. The integer however is still + * signed and will behave as such for all arithmetic operations. + * Bitwise operations can still be performed as they work at the bit + * level, making this data type particularly suitable for circuit design. + * + * + * @author Eduardo Pedroni + * @see Integer + * + */ +public class UnsignedInteger { + + private Integer value; + + /** + * Makes a new instance of UnsignedInteger with a specified value. + * + * @param i the value with which to initialise + */ + public UnsignedInteger(int i) { + value = new Integer(i); + } + + /** + * Makes a new instance of UnsignedInteger with a specified value. + * + * @param i the value with which to initialise + */ + public UnsignedInteger(Integer i) { + value = i; + } + + /** + * Makes a new instance of UnsignedInteger from the string representation + * of an unsigned integer. + * + * @param i the string with which to initialise + */ + public UnsignedInteger(String i) { + value = Integer.parseUnsignedInt(i); + } + + /** + * @return the wrapped Integer object + */ + public Integer get() { + return value; + } + + @Override + public String toString() { + return Integer.toUnsignedString(value); + } +} diff --git a/src/jcgp/backend/modules/mutator/PointMutator.java b/src/jcgp/backend/modules/mutator/PointMutator.java index ab8efad..44c453a 100644 --- a/src/jcgp/backend/modules/mutator/PointMutator.java +++ b/src/jcgp/backend/modules/mutator/PointMutator.java @@ -7,18 +7,21 @@ import jcgp.backend.population.Output; import jcgp.backend.resources.Resources; import jcgp.backend.resources.parameters.BooleanParameter; import jcgp.backend.resources.parameters.DoubleParameter; +import jcgp.backend.resources.parameters.IntegerParameter; import jcgp.backend.resources.parameters.Parameter; import jcgp.backend.resources.parameters.ParameterStatus; public class PointMutator implements Mutator { private DoubleParameter mutationRate; + private IntegerParameter nodesMutated; private BooleanParameter report; public PointMutator(final Resources resources) { mutationRate = new DoubleParameter(50, "Percent mutation", false, false) { @Override public void validate(Number newValue) { + nodesMutated.set((int) ((newValue.intValue()) * (((((double) resources.nodes() + resources.outputs()))) / 100))); if (newValue.doubleValue() <= 0 || newValue.doubleValue() > 100) { status = ParameterStatus.INVALID; status.setDetails("Mutation rate must be > 0 and <= 100"); @@ -30,7 +33,12 @@ public class PointMutator implements Mutator { } } }; - + nodesMutated = new IntegerParameter(0, "Genes mutated", true, false) { + @Override + public void validate(Number newValue) { + // blank + } + }; report = new BooleanParameter(false, "Report") { @Override public void validate(Boolean newValue) { @@ -41,9 +49,8 @@ public class PointMutator implements Mutator { @Override public void mutate(Chromosome chromosome, Resources resources) { - int mutations = (int) ((mutationRate.get()) * (((((double) resources.nodes() + resources.outputs()))) / 100)); - if (report.get()) resources.reportln("[Mutator] Number of mutations to be performed: " + mutations); - for (int i = 0; i < mutations; i++) { + if (report.get()) resources.reportln("[Mutator] Number of mutations to be performed: " + nodesMutated.get()); + for (int i = 0; i < nodesMutated.get(); i++) { MutableElement m = chromosome.getRandomMutableElement(); if (report.get()) resources.report("[Mutator] Mutation " + i + " selected " + m.toString() + ", "); @@ -75,7 +82,7 @@ public class PointMutator implements Mutator { @Override public Parameter<?>[] getLocalParameters() { - return new Parameter[] {mutationRate, report}; + return new Parameter[] {mutationRate, nodesMutated, report}; } @Override diff --git a/src/jcgp/backend/modules/problem/DigitalCircuit.java b/src/jcgp/backend/modules/problem/DigitalCircuit.java deleted file mode 100644 index d94197d..0000000 --- a/src/jcgp/backend/modules/problem/DigitalCircuit.java +++ /dev/null @@ -1,25 +0,0 @@ -package jcgp.backend.modules.problem; - -import java.util.ArrayList; - -import jcgp.backend.function.BitwiseLogic; -import jcgp.backend.resources.Resources; - -public class DigitalCircuit extends TestCaseProblem<Integer> { - - public DigitalCircuit(Resources resources) { - super(resources); - functionSet = new BitwiseLogic(); - - ArrayList<TestCase<Integer>> tc = new ArrayList<TestCase<Integer>>(); - tc.add(new TestCase<Integer>(new Integer[]{1, 2, 3}, new Integer[]{-4, 5, 6})); - - setTestCases(tc); - } - - @Override - public String toString() { - return "Digital circuit"; - } - -} diff --git a/src/jcgp/backend/modules/problem/DigitalCircuitProblem.java b/src/jcgp/backend/modules/problem/DigitalCircuitProblem.java new file mode 100644 index 0000000..e92989e --- /dev/null +++ b/src/jcgp/backend/modules/problem/DigitalCircuitProblem.java @@ -0,0 +1,85 @@ +package jcgp.backend.modules.problem; + +import jcgp.backend.function.BitwiseLogic; +import jcgp.backend.function.UnsignedInteger; +import jcgp.backend.population.Chromosome; +import jcgp.backend.population.Population; +import jcgp.backend.resources.Resources; + +public class DigitalCircuitProblem extends TestCaseProblem<UnsignedInteger> { + + public DigitalCircuitProblem(Resources resources) { + super(resources); + functionSet = new BitwiseLogic(); + } + + @Override + public void evaluate(Population population, Resources resources) { + // set fittest to 0, change it whenever a fitter one is found + population.setFittest(0); + + // for every chromosome in the population + for (int i = 0; i < resources.populationSize(); i++) { + // assume an initial fitness of 0 + int fitness = 0; + + // iterate over every test case + for (int t = 0; t < testCases.size(); t++) { + population.getChromosome(i).setInputs((Object[]) testCases.get(t).getInputs()); + // check each output + for (int o = 0; o < resources.outputs(); o++) { + Integer output = ((UnsignedInteger) population.getChromosome(i).getOutput(o).calculate()).get(); + Integer matches = ~(output ^ testCases.get(t).getOutput(o).get()); + // check only the relevant bits + int bits = (int) Math.pow(2.0, (double) resources.inputs()); + for (int b = 0; b < bits; b++) { + if (((matches >>> b) & 1) == 1) { + fitness++; + } + } + } + } + + // assign the resulting fitness to the respective individual + population.getChromosome(i).setFitness(fitness); + if (fitness >= population.getFittest().getFitness()) { + population.setFittest(i); + } + } + } + + @Override + protected int getMaxFitness() { + int maxFitness = (int) Math.pow(2.0, (double) resources.inputs()) * resources.outputs(); + return maxFitness; + } + + @Override + public String toString() { + return "Digital circuit"; + } + + @Override + public void addTestCase(String[] inputs, String[] outputs) { + UnsignedInteger[] inputCases = new UnsignedInteger[inputs.length]; + UnsignedInteger[] outputCases = new UnsignedInteger[outputs.length]; + for (int i = 0; i < inputCases.length; i++) { + inputCases[i] = new UnsignedInteger(inputs[i]); + } + for (int o = 0; o < outputCases.length; o++) { + outputCases[o] = new UnsignedInteger(outputs[o]); + } + + addTestCase(new TestCase<UnsignedInteger>(inputCases, outputCases)); + } + + @Override + public boolean isPerfectSolution(Chromosome fittest) { + return fittest.getFitness() >= maxFitness.get(); + } + + @Override + public String getFileExtension() { + return ".plu"; + } +} diff --git a/src/jcgp/backend/modules/problem/SymbolicRegression.java b/src/jcgp/backend/modules/problem/SymbolicRegression.java deleted file mode 100644 index 46b8e09..0000000 --- a/src/jcgp/backend/modules/problem/SymbolicRegression.java +++ /dev/null @@ -1,26 +0,0 @@ -package jcgp.backend.modules.problem; - -import java.util.ArrayList; - -import jcgp.backend.function.DoubleArithmetic; -import jcgp.backend.resources.Resources; - -public class SymbolicRegression extends TestCaseProblem<Double> { - - public SymbolicRegression(Resources resources) { - super(resources); - functionSet = new DoubleArithmetic(); - - ArrayList<TestCase<Double>> tc = new ArrayList<TestCase<Double>>(); - tc.add(new TestCase<Double>(new Double[]{1.0, 2.0, 3.0}, new Double[]{-4.0, 5.0, 6.0})); - tc.add(new TestCase<Double>(new Double[]{3.0, 2.0, 5.0}, new Double[]{2.0, 5.0, 9.0})); - - setTestCases(tc); - } - - @Override - public String toString() { - return "Symbolic regression"; - } - -} diff --git a/src/jcgp/backend/modules/problem/SymbolicRegressionProblem.java b/src/jcgp/backend/modules/problem/SymbolicRegressionProblem.java new file mode 100644 index 0000000..52df0f2 --- /dev/null +++ b/src/jcgp/backend/modules/problem/SymbolicRegressionProblem.java @@ -0,0 +1,124 @@ +package jcgp.backend.modules.problem; + +import jcgp.backend.function.DoubleArithmetic; +import jcgp.backend.population.Chromosome; +import jcgp.backend.population.Population; +import jcgp.backend.resources.Resources; +import jcgp.backend.resources.parameters.BooleanParameter; +import jcgp.backend.resources.parameters.DoubleParameter; +import jcgp.backend.resources.parameters.Parameter; +import jcgp.backend.resources.parameters.ParameterStatus; + +public class SymbolicRegressionProblem extends TestCaseProblem<Double> { + + private DoubleParameter errorThreshold, perfectionThreshold; + private BooleanParameter hitsBasedFitness; + + public SymbolicRegressionProblem(Resources resources) { + super(resources); + functionSet = new DoubleArithmetic(); + errorThreshold = new DoubleParameter(0.01, "Error threshold") { + @Override + public void validate(Number newValue) { + if (newValue.doubleValue() < 0) { + status = ParameterStatus.INVALID; + status.setDetails("Error threshold must be a positive value."); + } else if (newValue.doubleValue() == 0) { + status = ParameterStatus.WARNING; + status.setDetails("An error threshold of 0 is very rigorous and difficult to achieve."); + } else { + status = ParameterStatus.VALID; + } + } + }; + perfectionThreshold = new DoubleParameter(0.000001, "Perfection threshold") { + @Override + public void validate(Number newValue) { + if (newValue.doubleValue() < 0) { + status = ParameterStatus.INVALID; + status.setDetails("Perfection threshold must be a positive value."); + } else if (newValue.doubleValue() == 0) { + status = ParameterStatus.WARNING; + status.setDetails("A perfection threshold of 0 is very rigorous and difficult to achieve."); + } else { + status = ParameterStatus.VALID; + } + } + }; + hitsBasedFitness = new BooleanParameter(true, "Hits-based fitness") { + @Override + public void validate(Boolean newValue) { + // blank + } + }; + } + + @Override + public void evaluate(Population population, Resources resources) { + // set fittest to 0, change it whenever a fitter one is found + population.setFittest(0); + + // for every chromosome in the population + for (int i = 0; i < resources.populationSize(); i++) { + // assume an initial fitness of 0 + double fitness = 0; + // for each test case + for (int t = 0; t < testCases.size(); t++) { + population.getChromosome(i).setInputs((Object[]) testCases.get(t).getInputs()); + // check each output + for (int o = 0; o < resources.outputs(); o++) { + Double cgpValue = (Double) population.getChromosome(i).getOutput(o).calculate(); + Double dataValue = testCases.get(t).getOutput(o); + if (hitsBasedFitness.get()) { + if (Math.abs(cgpValue - dataValue) <= errorThreshold.get()) { + fitness++; + } + } else { + fitness += 1 - Math.abs(cgpValue - dataValue); + } + + } + } + // assign the resulting fitness to the respective individual + population.getChromosome(i).setFitness(fitness); + if (fitness >= population.getFittest().getFitness()) { + population.setFittest(i); + } + } + } + + + @Override + public String toString() { + return "Symbolic regression"; + } + + @Override + public void addTestCase(String[] inputs, String[] outputs) { + Double[] inputCases = new Double[inputs.length]; + Double[] outputCases = new Double[outputs.length]; + for (int i = 0; i < inputCases.length; i++) { + inputCases[i] = Double.parseDouble(inputs[i]); + } + for (int o = 0; o < outputCases.length; o++) { + outputCases[o] = Double.parseDouble(outputs[o]); + } + + addTestCase(new TestCase<Double>(inputCases, outputCases)); + } + + @Override + public boolean isPerfectSolution(Chromosome fittest) { + return fittest.getFitness() >= maxFitness.get() - perfectionThreshold.get(); + } + + @Override + public Parameter<?>[] getLocalParameters() { + return new Parameter[]{maxFitness, errorThreshold, perfectionThreshold, hitsBasedFitness}; + } + + @Override + public String getFileExtension() { + return ".dat"; + } +} diff --git a/src/jcgp/backend/modules/problem/TestCaseProblem.java b/src/jcgp/backend/modules/problem/TestCaseProblem.java index ee72860..ff13c2e 100644 --- a/src/jcgp/backend/modules/problem/TestCaseProblem.java +++ b/src/jcgp/backend/modules/problem/TestCaseProblem.java @@ -1,11 +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.population.Chromosome; -import jcgp.backend.population.Population; +import jcgp.backend.parser.TestCaseParser; import jcgp.backend.resources.Resources; import jcgp.backend.resources.parameters.IntegerParameter; import jcgp.backend.resources.parameters.Parameter; @@ -48,15 +48,16 @@ public abstract class TestCaseProblem<U extends Object> extends Problem { } } - private ObservableList<TestCase<U>> testCases; - private IntegerParameter maxFitness; - private final int inputCount, outputCount; + protected ObservableList<TestCase<U>> testCases; + protected IntegerParameter maxFitness; + protected Resources resources; + + protected TestCaseParser parser; public TestCaseProblem(Resources resources) { super(); - inputCount = resources.inputs(); - outputCount = resources.outputs(); + this.resources = resources; maxFitness = new IntegerParameter(0, "Max fitness", true, false) { @Override @@ -65,34 +66,26 @@ public abstract class TestCaseProblem<U extends Object> extends Problem { } }; testCases = FXCollections.observableArrayList(); + + parser = new TestCaseParser(this); } - - @Override - public void evaluate(Population population, Resources resources) { - // set fittest to 0, change it whenever a fitter one is found - population.setFittest(0); + public TestCaseProblem(Resources resources, File testCase) { + super(); - // for every chromosome in the population - for (int i = 0; i < resources.populationSize(); i++) { - // assume an initial fitness of 0 - int fitness = 0; - // for each test case - for (int t = 0; t < testCases.size(); t++) { - population.getChromosome(i).setInputs(testCases.get(t).getInputs()); - // check each output - for (int o = 0; o < resources.outputs(); o++) { - if (population.getChromosome(i).getOutput(o).calculate() == testCases.get(t).getOutput(o)) { - fitness++; - } - } - } - // assign the resulting fitness to the respective individual - population.getChromosome(i).setFitness(fitness); - if (fitness >= population.getFittest().getFitness()) { - population.setFittest(i); + 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 @@ -100,12 +93,7 @@ public abstract class TestCaseProblem<U extends Object> extends Problem { return new Parameter[]{maxFitness}; } - @Override - public boolean isPerfectSolution(Chromosome fittest) { - return fittest.getFitness() >= maxFitness.get(); - } - - private int getMaxFitness() { + protected int getMaxFitness() { int fitness = 0; for (TestCase<U> tc : testCases) { @@ -125,13 +113,15 @@ public abstract class TestCaseProblem<U extends Object> extends Problem { return testCases; } + public abstract void addTestCase(String[] inputs, String[] outputs); + public void addTestCase(TestCase<U> testCase) { - if (testCase.getInputs().length != inputCount) { + if (testCase.getInputs().length != resources.inputs()) { throw new IllegalArgumentException("Received test case with " + testCase.getInputs().length + - "inputs but need exactly " + inputCount); - } else if (testCase.getOutputs().length != outputCount) { + " inputs but need exactly " + resources.inputs()); + } else if (testCase.getOutputs().length != resources.outputs()) { throw new IllegalArgumentException("Received test case with " + testCase.getOutputs().length + - "outputs but need exactly " + outputCount); + " outputs but need exactly " + resources.outputs()); } else { this.testCases.add(testCase); maxFitness.set(getMaxFitness()); @@ -144,12 +134,22 @@ public abstract class TestCaseProblem<U extends Object> extends Problem { } public int getInputCount() { - return inputCount; + return resources.inputs(); } public int getOutputCount() { - return outputCount; + return resources.outputs(); + } + + public void parse(File file) { + parser.parse(file); } + + public void clearTestCases() { + testCases.clear(); + } + + public abstract String getFileExtension(); } diff --git a/src/jcgp/backend/parser/ChromosomeParser.java b/src/jcgp/backend/parser/ChromosomeParser.java index 74f638c..d5af1bd 100644 --- a/src/jcgp/backend/parser/ChromosomeParser.java +++ b/src/jcgp/backend/parser/ChromosomeParser.java @@ -17,7 +17,7 @@ import jcgp.backend.resources.Resources; * @author Eduardo Pedroni * */ -public class ChromosomeParser { +public abstract class ChromosomeParser { /** * Use this method to parse .chr files into a given chromosome. diff --git a/src/jcgp/backend/parser/FunctionParser.java b/src/jcgp/backend/parser/FunctionParser.java index 64a095c..ab94899 100644 --- a/src/jcgp/backend/parser/FunctionParser.java +++ b/src/jcgp/backend/parser/FunctionParser.java @@ -40,17 +40,10 @@ private FunctionSet functionSet; } 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 index 473b632..f96ebf9 100644 --- a/src/jcgp/backend/parser/ParameterParser.java +++ b/src/jcgp/backend/parser/ParameterParser.java @@ -4,6 +4,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.util.Scanner; + import jcgp.backend.resources.ModifiableResources; public class ParameterParser { diff --git a/src/jcgp/backend/parser/TestCaseParser.java b/src/jcgp/backend/parser/TestCaseParser.java index c997177..d47d663 100644 --- a/src/jcgp/backend/parser/TestCaseParser.java +++ b/src/jcgp/backend/parser/TestCaseParser.java @@ -1,13 +1,90 @@ package jcgp.backend.parser; 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 class TestCaseParser { - public static void parse(File file, TestCaseProblem<?> problem) { + private TestCaseProblem<?> problem; + + public TestCaseParser(TestCaseProblem<?> problem) { + this.problem = problem; + } + + public void parse(File file) { + FileReader fr; + try { + fr = new FileReader(file); + } catch (FileNotFoundException e) { + e.printStackTrace(); + return; + } + + Scanner in = new Scanner(fr); + boolean readingTestCases = false; + int inputs = 0, outputs = 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; + // set test cases? not safe probably + } 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); + } + } + in.close(); } + public static void parseParameters(File file, ModifiableResources resources) { + + FileReader fr; + try { + fr = new FileReader(file); + } catch (FileNotFoundException e) { + e.printStackTrace(); + return; + } + + 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])); + } else if (nextLine.startsWith(".o")) { + String[] split = nextLine.split(" +"); + resources.setOutputs(Integer.parseInt(split[1])); + } + } + in.close(); + } } diff --git a/src/jcgp/backend/population/Chromosome.java b/src/jcgp/backend/population/Chromosome.java index 71e19ec..f8830fa 100644 --- a/src/jcgp/backend/population/Chromosome.java +++ b/src/jcgp/backend/population/Chromosome.java @@ -15,7 +15,7 @@ public class Chromosome { private ArrayList<Node> activeNodes; - private int fitness = 0; + private double fitness = 0; private boolean recomputeActiveNodes = true; /** @@ -154,11 +154,11 @@ public class Chromosome { return inputs[index]; } - public int getFitness() { + public double getFitness() { return fitness; } - public void setFitness(int newFitness) { + public void setFitness(double newFitness) { fitness = newFitness; } diff --git a/src/jcgp/backend/resources/Resources.java b/src/jcgp/backend/resources/Resources.java index 0bf1ee1..151d536 100644 --- a/src/jcgp/backend/resources/Resources.java +++ b/src/jcgp/backend/resources/Resources.java @@ -155,7 +155,7 @@ public class Resources { } }; - inputs = new IntegerParameter(3, "Inputs", false, true) { + inputs = new IntegerParameter(3, "Inputs", true, false) { @Override public void validate(Number newValue) { if (newValue.intValue() <= 0) { @@ -167,7 +167,7 @@ public class Resources { } }; - outputs = new IntegerParameter(3, "Outputs", false, true) { + outputs = new IntegerParameter(3, "Outputs", true, false) { @Override public void validate(Number newValue) { if (newValue.intValue() <= 0) { diff --git a/src/jcgp/backend/tests/NodeTests.java b/src/jcgp/backend/tests/NodeTests.java index c9f247a..4054661 100644 --- a/src/jcgp/backend/tests/NodeTests.java +++ b/src/jcgp/backend/tests/NodeTests.java @@ -2,8 +2,8 @@ package jcgp.backend.tests; import static org.junit.Assert.assertTrue; import jcgp.backend.exceptions.InvalidArgumentsException; -import jcgp.backend.function.Function; import jcgp.backend.function.DoubleArithmetic; +import jcgp.backend.function.Function; import jcgp.backend.population.Chromosome; import jcgp.backend.population.Connection; import jcgp.backend.population.Node; |