aboutsummaryrefslogtreecommitdiffstats
path: root/src/jcgp/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/jcgp/backend')
-rw-r--r--src/jcgp/backend/function/BitwiseLogic.java124
-rw-r--r--src/jcgp/backend/function/BooleanLogic.java199
-rw-r--r--src/jcgp/backend/function/UnsignedInteger.java66
-rw-r--r--src/jcgp/backend/modules/mutator/PointMutator.java17
-rw-r--r--src/jcgp/backend/modules/problem/DigitalCircuit.java25
-rw-r--r--src/jcgp/backend/modules/problem/DigitalCircuitProblem.java85
-rw-r--r--src/jcgp/backend/modules/problem/SymbolicRegression.java26
-rw-r--r--src/jcgp/backend/modules/problem/SymbolicRegressionProblem.java124
-rw-r--r--src/jcgp/backend/modules/problem/TestCaseProblem.java86
-rw-r--r--src/jcgp/backend/parser/ChromosomeParser.java2
-rw-r--r--src/jcgp/backend/parser/FunctionParser.java7
-rw-r--r--src/jcgp/backend/parser/ParameterParser.java1
-rw-r--r--src/jcgp/backend/parser/TestCaseParser.java79
-rw-r--r--src/jcgp/backend/population/Chromosome.java6
-rw-r--r--src/jcgp/backend/resources/Resources.java4
-rw-r--r--src/jcgp/backend/tests/NodeTests.java2
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;