diff options
Diffstat (limited to 'src/jcgp/backend')
31 files changed, 592 insertions, 283 deletions
diff --git a/src/jcgp/backend/exceptions/ManagedModuleException.java b/src/jcgp/backend/exceptions/ManagedModuleException.java deleted file mode 100644 index 3452d35..0000000 --- a/src/jcgp/backend/exceptions/ManagedModuleException.java +++ /dev/null @@ -1,10 +0,0 @@ -package jcgp.backend.exceptions; - -public class ManagedModuleException extends RuntimeException { - - /** - * - */ - private static final long serialVersionUID = -3450063156524494967L; - -} diff --git a/src/jcgp/backend/function/BitwiseLogic.java b/src/jcgp/backend/function/BitwiseLogic.java index bfe361f..5d47ff7 100644 --- a/src/jcgp/backend/function/BitwiseLogic.java +++ b/src/jcgp/backend/function/BitwiseLogic.java @@ -1,8 +1,5 @@ package jcgp.backend.function; -import java.util.ArrayList; -import java.util.Arrays; - import jcgp.backend.exceptions.InvalidArgumentsException; import jcgp.backend.population.Connection; @@ -19,15 +16,13 @@ public class BitwiseLogic extends FunctionSet { new Nor(), new Xnor()}; - allowedFunctions = new ArrayList<Function>(Arrays.asList(functionList)); + enableAll(); } - public static class And extends Function { - private int arity = 2; - + public static class And extends Function { @Override public Object run(Connection... connections) { - if (connections.length < arity) { + if (connections.length < 2) { throw new InvalidArgumentsException("Not enough connections were given."); } else { int arg1 = ((int) connections[0].getValue()); @@ -40,7 +35,7 @@ public class BitwiseLogic extends FunctionSet { @Override public int getArity() { - return arity; + return 2; } @Override @@ -49,12 +44,10 @@ public class BitwiseLogic extends FunctionSet { } } - public static class Or extends Function { - private int arity = 2; - + public static class Or extends Function { @Override public Object run(Connection... connections) { - if (connections.length < arity) { + if (connections.length < 2) { throw new InvalidArgumentsException("Not enough connections were given."); } else { int arg1 = ((int) connections[0].getValue()); @@ -67,7 +60,7 @@ public class BitwiseLogic extends FunctionSet { @Override public int getArity() { - return arity; + return 2; } @Override @@ -76,12 +69,10 @@ public class BitwiseLogic extends FunctionSet { } } - public static class Not extends Function { - private int arity = 1; - + public static class Not extends Function { @Override public Object run(Connection... connections) { - if (connections.length < arity) { + if (connections.length < 1) { throw new InvalidArgumentsException("Not enough connections were given."); } else { int arg1 = ((int) connections[0].getValue()); @@ -93,7 +84,7 @@ public class BitwiseLogic extends FunctionSet { @Override public int getArity() { - return arity; + return 1; } @Override @@ -102,12 +93,10 @@ public class BitwiseLogic extends FunctionSet { } } - public static class Xor extends Function { - private int arity = 2; - + public static class Xor extends Function { @Override public Object run(Connection... connections) { - if (connections.length < arity) { + if (connections.length < 2) { throw new InvalidArgumentsException("Not enough connections were given."); } else { int arg1 = ((int) connections[0].getValue()); @@ -120,7 +109,7 @@ public class BitwiseLogic extends FunctionSet { @Override public int getArity() { - return arity; + return 2; } @Override @@ -129,12 +118,10 @@ public class BitwiseLogic extends FunctionSet { } } - public static class Nand extends Function { - private int arity = 2; - + public static class Nand extends Function { @Override public Object run(Connection... connections) { - if (connections.length < arity) { + if (connections.length < 2) { throw new InvalidArgumentsException("Not enough connections were given."); } else { int arg1 = ((int) connections[0].getValue()); @@ -147,7 +134,7 @@ public class BitwiseLogic extends FunctionSet { @Override public int getArity() { - return arity; + return 2; } @Override @@ -156,12 +143,10 @@ public class BitwiseLogic extends FunctionSet { } } - public static class Nor extends Function { - private int arity = 2; - + public static class Nor extends Function { @Override public Object run(Connection... connections) { - if (connections.length < arity) { + if (connections.length < 2) { throw new InvalidArgumentsException("Not enough connections were given."); } else { int arg1 = ((int) connections[0].getValue()); @@ -174,7 +159,7 @@ public class BitwiseLogic extends FunctionSet { @Override public int getArity() { - return arity; + return 2; } @Override @@ -183,12 +168,10 @@ public class BitwiseLogic extends FunctionSet { } } - public static class Xnor extends Function { - private int arity = 2; - + public static class Xnor extends Function { @Override public Object run(Connection... connections) { - if (connections.length < arity) { + if (connections.length < 2) { throw new InvalidArgumentsException("Not enough connections were given."); } else { int arg1 = ((int) connections[0].getValue()); @@ -201,7 +184,7 @@ public class BitwiseLogic extends FunctionSet { @Override public int getArity() { - return arity; + return 2; } @Override diff --git a/src/jcgp/backend/function/BooleanLogic.java b/src/jcgp/backend/function/BooleanLogic.java index e0b5c9c..9e7d1ff 100644 --- a/src/jcgp/backend/function/BooleanLogic.java +++ b/src/jcgp/backend/function/BooleanLogic.java @@ -1,7 +1,5 @@ package jcgp.backend.function; -import java.util.ArrayList; -import java.util.Arrays; import jcgp.backend.exceptions.InvalidArgumentsException; import jcgp.backend.population.Connection; @@ -19,15 +17,13 @@ public class BooleanLogic extends FunctionSet { new Nor(), new Xnor()}; - allowedFunctions = new ArrayList<Function>(Arrays.asList(functionList)); + enableAll(); } - public static class And extends Function { - private int arity = 2; - + public static class And extends Function { @Override public Boolean run(Connection... connections) { - if (connections.length < arity) { + if (connections.length < 2) { throw new InvalidArgumentsException("Not enough connections were given."); } else { Boolean arg1 = ((Boolean) connections[0].getValue()); @@ -40,7 +36,7 @@ public class BooleanLogic extends FunctionSet { @Override public int getArity() { - return arity; + return 2; } @Override @@ -49,12 +45,10 @@ public class BooleanLogic extends FunctionSet { } } - public static class Or extends Function { - private int arity = 2; - + public static class Or extends Function { @Override public Boolean run(Connection... connections) { - if (connections.length < arity) { + if (connections.length < 2) { throw new InvalidArgumentsException("Not enough connections were given."); } else { Boolean arg1 = ((Boolean) connections[0].getValue()); @@ -67,7 +61,7 @@ public class BooleanLogic extends FunctionSet { @Override public int getArity() { - return arity; + return 2; } @Override @@ -76,12 +70,10 @@ public class BooleanLogic extends FunctionSet { } } - public static class Not extends Function { - private int arity = 1; - + public static class Not extends Function { @Override public Boolean run(Connection... connections) { - if (connections.length < arity) { + if (connections.length < 1) { throw new InvalidArgumentsException("Not enough connections were given."); } else { Boolean arg1 = ((Boolean) connections[0].getValue()); @@ -93,7 +85,7 @@ public class BooleanLogic extends FunctionSet { @Override public int getArity() { - return arity; + return 1; } @Override @@ -102,12 +94,10 @@ public class BooleanLogic extends FunctionSet { } } - public static class Xor extends Function { - private int arity = 2; - + public static class Xor extends Function { @Override public Boolean run(Connection... connections) { - if (connections.length < arity) { + if (connections.length < 2) { throw new InvalidArgumentsException("Not enough connections were given."); } else { Boolean arg1 = ((Boolean) connections[0].getValue()); @@ -120,7 +110,7 @@ public class BooleanLogic extends FunctionSet { @Override public int getArity() { - return arity; + return 2; } @Override @@ -129,12 +119,10 @@ public class BooleanLogic extends FunctionSet { } } - public static class Nand extends Function { - private int arity = 2; - + public static class Nand extends Function { @Override public Boolean run(Connection... connections) { - if (connections.length < arity) { + if (connections.length < 2) { throw new InvalidArgumentsException("Not enough connections were given."); } else { Boolean arg1 = ((Boolean) connections[0].getValue()); @@ -147,7 +135,7 @@ public class BooleanLogic extends FunctionSet { @Override public int getArity() { - return arity; + return 2; } @Override @@ -156,12 +144,10 @@ public class BooleanLogic extends FunctionSet { } } - public static class Nor extends Function { - private int arity = 2; - + public static class Nor extends Function { @Override public Boolean run(Connection... connections) { - if (connections.length < arity) { + if (connections.length < 2) { throw new InvalidArgumentsException("Not enough connections were given."); } else { Boolean arg1 = ((Boolean) connections[0].getValue()); @@ -174,7 +160,7 @@ public class BooleanLogic extends FunctionSet { @Override public int getArity() { - return arity; + return 2; } @Override @@ -183,12 +169,10 @@ public class BooleanLogic extends FunctionSet { } } - public static class Xnor extends Function { - private int arity = 2; - + public static class Xnor extends Function { @Override public Boolean run(Connection... connections) { - if (connections.length < arity) { + if (connections.length < 2) { throw new InvalidArgumentsException("Not enough connections were given."); } else { Boolean arg1 = ((Boolean) connections[0].getValue()); @@ -201,7 +185,7 @@ public class BooleanLogic extends FunctionSet { @Override public int getArity() { - return arity; + return 2; } @Override diff --git a/src/jcgp/backend/function/FunctionSet.java b/src/jcgp/backend/function/FunctionSet.java index 4470ac8..78801fc 100644 --- a/src/jcgp/backend/function/FunctionSet.java +++ b/src/jcgp/backend/function/FunctionSet.java @@ -1,6 +1,7 @@ package jcgp.backend.function; import java.util.ArrayList; +import java.util.Collections; import java.util.Iterator; @@ -11,7 +12,7 @@ import java.util.Iterator; */ public abstract class FunctionSet { protected Function[] functionList; - protected ArrayList<Function> allowedFunctions; + protected ArrayList<Integer> allowedFunctions; protected String name; public int getAllowedFunctionCount() { @@ -23,7 +24,7 @@ public abstract class FunctionSet { } public Function getAllowedFunction(int index) { - return allowedFunctions.get(index); + return functionList[allowedFunctions.get(index)]; } public Function getFunction(int index) { @@ -32,7 +33,7 @@ public abstract class FunctionSet { public int getMaxArity(){ int arity = 0; - for (Function function : allowedFunctions) { + for (Function function : functionList) { if (function.getArity() > arity) { arity = function.getArity(); } @@ -46,9 +47,9 @@ public abstract class FunctionSet { public void disableFunction(int index) { if (index < functionList.length) { - for (Iterator<Function> iterator = allowedFunctions.iterator(); iterator.hasNext();) { - Function function = (Function) iterator.next(); - if (function == functionList[index]) { + for (Iterator<Integer> iterator = allowedFunctions.iterator(); iterator.hasNext();) { + int function = iterator.next(); + if (function == index) { iterator.remove(); } } @@ -58,8 +59,9 @@ public abstract class FunctionSet { } public void enableFunction(int index) { - if (!allowedFunctions.contains(functionList[index])) { - allowedFunctions.add(functionList[index]); + if (!allowedFunctions.contains(index)) { + allowedFunctions.add(index); + Collections.sort(allowedFunctions); } } @@ -69,6 +71,18 @@ public abstract class FunctionSet { } public boolean isEnabled(Function f) { - return allowedFunctions.contains(f); + for (int i = 0; i < allowedFunctions.size(); i++) { + if (functionList[allowedFunctions.get(i)] == f) { + return true; + } + } + return false; + } + + protected void enableAll() { + allowedFunctions = new ArrayList<Integer>(); + for (int i = 0; i < functionList.length; i++) { + allowedFunctions.add(i); + } } }
\ No newline at end of file diff --git a/src/jcgp/backend/function/Arithmetic.java b/src/jcgp/backend/function/IntegerArithmetic.java index 6971663..c08a72a 100644 --- a/src/jcgp/backend/function/Arithmetic.java +++ b/src/jcgp/backend/function/IntegerArithmetic.java @@ -1,31 +1,25 @@ package jcgp.backend.function; -import java.util.ArrayList; -import java.util.Arrays; - import jcgp.backend.exceptions.InvalidArgumentsException; import jcgp.backend.population.Connection; -public class Arithmetic extends FunctionSet { +public class IntegerArithmetic extends FunctionSet { - public Arithmetic() { - name = "Arithmetic"; + public IntegerArithmetic() { + name = "Integer Arithmetic"; functionList = new Function[]{ new Addition(), new Subtraction(), new Multiplication(), new Division()}; - allowedFunctions = new ArrayList<Function>(Arrays.asList(functionList)); + enableAll(); } public static class Addition extends Function { - - private int arity = 2; - @Override public Integer run(Connection... connections) { - if (connections.length < arity) { + if (connections.length < 2) { throw new InvalidArgumentsException("Not enough connections were given."); } else { Integer arg1 = ((Integer) connections[0].getValue()); @@ -38,7 +32,7 @@ public class Arithmetic extends FunctionSet { @Override public int getArity() { - return arity; + return 2; } @Override @@ -48,12 +42,9 @@ public class Arithmetic extends FunctionSet { } public static class Subtraction extends Function { - - private int arity = 2; - @Override public Integer run(Connection... connections) { - if (connections.length < arity) { + if (connections.length < 2) { throw new InvalidArgumentsException("Not enough connections were given."); } else { Integer arg1 = ((Integer) connections[0].getValue()); @@ -66,7 +57,7 @@ public class Arithmetic extends FunctionSet { @Override public int getArity() { - return arity; + return 2; } @Override @@ -76,12 +67,9 @@ public class Arithmetic extends FunctionSet { } public static class Multiplication extends Function { - - private int arity = 2; - @Override public Integer run(Connection... connections) { - if (connections.length < arity) { + if (connections.length < 2) { throw new InvalidArgumentsException("Not enough connections were given."); } else { Integer arg1 = ((Integer) connections[0].getValue()); @@ -94,7 +82,7 @@ public class Arithmetic extends FunctionSet { @Override public int getArity() { - return arity; + return 2; } @Override @@ -104,12 +92,9 @@ public class Arithmetic extends FunctionSet { } public static class Division extends Function { - - private int arity = 2; - @Override public Integer run(Connection... connections) { - if (connections.length < arity) { + if (connections.length < 2) { throw new InvalidArgumentsException("Not enough connections were given."); } else { Integer arg1 = ((Integer) connections[0].getValue()); @@ -127,7 +112,7 @@ public class Arithmetic extends FunctionSet { @Override public int getArity() { - return arity; + return 2; } @Override diff --git a/src/jcgp/backend/modules/Module.java b/src/jcgp/backend/modules/Module.java index 82c3d80..f2b91b0 100644 --- a/src/jcgp/backend/modules/Module.java +++ b/src/jcgp/backend/modules/Module.java @@ -1,11 +1,9 @@ package jcgp.backend.modules; -import jcgp.JCGP.Resources; -import jcgp.backend.parameters.Parameter; +import jcgp.backend.resources.parameters.Parameter; public interface Module { public Parameter[] getLocalParameters(); - public ModuleStatus getStatus(Resources resources); } diff --git a/src/jcgp/backend/modules/ModuleStatus.java b/src/jcgp/backend/modules/ModuleStatus.java deleted file mode 100644 index fec8490..0000000 --- a/src/jcgp/backend/modules/ModuleStatus.java +++ /dev/null @@ -1,16 +0,0 @@ -package jcgp.backend.modules; - -public enum ModuleStatus { - ERROR, WARNING, READY; - - private String details; - - public void setDetails(String details) { - this.details = details; - } - - public String getDetails() { - return details; - } - -} diff --git a/src/jcgp/backend/modules/ea/EvolutionaryAlgorithm.java b/src/jcgp/backend/modules/ea/EvolutionaryAlgorithm.java index 7719111..3aca104 100644 --- a/src/jcgp/backend/modules/ea/EvolutionaryAlgorithm.java +++ b/src/jcgp/backend/modules/ea/EvolutionaryAlgorithm.java @@ -1,9 +1,9 @@ package jcgp.backend.modules.ea; -import jcgp.JCGP.Resources; import jcgp.backend.modules.Module; import jcgp.backend.modules.mutator.Mutator; import jcgp.backend.population.Population; +import jcgp.backend.resources.Resources; public interface EvolutionaryAlgorithm extends Module { diff --git a/src/jcgp/backend/modules/ea/MuPlusLambda.java b/src/jcgp/backend/modules/ea/MuPlusLambda.java index ad8c5d8..0d16111 100644 --- a/src/jcgp/backend/modules/ea/MuPlusLambda.java +++ b/src/jcgp/backend/modules/ea/MuPlusLambda.java @@ -1,13 +1,12 @@ package jcgp.backend.modules.ea; -import jcgp.JCGP.Resources; -import jcgp.backend.modules.ModuleStatus; import jcgp.backend.modules.mutator.Mutator; -import jcgp.backend.parameters.BooleanParameter; -import jcgp.backend.parameters.IntegerParameter; -import jcgp.backend.parameters.Parameter; -import jcgp.backend.parameters.ParameterStatus; import jcgp.backend.population.Population; +import jcgp.backend.resources.Resources; +import jcgp.backend.resources.parameters.BooleanParameter; +import jcgp.backend.resources.parameters.IntegerParameter; +import jcgp.backend.resources.parameters.Parameter; +import jcgp.backend.resources.parameters.ParameterStatus; /** * (μ + λ) EA. @@ -62,8 +61,7 @@ public class MuPlusLambda implements EvolutionaryAlgorithm { @Override public void evolve(Population population, Mutator mutator, Resources resources) { - // TODO actually use parents and offspring - // select fittest chromosome + // select fittest chromosomes fittestChromosome = 0; for (int i = 1; i < resources.getInt("popSize"); i++) { @@ -79,6 +77,7 @@ public class MuPlusLambda implements EvolutionaryAlgorithm { mutator.mutate(population.getChromosome(i), resources); } } + } @Override @@ -95,10 +94,5 @@ public class MuPlusLambda implements EvolutionaryAlgorithm { public String toString() { return "(μ + λ)"; } - - @Override - public ModuleStatus getStatus(Resources resources) { - return ModuleStatus.READY; - } } diff --git a/src/jcgp/backend/modules/ea/TournamentSelection.java b/src/jcgp/backend/modules/ea/TournamentSelection.java index 32ac54d..baf6704 100644 --- a/src/jcgp/backend/modules/ea/TournamentSelection.java +++ b/src/jcgp/backend/modules/ea/TournamentSelection.java @@ -2,12 +2,11 @@ package jcgp.backend.modules.ea; import java.util.HashMap; -import jcgp.JCGP.Resources; -import jcgp.backend.modules.ModuleStatus; import jcgp.backend.modules.mutator.Mutator; -import jcgp.backend.parameters.IntegerParameter; -import jcgp.backend.parameters.Parameter; import jcgp.backend.population.Population; +import jcgp.backend.resources.Resources; +import jcgp.backend.resources.parameters.IntegerParameter; +import jcgp.backend.resources.parameters.Parameter; public class TournamentSelection implements EvolutionaryAlgorithm { @@ -51,9 +50,4 @@ public class TournamentSelection implements EvolutionaryAlgorithm { public String toString() { return "Tournament"; } - - @Override - public ModuleStatus getStatus(Resources resources) { - return null; - } } diff --git a/src/jcgp/backend/modules/fitness/FitnessFunction.java b/src/jcgp/backend/modules/fitness/FitnessFunction.java index ffce9b7..d3b76cb 100644 --- a/src/jcgp/backend/modules/fitness/FitnessFunction.java +++ b/src/jcgp/backend/modules/fitness/FitnessFunction.java @@ -1,8 +1,8 @@ package jcgp.backend.modules.fitness; -import jcgp.JCGP.Resources; import jcgp.backend.modules.Module; import jcgp.backend.population.Population; +import jcgp.backend.resources.Resources; public interface FitnessFunction extends Module { diff --git a/src/jcgp/backend/modules/fitness/TestCase.java b/src/jcgp/backend/modules/fitness/TestCase.java deleted file mode 100644 index 23f7ecf..0000000 --- a/src/jcgp/backend/modules/fitness/TestCase.java +++ /dev/null @@ -1,29 +0,0 @@ -package jcgp.backend.modules.fitness; - -public class TestCase { - - private Object[] inputs; - private Object[] outputs; - - public TestCase(Object[] inputs, Object[] outputs) { - this.inputs = inputs; - this.outputs = outputs; - } - - public Object getInput(int index) { - return inputs[index]; - } - - public Object getOutput(int index) { - return outputs[index]; - } - - public Object[] getInputs() { - return inputs; - } - - public Object[] getOutputs() { - return outputs; - } - -} diff --git a/src/jcgp/backend/modules/fitness/TestCaseEvaluator.java b/src/jcgp/backend/modules/fitness/TestCaseEvaluator.java deleted file mode 100644 index 5ff6973..0000000 --- a/src/jcgp/backend/modules/fitness/TestCaseEvaluator.java +++ /dev/null @@ -1,43 +0,0 @@ -package jcgp.backend.modules.fitness; - -import jcgp.JCGP.Resources; -import jcgp.backend.modules.ModuleStatus; -import jcgp.backend.parameters.Parameter; -import jcgp.backend.population.Population; - -public class TestCaseEvaluator implements FitnessFunction { - - @Override - public void evaluate(Population population, Resources resources) { - // for every chromosome in the population - for (int i = 0; i < resources.getInt("popSize"); i++) { - int fitness = 0; - // for every test case - for (int t = 0; t < resources.getTestCaseCount(); t++) { - population.getChromosome(i).setInputs(resources.getTestCase(t).getInputs()); - // check every output - for (int o = 0; o < resources.getInt("outputs"); o++) { - if (population.getChromosome(i).getOutput(o).calculate() == resources.getTestCase(t).getOutput(o)) { - fitness++; - } - } - } - population.getChromosome(i).setFitness(fitness); - } - } - - @Override - public Parameter[] getLocalParameters() { - return null; - } - - @Override - public String toString() { - return "Test case"; - } - - @Override - public ModuleStatus getStatus(Resources resources) { - return null; - } -} diff --git a/src/jcgp/backend/modules/fitness/testcase/TestCaseEvaluator.java b/src/jcgp/backend/modules/fitness/testcase/TestCaseEvaluator.java new file mode 100644 index 0000000..51676e3 --- /dev/null +++ b/src/jcgp/backend/modules/fitness/testcase/TestCaseEvaluator.java @@ -0,0 +1,75 @@ +package jcgp.backend.modules.fitness.testcase; + +import java.util.ArrayList; + +import jcgp.backend.modules.fitness.FitnessFunction; +import jcgp.backend.population.Population; +import jcgp.backend.resources.Resources; + +/** + * + * This fitness function module implements a simple test case evaluator. + * + * A TestCase object is a + * + * + * @author Eduardo Pedroni + * + */ +public abstract class TestCaseEvaluator implements FitnessFunction { + + public static class TestCase<T> { + + private T[] inputs; + private T[] outputs; + + public TestCase(T[] inputs, T[] outputs) { + this.inputs = inputs; + this.outputs = outputs; + } + + public T getInput(int index) { + return inputs[index]; + } + + public T getOutput(int index) { + return outputs[index]; + } + + public T[] getInputs() { + return inputs; + } + + public T[] getOutputs() { + return outputs; + } + } + + protected ArrayList<TestCase> testCases; + + @Override + public void evaluate(Population population, Resources resources) { + // for every chromosome in the population + for (int i = 0; i < resources.getInt("popSize"); 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.getInt("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); + } + } + + public int getMaxFitness() { + return 0; + } +} + diff --git a/src/jcgp/backend/modules/mutator/Mutator.java b/src/jcgp/backend/modules/mutator/Mutator.java index fd7cd27..ffdd35c 100644 --- a/src/jcgp/backend/modules/mutator/Mutator.java +++ b/src/jcgp/backend/modules/mutator/Mutator.java @@ -1,8 +1,8 @@ package jcgp.backend.modules.mutator; -import jcgp.JCGP.Resources; import jcgp.backend.modules.Module; import jcgp.backend.population.Chromosome; +import jcgp.backend.resources.Resources; public interface Mutator extends Module { diff --git a/src/jcgp/backend/modules/mutator/PointMutator.java b/src/jcgp/backend/modules/mutator/PointMutator.java index cdac8bb..54d5f3d 100644 --- a/src/jcgp/backend/modules/mutator/PointMutator.java +++ b/src/jcgp/backend/modules/mutator/PointMutator.java @@ -1,33 +1,39 @@ package jcgp.backend.modules.mutator; import jcgp.backend.function.Function; -import jcgp.backend.modules.ModuleStatus; -import jcgp.backend.parameters.DoubleParameter; -import jcgp.backend.parameters.Parameter; import jcgp.backend.population.Chromosome; import jcgp.backend.population.MutableElement; import jcgp.backend.population.Node; import jcgp.backend.population.Output; -import jcgp.JCGP.Resources; +import jcgp.backend.resources.Resources; +import jcgp.backend.resources.parameters.DoubleParameter; +import jcgp.backend.resources.parameters.Parameter; +import jcgp.backend.resources.parameters.ParameterStatus; public class PointMutator implements Mutator { private DoubleParameter mutationRate; - private ModuleStatus status = ModuleStatus.READY; - - public PointMutator() { - mutationRate = new DoubleParameter(0.5, "Percent mutation", false, false) { + public PointMutator(final Resources resources) { + mutationRate = new DoubleParameter(50, "Percent mutation", false, false) { @Override public void validate(double newValue) { - // TODO this + if (newValue <= 0 || newValue > 100) { + status = ParameterStatus.INVALID; + status.setDetails("Mutation rate must be > 0 and <= 100"); + } else if ((int) ((newValue / 100) * resources.getDouble("nodes")) <= 0) { + status = ParameterStatus.WARNING; + status.setDetails("With mutation rate " + mutationRate.get() + ", 0 genes will be mutated."); + } else { + status = ParameterStatus.VALID; + } } }; } @Override public void mutate(Chromosome chromosome, Resources resources) { - int mutations = (int) Math.ceil(((mutationRate.get()) * ((((resources.getDouble("nodes")) + (resources.getDouble("outputs")))) / (double) 100))); + int mutations = (int) ((mutationRate.get()) * ((((resources.getDouble("nodes")) + (resources.getDouble("outputs")))) / 100)); for (int i = 0; i < mutations; i++) { MutableElement m = chromosome.getRandomMutableElement(); @@ -55,18 +61,4 @@ public class PointMutator implements Mutator { return "Point mutation"; } - @Override - public ModuleStatus getStatus(Resources resources) { - if (mutationRate.get() <= 0 || mutationRate.get() > 100) { - status = ModuleStatus.ERROR; - status.setDetails("Mutation rate must be > 0 and <= 100"); - } else if ((int) ((mutationRate.get() / 100) * resources.getDouble("nodes")) > 0) { - status = ModuleStatus.WARNING; - status.setDetails("With mutation rate " + mutationRate.get() + ", no mutations will occur."); - } else { - status = ModuleStatus.READY; - status.setDetails(""); - } - return status; - } } diff --git a/src/jcgp/backend/population/Chromosome.java b/src/jcgp/backend/population/Chromosome.java index c7493b9..d438375 100644 --- a/src/jcgp/backend/population/Chromosome.java +++ b/src/jcgp/backend/population/Chromosome.java @@ -2,8 +2,8 @@ package jcgp.backend.population; import java.util.ArrayList; -import jcgp.JCGP.Resources; import jcgp.backend.exceptions.ParameterMismatchException; +import jcgp.backend.resources.Resources; public class Chromosome { diff --git a/src/jcgp/backend/population/Node.java b/src/jcgp/backend/population/Node.java index f1d37a1..6960ded 100644 --- a/src/jcgp/backend/population/Node.java +++ b/src/jcgp/backend/population/Node.java @@ -37,7 +37,7 @@ public class Node extends Gene implements MutableElement, Connection { public void initialise(Function newFunction, Connection ... newConnections) throws InsufficientConnectionsException { function = newFunction; - if (newConnections.length == function.getArity()) { + if (newConnections.length == chromosome.getResources().getInt("arity")) { connections = newConnections; } else { throw new InsufficientConnectionsException(); diff --git a/src/jcgp/backend/population/Population.java b/src/jcgp/backend/population/Population.java index 7b62d27..d2e6058 100644 --- a/src/jcgp/backend/population/Population.java +++ b/src/jcgp/backend/population/Population.java @@ -1,7 +1,6 @@ package jcgp.backend.population; -import jcgp.JCGP.Resources; - +import jcgp.backend.resources.Resources; public class Population { @@ -56,7 +55,6 @@ public class Population { return chromosomes[resources.getRandomInt(chromosomes.length)]; } - /** * Copy a chromosome into a different position. * After this returns, the target chromosome has @@ -75,4 +73,6 @@ public class Population { } + + } diff --git a/src/jcgp/backend/resources/Console.java b/src/jcgp/backend/resources/Console.java new file mode 100644 index 0000000..6bbd5ba --- /dev/null +++ b/src/jcgp/backend/resources/Console.java @@ -0,0 +1,11 @@ +package jcgp.backend.resources; + +public interface Console { + + public void println(String s); + + public void print(String s); + + public void flush(); + +} diff --git a/src/jcgp/backend/resources/ModifiableResources.java b/src/jcgp/backend/resources/ModifiableResources.java new file mode 100644 index 0000000..3e6b55e --- /dev/null +++ b/src/jcgp/backend/resources/ModifiableResources.java @@ -0,0 +1,42 @@ +package jcgp.backend.resources; + +import jcgp.backend.resources.parameters.BooleanParameter; +import jcgp.backend.resources.parameters.DoubleParameter; +import jcgp.backend.resources.parameters.IntegerParameter; + +/** + * + * This subclass of Resources allows modifications to be made. + * A read-only cast of this class is passed to modules for safety, + * and only classes with access to a JCGP instance may modify + * the resources. + * + * @author eddy + * + */ +public class ModifiableResources extends Resources { + + public ModifiableResources() { + super(); + } + + public void set(String key, Object value) { + if (parameters.get(key) instanceof IntegerParameter) { + ((IntegerParameter) parameters.get(key)).set(((Integer) value).intValue()); + } else if (parameters.get(key) instanceof DoubleParameter) { + ((DoubleParameter) parameters.get(key)).set(((Double) value).doubleValue()); + } else if (parameters.get(key) instanceof BooleanParameter) { + ((BooleanParameter) parameters.get(key)).set(((Boolean) value).booleanValue()); + } + } + + public void setFunctionSet(int index) { + functionSet = functionSets[index]; + set("arity", functionSet.getMaxArity()); + } + + public void setConsole(Console console) { + this.console = console; + } + +} diff --git a/src/jcgp/backend/resources/Resources.java b/src/jcgp/backend/resources/Resources.java new file mode 100644 index 0000000..c1c3e4c --- /dev/null +++ b/src/jcgp/backend/resources/Resources.java @@ -0,0 +1,310 @@ +package jcgp.backend.resources; + +import java.util.HashMap; +import java.util.Random; + +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import jcgp.backend.function.BitwiseLogic; +import jcgp.backend.function.BooleanLogic; +import jcgp.backend.function.Function; +import jcgp.backend.function.FunctionSet; +import jcgp.backend.function.IntegerArithmetic; +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; + +/** + * + * The resources class encapsulates all of the resources based on which the program operates. + * Each instance of JCGP contains a single instance of Resources, which gets passed to the selected + * modules as the program executes. + * + * @author Eduardo Pedroni + * + */ +public class Resources { + protected HashMap<String, Parameter> parameters = new HashMap<String, Parameter>(); + + protected Random numberGenerator = new Random(); + + // function sets + protected FunctionSet[] functionSets = new FunctionSet[] { + new IntegerArithmetic(), + new BitwiseLogic(), + new BooleanLogic() }; + protected FunctionSet functionSet = functionSets[0]; + + // GUI console + protected Console console; + + public Resources() { + createBaseParameters(); + } + + public int getInt(String key) { + if (parameters.get(key) instanceof IntegerParameter) { + return ((IntegerParameter) parameters.get(key)).get(); + } else if (parameters.get(key) instanceof DoubleParameter) { + return (int) ((DoubleParameter) parameters.get(key)).get(); + } else { + throw new ClassCastException("Could not cast " + parameters.get(key).getClass() + " to int."); + } + } + + public double getDouble(String key) { + if (parameters.get(key) instanceof IntegerParameter) { + return ((IntegerParameter) parameters.get(key)).get(); + } else if (parameters.get(key) instanceof DoubleParameter) { + return ((DoubleParameter) parameters.get(key)).get(); + } else { + throw new ClassCastException("Could not cast " + parameters.get(key).getClass() + " to double."); + } + } + + public boolean getBoolean(String key) { + if (parameters.get(key) instanceof BooleanParameter) { + return ((BooleanParameter) parameters.get(key)).get(); + } else { + throw new ClassCastException("Could not cast " + parameters.get(key).getClass() + " to int."); + } + } + + public Parameter getParameter(String key) { + return parameters.get(key); + } + + public boolean contains(String key) { + return parameters.containsKey(key); + } + + private void createBaseParameters() { + parameters.put("rows", new IntegerParameter(8, "Rows", false, true) { + @Override + public void validate(int newValue) { + if (newValue <= 0) { + status = ParameterStatus.INVALID; + status.setDetails("Chromosome must have at least 1 row."); + } else { + status = ParameterStatus.VALID; + } + } + }); + parameters.put("columns", new IntegerParameter(9, "Columns", false, true) { + @Override + public void validate(int newValue) { + if (newValue <= 0) { + status = ParameterStatus.INVALID; + status.setDetails("Chromosome must have at least 1 column."); + } else { + status = ParameterStatus.VALID; + } + } + }); + parameters.put("inputs", new IntegerParameter(3, "Inputs", false, true) { + @Override + public void validate(int newValue) { + if (newValue <= 0) { + status = ParameterStatus.INVALID; + status.setDetails("Chromosome must have at least 1 input."); + } else { + status = ParameterStatus.VALID; + } + } + }); + parameters.put("outputs", new IntegerParameter(3, "Outputs", false, true) { + @Override + public void validate(int newValue) { + if (newValue <= 0) { + status = ParameterStatus.INVALID; + status.setDetails("Chromosome must have at least 1 output."); + } else { + status = ParameterStatus.VALID; + } + } + }); + parameters.put("popSize", new IntegerParameter(5, "Population", false, true) { + @Override + public void validate(int newValue) { + if (newValue <= 0) { + status = ParameterStatus.INVALID; + status.setDetails("Population size must be at least 1."); + } else { + status = ParameterStatus.VALID; + } + } + }); + parameters.put("levelsBack", new IntegerParameter(2, "Levels back", false, true) { + @Override + public void validate(int newValue) { + if (newValue <= 0) { + status = ParameterStatus.INVALID; + status.setDetails("Levels back must be at least 1."); + } else if (newValue > getInt("columns")) { + status = ParameterStatus.INVALID; + status.setDetails("Levels back must be less than or equal to the number of columns."); + } else { + status = ParameterStatus.VALID; + } + } + }); + + IntegerParameter nodes = new IntegerParameter(1, "Nodes", true, false) { + @Override + public void validate(int newValue) { + // blank + } + }; + nodes.valueProperty().bind(((IntegerParameter) parameters.get("rows")).valueProperty().multiply(((IntegerParameter) parameters.get("columns")).valueProperty())); + parameters.put("nodes", nodes); + + parameters.put("generations", new IntegerParameter(1000000, "Generations") { + @Override + public void validate(int newValue) { + if (newValue <= 0) { + status = ParameterStatus.INVALID; + status.setDetails("Number of generations must be greater than 0."); + } else if (newValue < getInt("currentGen")) { + status = ParameterStatus.WARNING_RESET; + status.setDetails("Setting generations to less than the current generation will cause the experiment to restart."); + } else { + status = ParameterStatus.VALID; + } + } + }); + parameters.put("currentGen", new IntegerParameter(1, "Generation", true, false) { + @Override + public void validate(int newValue) { + // blank + } + }); + + parameters.put("runs", new IntegerParameter(5, "Runs") { + @Override + public void validate(int newValue) { + if (newValue <= 0) { + status = ParameterStatus.INVALID; + status.setDetails("Number of runs must be greater than 0."); + } else if (newValue < getInt("currentRun")) { + status = ParameterStatus.WARNING_RESET; + status.setDetails("Setting runs to less than the current run will cause the experiment to restart."); + } else { + status = ParameterStatus.VALID; + } + } + }); + parameters.put("currentRun", new IntegerParameter(1, "Run", true, false) { + @Override + public void validate(int newValue) { + // blank + } + }); + + parameters.put("arity", new IntegerParameter(functionSet.getMaxArity(), "Max arity", true, false) { + @Override + public void validate(int newValue) { + // blank + } + }); + + IntegerParameter seed = new IntegerParameter(1234, "Seed", false, true) { + @Override + public void validate(int newValue) { + status = ParameterStatus.VALID; + } + }; + seed.valueProperty().addListener(new ChangeListener<Number>() { + @Override + public void changed( + ObservableValue<? extends Number> observable, + Number oldValue, Number newValue) { + numberGenerator.setSeed(newValue.longValue()); + } + }); + numberGenerator.setSeed(seed.get()); + parameters.put("seed", seed); + + parameters.put("report", new IntegerParameter(1, "Report", false, false) { + @Override + public void validate(int newValue) { + if (newValue > getInt("generations")) { + status = ParameterStatus.WARNING; + status.setDetails("No reports will be printed."); + } else { + status = ParameterStatus.VALID; + } + } + }); + } + + /* + * Utility functions + */ + public int getRandomInt(int limit) { + return numberGenerator.nextInt(limit); + } + + public double getRandomDouble(int limit) { + return numberGenerator.nextDouble() * limit; + } + + public double getRandomDouble() { + return numberGenerator.nextDouble(); + } + + /* + * FunctionSet functions + */ + public Function getRandomFunction() { + Function f = functionSet.getAllowedFunction(numberGenerator.nextInt(functionSet.getAllowedFunctionCount())); + return f; + } + + public Function getFunction(int index) { + return functionSet.getAllowedFunction(index); + } + + /** + * @return the functionSets + */ + public FunctionSet[] getFunctionSets() { + return functionSets; + } + + /** + * @return the functionSet + */ + public FunctionSet getFunctionSet() { + return functionSet; + } + +// /* +// * Test cases +// */ +// public TestCase getTestCase(int index) { +// return testCases[index]; +// } +// +// public int getTestCaseCount() { +// return testCases.length; +// } + + /* + * Console functionality + */ + public void println(String s) { + System.out.println(s); + if (console != null) { + console.println(s); + } + } + + public void print(String s) { + System.out.print(s); + if (console != null) { + console.print(s); + } + } +}
\ No newline at end of file diff --git a/src/jcgp/backend/parameters/BooleanParameter.java b/src/jcgp/backend/resources/parameters/BooleanParameter.java index 43825be..cd17649 100644 --- a/src/jcgp/backend/parameters/BooleanParameter.java +++ b/src/jcgp/backend/resources/parameters/BooleanParameter.java @@ -1,4 +1,4 @@ -package jcgp.backend.parameters; +package jcgp.backend.resources.parameters; import javafx.beans.property.SimpleBooleanProperty; @@ -35,6 +35,7 @@ public abstract class BooleanParameter extends Parameter { public abstract void validate(boolean newValue); + @Override public SimpleBooleanProperty valueProperty() { return value; } diff --git a/src/jcgp/backend/parameters/DoubleParameter.java b/src/jcgp/backend/resources/parameters/DoubleParameter.java index 53551f5..8464c83 100644 --- a/src/jcgp/backend/parameters/DoubleParameter.java +++ b/src/jcgp/backend/resources/parameters/DoubleParameter.java @@ -1,4 +1,4 @@ -package jcgp.backend.parameters; +package jcgp.backend.resources.parameters; import javafx.beans.property.SimpleDoubleProperty; @@ -26,6 +26,7 @@ public abstract class DoubleParameter extends Parameter { } } + @Override public SimpleDoubleProperty valueProperty() { return value; } diff --git a/src/jcgp/backend/parameters/IntegerParameter.java b/src/jcgp/backend/resources/parameters/IntegerParameter.java index 68095d9..2a7b2a7 100644 --- a/src/jcgp/backend/parameters/IntegerParameter.java +++ b/src/jcgp/backend/resources/parameters/IntegerParameter.java @@ -1,4 +1,4 @@ -package jcgp.backend.parameters; +package jcgp.backend.resources.parameters; import javafx.beans.property.SimpleIntegerProperty; @@ -27,6 +27,7 @@ public abstract class IntegerParameter extends Parameter { } } + @Override public SimpleIntegerProperty valueProperty() { return value; } diff --git a/src/jcgp/backend/parameters/Parameter.java b/src/jcgp/backend/resources/parameters/Parameter.java index ddd5d5b..7e12ff8 100644 --- a/src/jcgp/backend/parameters/Parameter.java +++ b/src/jcgp/backend/resources/parameters/Parameter.java @@ -1,4 +1,4 @@ -package jcgp.backend.parameters; +package jcgp.backend.resources.parameters; import javafx.beans.property.Property; diff --git a/src/jcgp/backend/parameters/ParameterStatus.java b/src/jcgp/backend/resources/parameters/ParameterStatus.java index 86abe33..11da4c2 100644 --- a/src/jcgp/backend/parameters/ParameterStatus.java +++ b/src/jcgp/backend/resources/parameters/ParameterStatus.java @@ -1,4 +1,4 @@ -package jcgp.backend.parameters; +package jcgp.backend.resources.parameters; public enum ParameterStatus { INVALID, WARNING, WARNING_RESET, VALID; diff --git a/src/jcgp/backend/tests/ChromosomeTests.java b/src/jcgp/backend/tests/ChromosomeTests.java index 1cd067e..a16ba75 100644 --- a/src/jcgp/backend/tests/ChromosomeTests.java +++ b/src/jcgp/backend/tests/ChromosomeTests.java @@ -2,13 +2,13 @@ package jcgp.backend.tests; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import jcgp.JCGP.Resources; import jcgp.backend.population.Chromosome; import jcgp.backend.population.Connection; import jcgp.backend.population.Input; import jcgp.backend.population.MutableElement; import jcgp.backend.population.Node; import jcgp.backend.population.Output; +import jcgp.backend.resources.ModifiableResources; import org.junit.Before; import org.junit.BeforeClass; @@ -40,11 +40,11 @@ import org.junit.Test; public class ChromosomeTests { private Chromosome chromosome; - private static Resources resources; + private static ModifiableResources resources; @BeforeClass public static void setUpBeforeClass() { - resources = new Resources(); + resources = new ModifiableResources(); } @Before diff --git a/src/jcgp/backend/tests/NodeTests.java b/src/jcgp/backend/tests/NodeTests.java index 7121e81..2294816 100644 --- a/src/jcgp/backend/tests/NodeTests.java +++ b/src/jcgp/backend/tests/NodeTests.java @@ -1,12 +1,13 @@ package jcgp.backend.tests; import static org.junit.Assert.assertTrue; -import jcgp.JCGP.Resources; -import jcgp.backend.function.Arithmetic; +import jcgp.backend.exceptions.InvalidArgumentsException; import jcgp.backend.function.Function; +import jcgp.backend.function.IntegerArithmetic; import jcgp.backend.population.Chromosome; import jcgp.backend.population.Connection; import jcgp.backend.population.Node; +import jcgp.backend.resources.Resources; import org.junit.Before; import org.junit.BeforeClass; @@ -48,7 +49,7 @@ public class NodeTests { public void setUp() throws Exception { node = new Node(chromosome, 0, 0, resources.getInt("arity")); // make node with anonymous addition function and hard-coded value connections - node.initialise(new Arithmetic.Addition(), + node.initialise(new IntegerArithmetic.Addition(), new Connection[]{new Connection() { @Override @@ -126,7 +127,7 @@ public class NodeTests { ((int) node.getValue()) == arg1 + arg2); // put in a different function, check the output has changed appropriately - node.setFunction(new Arithmetic.Subtraction()); + node.setFunction(new IntegerArithmetic.Subtraction()); assertTrue("Node did not return expected value (difference of arguments).", ((Integer) node.getValue()) == arg1 - arg2); @@ -166,7 +167,28 @@ public class NodeTests { } }; - node.initialise(null, conn0, conn1); + + Function function = new Function() { + @Override + public Object run(Connection... connections) + throws InvalidArgumentsException { + // blank + return null; + } + + @Override + public int getArity() { + return 2; + } + + @Override + public String getName() { + // blank + return null; + } + }; + + node.initialise(function, conn0, conn1); assertTrue("Connection 0 is incorrect.", node.getConnection(0) == conn0); assertTrue("Connection 1 is incorrect.", node.getConnection(1) == conn1); diff --git a/src/jcgp/backend/tests/OutputTests.java b/src/jcgp/backend/tests/OutputTests.java index 7ff8a4a..b2bc7ec 100644 --- a/src/jcgp/backend/tests/OutputTests.java +++ b/src/jcgp/backend/tests/OutputTests.java @@ -1,10 +1,10 @@ package jcgp.backend.tests; import static org.junit.Assert.assertTrue; -import jcgp.JCGP.Resources; import jcgp.backend.population.Chromosome; import jcgp.backend.population.Connection; import jcgp.backend.population.Output; +import jcgp.backend.resources.Resources; import org.junit.Before; import org.junit.BeforeClass; diff --git a/src/jcgp/backend/tests/PopulationTests.java b/src/jcgp/backend/tests/PopulationTests.java index 51b5168..31df8b9 100644 --- a/src/jcgp/backend/tests/PopulationTests.java +++ b/src/jcgp/backend/tests/PopulationTests.java @@ -1,9 +1,9 @@ package jcgp.backend.tests; import static org.junit.Assert.assertTrue; -import jcgp.JCGP.Resources; import jcgp.backend.population.Chromosome; import jcgp.backend.population.Population; +import jcgp.backend.resources.Resources; import org.junit.Before; import org.junit.BeforeClass; |