diff options
| author | Eduardo Pedroni <ep625@york.ac.uk> | 2014-04-25 19:38:16 +0100 | 
|---|---|---|
| committer | Eduardo Pedroni <ep625@york.ac.uk> | 2014-04-25 19:38:16 +0100 | 
| commit | b0c0698e5503c2506217117bf144fde31e6f6601 (patch) | |
| tree | 11a6e20fb565f1e75fb25852e757e4a37e4c313b /src/jcgp | |
| parent | 9ac2848be66c39acdc291dc3b48b91178acc1a05 (diff) | |
Commented lots of packages.
Diffstat (limited to 'src/jcgp')
44 files changed, 2486 insertions, 1924 deletions
| diff --git a/src/jcgp/JCGP.java b/src/jcgp/JCGP.java index f980c00..1e6d628 100644 --- a/src/jcgp/JCGP.java +++ b/src/jcgp/JCGP.java @@ -5,12 +5,15 @@ import java.io.File;  import jcgp.backend.modules.es.EvolutionaryStrategy;  import jcgp.backend.modules.es.MuPlusLambda;  import jcgp.backend.modules.es.TournamentSelection; +import jcgp.backend.modules.mutator.FixedPointMutator;  import jcgp.backend.modules.mutator.Mutator; -import jcgp.backend.modules.mutator.PointMutator; +import jcgp.backend.modules.mutator.PercentPointMutator; +import jcgp.backend.modules.mutator.ProbabilisticMutator;  import jcgp.backend.modules.problem.DigitalCircuitProblem;  import jcgp.backend.modules.problem.Problem;  import jcgp.backend.modules.problem.SymbolicRegressionProblem;  import jcgp.backend.modules.problem.TestCaseProblem; +import jcgp.backend.modules.problem.TravellingSalesmanProblem;  import jcgp.backend.parsers.ChromosomeParser;  import jcgp.backend.parsers.FunctionParser;  import jcgp.backend.parsers.ParameterParser; @@ -49,19 +52,22 @@ public class JCGP {  	 */  	// mutators  	private Mutator[] mutators = new Mutator[] { -			new PointMutator(resources) }; +			new PercentPointMutator(resources), +			new FixedPointMutator(resources), +			new ProbabilisticMutator(resources)};  	private Mutator mutator = mutators[0];  	// evolutionary algorithms  	private EvolutionaryStrategy[] evolutionaryStrategies = new EvolutionaryStrategy[] {  			new MuPlusLambda(resources), -			new TournamentSelection(resources) }; +			new TournamentSelection(resources)};  	private EvolutionaryStrategy evolutionaryStrategy = evolutionaryStrategies[0];  	// problem types  	private Problem[] problems = new Problem[] {  			new SymbolicRegressionProblem(resources), -			new DigitalCircuitProblem(resources) }; +			new DigitalCircuitProblem(resources), +			new TravellingSalesmanProblem(resources)};  	private Problem problem = problems[0];  	/* @@ -178,7 +184,6 @@ public class JCGP {  	}  	public void nextGeneration() { -		System.out.println("service: doing next gen");  		if (!finished) {  			problem.evaluate(population, (Resources) resources);  			reportGeneration(); @@ -264,12 +269,9 @@ public class JCGP {  		reset();  	} -	public void loadTestCases(File file) { -		if (problem instanceof TestCaseProblem) { -			TestCaseParser.parseParameters(file, resources); -			reset(); -			TestCaseParser.parse(file, (TestCaseProblem<?>) problem, resources); -		} +	public void loadProblemData(File file) { +		problem.parse(file, resources); +		reset();  	}  	public void loadChromosome(File file, int chromosomeIndex) { diff --git a/src/jcgp/backend/function/BitwiseLogic.java b/src/jcgp/backend/function/BitwiseLogic.java deleted file mode 100644 index 2466f36..0000000 --- a/src/jcgp/backend/function/BitwiseLogic.java +++ /dev/null @@ -1,506 +0,0 @@ -package jcgp.backend.function; - -import jcgp.backend.population.Connection; - -public class BitwiseLogic extends FunctionSet { -	 -	public BitwiseLogic() { -		name = "32-bit Logic"; -		functionList = new Function[]{ -				new ConstantZero(), -				new ConstantOne(), -				new WireA(), -				new WireB(), -				new NotA(), -				new NotB(), -				new And(), -				new AndNotA(), -				new AndNotB(), -				new Nor(), -				new Xor(), -				new Xnor(), -				new Or(), -				new OrNotA(), -				new OrNotB(), -				new Nand() -//				new Mux1(), -//				new Mux2(), -//				new Mux3(), -//				new Mux4() -				}; -		 -		enableAll(); -	} -	 -	public static class ConstantZero extends Function { -		@Override -		public UnsignedInteger run(Connection... connections) { -			return new UnsignedInteger(0); -		} - -		@Override -		public int getArity() { -			return 0; -		} - -		@Override -		public String getName() { -			return "0"; -		} -	} -	 -	public static class ConstantOne extends Function { -		@Override -		public UnsignedInteger run(Connection... connections) { -			return new UnsignedInteger(0xFFFF); -		} - -		@Override -		public int getArity() { -			return 0; -		} - -		@Override -		public String getName() { -			return "1"; -		} -	} -	 -	public static class WireA extends Function { -		@Override -		public UnsignedInteger run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				return ((UnsignedInteger) connections[0].getValue()); -			} -		} - -		@Override -		public int getArity() { -			return 2; -		} - -		@Override -		public String getName() { -			return "Wire A"; -		} -	} -	 -	public static class WireB extends Function { -		@Override -		public UnsignedInteger run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				return ((UnsignedInteger) connections[1].getValue()); -			} -		} - -		@Override -		public int getArity() { -			return 2; -		} - -		@Override -		public String getName() { -			return "Wire B"; -		} -	} -	 -	public static class NotA extends Function { -		@Override -		public UnsignedInteger run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				return new UnsignedInteger(~((UnsignedInteger) connections[0].getValue()).get()); -			} -		} - -		@Override -		public int getArity() { -			return 2; -		} - -		@Override -		public String getName() { -			return "Not A"; -		} -	} -	 -	public static class NotB extends Function { -		@Override -		public UnsignedInteger run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				return new UnsignedInteger(~((UnsignedInteger) connections[1].getValue()).get()); -			} -		} - -		@Override -		public int getArity() { -			return 2; -		} - -		@Override -		public String getName() { -			return "Not B"; -		} -	} -	 -	public static class And extends Function { -		@Override -		public UnsignedInteger run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); -				UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); -				Integer result = in0.get() & in1.get(); -				 -				return new UnsignedInteger(result); -			} -		} - -		@Override -		public int getArity() { -			return 2; -		} - -		@Override -		public String getName() { -			return "And"; -		} -	} -	 -	public static class AndNotA extends Function { -		@Override -		public UnsignedInteger run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); -				UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); -				Integer result = ~(in0.get()) & in1.get(); -				 -				return new UnsignedInteger(result); -			} -		} - -		@Override -		public int getArity() { -			return 2; -		} - -		@Override -		public String getName() { -			return "And !A"; -		} -	} -	 -	public static class AndNotB extends Function { -		@Override -		public UnsignedInteger run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); -				UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); -				Integer result = in0.get() & ~(in1.get()); -				 -				return new UnsignedInteger(result); -			} -		} - -		@Override -		public int getArity() { -			return 2; -		} - -		@Override -		public String getName() { -			return "And !B"; -		} -	} -	 -	public static class Nor extends Function { -		@Override -		public UnsignedInteger run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); -				UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); -				Integer result = in0.get() | in1.get(); - -				return new UnsignedInteger(~result); -			} -		} - -		@Override -		public int getArity() { -			return 2; -		} - -		@Override -		public String getName() { -			return "Nor"; -		} -	} -	 -	public static class Xor extends Function { -		@Override -		public UnsignedInteger run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); -				UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); -				Integer result = in0.get() ^ in1.get(); - -				return new UnsignedInteger(result); -			} -		} - -		@Override -		public int getArity() { -			return 2; -		} - -		@Override -		public String getName() { -			return "Xor"; -		} -	} -	 -	public static class Xnor extends Function { -		@Override -		public UnsignedInteger run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); -				UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); -				Integer result = in0.get() ^ in1.get(); - -				return new UnsignedInteger(~result); -			} -		} - -		@Override -		public int getArity() { -			return 2; -		} - -		@Override -		public String getName() { -			return "Xnor"; -		} -	} -	 -	public static class Or extends Function { -		@Override -		public UnsignedInteger run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); -				UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); -				Integer result = in0.get() | in1.get(); - -				return new UnsignedInteger(result); -			} -		} - -		@Override -		public int getArity() { -			return 2; -		} - -		@Override -		public String getName() { -			return "Or"; -		} -	} -	 -	public static class OrNotA extends Function { -		@Override -		public UnsignedInteger run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); -				UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); -				Integer result = ~in0.get() | in1.get(); - -				return new UnsignedInteger(result); -			} -		} - -		@Override -		public int getArity() { -			return 2; -		} - -		@Override -		public String getName() { -			return "Or !A"; -		} -	} -	 -	public static class OrNotB extends Function { -		@Override -		public UnsignedInteger run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); -				UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); -				Integer result = in0.get() | ~in1.get(); - -				return new UnsignedInteger(result); -			} -		} - -		@Override -		public int getArity() { -			return 2; -		} - -		@Override -		public String getName() { -			return "Or !B"; -		} -	} - -	public static class Nand extends Function { -		@Override -		public UnsignedInteger run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); -				UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); -				Integer result = in0.get() & in1.get(); - -				return new UnsignedInteger(~result); -			} -		} - -		@Override -		public int getArity() { -			return 2; -		} - -		@Override -		public String getName() { -			return "Nand"; -		} -	} -	 -	public static class Mux1 extends Function { -		@Override -		public UnsignedInteger run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); -				UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); -				UnsignedInteger in2 = ((UnsignedInteger) connections[2].getValue()); -				Integer result = ((in0.get() & ~in2.get()) | (in1.get() & in2.get())); - -				return new UnsignedInteger(result); -			} -		} - -		@Override -		public int getArity() { -			return 3; -		} - -		@Override -		public String getName() { -			return "Mux1"; -		} -	} -	 -	public static class Mux2 extends Function { -		@Override -		public UnsignedInteger run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); -				UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); -				UnsignedInteger in2 = ((UnsignedInteger) connections[2].getValue()); -				Integer result = ((in0.get() & ~in2.get()) | (~in1.get() & in2.get())); - -				return new UnsignedInteger(result); -			} -		} - -		@Override -		public int getArity() { -			return 3; -		} - -		@Override -		public String getName() { -			return "Mux2"; -		} -	} -	 -	public static class Mux3 extends Function { -		@Override -		public UnsignedInteger run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); -				UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); -				UnsignedInteger in2 = ((UnsignedInteger) connections[2].getValue()); -				Integer result = ((~in0.get() & ~in2.get()) | (in1.get() & in2.get())); - -				return new UnsignedInteger(result); -			} -		} - -		@Override -		public int getArity() { -			return 3; -		} - -		@Override -		public String getName() { -			return "Mux3"; -		} -	} -	 -	public static class Mux4 extends Function { -		@Override -		public UnsignedInteger run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				UnsignedInteger in0 = ((UnsignedInteger) connections[0].getValue()); -				UnsignedInteger in1 = ((UnsignedInteger) connections[1].getValue()); -				UnsignedInteger in2 = ((UnsignedInteger) connections[2].getValue()); -				Integer result = ((~in0.get() & ~in2.get()) | (~in1.get() & in2.get())); - -				return new UnsignedInteger(result); -			} -		} - -		@Override -		public int getArity() { -			return 3; -		} - -		@Override -		public String getName() { -			return "Mux4"; -		} -	} -} diff --git a/src/jcgp/backend/function/DigitalCircuitFunctions.java b/src/jcgp/backend/function/DigitalCircuitFunctions.java new file mode 100644 index 0000000..31cdf17 --- /dev/null +++ b/src/jcgp/backend/function/DigitalCircuitFunctions.java @@ -0,0 +1,504 @@ +package jcgp.backend.function; + +public class DigitalCircuitFunctions extends FunctionSet { +	 +	public DigitalCircuitFunctions() { +		name = "32-bit Logic"; +		functionList = new Function[]{ +				new ConstantZero(), +				new ConstantOne(), +				new WireA(), +				new WireB(), +				new NotA(), +				new NotB(), +				new And(), +				new AndNotA(), +				new AndNotB(), +				new Nor(), +				new Xor(), +				new Xnor(), +				new Or(), +				new OrNotA(), +				new OrNotB(), +				new Nand(), +				new Mux1(), +				new Mux2(), +				new Mux3(), +				new Mux4() +				}; +		 +		enableAll(); +	} +	 +	public static class ConstantZero extends Function { +		@Override +		public UnsignedInteger run(Object... args) { +			return new UnsignedInteger(0); +		} + +		@Override +		public int getArity() { +			return 0; +		} + +		@Override +		public String toString() { +			return "0"; +		} +	} +	 +	public static class ConstantOne extends Function { +		@Override +		public UnsignedInteger run(Object... args) { +			return new UnsignedInteger(0xFFFF); +		} + +		@Override +		public int getArity() { +			return 0; +		} + +		@Override +		public String toString() { +			return "1"; +		} +	} +	 +	public static class WireA extends Function { +		@Override +		public UnsignedInteger run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " in but arity is " + getArity() + "."); +			} else { +				return ((UnsignedInteger) args[0]); +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Wire A"; +		} +	} +	 +	public static class WireB extends Function { +		@Override +		public UnsignedInteger run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " in but arity is " + getArity() + "."); +			} else { +				return ((UnsignedInteger) args[1]); +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Wire B"; +		} +	} +	 +	public static class NotA extends Function { +		@Override +		public UnsignedInteger run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " in but arity is " + getArity() + "."); +			} else { +				return new UnsignedInteger(~((UnsignedInteger) args[0]).get()); +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Not A"; +		} +	} +	 +	public static class NotB extends Function { +		@Override +		public UnsignedInteger run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " in but arity is " + getArity() + "."); +			} else { +				return new UnsignedInteger(~((UnsignedInteger) args[1]).get()); +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Not B"; +		} +	} +	 +	public static class And extends Function { +		@Override +		public UnsignedInteger run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " in but arity is " + getArity() + "."); +			} else { +				UnsignedInteger in0 = ((UnsignedInteger) args[0]); +				UnsignedInteger in1 = ((UnsignedInteger) args[1]); +				Integer result = in0.get() & in1.get(); +				 +				return new UnsignedInteger(result); +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "And"; +		} +	} +	 +	public static class AndNotA extends Function { +		@Override +		public UnsignedInteger run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " in but arity is " + getArity() + "."); +			} else { +				UnsignedInteger in0 = ((UnsignedInteger) args[0]); +				UnsignedInteger in1 = ((UnsignedInteger) args[1]); +				Integer result = ~(in0.get()) & in1.get(); +				 +				return new UnsignedInteger(result); +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "And !A"; +		} +	} +	 +	public static class AndNotB extends Function { +		@Override +		public UnsignedInteger run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " in but arity is " + getArity() + "."); +			} else { +				UnsignedInteger in0 = ((UnsignedInteger) args[0]); +				UnsignedInteger in1 = ((UnsignedInteger) args[1]); +				Integer result = in0.get() & ~(in1.get()); +				 +				return new UnsignedInteger(result); +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "And !B"; +		} +	} +	 +	public static class Nor extends Function { +		@Override +		public UnsignedInteger run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " in but arity is " + getArity() + "."); +			} else { +				UnsignedInteger in0 = ((UnsignedInteger) args[0]); +				UnsignedInteger in1 = ((UnsignedInteger) args[1]); +				Integer result = in0.get() | in1.get(); + +				return new UnsignedInteger(~result); +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Nor"; +		} +	} +	 +	public static class Xor extends Function { +		@Override +		public UnsignedInteger run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " in but arity is " + getArity() + "."); +			} else { +				UnsignedInteger in0 = ((UnsignedInteger) args[0]); +				UnsignedInteger in1 = ((UnsignedInteger) args[1]); +				Integer result = in0.get() ^ in1.get(); + +				return new UnsignedInteger(result); +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Xor"; +		} +	} +	 +	public static class Xnor extends Function { +		@Override +		public UnsignedInteger run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " in but arity is " + getArity() + "."); +			} else { +				UnsignedInteger in0 = ((UnsignedInteger) args[0]); +				UnsignedInteger in1 = ((UnsignedInteger) args[1]); +				Integer result = in0.get() ^ in1.get(); + +				return new UnsignedInteger(~result); +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Xnor"; +		} +	} +	 +	public static class Or extends Function { +		@Override +		public UnsignedInteger run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " in but arity is " + getArity() + "."); +			} else { +				UnsignedInteger in0 = ((UnsignedInteger) args[0]); +				UnsignedInteger in1 = ((UnsignedInteger) args[1]); +				Integer result = in0.get() | in1.get(); + +				return new UnsignedInteger(result); +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Or"; +		} +	} +	 +	public static class OrNotA extends Function { +		@Override +		public UnsignedInteger run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " in but arity is " + getArity() + "."); +			} else { +				UnsignedInteger in0 = ((UnsignedInteger) args[0]); +				UnsignedInteger in1 = ((UnsignedInteger) args[1]); +				Integer result = ~in0.get() | in1.get(); + +				return new UnsignedInteger(result); +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Or !A"; +		} +	} +	 +	public static class OrNotB extends Function { +		@Override +		public UnsignedInteger run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " in but arity is " + getArity() + "."); +			} else { +				UnsignedInteger in0 = ((UnsignedInteger) args[0]); +				UnsignedInteger in1 = ((UnsignedInteger) args[1]); +				Integer result = in0.get() | ~in1.get(); + +				return new UnsignedInteger(result); +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Or !B"; +		} +	} + +	public static class Nand extends Function { +		@Override +		public UnsignedInteger run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " in but arity is " + getArity() + "."); +			} else { +				UnsignedInteger in0 = ((UnsignedInteger) args[0]); +				UnsignedInteger in1 = ((UnsignedInteger) args[1]); +				Integer result = in0.get() & in1.get(); + +				return new UnsignedInteger(~result); +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Nand"; +		} +	} +	 +	public static class Mux1 extends Function { +		@Override +		public UnsignedInteger run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " in but arity is " + getArity() + "."); +			} else { +				UnsignedInteger in0 = ((UnsignedInteger) args[0]); +				UnsignedInteger in1 = ((UnsignedInteger) args[1]); +				UnsignedInteger in2 = ((UnsignedInteger) args[2]); +				Integer result = ((in0.get() & ~in2.get()) | (in1.get() & in2.get())); + +				return new UnsignedInteger(result); +			} +		} + +		@Override +		public int getArity() { +			return 3; +		} + +		@Override +		public String toString() { +			return "Mux1"; +		} +	} +	 +	public static class Mux2 extends Function { +		@Override +		public UnsignedInteger run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " in but arity is " + getArity() + "."); +			} else { +				UnsignedInteger in0 = ((UnsignedInteger) args[0]); +				UnsignedInteger in1 = ((UnsignedInteger) args[1]); +				UnsignedInteger in2 = ((UnsignedInteger) args[2]); +				Integer result = ((in0.get() & ~in2.get()) | (~in1.get() & in2.get())); + +				return new UnsignedInteger(result); +			} +		} + +		@Override +		public int getArity() { +			return 3; +		} + +		@Override +		public String toString() { +			return "Mux2"; +		} +	} +	 +	public static class Mux3 extends Function { +		@Override +		public UnsignedInteger run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " in but arity is " + getArity() + "."); +			} else { +				UnsignedInteger in0 = ((UnsignedInteger) args[0]); +				UnsignedInteger in1 = ((UnsignedInteger) args[1]); +				UnsignedInteger in2 = ((UnsignedInteger) args[2]); +				Integer result = ((~in0.get() & ~in2.get()) | (in1.get() & in2.get())); + +				return new UnsignedInteger(result); +			} +		} + +		@Override +		public int getArity() { +			return 3; +		} + +		@Override +		public String toString() { +			return "Mux3"; +		} +	} +	 +	public static class Mux4 extends Function { +		@Override +		public UnsignedInteger run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " in but arity is " + getArity() + "."); +			} else { +				UnsignedInteger in0 = ((UnsignedInteger) args[0]); +				UnsignedInteger in1 = ((UnsignedInteger) args[1]); +				UnsignedInteger in2 = ((UnsignedInteger) args[2]); +				Integer result = ((~in0.get() & ~in2.get()) | (~in1.get() & in2.get())); + +				return new UnsignedInteger(result); +			} +		} + +		@Override +		public int getArity() { +			return 3; +		} + +		@Override +		public String toString() { +			return "Mux4"; +		} +	} +} diff --git a/src/jcgp/backend/function/DoubleArithmetic.java b/src/jcgp/backend/function/DoubleArithmetic.java deleted file mode 100644 index ce4826f..0000000 --- a/src/jcgp/backend/function/DoubleArithmetic.java +++ /dev/null @@ -1,589 +0,0 @@ -package jcgp.backend.function; - -import jcgp.backend.population.Connection; - -public class DoubleArithmetic extends FunctionSet { -	 -	public final static double DIVISION_LIMIT = 0.0001; -	 -	public DoubleArithmetic() { -		name = "Double Arithmetic"; -		functionList = new Function[]{ -				new Absolute(), -				new SquareRoot(), -				new Reciprocal(), -				new Sine(), -				new Cosine(), -				new Tangent(), -				new Exponential(), -				new HyperbolicSine(), -				new HyperbolicCosine(), -				new HyperbolicTangent(), -				new NaturalLog(), -				new LogBaseTen(), -				new SineAB(), -				new CosineAB(), -				new Hypotenuse(), -				new Power(), -				new Addition(), -				new Subtraction(), -				new Multiplication(), -				new Division()}; -		 -		enableAll(); -	} -	 -	/** -	 * Absolute returns the positive value of input 0. -	 *  -	 * @see Math.abs() -	 */ -	public static class Absolute extends Function { -		@Override -		public Double run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				Double in0 = ((Double) connections[0].getValue()); -				return Math.abs(in0); -			} -		} - -		@Override -		public int getArity() { -			return 1; -		} - -		@Override -		public String getName() { -			return "Absolute"; -		} -	} -	 -	/** -	 * Protected square root function, returns the square root of the absolute -	 * value of input 0. -	 *  -	 * @see Math.abs(), Math.sqrt() -	 */ -	public static class SquareRoot extends Function { -		@Override -		public Double run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				Double in0 = ((Double) connections[0].getValue()); -				return Math.sqrt(Math.abs(in0)); -			} -		} - -		@Override -		public int getArity() { -			return 1; -		} - -		@Override -		public String getName() { -			return "Square root"; -		} -	} -	 -	/** -	 * Protected reciprocal function, returns (1 / input 0). If input 0 is less than -	 * {@link DoubleArithmetic.}DIVISION_LIMIT, this returns it unchanged. -	 * -	 */ -	public static class Reciprocal extends Function { -		@Override -		public Double run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				Double in0 = ((Double) connections[0].getValue()); -				return in0 < DIVISION_LIMIT ? in0 : (1 / in0); -			} -		} - -		@Override -		public int getArity() { -			return 1; -		} - -		@Override -		public String getName() { -			return "Reciprocal"; -		} -	} -	 -	/** -	 * Sine function, in radians. -	 * -	 * @see Math.sin() -	 */ -	public static class Sine extends Function { -		@Override -		public Double run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				Double in0 = ((Double) connections[0].getValue()); -				return Math.sin(in0); -			} -		} - -		@Override -		public int getArity() { -			return 1; -		} - -		@Override -		public String getName() { -			return "Sin"; -		} -	} -	 -	/** -	 * Cosine function, in radians. -	 * -	 * @see Math.cos() -	 */ -	public static class Cosine extends Function { -		@Override -		public Double run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				Double in0 = ((Double) connections[0].getValue()); -				return Math.cos(in0); -			} -		} - -		@Override -		public int getArity() { -			return 1; -		} - -		@Override -		public String getName() { -			return "Cos"; -		} -	} -	 -	/** -	 * Protected tangent function, in radians. Returns the tangent of input 0. -	 * If input 0 is less than {@link DoubleArithmetic.}DIVISION_LIMIT,  -	 * this returns it unchanged. -	 * -	 * @see Math.tan() -	 */ -	public static class Tangent extends Function { -		@Override -		public Double run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				Double in0 = ((Double) connections[0].getValue()); -				return in0 < DIVISION_LIMIT ? in0 : Math.tan(in0); -			} -		} - -		@Override -		public int getArity() { -			return 1; -		} - -		@Override -		public String getName() { -			return "Tan"; -		} -	} -	 -	/** -	 * Exponential function. Returns the exponential of input 0. -	 * -	 * @see Math.exp() -	 */ -	public static class Exponential extends Function { -		@Override -		public Double run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				Double in0 = ((Double) connections[0].getValue()); -				return Math.exp(in0); -			} -		} - -		@Override -		public int getArity() { -			return 1; -		} - -		@Override -		public String getName() { -			return "Exp"; -		} -	} -	 -	/** -	 * Returns the hyperbolic sine of input 0. -	 * -	 * @see Math.sinh() -	 */ -	public static class HyperbolicSine extends Function { -		@Override -		public Double run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				Double in0 = ((Double) connections[0].getValue()); -				return Math.sinh(in0); -			} -		} - -		@Override -		public int getArity() { -			return 1; -		} - -		@Override -		public String getName() { -			return "Sinh"; -		} -	} -	 -	/** -	 * Returns the hyperbolic cosine of input 0. -	 * -	 * @see Math.cosh() -	 */ -	public static class HyperbolicCosine extends Function { -		@Override -		public Double run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				Double in0 = ((Double) connections[0].getValue()); -				return Math.cosh(in0); -			} -		} - -		@Override -		public int getArity() { -			return 1; -		} - -		@Override -		public String getName() { -			return "Cosh"; -		} -	} -	 -	/** -	 * Returns the hyperbolic tangent of input 0. -	 * -	 * @see Math.tanh() -	 */ -	public static class HyperbolicTangent extends Function { -		@Override -		public Double run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				Double in0 = ((Double) connections[0].getValue()); -				return Math.tanh(in0); -			} -		} - -		@Override -		public int getArity() { -			return 1; -		} - -		@Override -		public String getName() { -			return "Tanh"; -		} -	} -	 -	/** -	 * Protected natural log function. Returns the natural log of the absolute -	 * value of input 0. If input 0 is less than {@link DoubleArithmetic.}DIVISION_LIMIT,  -	 * this returns it unchanged. -	 * -	 * @see Math.log(), Math.abs() -	 */ -	public static class NaturalLog extends Function { -		@Override -		public Double run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				Double in0 = ((Double) connections[0].getValue()); -				return in0 < DIVISION_LIMIT ? in0 : Math.log(Math.abs(in0)); -			} -		} - -		@Override -		public int getArity() { -			return 1; -		} - -		@Override -		public String getName() { -			return "Ln"; -		} -	} -	 -	/** -	 * Protected log base 10 function. Returns the log to base 10 the absolute -	 * value of input 0. If input 0 is less than {@link DoubleArithmetic.}DIVISION_LIMIT,  -	 * this returns it unchanged. -	 * -	 * @see Math.log10(), Math.abs() -	 */ -	public static class LogBaseTen extends Function { -		@Override -		public Double run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				Double in0 = ((Double) connections[0].getValue()); -				return in0 < DIVISION_LIMIT ? in0 : Math.log10(Math.abs(in0)); -			} -		} - -		@Override -		public int getArity() { -			return 1; -		} - -		@Override -		public String getName() { -			return "Log"; -		} -	} -	 -	/** -	 * Sine of sum. Returns the sine of the sum of inputs 0 and 1. -	 * -	 * @see Math.sin() -	 */ -	public static class SineAB extends Function { -		@Override -		public Double run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				Double in0 = ((Double) connections[0].getValue()); -				Double in1 = ((Double) connections[1].getValue()); -				return Math.sin(in0 + in1); -			} -		} - -		@Override -		public int getArity() { -			return 2; -		} - -		@Override -		public String getName() { -			return "Sin(a+b)"; -		} -	} -	 -	/** -	 * Cosine of sum. Returns the cosine of the sum of inputs 0 and 1. -	 * -	 * @see Math.cos() -	 */ -	public static class CosineAB extends Function { -		@Override -		public Double run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				Double in0 = ((Double) connections[0].getValue()); -				Double in1 = ((Double) connections[1].getValue()); -				return Math.cos(in0 + in1); -			} -		} - -		@Override -		public int getArity() { -			return 2; -		} - -		@Override -		public String getName() { -			return "Cos(a+b)"; -		} -	} -	 -	/** -	 * Hypotenuse function. Returns the square root of input 0 squared -	 * plus input 1 squared. -	 * -	 * @see Math.hypot() -	 */ -	public static class Hypotenuse extends Function { -		@Override -		public Double run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				Double in0 = ((Double) connections[0].getValue()); -				Double in1 = ((Double) connections[1].getValue()); -				return Math.hypot(in0, in1); -			} -		} - -		@Override -		public int getArity() { -			return 2; -		} - -		@Override -		public String getName() { -			return "Hypotenuse"; -		} -	} -	 -	/** -	 * Power function. Returns the absolute value of input 0 to the power of input 1. -	 * -	 * @see Math.abs(), Math.pow -	 */ -	public static class Power extends Function { -		@Override -		public Double run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				Double in0 = ((Double) connections[0].getValue()); -				Double in1 = ((Double) connections[1].getValue()); -				return Math.pow(Math.abs(in0), in1); -			} -		} - -		@Override -		public int getArity() { -			return 2; -		} - -		@Override -		public String getName() { -			return "Power"; -		} -	} -	 -	/** -	 * Addition returns the sum of inputs 0 and 1. -	 * -	 */ -	public static class Addition extends Function { -		@Override -		public Double run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				Double in0 = ((Double) connections[0].getValue()); -				Double in1 = ((Double) connections[1].getValue()); -				return in0 + in1; -			} -		} - -		@Override -		public int getArity() { -			return 2; -		} - -		@Override -		public String getName() { -			return "Addition"; -		} -	} - -	/** -	 * Subtraction returns the difference between inputs 0 and 1. -	 * -	 */ -	public static class Subtraction extends Function { -		@Override -		public Double run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				Double in0 = ((Double) connections[0].getValue()); -				Double in1 = ((Double) connections[1].getValue()); -				return in0 - in1; -			} -		} - -		@Override -		public int getArity() { -			return 2; -		} - -		@Override -		public String getName() { -			return "Subtraction"; -		} -	} - -	/** -	 * Multiplication returns the product of inputs 0 and 1. -	 * -	 */ -	public static class Multiplication extends Function { -		@Override -		public Double run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				Double in0 = ((Double) connections[0].getValue()); -				Double in1 = ((Double) connections[1].getValue()); -				return in0 * in1; -			}  -		} - -		@Override -		public int getArity() { -			return 2; -		} - -		@Override -		public String getName() { -			return "Multiplication"; -		} -	} - -	/** -	 * Protected division, returns the quotient of input 0 (the dividend) and input 1 (the divisor). -	 * If the divisor is less than {@link DoubleArithmetic.}DIVISION_LIMIT, this returns the it unchanged. -	 * -	 */ -	public static class Division extends Function { -		@Override -		public Double run(Connection... connections) { -			if (connections.length < getArity()) { -				throw new IllegalArgumentException(getName() + " received " + connections.length + " connections but arity is " + getArity() + "."); -			} else { -				Double in0 = ((Double) connections[0].getValue()); -				Double in1 = ((Double) connections[1].getValue()); - -				return in1 < DIVISION_LIMIT ? in0 : (in0 / in1); -			}  -		} - -		@Override -		public int getArity() { -			return 2; -		} - -		@Override -		public String getName() { -			return "Division"; -		} -	} -} diff --git a/src/jcgp/backend/function/Function.java b/src/jcgp/backend/function/Function.java index 30bbcf0..fdacac0 100644 --- a/src/jcgp/backend/function/Function.java +++ b/src/jcgp/backend/function/Function.java @@ -1,13 +1,28 @@  package jcgp.backend.function; -import jcgp.backend.exceptions.InvalidArgumentsException; -import jcgp.backend.population.Connection; - +/** + * Function is a callback wrapper.  + * <br><br> + * A concrete implementation of Function overrides {@code run()} to perform + * any arbitrary operation on the arguments specified. It must also override + * {@code getArity()} to return the function arity. + *  + *  + * @author Eduardo Pedroni + * + */  public abstract class Function { -			 -	public abstract Object run(Connection ... connections) throws InvalidArgumentsException; -	public abstract int getArity(); +	/** +	 * Executes the function. +	 *  +	 * @param args the function arguments +	 * @return the function result +	 */ +	public abstract Object run(Object... args); -	public abstract String getName();	 +	/** +	 * @return the arity of the function. +	 */ +	public abstract int getArity();  } diff --git a/src/jcgp/backend/function/FunctionSet.java b/src/jcgp/backend/function/FunctionSet.java index 1712b51..926ed68 100644 --- a/src/jcgp/backend/function/FunctionSet.java +++ b/src/jcgp/backend/function/FunctionSet.java @@ -6,6 +6,22 @@ import java.util.Iterator;  /** + * FunctionSet encapsulates a group of functions. This is usually done to + * simplify the implementation of problem types. + * <br><br> + * FunctionSet contains a variety of useful methods for acquiring general + * information, such as the maximum arity across all functions and the total + * number of functions. + * <br><br> + * In addition, FunctionSet offers the ability to enable and disable functions. + * Accessing the functions through {@code getAllowedFunction()} will return + * allowed functions only, providing an easy way to control which functions + * can be used in mutations. + * <br><br> + * An implementation of FunctionSet must simply set the name field and initialise + * the functionList array with all of the functions. It is advisable to call + * {@code enableAll()} to enable all functions once the array is initialised. + *    *    * @author Eduardo Pedroni   * @@ -15,25 +31,55 @@ public abstract class FunctionSet {  		protected ArrayList<Integer> allowedFunctions;  		protected String name; +		/** +		 * @return the number of currently allowed functions. +		 */  		public int getAllowedFunctionCount() {  			return allowedFunctions.size();  		} +		/** +		 * @return the total number of functions, including disabled ones. +		 */  		public int getTotalFunctionCount() {  			return functionList.length;  		} +		/** +		 * Returns an allowed function. This throws an +		 * ArrayIndexOutOfBoundsException if the supplied  +		 * index is beyond the count of allowed functions. +		 *  +		 * @param index the allowed function index. +		 * @return the allowed function object. +		 */  		public Function getAllowedFunction(int index) {  			return functionList[allowedFunctions.get(index)];  		} +		/** +		 * Returns a function from the complete collection, +		 * enabled or disabled alike. This throws an +		 * ArrayIndexOutOfBoundsException if the supplied  +		 * index is beyond the count of allowed functions. +		 *  +		 * @param index the function index. +		 * @return the function object. +		 */  		public Function getFunction(int index) {  			return functionList[index];  		} +		/** +		 * Computes and returns the maximum arity out of +		 * all the function, enabled or disabled. +		 *  +		 * @return +		 */  		public int getMaxArity(){  			int arity = 0;  			for (Function function : functionList) { +				// if a higher arity is found, store it  				if (function.getArity() > arity) {  					arity = function.getArity();  				} @@ -41,25 +87,39 @@ public abstract class FunctionSet {  			return arity;  		} -		public String getName() { -			return name; -		} -		 +		/** +		 * Disables the indexed function. If the function +		 * is already disabled, this does nothing. +		 *  +		 * @param index the function to disable. +		 */  		public void disableFunction(int index) { +			/* +			 * allowedFunctions is a list of the indices of all allowed functions,  +			 * as addressed in functionList. This method iterates through the whole +			 * list of allowed functions and removes any elements which are equal +			 * to the specified index. +			 */  			if (index < functionList.length) {  				for (Iterator<Integer> iterator = allowedFunctions.iterator(); iterator.hasNext();) {  					int function = iterator.next();  					if (function == index) {  						iterator.remove(); -						break;  					}  				}  			} else { -				throw new IndexOutOfBoundsException("Function " + index + " does not exist, the set only has " + functionList.length + " functions."); +				throw new ArrayIndexOutOfBoundsException("Function " + index + " does not exist, the set only has " + functionList.length + " functions.");  			}  		} +		/** +		 * Disables the indexed function. If the function is +		 * already enabled, this does nothing.  +		 *  +		 * @param index the function to disable. +		 */  		public void enableFunction(int index) { +			// add the specified index to the list of allowed indices  			if (!allowedFunctions.contains(index)) {  				allowedFunctions.add(index);  				Collections.sort(allowedFunctions); @@ -71,16 +131,26 @@ public abstract class FunctionSet {  			return name;  		} -		public boolean isEnabled(Function f) { +		/** +		 * Checks if a specified function is enabled. If the function +		 * does not belong in the FunctionSet, this returns false. +		 *  +		 * @param function the function to check. +		 * @return true if the function is enabled. +		 */ +		public boolean isEnabled(Function function) {  			for (int i = 0; i < allowedFunctions.size(); i++) { -				if (functionList[allowedFunctions.get(i)] == f) { +				if (functionList[allowedFunctions.get(i)] == function) {  					return true;  				}  			}  			return false;  		} -		protected void enableAll() { +		/** +		 * Enables all functions.  +		 */ +		public void enableAll() {  			allowedFunctions = new ArrayList<Integer>();  			for (int i = 0; i < functionList.length; i++) {  				allowedFunctions.add(i); diff --git a/src/jcgp/backend/function/SymbolicRegressionFunctions.java b/src/jcgp/backend/function/SymbolicRegressionFunctions.java new file mode 100644 index 0000000..a35f258 --- /dev/null +++ b/src/jcgp/backend/function/SymbolicRegressionFunctions.java @@ -0,0 +1,587 @@ +package jcgp.backend.function; + +public class SymbolicRegressionFunctions extends FunctionSet { +	 +	public final static double DIVISION_LIMIT = 0.0001; +	 +	public SymbolicRegressionFunctions() { +		name = "Symbolic regression functions"; +		functionList = new Function[] { +				new Absolute(), +				new SquareRoot(), +				new Reciprocal(), +				new Sine(), +				new Cosine(), +				new Tangent(), +				new Exponential(), +				new HyperbolicSine(), +				new HyperbolicCosine(), +				new HyperbolicTangent(), +				new NaturalLog(), +				new LogBaseTen(), +				new SineAB(), +				new CosineAB(), +				new Hypotenuse(), +				new Power(), +				new Addition(), +				new Subtraction(), +				new Multiplication(), +				new Division()}; +		 +		enableAll(); +	} +	 +	/** +	 * Absolute returns the positive value of input 0. +	 *  +	 * @see Math +	 */ +	public static class Absolute extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				return Math.abs(in0); +			} +		} + +		@Override +		public int getArity() { +			return 1; +		} + +		@Override +		public String toString() { +			return "Absolute"; +		} +	} +	 +	/** +	 * Protected square root function, returns the square root of the absolute +	 * value of input 0. +	 *  +	 * @see Math +	 */ +	public static class SquareRoot extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				return Math.sqrt(Math.abs(in0)); +			} +		} + +		@Override +		public int getArity() { +			return 1; +		} + +		@Override +		public String toString() { +			return "Square root"; +		} +	} +	 +	/** +	 * Protected reciprocal function, returns (1 / input 0). If input 0 is less than +	 * {@code DoubleArithmetic.DIVISION_LIMIT}, this returns it unchanged. +	 * +	 */ +	public static class Reciprocal extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				return in0 < DIVISION_LIMIT ? in0 : (1 / in0); +			} +		} + +		@Override +		public int getArity() { +			return 1; +		} + +		@Override +		public String toString() { +			return "Reciprocal"; +		} +	} +	 +	/** +	 * Sine function, in radians. +	 * +	 * @see Math +	 */ +	public static class Sine extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				return Math.sin(in0); +			} +		} + +		@Override +		public int getArity() { +			return 1; +		} + +		@Override +		public String toString() { +			return "Sin"; +		} +	} +	 +	/** +	 * Cosine function, in radians. +	 * +	 * @see Math +	 */ +	public static class Cosine extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				return Math.cos(in0); +			} +		} + +		@Override +		public int getArity() { +			return 1; +		} + +		@Override +		public String toString() { +			return "Cos"; +		} +	} +	 +	/** +	 * Protected tangent function, in radians. Returns the tangent of input 0. +	 * If input 0 is less than {@link DoubleArithmetic.}DIVISION_LIMIT,  +	 * this returns it unchanged. +	 * +	 * @see Math +	 */ +	public static class Tangent extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				return in0 < DIVISION_LIMIT ? in0 : Math.tan(in0); +			} +		} + +		@Override +		public int getArity() { +			return 1; +		} + +		@Override +		public String toString() { +			return "Tan"; +		} +	} +	 +	/** +	 * Exponential function. Returns the exponential of input 0. +	 * +	 * @see Math +	 */ +	public static class Exponential extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				return Math.exp(in0); +			} +		} + +		@Override +		public int getArity() { +			return 1; +		} + +		@Override +		public String toString() { +			return "Exp"; +		} +	} +	 +	/** +	 * Returns the hyperbolic sine of input 0. +	 * +	 * @see Math +	 */ +	public static class HyperbolicSine extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				return Math.sinh(in0); +			} +		} + +		@Override +		public int getArity() { +			return 1; +		} + +		@Override +		public String toString() { +			return "Sinh"; +		} +	} +	 +	/** +	 * Returns the hyperbolic cosine of input 0. +	 * +	 * @see Math +	 */ +	public static class HyperbolicCosine extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				return Math.cosh(in0); +			} +		} + +		@Override +		public int getArity() { +			return 1; +		} + +		@Override +		public String toString() { +			return "Cosh"; +		} +	} +	 +	/** +	 * Returns the hyperbolic tangent of input 0. +	 * +	 * @see Math +	 */ +	public static class HyperbolicTangent extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				return Math.tanh(in0); +			} +		} + +		@Override +		public int getArity() { +			return 1; +		} + +		@Override +		public String toString() { +			return "Tanh"; +		} +	} +	 +	/** +	 * Protected natural log function. Returns the natural log of the absolute +	 * value of input 0. If input 0 is less than {@link DoubleArithmetic.}DIVISION_LIMIT,  +	 * this returns it unchanged. +	 * +	 * @see Math +	 */ +	public static class NaturalLog extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				return in0 < DIVISION_LIMIT ? in0 : Math.log(Math.abs(in0)); +			} +		} + +		@Override +		public int getArity() { +			return 1; +		} + +		@Override +		public String toString() { +			return "Ln"; +		} +	} +	 +	/** +	 * Protected log base 10 function. Returns the log to base 10 the absolute +	 * value of input 0. If input 0 is less than {@link DoubleArithmetic.}DIVISION_LIMIT,  +	 * this returns it unchanged. +	 * +	 * @see Math +	 */ +	public static class LogBaseTen extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				return in0 < DIVISION_LIMIT ? in0 : Math.log10(Math.abs(in0)); +			} +		} + +		@Override +		public int getArity() { +			return 1; +		} + +		@Override +		public String toString() { +			return "Log"; +		} +	} +	 +	/** +	 * Sine of sum. Returns the sine of the sum of inputs 0 and 1. +	 * +	 * @see Math +	 */ +	public static class SineAB extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				Double in1 = ((Double) args[1]); +				return Math.sin(in0 + in1); +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Sin(a+b)"; +		} +	} +	 +	/** +	 * Cosine of sum. Returns the cosine of the sum of inputs 0 and 1. +	 * +	 * @see Math +	 */ +	public static class CosineAB extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				Double in1 = ((Double) args[1]); +				return Math.cos(in0 + in1); +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Cos(a+b)"; +		} +	} +	 +	/** +	 * Hypotenuse function. Returns the square root of input 0 squared +	 * plus input 1 squared. +	 * +	 * @see Math +	 */ +	public static class Hypotenuse extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				Double in1 = ((Double) args[1]); +				return Math.hypot(in0, in1); +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Hypotenuse"; +		} +	} +	 +	/** +	 * Power function. Returns the absolute value of input 0 to the power of input 1. +	 * +	 * @see Math +	 */ +	public static class Power extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				Double in1 = ((Double) args[1]); +				return Math.pow(Math.abs(in0), in1); +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Power"; +		} +	} +	 +	/** +	 * Addition returns the sum of inputs 0 and 1. +	 * +	 */ +	public static class Addition extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				Double in1 = ((Double) args[1]); +				return in0 + in1; +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Addition"; +		} +	} + +	/** +	 * Subtraction returns the difference between inputs 0 and 1. +	 * +	 */ +	public static class Subtraction extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				Double in1 = ((Double) args[1]); +				return in0 - in1; +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Subtraction"; +		} +	} + +	/** +	 * Multiplication returns the product of inputs 0 and 1. +	 * +	 */ +	public static class Multiplication extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				Double in1 = ((Double) args[1]); +				return in0 * in1; +			}  +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Multiplication"; +		} +	} + +	/** +	 * Protected division, returns the quotient of input 0 (the dividend) and input 1 (the divisor). +	 * If the divisor is less than {@code DoubleArithmetic.DIVISION_LIMIT}, this returns it unchanged. +	 * +	 */ +	public static class Division extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				Double in1 = ((Double) args[1]); + +				return in1 < DIVISION_LIMIT ? in0 : (in0 / in1); +			}  +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Division"; +		} +	} +} diff --git a/src/jcgp/backend/function/TravellingSalesmanFunctions.java b/src/jcgp/backend/function/TravellingSalesmanFunctions.java new file mode 100644 index 0000000..472b7ad --- /dev/null +++ b/src/jcgp/backend/function/TravellingSalesmanFunctions.java @@ -0,0 +1,396 @@ +package jcgp.backend.function; + +public class TravellingSalesmanFunctions extends FunctionSet { +		 +	public TravellingSalesmanFunctions() { +		name = "Travelling salesman functions"; +		functionList = new Function[]{ +				new SquareRoot(), +				new Square(), +				new Cube(), +				new ScaledExponential(), +				new AbsoluteSineAB(), +				new AbsoluteCosineAB(), +				new AbsoluteHyperbolicTangentAB(), +				new ScaledHypotenuse(), +				new ScaledAddition(), +				new SymmetricSubtraction(), +				new Multiplication(), +				new BoundedDivision() }; +		 +		enableAll(); +	} +	 +	/** +	 * Protected square root function, returns the square root of the absolute +	 * value of input 0. +	 *  +	 * @see Math +	 */ +	public static class SquareRoot extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				return Math.sqrt(Math.abs(in0)); +			} +		} + +		@Override +		public int getArity() { +			return 1; +		} + +		@Override +		public String toString() { +			return "Square root"; +		} +	} +	 +	/** +	 * Square function, returns the square of the +	 * value of input 0. +	 *  +	 */ +	public static class Square extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				return in0 * in0; +			} +		} + +		@Override +		public int getArity() { +			return 1; +		} + +		@Override +		public String toString() { +			return "Square"; +		} +	} +	 +	/** +	 * Cube function, returns the value of input 0 cubed. +	 *  +	 */ +	public static class Cube extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				return in0 * in0 * in0; +			} +		} + +		@Override +		public int getArity() { +			return 1; +		} + +		@Override +		public String toString() { +			return "Cube"; +		} +	} +	 +	/** +	 * Scaled exponential function. Returns the exponential of input 0  +	 * scaled to the range 0 < x < 1. +	 * +	 * @see Math +	 */ +	public static class ScaledExponential extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				return (Math.exp(in0) - 1) / (Math.exp(-1) - 1); +			} +		} + +		@Override +		public int getArity() { +			return 1; +		} + +		@Override +		public String toString() { +			return "Scaled Exp"; +		} +	} +	 +	/** +	 * Sine of sum. Returns the absolute value of the sine  +	 * of the sum of inputs 0 and 1, in radians. +	 * +	 * @see Math +	 */ +	public static class AbsoluteSineAB extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				Double in1 = ((Double) args[1]); +				return Math.abs(Math.sin(in0 + in1)); +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Abs Sin(a+b)"; +		} +	} +	 +	/** +	 * Cosine of sum. Returns the absolute value of the cosine  +	 * of the sum of inputs 0 and 1, in radians. +	 * +	 * @see Math +	 */ +	public static class AbsoluteCosineAB extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				Double in1 = ((Double) args[1]); +				return Math.abs(Math.cos(in0 + in1)); +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Abs Cos(a+b)"; +		} +	} +	 +	/** +	 * Hyperbolic tangent of sum. Returns the absolute value of the sine  +	 * of the sum of inputs 0 and 1, in radians. +	 * +	 * @see Math +	 */ +	public static class AbsoluteHyperbolicTangentAB extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				Double in1 = ((Double) args[1]); +				return Math.abs(Math.tanh(in0 + in1)); +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Abs Tanh(a+b)"; +		} +	} +	 +	/** +	 * Scaled hypotenuse function. Returns the square root of input 0 squared +	 * plus input 1 squared, scaled to the range 0 < x < 1. +	 * +	 * @see Math +	 */ +	public static class ScaledHypotenuse extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				Double in1 = ((Double) args[1]); +				return Math.hypot(in0, in1) / Math.sqrt(2); +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Scaled Hypotenuse"; +		} +	} +	 +	/** +	 * Scaled addition returns the sum of inputs 0 and 1 scaled +	 * to the range 0 < x < 1. +	 * +	 */ +	public static class ScaledAddition extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				Double in1 = ((Double) args[1]); +				return (in0 + in1) / 2.0; +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Scaled Addition"; +		} +	} + +	/** +	 * Symmetric subtraction returns the absolute difference between inputs 0 and 1, +	 * scaled to the range 0 < x < 1. +	 * +	 */ +	public static class SymmetricSubtraction extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				Double in1 = ((Double) args[1]); +				return Math.abs(in0 - in1) / 2.0; +			} +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Symmetric Subtraction"; +		} +	} + +	/** +	 * Multiplication returns the product of inputs 0 and 1. +	 * +	 */ +	public static class Multiplication extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				Double in1 = ((Double) args[1]); +				return in0 * in1; +			}  +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Multiplication"; +		} +	} +	 +	/** +	 * Multiplication returns the product of inputs 0 and 1, squared. +	 * +	 */ +	public static class SquaredMultiplication extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = ((Double) args[0]); +				Double in1 = ((Double) args[1]); +				return in0 * in1 * in0 * in1; +			}  +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Squared Multiplication"; +		} +	} + +	/** +	 * Bounded division, returns the quotient of the two inputs where the larger +	 * is the denominator.  +	 * +	 */ +	public static class BoundedDivision extends Function { +		@Override +		public Double run(Object... args) { +			if (args.length < getArity()) { +				throw new IllegalArgumentException(toString() + " received " + args.length + " arguments but arity is " + getArity() + "."); +			} else { +				Double in0 = Math.abs((Double) args[0]); +				Double in1 = Math.abs((Double) args[1]); +				Double result; +				 +				if (in1 < 1e-10) { +					result = 1.0; +				} else if (in1 > in0) { +					result = in0 / in1; +				} else { +					result = in1 / in0; +				} + +				return result; +			}  +		} + +		@Override +		public int getArity() { +			return 2; +		} + +		@Override +		public String toString() { +			return "Bounded Division"; +		} +	} +} diff --git a/src/jcgp/backend/modules/Module.java b/src/jcgp/backend/modules/Module.java index a6b4d73..7efbf3a 100644 --- a/src/jcgp/backend/modules/Module.java +++ b/src/jcgp/backend/modules/Module.java @@ -2,8 +2,22 @@ package jcgp.backend.modules;  import jcgp.backend.resources.parameters.Parameter; +/** + * This interface defines the expected behaviour of a module. Specifically, a module + * is expected to be able to return a list of local parameters. When a user interface + * is used, it is expected to display the parameters of each module and allow user + * interaction for parameters which are not monitors. + *  + * @see Parameter + *  + * @author Eduardo Pedroni + * + */  public interface Module { +	/** +	 * @return a list of generic parameters exposed by the module. +	 */  	public abstract Parameter<?>[] getLocalParameters();  } diff --git a/src/jcgp/backend/modules/es/EvolutionaryStrategy.java b/src/jcgp/backend/modules/es/EvolutionaryStrategy.java index 8ab287d..70e3cd2 100644 --- a/src/jcgp/backend/modules/es/EvolutionaryStrategy.java +++ b/src/jcgp/backend/modules/es/EvolutionaryStrategy.java @@ -5,8 +5,42 @@ import jcgp.backend.modules.mutator.Mutator;  import jcgp.backend.population.Population;  import jcgp.backend.resources.Resources; +/** + * This interface specifies the required behaviour of an evolutionary strategy. The evolutionary + * strategy's job is to generate the next population of solutions. In JCGP this is done by modifying + * the provided population object rather than creating a new one.  + * <br><br> + * A typical implementation of EvolutionaryStratey iterates through the chromosomes + * in the population and selects the individual(s) to be promoted. It then uses + * {@code mutator.mutate()} to generically mutate the promoted individual(s). Parameter-dependent + * strategies can be implemented by accessing the parameters via the resources + * argument. + * <br><br> + * Parameters may be specified to control the implemented strategy. Any parameters + * returned by {@code getLocalParameters()} should be displayed by the user interface, + * if it is being used. See {@link Parameter} for more information.  + * <br><br> + * It is advisable to use {@code Resources.reportln()} and {@code Resources.report()} + * to print any relevant information. Note that reportln() and report() are affected + * by the report interval base parameter. Use {@code Resources.println()} and + * {@code Resources.print()} to print information regardless of the current generation. + * See {@link Resources} for more information. + *  + * @see Module + *  + * @author Eduardo Pedroni + * + */  public interface EvolutionaryStrategy extends Module { +	/** +	 * Performs the selection algorithm and uses the mutator to create +	 * the next generation of solutions. +	 *  +	 * @param population the population to evolve. +	 * @param mutator the mutator with which to mutate the promoted individuals. +	 * @param resources parameters and utilities for optional reference. +	 */  	public abstract void evolve(Population population, Mutator mutator, Resources resources);  } diff --git a/src/jcgp/backend/modules/es/MuPlusLambda.java b/src/jcgp/backend/modules/es/MuPlusLambda.java index 6a3883b..50bf265 100644 --- a/src/jcgp/backend/modules/es/MuPlusLambda.java +++ b/src/jcgp/backend/modules/es/MuPlusLambda.java @@ -9,41 +9,59 @@ import jcgp.backend.resources.parameters.Parameter;  import jcgp.backend.resources.parameters.ParameterStatus;  /** - * (μ + λ) EA. - *  + * (μ + λ)-ES + * <br><br> + * This strategy selects the μ fittest chromosomes from the population. + * The promoted individuals are copied into the new population and mutated + * λ times, but also carried forward unchanged. The total population size + * is μ + λ.  + * <br><br> + * Two integer parameters are used to control this strategy: parents + * and offspring. They are constrained in that they must always add up to + * the population size, and must never be smaller than 1. + * <br> + * One additional parameter, report, controls whether a detailed log of the + * algorithm's operation is to be printed or not. Reports respect the report + * interval base parameter.   *  + * @see EvolutionaryStrategy   * @author Eduardo Pedroni   *   */  public class MuPlusLambda implements EvolutionaryStrategy { -	private IntegerParameter parents, offspring; +	private IntegerParameter mu, lambda;  	private BooleanParameter report; +	/** +	 * Creates a new instance of MuPlusLambda.  +	 *  +	 * @param resources a reference to the experiment's resources. +	 */  	public MuPlusLambda(final Resources resources) { -		parents = new IntegerParameter(1, "Parents") { +		mu = new IntegerParameter(1, "Parents (μ)") {  			@Override  			public void validate(Number newValue) { -				if (newValue.intValue() + offspring.get() != resources.populationSize()) { +				if (newValue.intValue() + lambda.get() != resources.populationSize()) {  					status = ParameterStatus.INVALID;  					status.setDetails("Parents + offspring must equal population size.");  				} else if (newValue.intValue() <= 0) {  					status = ParameterStatus.INVALID; -					status.setDetails("EA needs at least 1 parent."); +					status.setDetails("ES needs at least 1 parent.");  				} else {  					status = ParameterStatus.VALID;  				}  			}  		}; -		offspring = new IntegerParameter(4, "Offspring") { +		lambda = new IntegerParameter(4, "Offspring (λ)") {  			@Override  			public void validate(Number newValue) { -				if (newValue.intValue() + parents.get() != resources.populationSize()) { +				if (newValue.intValue() + mu.get() != resources.populationSize()) {  					status = ParameterStatus.INVALID;  					status.setDetails("Parents + offspring must equal population size.");  				} else if (newValue.intValue() <= 0) {  					status = ParameterStatus.INVALID; -					status.setDetails("EA needs at least 1 offspring."); +					status.setDetails("ES needs at least 1 offspring.");  				} else {  					status = ParameterStatus.VALID;  				} @@ -58,32 +76,31 @@ public class MuPlusLambda implements EvolutionaryStrategy {  	}  	@Override -	public void evolve(Population population, Mutator mutator, Resources resources) { -		// select fittest chromosomes -		if (report.get()) resources.reportln("[ES] Selected chromosome: " + population.getFittestIndex()); -		 -		// create copies of fittest chromosome, mutate them -		for (int i = 0; i < resources.populationSize(); i++) { -			if (i != population.getFittestIndex()) { -				if (report.get()) resources.reportln("[ES] Copying fittest chromosome to population position " + i); -				population.copyChromosome(population.getFittestIndex(), i); -				if (report.get()) resources.reportln("[ES] Mutating copied chromosome"); -				mutator.mutate(population.getChromosome(i), resources); -			} +	public void evolve(Population population, Mutator mutator, Resources resources) {		 +		/* Population is sorted in ascending order of fitness, so leave the last +		 * mu chromosomes intact +		 */ +		for (int i = 0; i < resources.populationSize() - mu.get(); i++) { +			// select a random parent out of the lambda offspring individuals +			int randomParent = resources.populationSize() - 1 - resources.getRandomInt(mu.get()); +			if (report.get()) resources.reportln("[ES] Copying Chr " + randomParent + " to population position " + i); +			population.copyChromosome(randomParent, i); +			 +			// mutate selected chromosome +			if (report.get()) resources.reportln("[ES] Mutating copied chromosome"); +			mutator.mutate(population.getChromosome(i), resources);  		} -		if (report.get()) resources.reportln("[ES] Generation is complete."); -		 +		if (report.get()) resources.reportln("[ES] Generation is complete");  	}  	@Override  	public Parameter<?>[] getLocalParameters() { -		return new Parameter[] {parents, offspring, report}; +		return new Parameter[] {mu, lambda, report};  	}  	@Override  	public String toString() {  		return "(μ + λ)";  	} -	  } diff --git a/src/jcgp/backend/modules/es/TournamentSelection.java b/src/jcgp/backend/modules/es/TournamentSelection.java index 7cc9706..43fea81 100644 --- a/src/jcgp/backend/modules/es/TournamentSelection.java +++ b/src/jcgp/backend/modules/es/TournamentSelection.java @@ -1,35 +1,118 @@  package jcgp.backend.modules.es; +import java.util.Arrays; +  import jcgp.backend.modules.mutator.Mutator; +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.IntegerParameter;  import jcgp.backend.resources.parameters.Parameter; +import jcgp.backend.resources.parameters.ParameterStatus; +/** + * Tournament selection + * <br><br> + * This strategy generates a new population by selecting a specified number + * of chromosomes from the original population and selecting the fittest out + * of the isolated subset (the tournament). The selected individual is mutated + * using the specified mutator. This process is repeated until the new population + * is complete. + * <br><br> + * One integer parameter is used to control this strategy: tournament + * size. This must always be greater than 0 and smaller than or equal to the + * population size. Setting it to equal population size results in the same + * chromosome being selected for every tournament, and setting it to 1 leads + * to an effectively random search. + * <br> + * One additional parameter, report, controls whether a detailed log of the + * algorithm's operation is to be printed or not. Reports respect the report + * interval base parameter. + *  + * @see EvolutionaryStrategy + * @author Eduardo Pedroni + * + */  public class TournamentSelection implements EvolutionaryStrategy {  	private IntegerParameter tournamentSize; +	private BooleanParameter report; -	public TournamentSelection(Resources resources) {		 +	/** +	 * Creates a new instance of TournamentSelection.  +	 *  +	 * @param resources a reference to the experiment's resources. +	 */ +	public TournamentSelection(final Resources resources) {		  		tournamentSize = new IntegerParameter(1, "Tournament size") {  			@Override  			public void validate(Number newValue) { -				// TODO this +				if (newValue.intValue() <= 0) { +					status = ParameterStatus.INVALID; +					status.setDetails("Tournament size must be greater than 0."); +				} else if (newValue.intValue() > resources.populationSize()) { +					status = ParameterStatus.INVALID; +					status.setDetails("Tournament size must not be greater than the population size."); +				} else if (newValue.intValue() == 1) { +					status = ParameterStatus.WARNING; +					status.setDetails("A tournament size of 1 results in a random search."); +				} else if (newValue.intValue() == resources.populationSize()) { +					status = ParameterStatus.WARNING; +					status.setDetails("A tournament size equal to population size results in the same individual being selected every time."); +				} else { +					status = ParameterStatus.VALID; +				} +			} +		}; +		report = new BooleanParameter(false, "Report") { +			@Override +			public void validate(Boolean newValue) { +				// blank  			}  		};  	}  	@Override  	public Parameter<?>[] getLocalParameters() { -		return new Parameter[] {tournamentSize}; +		return new Parameter[] {tournamentSize, report};  	}  	@Override -	public void evolve(Population population, Mutator mutator, -			Resources parameters) { -		tournamentSize.set(tournamentSize.get() + 1); -		// TODO implement this - +	public void evolve(Population population, Mutator mutator, Resources resources) { +		/* Create an entirely new population by isolating random subsets of +		 * the original population and choosing the fittest individual within +		 * that subset. Each chosen individual is mutated and copied back into the +		 * population. +		 */ +		Chromosome[] newPopulation = new Chromosome[resources.populationSize()]; +		 +		// start by selecting all of the chromosomes that will be promoted +		for (int i = 0; i < resources.populationSize(); i++) { +			if (report.get()) resources.reportln("[ES] Starting tournament " + i); +			 +			/* the population is sorted in ascending order of fitness, +			 * meaning the higher the index of the contender, the fitter +			 * it is +			 */ +			int[] contenders = new int[tournamentSize.get()]; +			for (int t = 0; t < tournamentSize.get() - 1; t++) { +				contenders[t] = resources.getRandomInt(resources.populationSize()); +			} +			if (report.get()) resources.reportln("[ES] Selected contenders: " + Arrays.toString(contenders)); +			Arrays.sort(contenders); +			if (report.get()) resources.reportln("[ES] Chr " + contenders[contenders.length - 1] + " wins the tournament, copying and mutating..."); +			// create a copy of the selected chromosome and mutate it +			newPopulation[i] = new Chromosome(population.getChromosome(contenders[contenders.length - 1])); +			mutator.mutate(newPopulation[i], resources); +		} +		if (report.get()) resources.reportln("[ES] Tournaments are finished, copying new chromosomes into population"); +		// newPopulation has been generated, copy into the population +		for (int c = 0; c < resources.populationSize(); c++) { +			population.getChromosome(c).copyGenes(newPopulation[c]); +		} +		 +		if (report.get()) resources.reportln("[ES] Generation is complete");  	}  	@Override diff --git a/src/jcgp/backend/modules/mutator/FixedPointMutator.java b/src/jcgp/backend/modules/mutator/FixedPointMutator.java new file mode 100644 index 0000000..4088918 --- /dev/null +++ b/src/jcgp/backend/modules/mutator/FixedPointMutator.java @@ -0,0 +1,64 @@ +package jcgp.backend.modules.mutator; + +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; + +/** + * Fixed point mutator + * <br><br> + * This operator uses the point mutator  + * algorithm to mutate a user-defined fixed + * number of genes. + *  + *  + * @see PointMutator + * @author Eduardo Pedroni + * + */ +public class FixedPointMutator extends PointMutator { + +	private IntegerParameter geneMutated; +	private BooleanParameter report; + +	/** +	 * Creates a new instance of FixedPointMutator.  +	 *  +	 * @param resources a reference to the experiment's resources. +	 */ +	public FixedPointMutator(final Resources resources) { +		geneMutated = new IntegerParameter(5, "Genes mutated", false, false) { +			@Override +			public void validate(Number newValue) { +				if (newValue.intValue() <= 0) { +					status = ParameterStatus.INVALID; +					status.setDetails("At least 1 mutation must take place."); +				} else if (newValue.intValue() > (resources.nodes() * (resources.arity() + 1)) + resources.outputs()) { +					status = ParameterStatus.WARNING; +					status.setDetails("More genes are mutated than there are genes in the genotype."); +				} else { +					status = ParameterStatus.VALID; +				} +			} +		}; +		report = new BooleanParameter(false, "Report") { +			@Override +			public void validate(Boolean newValue) { +				// blank +			} +		}; +	} + +	@Override +	public Parameter<?>[] getLocalParameters() { +		return new Parameter[] {geneMutated, report}; +	} + +	@Override +	public String toString() { +		return "Fixed point mutation"; +	} + +} diff --git a/src/jcgp/backend/modules/mutator/Mutator.java b/src/jcgp/backend/modules/mutator/Mutator.java index 1d5b99a..7435cc1 100644 --- a/src/jcgp/backend/modules/mutator/Mutator.java +++ b/src/jcgp/backend/modules/mutator/Mutator.java @@ -4,8 +4,35 @@ import jcgp.backend.modules.Module;  import jcgp.backend.population.Chromosome;  import jcgp.backend.resources.Resources; +/** + * This interface specifies the required behaviour of a mutation operator. Its job is  + * to modify the connections and functions of the chromosome according to the operator's + * parameters. + * <br><br> + * Parameters may be specified to control the implemented mutation. Any parameters + * returned by {@code getLocalParameters()} should be displayed by the user interface, + * if it is being used. See {@link Parameter} for more information.  + * <br><br> + * It is advisable to use {@code Resources.reportln()} and {@code Resources.report()} + * to print any relevant information. Note that reportln() and report() are affected + * by the report interval base parameter. Use {@code Resources.println()} and + * {@code Resources.print()} to print information regardless of the current generation. + * See {@link Resources} for more information. + *  + * @see Module + *  + * @author Eduardo Pedroni + * + */  public interface Mutator extends Module { +	/** +	 * Applies mutations to the specified chromosome according +	 * to the parameter values. +	 *  +	 * @param chromosome the chromosome to mutate. +	 * @param resources parameters and utilities for optional reference. +	 */  	void mutate(Chromosome chromosome, Resources resources);  } diff --git a/src/jcgp/backend/modules/mutator/PercentPointMutator.java b/src/jcgp/backend/modules/mutator/PercentPointMutator.java new file mode 100644 index 0000000..4057027 --- /dev/null +++ b/src/jcgp/backend/modules/mutator/PercentPointMutator.java @@ -0,0 +1,73 @@ +package jcgp.backend.modules.mutator; + +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; + +/** + * Percent point mutator + * <br><br> + * This operator calculates how many genes to mutate based on the mutation rate + * parameter. The total number of genes is computed from the number of nodes,  + * the arity and the number of outputs. It then uses the point mutation  + * algorithm to perform the required number of mutations. + *  + *  + * @see PointMutator + * @author Eduardo Pedroni + * + */ +public class PercentPointMutator extends PointMutator { +	 +	private DoubleParameter mutationRate; +	private IntegerParameter genesMutated; +	private BooleanParameter report; + +	/** +	 * Creates a new instance of PointMutator.  +	 *  +	 * @param resources a reference to the experiment's resources. +	 */ +	public PercentPointMutator(final Resources resources) { +		mutationRate = new DoubleParameter(10, "Percent mutation", false, false) { +			@Override +			public void validate(Number newValue) { +				genesMutated.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"); +				} else if (genesMutated.get() <=  0) { +					status = ParameterStatus.WARNING; +					status.setDetails("With mutation rate " + mutationRate.get() + ", 0 genes will be mutated."); +				} else { +					status = ParameterStatus.VALID; +				} +			} +		}; +		genesMutated = 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) { +				// blank +			} +		}; +	} + +	@Override +	public Parameter<?>[] getLocalParameters() { +		return new Parameter[] {mutationRate, genesMutated, report}; +	} + +	@Override +	public String toString() { +		return "Percent point mutation"; +	} +} diff --git a/src/jcgp/backend/modules/mutator/PointMutator.java b/src/jcgp/backend/modules/mutator/PointMutator.java index 44c453a..17c6996 100644 --- a/src/jcgp/backend/modules/mutator/PointMutator.java +++ b/src/jcgp/backend/modules/mutator/PointMutator.java @@ -6,88 +6,69 @@ import jcgp.backend.population.Node;  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; +/** + * Point mutator + * <br><br> + * In point mutation, a number of random genes + * is picked and mutated until all required + * mutations have been performed. The actual number + * of genes to be mutated can be defined in any + * arbitrary way. + *  + * @author Eduardo Pedroni + * + */ +public abstract class PointMutator implements Mutator { -	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"); -				} else if ((int) ((newValue.doubleValue() / 100) * (double) resources.nodes()) <=  0) { -					status = ParameterStatus.WARNING; -					status.setDetails("With mutation rate " + mutationRate.get() + ", 0 genes will be mutated."); -				} else { -					status = ParameterStatus.VALID; -				} -			} -		}; -		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) { -				// blank -			} -		}; -	} +	protected IntegerParameter genesMutated; +	protected BooleanParameter report;  	@Override  	public void mutate(Chromosome chromosome, Resources resources) { -		if (report.get()) resources.reportln("[Mutator] Number of mutations to be performed: " + nodesMutated.get()); -		for (int i = 0; i < nodesMutated.get(); i++) { +		if (report.get()) resources.reportln("[Mutator] Number of mutations to be performed: " + genesMutated.get()); +		 +		// for however many genes must be mutated +		for (int i = 0; i < genesMutated.get(); i++) { +			  			MutableElement m = chromosome.getRandomMutableElement(); -			if (report.get()) resources.report("[Mutator] Mutation " + i + " selected " + m.toString() + ", "); +			if (report.get()) resources.report("[Mutator] Mutation " + i + " selected " + m + ", "); +			 +			// outputs and nodes are mutated differently  			if (m instanceof Output) { -				if (report.get()) resources.report("changed source from " + ((Output) m).getSource().toString() + " "); +				if (report.get()) resources.report("changed source from " + ((Output) m).getSource() + " "); +				// outputs are easy, simply set to a different random connection, any will do  				m.setConnection(0, chromosome.getRandomConnection()); -				if (report.get()) resources.reportln("to " + ((Output) m).getSource().toString()); +				if (report.get()) resources.reportln("to " + ((Output) m).getSource());  			} else if (m instanceof Node) { +				/* nodes are more complicated, first we must decide whether to mutate the function +				 * or a connection +				 * we do this by generating a random int between 0 and 1 + arity +				 */  				int geneType = resources.getRandomInt(1 + resources.arity()); +				 +				// if the int is less than 1, mutate function, else mutate connections   				if (geneType < 1) { -					if (report.get()) resources.report("changed function from " + ((Node) m).getFunction().getName() + " "); +					if (report.get()) resources.report("changed function from " + ((Node) m).getFunction() + " ");  					((Node) m).setFunction(resources.getRandomFunction()); -					if (report.get()) resources.reportln("to " + ((Node) m).getFunction().getName()); +					if (report.get()) resources.reportln("to " + ((Node) m).getFunction());  				} else { -					int connection = resources.getRandomInt(resources.arity()); -					if (report.get()) resources.report("changed connection " + connection + " from " + ((Node) m).getConnection(connection) + " "); +					// if we decided to mutate connection, subtract 1 from geneType so it fits into the arity range +					geneType -= 1; +					if (report.get()) resources.report("changed connection " + geneType + " from " + ((Node) m).getConnection(geneType) + " "); -					m.setConnection(connection, chromosome.getRandomConnection(((Node) m).getColumn())); +					m.setConnection(geneType, chromosome.getRandomConnection(((Node) m).getColumn())); -					if (report.get()) resources.reportln("to " + ((Node) m).getConnection(connection)); +					if (report.get()) resources.reportln("to " + ((Node) m).getConnection(geneType));  				}  			}  		}  	} -	@Override -	public Parameter<?>[] getLocalParameters() { -		return new Parameter[] {mutationRate, nodesMutated, report}; -	} - -	@Override -	public String toString() { -		return "Point mutation"; -	} -  } diff --git a/src/jcgp/backend/modules/mutator/ProbabilisticMutator.java b/src/jcgp/backend/modules/mutator/ProbabilisticMutator.java new file mode 100644 index 0000000..e3c1d03 --- /dev/null +++ b/src/jcgp/backend/modules/mutator/ProbabilisticMutator.java @@ -0,0 +1,131 @@ +package jcgp.backend.modules.mutator; + +import jcgp.backend.population.Chromosome; +import jcgp.backend.population.Node; +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.Parameter; +import jcgp.backend.resources.parameters.ParameterStatus; + +/** + * Probabilistic mutator + * <br><br> + * This operator iterates through every mutable gene in the chromosome and  + * decides whether to mutate each of them individually.  + * The decision is made based on the difference between the mutation probability + * and a randomly generated double between 0 and 100. + *  + *  + * @see Mutator + * @author Eduardo Pedroni + * + */ +public class ProbabilisticMutator implements Mutator { + +	private DoubleParameter mutationProbability; +	private BooleanParameter report; +	 +	private Resources resources; +	 +	/** +	 * Creates a new instance of ProbabilisticMutator.  +	 *  +	 * @param resources a reference to the experiment's resources. +	 */ +	public ProbabilisticMutator(Resources resources) { +		this.resources = resources; +		 +		mutationProbability = new DoubleParameter(10, "Mutation probability", false, false) { +			@Override +			public void validate(Number newValue) { +				if (newValue.doubleValue() <= 0 || newValue.doubleValue() > 100) { +					status = ParameterStatus.INVALID; +					status.setDetails("Mutation rate must be > 0 and <= 100"); +				} else { +					status = ParameterStatus.VALID; +				} +			} +		}; +		report = new BooleanParameter(false, "Report") { +			@Override +			public void validate(Boolean newValue) { +				// blank +			} +		}; +	} +	 +	@Override +	public Parameter<?>[] getLocalParameters() { +		return new Parameter<?>[] {mutationProbability, report}; +	} + +	@Override +	public void mutate(Chromosome chromosome, Resources resources) { +		if (report.get()) resources.reportln("[Mutator] Starting mutations"); +		 +		// go through nodes - [rows][columns] +		for (int r = 0; r < resources.rows(); r++) { +			for (int c = 0; c < resources.columns(); c++) { +				// go through all connections +				for (int a = 0; a < resources.arity(); a++) { +					if (mutate()) { +						Node n = chromosome.getNode(r, c); +						 +						if (report.get()) resources.report("[Mutator] Mutating " + n + +								", changed connection " + a + " from " + n.getConnection(a) + " "); +						 +						n.setConnection(a, chromosome.getRandomConnection(c)); +						 +						if (report.get()) resources.reportln("to " + n.getConnection(a)); +						 +					} +				} +				// deal with node function next +				if (mutate()) { +					Node n = chromosome.getNode(r, c); +					if (report.get()) resources.report("[Mutator] Mutating " + n + +							", changed function from " + n.getFunction()); +					 +					n.setFunction(resources.getRandomFunction()); +					 +					if (report.get()) resources.reportln(" to " + n.getFunction()); +				} +			} +		} +		// finally, mutate outputs +		for (int o = 0; o < resources.outputs(); o++) { +			if (mutate()) { +				Output out = chromosome.getOutput(o); +				 +				if (report.get()) resources.report("[Mutator] Mutating " + out + +						", changed source from " + out.getSource()); +				 +				out.setConnection(0, chromosome.getRandomConnection()); +				 +				if (report.get()) resources.reportln("to " + out.getSource()); +			} +		} +		 +		if (report.get()) resources.reportln("[Mutator] Mutation finished "); + +	} +	 +	/** +	 * This method offers a shorthand to decide whether a mutation should occur or not. +	 * A random double is generated in the range 0 <= x < 100 and compared with the +	 * mutation probability parameter. If the generated number is less than the mutation +	 * probability, this returns true meaning a mutation should occur. +	 *  +	 * @return true if a mutation should be performed, false if otherwise. +	 */ +	private boolean mutate() { +		return resources.getRandomDouble(100) < mutationProbability.get(); +	} + +	@Override +	public String toString() { +		return "Probabilistic mutation"; +	} +} diff --git a/src/jcgp/backend/modules/problem/DigitalCircuitProblem.java b/src/jcgp/backend/modules/problem/DigitalCircuitProblem.java index 3c30e4c..099f527 100644 --- a/src/jcgp/backend/modules/problem/DigitalCircuitProblem.java +++ b/src/jcgp/backend/modules/problem/DigitalCircuitProblem.java @@ -1,6 +1,6 @@  package jcgp.backend.modules.problem; -import jcgp.backend.function.BitwiseLogic; +import jcgp.backend.function.DigitalCircuitFunctions;  import jcgp.backend.function.UnsignedInteger;  import jcgp.backend.population.Chromosome;  import jcgp.backend.population.Population; @@ -10,14 +10,13 @@ public class DigitalCircuitProblem extends TestCaseProblem<UnsignedInteger> {  	public DigitalCircuitProblem(Resources resources) {  		super(resources); -		functionSet = new BitwiseLogic(); +		functionSet = new DigitalCircuitFunctions(); +		setProblemName("Symbolic regression"); +		setFileExtension(".plu");  	}  	@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 @@ -42,10 +41,10 @@ public class DigitalCircuitProblem extends TestCaseProblem<UnsignedInteger> {  			// assign the resulting fitness to the respective individual  			population.getChromosome(i).setFitness(fitness); -			if (fitness >= population.getFittest().getFitness()) { -				population.setFittest(i); -			}  		} +		 +		// sort population +		population.sortAscending();  	}  	@Override @@ -77,9 +76,4 @@ public class DigitalCircuitProblem extends TestCaseProblem<UnsignedInteger> {  	public boolean isPerfectSolution(Chromosome fittest) {  		return fittest.getFitness() >= maxFitness.get();  	} - -	@Override -	public String getFileExtension() { -		return ".plu"; -	}  } diff --git a/src/jcgp/backend/modules/problem/Problem.java b/src/jcgp/backend/modules/problem/Problem.java index d01f5b0..07183ea 100644 --- a/src/jcgp/backend/modules/problem/Problem.java +++ b/src/jcgp/backend/modules/problem/Problem.java @@ -1,14 +1,19 @@  package jcgp.backend.modules.problem; +import java.io.File; +  import jcgp.backend.function.FunctionSet;  import jcgp.backend.modules.Module;  import jcgp.backend.population.Chromosome;  import jcgp.backend.population.Population; +import jcgp.backend.resources.ModifiableResources;  import jcgp.backend.resources.Resources;  public abstract class Problem implements Module {  	protected FunctionSet functionSet; +	private String fileExtension = ".*"; +	private String name = this.getClass().getSimpleName();  	public abstract void evaluate(Population population, Resources resources); @@ -17,4 +22,27 @@ public abstract class Problem implements Module {  	}  	public abstract boolean isPerfectSolution(Chromosome fittest); +	 +	public abstract void parse(File file, ModifiableResources resources); +	 +	public void setFileExtension(String fileExtension) { +		this.fileExtension = fileExtension; +	} +	 +	public String getFileExtension() { +		return fileExtension; +	} +	 +	public void setProblemName(String newName) { +		this.name = newName; +	} +	 +	public String getProblemName() { +		return name; +	} +	 +	@Override +	public String toString() { +		return name; +	}  } diff --git a/src/jcgp/backend/modules/problem/SymbolicRegressionProblem.java b/src/jcgp/backend/modules/problem/SymbolicRegressionProblem.java index 52df0f2..5468157 100644 --- a/src/jcgp/backend/modules/problem/SymbolicRegressionProblem.java +++ b/src/jcgp/backend/modules/problem/SymbolicRegressionProblem.java @@ -1,6 +1,6 @@  package jcgp.backend.modules.problem; -import jcgp.backend.function.DoubleArithmetic; +import jcgp.backend.function.SymbolicRegressionFunctions;  import jcgp.backend.population.Chromosome;  import jcgp.backend.population.Population;  import jcgp.backend.resources.Resources; @@ -16,7 +16,9 @@ public class SymbolicRegressionProblem extends TestCaseProblem<Double> {  	public SymbolicRegressionProblem(Resources resources) {  		super(resources); -		functionSet = new DoubleArithmetic(); +		functionSet = new SymbolicRegressionFunctions(); +		setProblemName("Symbolic regression"); +		setFileExtension(".dat");  		errorThreshold = new DoubleParameter(0.01, "Error threshold") {  			@Override  			public void validate(Number newValue) { @@ -45,7 +47,7 @@ public class SymbolicRegressionProblem extends TestCaseProblem<Double> {  				}  			}  		}; -		hitsBasedFitness = new BooleanParameter(true, "Hits-based fitness") { +		hitsBasedFitness = new BooleanParameter(true, "HITS-based fitness") {  			@Override  			public void validate(Boolean newValue) {  				// blank @@ -55,9 +57,6 @@ public class SymbolicRegressionProblem extends TestCaseProblem<Double> {  	@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 @@ -81,18 +80,12 @@ public class SymbolicRegressionProblem extends TestCaseProblem<Double> {  			}  			// assign the resulting fitness to the respective individual  			population.getChromosome(i).setFitness(fitness); -			if (fitness >= population.getFittest().getFitness()) { -				population.setFittest(i); -			}  		} +		 +		// sort population +		population.sortAscending();  	} -	 -	@Override -	public String toString() { -		return "Symbolic regression"; -	} -  	@Override  	public void addTestCase(String[] inputs, String[] outputs) {  		Double[] inputCases = new Double[inputs.length]; @@ -116,9 +109,4 @@ public class SymbolicRegressionProblem extends TestCaseProblem<Double> {  	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 d8dd32b..6c4a7dc 100644 --- a/src/jcgp/backend/modules/problem/TestCaseProblem.java +++ b/src/jcgp/backend/modules/problem/TestCaseProblem.java @@ -1,9 +1,12 @@  package jcgp.backend.modules.problem; +import java.io.File;  import java.util.List;  import javafx.collections.FXCollections;  import javafx.collections.ObservableList; +import jcgp.backend.parsers.TestCaseParser; +import jcgp.backend.resources.ModifiableResources;  import jcgp.backend.resources.Resources;  import jcgp.backend.resources.parameters.DoubleParameter;  import jcgp.backend.resources.parameters.Parameter; @@ -116,7 +119,10 @@ public abstract class TestCaseProblem<U extends Object> extends Problem {  		testCases.clear();  	} -	public abstract String getFileExtension(); +	public void parse(File file, ModifiableResources resources) { +		TestCaseParser.parseParameters(file, resources); +		TestCaseParser.parse(file, this, resources); +	}  } diff --git a/src/jcgp/backend/modules/problem/TravellingSalesmanProblem.java b/src/jcgp/backend/modules/problem/TravellingSalesmanProblem.java new file mode 100644 index 0000000..6491ec6 --- /dev/null +++ b/src/jcgp/backend/modules/problem/TravellingSalesmanProblem.java @@ -0,0 +1,43 @@ +package jcgp.backend.modules.problem; + +import java.io.File; + +import jcgp.backend.function.TravellingSalesmanFunctions; +import jcgp.backend.population.Chromosome; +import jcgp.backend.population.Population; +import jcgp.backend.resources.ModifiableResources; +import jcgp.backend.resources.Resources; +import jcgp.backend.resources.parameters.Parameter; + +public class TravellingSalesmanProblem extends Problem { +	 +	public TravellingSalesmanProblem(Resources resources) { +		functionSet = new TravellingSalesmanFunctions(); +		setProblemName("Travelling salesman"); +		setFileExtension(".tsp"); +	} + +	@Override +	public Parameter<?>[] getLocalParameters() { +		// TODO Auto-generated method stub +		return null; +	} + +	@Override +	public void evaluate(Population population, Resources resources) { +		// TODO Auto-generated method stub + +	} + +	@Override +	public boolean isPerfectSolution(Chromosome fittest) { +		// TODO Auto-generated method stub +		return false; +	} + +	@Override +	public void parse(File file, ModifiableResources resources) { +		// TODO Auto-generated method stub +		 +	} +} diff --git a/src/jcgp/backend/parser/ChromosomeParser.java b/src/jcgp/backend/parser/ChromosomeParser.java deleted file mode 100644 index fd03b7d..0000000 --- a/src/jcgp/backend/parser/ChromosomeParser.java +++ /dev/null @@ -1,177 +0,0 @@ -package jcgp.backend.parser; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.PrintWriter; -import java.util.Scanner; - -import jcgp.backend.population.Chromosome; -import jcgp.backend.population.Connection; -import jcgp.backend.population.Input; -import jcgp.backend.population.Node; -import jcgp.backend.resources.Resources; - -/** - * This class includes a method for parsing .chr files and another - * for writing .chr files from given chromosomes. - *  - * @author Eduardo Pedroni - * - */ -public abstract class ChromosomeParser { - -	/** -	 * Use this method to parse .chr files into a given chromosome. -	 * <br><br> -	 * This is not fully defensive as it doesn't check for number of inputs,  -	 * doesn't compare rows and columns individually and doesn't account for levels back. It -	 * is not viable to implement these defensive measures with the chromosome format used  -	 * by CGP. -	 *  -	 * @param file the .chr file to parse from -	 * @param chromosome the chromosome to configure -	 * @param resources the experiment resources -	 */ -	public static void parse(File file, Chromosome chromosome, Resources resources) { -		/*  -		 * Count the nodes to make sure the size of the .chr file matches the experiment parameters. -		 *  -		 * We do this by using the scanner to get the node and output portions of the file as they -		 * are separated by 3 tab characters. Every number is replaced by a single known character,  -		 * and the length of the string with the new characters is compared with that of a string -		 * where the new known character has been removed, yielding the total number of values. -		 *  -		 */ -		FileReader fr; -		try { -			fr = new FileReader(file); -		} catch (FileNotFoundException e) { -			e.printStackTrace(); -			return; -		} -		Scanner in = new Scanner(fr); -		in.useDelimiter("\\t\\t\\t"); -		String geneString = in.next().replaceAll("[0-9]+", "g"); -		String outString = in.next().replaceAll("[0-9]+", "o"); -		int geneCount = geneString.length() - geneString.replace("g", "").length(); -		int outCount = outString.length() - outString.replace("o", "").length(); -		in.close(); -		 -		 -		// if the acquired values match the current parameters, apply them to the chromosome -		if ((geneCount == resources.nodes() * (resources.arity() + 1)) -				&& outCount == resources.outputs()) { -			// prepare a new scanner -			try { -				fr = new FileReader(file); -			} catch (FileNotFoundException e) { -				e.printStackTrace(); -				return; -			} -			in = new Scanner(fr); -			 -			int gene; -			Connection newConnection; -			Node changingNode; -			// for all nodes, columns first -			for (int c = 0; c < resources.columns(); c++) { -				for (int r = 0; r < resources.rows(); r++) { -					// store the changing node -					changingNode = chromosome.getNode(r, c); - -					// for every connection -					for (int i = 0; i < resources.arity(); i++) { -						// get connection number from the .chr file -						gene = in.nextInt(); -						System.out.println("r: " + r + " c: " + c + " i: " + i + " gene: " + gene); -						if (gene < resources.inputs()) { -							// connection was an input -							newConnection = chromosome.getInput(gene); -						} else { -							// connection was another node, calculate which from its number -							newConnection = chromosome.getNode((gene - resources.inputs()) % resources.rows(),  -									(gene - resources.inputs()) / resources.rows()); -						} -						changingNode.setConnection(i, newConnection); -					} - -					// set the function, straight indexing should work - this is not entirely -					// safe, but it is not viable to check for functionset compatibility -					changingNode.setFunction(resources.getFunction(in.nextInt())); -				} -			} - -			// outputs -			for (int o = 0; o < resources.outputs(); o ++) { -				gene = in.nextInt(); -				if (gene < resources.inputs()) { -					// connection was an input -					newConnection = chromosome.getInput(gene); -				} else { -					// connection was another node, calculate which from its number -					newConnection = chromosome.getNode((gene - resources.inputs()) % resources.rows(),  -							(gene - resources.inputs()) / resources.rows()); -				} -				chromosome.getOutput(o).setConnection(0, newConnection); -			} -			in.close(); -		} else { -			throw new IllegalArgumentException("The topology of the chromosome in " + file.getName() + " does not match that of the experiment."); -		} -	} -	 -	/** -	 * Writes a chromosome into the specified .chr file. -	 *  -	 *  -	 * @param file the file to write to -	 * @param chromosome the chromosome to save -	 */ -	public static void save(File file, Chromosome chromosome, Resources resources) { -		PrintWriter writer; -		try { -			writer = new PrintWriter(file); -		} catch (FileNotFoundException e) { -			// something bad happened -			return; -		} -		 -		// for all nodes, columns first -		for (int c = 0; c < resources.columns(); c++) { -			for (int r = 0; r < resources.rows(); r++) { -				for (int i = 0; i < resources.arity(); i++) { -					// print the connections, separated by spaces -					Connection conn = chromosome.getNode(r, c).getConnection(i); -					if (conn instanceof Input) { -						writer.print(" " + ((Input) conn).getIndex()); -					} else if (conn instanceof Node) { -						writer.print(" " + (((((Node) conn).getColumn() + 1) * resources.inputs()) + ((Node) conn).getRow())); -					} else { -						throw new ClassCastException("Could not handle " + conn.getClass() + " as a subclass of Connection"); -					} -				} -				// print the function numbers -				writer.print(" " + resources.getFunctionIndex(chromosome.getNode(r, c).getFunction())); -				// node is done, print tab -				writer.print("\t"); -			} -		} -		// nodes are done, print two tabs to separate from output -		writer.print("\t\t"); -		for (int o = 0; o < resources.outputs(); o ++) { -			Connection source = chromosome.getOutput(o).getSource(); -			if (source instanceof Input) { -				writer.print(" " + ((Input) source).getIndex()); -			} else if (source instanceof Node) { -				writer.print(" " + (((((Node) source).getColumn() + 1) * resources.inputs()) + ((Node) source).getRow())); -			} else { -				throw new ClassCastException("Could not handle " + source.getClass() + " as a subclass of Connection"); -			} -		} -		 -		writer.close(); -		System.out.println("writer is closed"); -	} -	 -} diff --git a/src/jcgp/backend/parser/FunctionParser.java b/src/jcgp/backend/parser/FunctionParser.java deleted file mode 100644 index ab94899..0000000 --- a/src/jcgp/backend/parser/FunctionParser.java +++ /dev/null @@ -1,51 +0,0 @@ -package jcgp.backend.parser; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.util.Scanner; - -import jcgp.backend.function.FunctionSet; -import jcgp.backend.modules.problem.Problem; - -public class FunctionParser { - -private FunctionSet functionSet; -	 -	private FunctionParser(Problem problem) { -		this.functionSet = problem.getFunctionSet(); -	} - -	public static void parseFunctions(File file, Problem problem) { -		FunctionParser pp = new FunctionParser(problem); -		 -		FileReader fr; -		try { -			fr = new FileReader(file); -		} catch (FileNotFoundException e) { -			e.printStackTrace(); -			return; -		} -		 -		Scanner in = new Scanner(fr); -		 -		while (in.hasNextLine()) { -			String line = in.nextLine(); -			if (line.substring(line.length() - 1).matches("[0-9]")) { -				pp.parseAndSet(line.split("[^0-9]+")); -			} -		} -		 -		in.close(); -	} -	 -	private void parseAndSet(String[] splitString) { -		int functionIndex = Integer.parseInt(splitString[splitString.length - 1]); -		if (Integer.parseInt(splitString[0]) != 0) { -			functionSet.enableFunction(functionIndex); -		} else { -			functionSet.disableFunction(functionIndex); -		} -		 -	}	 -} diff --git a/src/jcgp/backend/parser/ParameterParser.java b/src/jcgp/backend/parser/ParameterParser.java deleted file mode 100644 index f96ebf9..0000000 --- a/src/jcgp/backend/parser/ParameterParser.java +++ /dev/null @@ -1,77 +0,0 @@ -package jcgp.backend.parser; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.util.Scanner; - -import jcgp.backend.resources.ModifiableResources; - -public class ParameterParser { -	 -	private ModifiableResources resources; -	 -	private ParameterParser(ModifiableResources resources) { -		this.resources = resources; -	} - -	public static void parseParameters(File file, ModifiableResources resources) { -		ParameterParser pp = new ParameterParser(resources); -		 -		FileReader fr; -		try { -			fr = new FileReader(file); -		} catch (FileNotFoundException e) { -			e.printStackTrace(); -			return; -		} -		 -		Scanner in = new Scanner(fr); -		 -		while (in.hasNextLine()) { -			pp.parseAndSet(in.nextLine().split("( |\t)+")); -		} -		 -		in.close(); -	} -	 -	private void parseAndSet(String[] splitString) { -		switch (splitString[1]) { -		 -		case "population_size": -			resources.setPopulationSize(Integer.parseInt(splitString[0])); -			break; -			 -		case "num_generations": -			resources.setGenerations(Integer.parseInt(splitString[0])); -			break; -			 -		case "num_runs_total": -			resources.setRuns(Integer.parseInt(splitString[0])); -			break; -			 -		case "num_rows": -			resources.setRows(Integer.parseInt(splitString[0])); -			break; -			 -		case "num_cols": -			resources.setColumns(Integer.parseInt(splitString[0])); -			break; - -		case "levels_back": -			resources.setLevelsBack(Integer.parseInt(splitString[0])); -			break; -		 -		case "report_interval": -			resources.setReportInterval(Integer.parseInt(splitString[0])); -			break; -		 -		case "global_seed": -			resources.setSeed(Integer.parseInt(splitString[0])); -			break; - -		default: -			break; -		} -	} -} diff --git a/src/jcgp/backend/parser/TestCaseParser.java b/src/jcgp/backend/parser/TestCaseParser.java deleted file mode 100644 index d47d663..0000000 --- a/src/jcgp/backend/parser/TestCaseParser.java +++ /dev/null @@ -1,90 +0,0 @@ -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 { - -	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/parsers/ChromosomeParser.java b/src/jcgp/backend/parsers/ChromosomeParser.java index fe58ff8..ed1399a 100644 --- a/src/jcgp/backend/parsers/ChromosomeParser.java +++ b/src/jcgp/backend/parsers/ChromosomeParser.java @@ -11,6 +11,7 @@ import jcgp.backend.population.Connection;  import jcgp.backend.population.Input;  import jcgp.backend.population.Node;  import jcgp.backend.resources.ModifiableResources; +import jcgp.backend.resources.Resources;  /**   * This class includes a method for parsing .chr files and another @@ -33,7 +34,7 @@ public abstract class ChromosomeParser {  	 * @param chromosome the chromosome to configure  	 * @param resources the experiment resources  	 */ -	public static void parse(File file, Chromosome chromosome, ModifiableResources resources) { +	public static void parse(File file, Chromosome chromosome, Resources resources) {  		/*   		 * Count the nodes to make sure the size of the .chr file matches the experiment parameters.  		 *  diff --git a/src/jcgp/backend/parsers/FunctionParser.java b/src/jcgp/backend/parsers/FunctionParser.java index 6d6c73b..cc52ce9 100644 --- a/src/jcgp/backend/parsers/FunctionParser.java +++ b/src/jcgp/backend/parsers/FunctionParser.java @@ -11,7 +11,7 @@ import jcgp.backend.resources.ModifiableResources;  /**   * Parses the functions from a .par file.  - * Functions marked with a 1 will be enabled,  + * Functions marked with a 1 are enabled,    * and those marked with 0 are disabled.   *    * @author Eduardo Pedroni @@ -25,7 +25,7 @@ public abstract class FunctionParser {  		try {  			fr = new FileReader(file);  		} catch (FileNotFoundException e) { -			resources.println("[Parser] Error: could not find " + file.getAbsolutePath() + "."); +			resources.println("[Parser] Error: could not find " + file.getAbsolutePath());  			return;  		} @@ -40,14 +40,14 @@ public abstract class FunctionParser {  				int functionIndex = Integer.parseInt(splitString[splitString.length - 1]);  				if (Integer.parseInt(splitString[0]) != 0 && !functionSet.isEnabled(functionSet.getFunction(functionIndex))) {  					functionSet.enableFunction(functionIndex); -					resources.println("[Parser] Enabled function: " + functionSet.getFunction(functionIndex).getName() + "."); +					resources.println("[Parser] Enabled function: " + functionSet.getFunction(functionIndex));  				} else if (Integer.parseInt(splitString[0]) == 0 && functionSet.isEnabled(functionSet.getFunction(functionIndex))) {  					functionSet.disableFunction(functionIndex); -					resources.println("[Parser] Disabled function: " + functionSet.getFunction(functionIndex).getName() + "."); +					resources.println("[Parser] Disabled function: " + functionSet.getFunction(functionIndex));  				}  			}  		}  		in.close(); -		resources.println("[Parser] Finished parsing functions."); +		resources.println("[Parser] Finished parsing functions");  	}  } diff --git a/src/jcgp/backend/population/Chromosome.java b/src/jcgp/backend/population/Chromosome.java index f8830fa..9e53f85 100644 --- a/src/jcgp/backend/population/Chromosome.java +++ b/src/jcgp/backend/population/Chromosome.java @@ -5,7 +5,7 @@ import java.util.ArrayList;  import jcgp.backend.exceptions.ParameterMismatchException;  import jcgp.backend.resources.Resources; -public class Chromosome { +public class Chromosome implements Comparable<Chromosome> {  	private Resources resources; @@ -276,7 +276,7 @@ public class Chromosome {  		}  	} -	public boolean compareTo(Chromosome chromosome) { +	public boolean compareGenesTo(Chromosome chromosome) {  		for (int r = 0; r < resources.rows(); r++) {  			for (int c = 0; c < resources.columns(); c++) {  				if (!(nodes[r][c].copyOf(chromosome.getNode(r, c)))) { @@ -294,7 +294,7 @@ public class Chromosome {  		return true;  	} -	public boolean compareActiveTo(Chromosome chromosome) { +	public boolean compareActiveGenesTo(Chromosome chromosome) {  		// update list if it is out of date  		computeActiveNodes(); @@ -310,7 +310,6 @@ public class Chromosome {  	}  	public void printNodes() { -		// TODO make this proper  		int arity = resources.arity();  		for (int r = 0; r < resources.rows(); r++) { @@ -320,7 +319,7 @@ public class Chromosome {  				for (int i = 0; i < arity; i++) {  					System.out.print("C" + i + ": (" + nodes[r][c].getConnection(i).toString() + ") ");  				} -				System.out.print("F: " + nodes[r][c].getFunction().getName() + "\t"); +				System.out.print("F: " + nodes[r][c].getFunction() + "\t");  			}  			System.out.print("\n");  		} @@ -335,4 +334,15 @@ public class Chromosome {  	public Resources getResources() {  		return resources;  	} + +	@Override +	public int compareTo(Chromosome o) { +		if (fitness < o.getFitness()) { +			return -1; +		} else if (fitness > o.getFitness()) { +			return 1; +		} else { +			return 0; +		} +	}  } diff --git a/src/jcgp/backend/population/Population.java b/src/jcgp/backend/population/Population.java index b6dd055..d99c64e 100644 --- a/src/jcgp/backend/population/Population.java +++ b/src/jcgp/backend/population/Population.java @@ -1,12 +1,14 @@  package jcgp.backend.population; +import java.util.Arrays; +import java.util.Collections; +  import jcgp.backend.resources.Resources;  public class Population {  	private final Chromosome[] chromosomes;  	private final Resources resources; -	private int fittest = 0;  	/**  	 * Initialise a random population according to the parameters specified @@ -77,25 +79,26 @@ public class Population {  			chromosomes[c].reinitialiseConnections();  		}  	} - -	public void setFittest(int fittest) { -		this.fittest = fittest; -	} -	 -	public void setFittest(Chromosome fittest) { -		for (int i = 0; i < chromosomes.length; i++) { -			if (chromosomes[i] == fittest) { -				this.fittest = i; -				return; -			} -		} -	}  	public Chromosome getFittest() { -		return chromosomes[fittest]; +		return chromosomes[chromosomes.length - 1];  	}  	public int getFittestIndex() { -		return fittest; +		return chromosomes.length - 1; +	} + +	/** +	 * Sort the population into ascending order of fitness. +	 */ +	public void sortAscending() { +		Arrays.sort(chromosomes); +	} +	 +	/** +	 * Sort the population into descending order of fitness. +	 */ +	public void sortDescending() { +		Arrays.sort(chromosomes, Collections.reverseOrder());  	}  } diff --git a/src/jcgp/backend/resources/ModifiableResources.java b/src/jcgp/backend/resources/ModifiableResources.java index 048e460..53dc815 100644 --- a/src/jcgp/backend/resources/ModifiableResources.java +++ b/src/jcgp/backend/resources/ModifiableResources.java @@ -1,7 +1,10 @@  package jcgp.backend.resources; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue;  import jcgp.backend.function.FunctionSet;  import jcgp.backend.resources.parameters.IntegerParameter; +import jcgp.backend.resources.parameters.ParameterStatus;  /**   *  @@ -10,13 +13,13 @@ import jcgp.backend.resources.parameters.IntegerParameter;   * and only classes with access to a JCGP instance may modify   * the resources.   *  - * @author eddy + * @author Eduardo Pedroni   *   */  public class ModifiableResources extends Resources {  	public ModifiableResources() { -		super(); +		createBaseParameters();  	}  	public void setValues(String filePath) { @@ -214,21 +217,159 @@ public class ModifiableResources extends Resources {  		this.console = console;  	} -	/* -	 * Console functionality -	 * These are not affected by parameter report interval -	 */ -	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); -		} +	private void createBaseParameters() { +		rows = new IntegerParameter(5, "Rows", false, true) { +			@Override +			public void validate(Number newValue) { +				if (newValue.intValue() <= 0) { +					status = ParameterStatus.INVALID; +					status.setDetails("Chromosome must have at least 1 row."); +				} else { +					status = ParameterStatus.VALID; +				} +			} +		}; +		 +		columns = new IntegerParameter(5, "Columns", false, true) { +			@Override +			public void validate(Number newValue) { +				if (newValue.intValue() <= 0) { +					status = ParameterStatus.INVALID; +					status.setDetails("Chromosome must have at least 1 column."); +				} else { +					status = ParameterStatus.VALID; +				} +			} +		}; +		 +		inputs = new IntegerParameter(3, "Inputs", true, false) { +			@Override +			public void validate(Number newValue) { +				if (newValue.intValue() <= 0) { +					status = ParameterStatus.INVALID; +					status.setDetails("Chromosome must have at least 1 input."); +				} else { +					status = ParameterStatus.VALID; +				} +			} +		}; +		 +		outputs = new IntegerParameter(3, "Outputs", true, false) { +			@Override +			public void validate(Number newValue) { +				if (newValue.intValue() <= 0) { +					status = ParameterStatus.INVALID; +					status.setDetails("Chromosome must have at least 1 output."); +				} else { +					status = ParameterStatus.VALID; +				} +			} +		}; +		 +		populationSize = new IntegerParameter(5, "Population", false, true) { +			@Override +			public void validate(Number newValue) { +				if (newValue.intValue() <= 0) { +					status = ParameterStatus.INVALID; +					status.setDetails("Population size must be at least 1."); +				} else { +					status = ParameterStatus.VALID; +				} +			} +		}; +		 +		levelsBack = new IntegerParameter(2, "Levels back", false, true) { +			@Override +			public void validate(Number newValue) { +				if (newValue.intValue() <= 0) { +					status = ParameterStatus.INVALID; +					status.setDetails("Levels back must be at least 1."); +				} else if (newValue.intValue() > columns.get()) { +					status = ParameterStatus.INVALID; +					status.setDetails("Levels back must be less than or equal to the number of columns."); +				} else { +					status = ParameterStatus.VALID; +				} +			} +		}; +		 +		generations = new IntegerParameter(1000000, "Generations") { +			@Override +			public void validate(Number newValue) { +				if (newValue.intValue() <= 0) { +					status = ParameterStatus.INVALID; +					status.setDetails("Number of generations must be greater than 0."); +				} else if (newValue.intValue() < currentGeneration.get()) { +					status = ParameterStatus.WARNING_RESET; +					status.setDetails("Setting generations to less than the current generation will cause the experiment to restart."); +				} else { +					status = ParameterStatus.VALID; +				} +			} +		}; +		 +		currentGeneration = new IntegerParameter(1, "Generation", true, false) { +			@Override +			public void validate(Number newValue) { +				// blank +			} +		}; + +		runs = new IntegerParameter(5, "Runs") { +			@Override +			public void validate(Number newValue) { +				if (newValue.intValue() <= 0) { +					status = ParameterStatus.INVALID; +					status.setDetails("Number of runs must be greater than 0."); +				} else if (newValue.intValue() < currentRun.get()) { +					status = ParameterStatus.WARNING_RESET; +					status.setDetails("Setting runs to less than the current run will cause the experiment to restart."); +				} else { +					status = ParameterStatus.VALID; +				} +			} +		}; +		 +		currentRun = new IntegerParameter(1, "Run", true, false) { +			@Override +			public void validate(Number newValue) { +				// blank +			} +		}; + +		arity = new IntegerParameter(0, "Max arity", true, false) { +			@Override +			public void validate(Number newValue) { +				// blank +			} +		}; +		 +		seed = new IntegerParameter(1234, "Seed", false, true) { +			@Override +			public void validate(Number 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()); +		 +		reportInterval = new IntegerParameter(1, "Report interval", false, false) { +			@Override +			public void validate(Number newValue) { +				if (newValue.intValue() > generations.get()) { +					status = ParameterStatus.WARNING; +					status.setDetails("No reports will be printed."); +				} else { +					status = ParameterStatus.VALID; +				} +			} +		};  	}  } diff --git a/src/jcgp/backend/resources/Resources.java b/src/jcgp/backend/resources/Resources.java index e83680f..e1438f1 100644 --- a/src/jcgp/backend/resources/Resources.java +++ b/src/jcgp/backend/resources/Resources.java @@ -2,12 +2,9 @@ package jcgp.backend.resources;  import java.util.Random; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue;  import jcgp.backend.function.Function;  import jcgp.backend.function.FunctionSet;  import jcgp.backend.resources.parameters.IntegerParameter; -import jcgp.backend.resources.parameters.ParameterStatus;  /**   *  @@ -28,10 +25,6 @@ public class Resources {  	// GUI console  	protected Console console; -	public Resources() { -		createBaseParameters(); -	} -	  	/**  	 * @return the rows  	 */ @@ -129,162 +122,6 @@ public class Resources {  	public int reportInterval() {  		return reportInterval.get();  	} - -	private void createBaseParameters() { -		rows = new IntegerParameter(5, "Rows", false, true) { -			@Override -			public void validate(Number newValue) { -				if (newValue.intValue() <= 0) { -					status = ParameterStatus.INVALID; -					status.setDetails("Chromosome must have at least 1 row."); -				} else { -					status = ParameterStatus.VALID; -				} -			} -		}; -		 -		columns = new IntegerParameter(5, "Columns", false, true) { -			@Override -			public void validate(Number newValue) { -				if (newValue.intValue() <= 0) { -					status = ParameterStatus.INVALID; -					status.setDetails("Chromosome must have at least 1 column."); -				} else { -					status = ParameterStatus.VALID; -				} -			} -		}; -		 -		inputs = new IntegerParameter(3, "Inputs", true, false) { -			@Override -			public void validate(Number newValue) { -				if (newValue.intValue() <= 0) { -					status = ParameterStatus.INVALID; -					status.setDetails("Chromosome must have at least 1 input."); -				} else { -					status = ParameterStatus.VALID; -				} -			} -		}; -		 -		outputs = new IntegerParameter(3, "Outputs", true, false) { -			@Override -			public void validate(Number newValue) { -				if (newValue.intValue() <= 0) { -					status = ParameterStatus.INVALID; -					status.setDetails("Chromosome must have at least 1 output."); -				} else { -					status = ParameterStatus.VALID; -				} -			} -		}; -		 -		populationSize = new IntegerParameter(5, "Population", false, true) { -			@Override -			public void validate(Number newValue) { -				if (newValue.intValue() <= 0) { -					status = ParameterStatus.INVALID; -					status.setDetails("Population size must be at least 1."); -				} else { -					status = ParameterStatus.VALID; -				} -			} -		}; -		 -		levelsBack = new IntegerParameter(2, "Levels back", false, true) { -			@Override -			public void validate(Number newValue) { -				if (newValue.intValue() <= 0) { -					status = ParameterStatus.INVALID; -					status.setDetails("Levels back must be at least 1."); -				} else if (newValue.intValue() > columns.get()) { -					status = ParameterStatus.INVALID; -					status.setDetails("Levels back must be less than or equal to the number of columns."); -				} else { -					status = ParameterStatus.VALID; -				} -			} -		}; -		 -		generations = new IntegerParameter(1000000, "Generations") { -			@Override -			public void validate(Number newValue) { -				if (newValue.intValue() <= 0) { -					status = ParameterStatus.INVALID; -					status.setDetails("Number of generations must be greater than 0."); -				} else if (newValue.intValue() < currentGeneration.get()) { -					status = ParameterStatus.WARNING_RESET; -					status.setDetails("Setting generations to less than the current generation will cause the experiment to restart."); -				} else { -					status = ParameterStatus.VALID; -				} -			} -		}; -		 -		currentGeneration = new IntegerParameter(1, "Generation", true, false) { -			@Override -			public void validate(Number newValue) { -				// blank -			} -		}; - -		runs = new IntegerParameter(5, "Runs") { -			@Override -			public void validate(Number newValue) { -				if (newValue.intValue() <= 0) { -					status = ParameterStatus.INVALID; -					status.setDetails("Number of runs must be greater than 0."); -				} else if (newValue.intValue() < currentRun.get()) { -					status = ParameterStatus.WARNING_RESET; -					status.setDetails("Setting runs to less than the current run will cause the experiment to restart."); -				} else { -					status = ParameterStatus.VALID; -				} -			} -		}; -		 -		currentRun = new IntegerParameter(1, "Run", true, false) { -			@Override -			public void validate(Number newValue) { -				// blank -			} -		}; - -		arity = new IntegerParameter(0, "Max arity", true, false) { -			@Override -			public void validate(Number newValue) { -				// blank -			} -		}; -		 -		seed = new IntegerParameter(1234, "Seed", false, true) { -			@Override -			public void validate(Number 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()); -		 -		reportInterval = new IntegerParameter(1, "Report interval", false, false) { -			@Override -			public void validate(Number newValue) { -				if (newValue.intValue() > generations.get()) { -					status = ParameterStatus.WARNING; -					status.setDetails("No reports will be printed."); -				} else { -					status = ParameterStatus.VALID; -				} -			} -		}; -	}  	/*  	 * Utility functions @@ -355,4 +192,22 @@ public class Resources {  			}  		}  	} +	 +	/* +	 * Console functionality +	 * These are not affected by parameter report interval +	 */ +	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/tests/ChromosomeTests.java b/src/jcgp/backend/tests/ChromosomeTests.java index 36278ba..bc0c57d 100644 --- a/src/jcgp/backend/tests/ChromosomeTests.java +++ b/src/jcgp/backend/tests/ChromosomeTests.java @@ -2,7 +2,7 @@ package jcgp.backend.tests;  import static org.junit.Assert.assertTrue;  import static org.junit.Assert.fail; -import jcgp.backend.function.DoubleArithmetic; +import jcgp.backend.function.SymbolicRegressionFunctions;  import jcgp.backend.population.Chromosome;  import jcgp.backend.population.Connection;  import jcgp.backend.population.Input; @@ -46,7 +46,7 @@ public class ChromosomeTests {  	@BeforeClass  	public static void setUpBeforeClass() {  		resources = new ModifiableResources(); -		resources.setFunctionSet(new DoubleArithmetic()); +		resources.setFunctionSet(new SymbolicRegressionFunctions());  	}  	@Before @@ -285,12 +285,12 @@ public class ChromosomeTests {  	public void compareActiveTest() {  		// create a clone of the chromosome, compare active nodes - should return true  		Chromosome c = new Chromosome(chromosome); -		assertTrue("Active nodes did not match.", chromosome.compareActiveTo(c)); -		assertTrue("Symmetry not obeyed.", c.compareActiveTo(chromosome)); +		assertTrue("Active nodes did not match.", chromosome.compareActiveGenesTo(c)); +		assertTrue("Symmetry not obeyed.", c.compareActiveGenesTo(chromosome));  		// create a new random chromosome, this time they should not match  		c = new Chromosome(resources); -		assertTrue("Active nodes did match.", !chromosome.compareActiveTo(c)); +		assertTrue("Active nodes did match.", !chromosome.compareActiveGenesTo(c));  	}  	/** @@ -300,12 +300,12 @@ public class ChromosomeTests {  	public void compareTest() {  		// create a clone of the chromosome, compare - should return true  		Chromosome c = new Chromosome(chromosome); -		assertTrue("Chromosomes did not match.", chromosome.compareTo(c)); -		assertTrue("Symmetry not obeyed.", c.compareTo(chromosome)); +		assertTrue("Chromosomes did not match.", chromosome.compareGenesTo(c)); +		assertTrue("Symmetry not obeyed.", c.compareGenesTo(chromosome));  		// create a new random chromosome, this time they should not match  		c = new Chromosome(resources); -		assertTrue("Chromosomes did match.", !chromosome.compareTo(c)); +		assertTrue("Chromosomes did match.", !chromosome.compareGenesTo(c));  	}  	/**  	 * Utility for creating a chromosome of known configuration. diff --git a/src/jcgp/backend/tests/NodeTests.java b/src/jcgp/backend/tests/NodeTests.java index 4054661..c63b41e 100644 --- a/src/jcgp/backend/tests/NodeTests.java +++ b/src/jcgp/backend/tests/NodeTests.java @@ -2,7 +2,7 @@ package jcgp.backend.tests;  import static org.junit.Assert.assertTrue;  import jcgp.backend.exceptions.InvalidArgumentsException; -import jcgp.backend.function.DoubleArithmetic; +import jcgp.backend.function.SymbolicRegressionFunctions;  import jcgp.backend.function.Function;  import jcgp.backend.population.Chromosome;  import jcgp.backend.population.Connection; @@ -41,7 +41,7 @@ public class NodeTests {  	public static void setUpBeforeClass() {  		resources = new ModifiableResources(); -		resources.setFunctionSet(new DoubleArithmetic()); +		resources.setFunctionSet(new SymbolicRegressionFunctions());  		chromosome = new Chromosome(resources);  	} @@ -49,7 +49,7 @@ public class NodeTests {  	public void setUp() throws Exception {  		node = new Node(chromosome, 0, 0, resources.arity());  		// make node with anonymous addition function and hard-coded value connections -		node.initialise(new DoubleArithmetic.Addition(), +		node.initialise(new SymbolicRegressionFunctions.Addition(),  				new Connection[]{new Connection() {  					@Override @@ -80,7 +80,7 @@ public class NodeTests {  		Function f = new Function() {  			@Override -			public Object run(Connection... connections) { +			public Object run(Object... connections) {  				// blank  				return 0;  			} @@ -90,12 +90,6 @@ public class NodeTests {  				// blank  				return 0;  			} - -			@Override -			public String getName() { -				// blank -				return null; -			}  		};  		node.setFunction(f); @@ -113,7 +107,7 @@ public class NodeTests {  				((int) node.getValue()) == arg1 + arg2);  		// put in a different function, check the output has changed appropriately -		node.setFunction(new DoubleArithmetic.Subtraction()); +		node.setFunction(new SymbolicRegressionFunctions.Subtraction());  		assertTrue("Node did not return expected value (difference of arguments).", ((Integer) node.getValue()) == arg1 - arg2); @@ -142,7 +136,7 @@ public class NodeTests {  		Function function = new Function() {  			@Override -			public Object run(Connection... connections) +			public Object run(Object... connections)  					throws InvalidArgumentsException {  				// blank  				return null; @@ -152,12 +146,6 @@ public class NodeTests {  			public int getArity() {  				return 2;  			} - -			@Override -			public String getName() { -				// blank -				return null; -			}  		};  		node.initialise(function, conn0, conn1); diff --git a/src/jcgp/backend/tests/OutputTests.java b/src/jcgp/backend/tests/OutputTests.java index 95b7fc7..8cc10a8 100644 --- a/src/jcgp/backend/tests/OutputTests.java +++ b/src/jcgp/backend/tests/OutputTests.java @@ -1,7 +1,7 @@  package jcgp.backend.tests;  import static org.junit.Assert.assertTrue; -import jcgp.backend.function.DoubleArithmetic; +import jcgp.backend.function.SymbolicRegressionFunctions;  import jcgp.backend.population.Chromosome;  import jcgp.backend.population.Connection;  import jcgp.backend.population.Output; @@ -35,7 +35,7 @@ public class OutputTests {  	@BeforeClass  	public static void setUpBeforeClass() {  		resources = new ModifiableResources(); -		resources.setFunctionSet(new DoubleArithmetic()); +		resources.setFunctionSet(new SymbolicRegressionFunctions());  		chromosome = new Chromosome(resources);  	} diff --git a/src/jcgp/backend/tests/PopulationTests.java b/src/jcgp/backend/tests/PopulationTests.java index fca9c4f..2f36ce1 100644 --- a/src/jcgp/backend/tests/PopulationTests.java +++ b/src/jcgp/backend/tests/PopulationTests.java @@ -1,7 +1,7 @@  package jcgp.backend.tests;  import static org.junit.Assert.assertTrue; -import jcgp.backend.function.DoubleArithmetic; +import jcgp.backend.function.SymbolicRegressionFunctions;  import jcgp.backend.population.Chromosome;  import jcgp.backend.population.Population;  import jcgp.backend.resources.ModifiableResources; @@ -32,7 +32,7 @@ public class PopulationTests {  	@BeforeClass  	public static void setUpBeforeClass() throws Exception {  		resources = new ModifiableResources(); -		resources.setFunctionSet(new DoubleArithmetic()); +		resources.setFunctionSet(new SymbolicRegressionFunctions());  	}  	@Before @@ -64,6 +64,6 @@ public class PopulationTests {  		// initialise a population with a copy of it  		population = new Population(oc, resources);  		// check that the first parent chromosome is identical to, but not the same instance as, the one given -		assertTrue("Incorrect chromosome in population.", population.getChromosome(0).compareTo(oc) && population.getChromosome(0) != oc); +		assertTrue("Incorrect chromosome in population.", population.getChromosome(0).compareGenesTo(oc) && population.getChromosome(0) != oc);  	}  } diff --git a/src/jcgp/gui/console/GUIConsole.java b/src/jcgp/gui/console/GUIConsole.java index e77e222..de4b378 100644 --- a/src/jcgp/gui/console/GUIConsole.java +++ b/src/jcgp/gui/console/GUIConsole.java @@ -38,7 +38,6 @@ public class GUIConsole extends AnchorPane implements Console {  			@Override  			public Event dispatchEvent(Event event, EventDispatchChain tail) {  				if (event instanceof MouseEvent) { -					//shot in the dark guess for OSX, might not work  					MouseEvent mouseEvent = (MouseEvent)event;  					if (mouseEvent.getButton() == MouseButton.SECONDARY ||   							(mouseEvent.getButton() == MouseButton.PRIMARY && mouseEvent.isControlDown())) { diff --git a/src/jcgp/gui/population/FunctionSelector.java b/src/jcgp/gui/population/FunctionSelector.java index 28eb54d..69d0d31 100644 --- a/src/jcgp/gui/population/FunctionSelector.java +++ b/src/jcgp/gui/population/FunctionSelector.java @@ -31,7 +31,7 @@ public class FunctionSelector extends VBox {  		for (int i = 0; i < fs.getAllowedFunctionCount(); i++) {  			final int index = i; -			Label l = new Label(fs.getAllowedFunction(i).getName()); +			Label l = new Label(fs.getAllowedFunction(i).toString());  			l.setMaxWidth(Double.MAX_VALUE);  			l.setStyle("-fx-background-color: #FFFFFF; -fx-border-color: #A0A0A0; -fx-border-width: 0 0 1 0; -fx-padding: 2"); diff --git a/src/jcgp/gui/population/GUINode.java b/src/jcgp/gui/population/GUINode.java index f50edd3..731db8f 100644 --- a/src/jcgp/gui/population/GUINode.java +++ b/src/jcgp/gui/population/GUINode.java @@ -454,9 +454,9 @@ public class GUINode extends GUIGene {  	public void updateText() {  		if (parent.isEvaluating()) { -			text.setText(node.getFunction().getName() + "\n" + value.toString()); +			text.setText(node.getFunction() + "\n" + value.toString());  		} else { -			text.setText(node.getFunction().getName()); +			text.setText(node.getFunction().toString());  		}  	} diff --git a/src/jcgp/gui/settings/SettingsPane.java b/src/jcgp/gui/settings/SettingsPane.java index 302e96d..7fc5621 100644 --- a/src/jcgp/gui/settings/SettingsPane.java +++ b/src/jcgp/gui/settings/SettingsPane.java @@ -126,17 +126,13 @@ public class SettingsPane extends AnchorPane {  		final VBox eaParameters = new VBox(2); -		if (jcgp.getEvolutionaryStrategy().getLocalParameters() != null) { -			refreshParameters(jcgp.getEvolutionaryStrategy().getLocalParameters(), eaParameters); -		} +		refreshParameters(jcgp.getEvolutionaryStrategy().getLocalParameters(), eaParameters);  		eaCBox.setOnAction(new EventHandler<ActionEvent>() {  			@Override  			public void handle(ActionEvent event) {  				jcgp.setEvolutionaryStrategy(eaCBox.getSelectionModel().getSelectedIndex()); -				if (eaCBox.getSelectionModel().getSelectedItem().getLocalParameters() != null) { -					refreshParameters(eaCBox.getSelectionModel().getSelectedItem().getLocalParameters(), eaParameters); -				} +				refreshParameters(eaCBox.getSelectionModel().getSelectedItem().getLocalParameters(), eaParameters);  			}  		}); @@ -157,17 +153,13 @@ public class SettingsPane extends AnchorPane {  		mutatorCBox.prefWidthProperty().bind(mainContainer.widthProperty());  		final VBox mutatorParameters = new VBox(2); -		if (jcgp.getEvolutionaryStrategy().getLocalParameters() != null) { -			refreshParameters(jcgp.getMutator().getLocalParameters(), mutatorParameters); -		} +		refreshParameters(jcgp.getMutator().getLocalParameters(), mutatorParameters);  		mutatorCBox.setOnAction(new EventHandler<ActionEvent>() {  			@Override  			public void handle(ActionEvent event) {  				jcgp.setMutator(mutatorCBox.getSelectionModel().getSelectedIndex()); -				if (mutatorCBox.getSelectionModel().getSelectedItem().getLocalParameters() != null) { -					refreshParameters(mutatorCBox.getSelectionModel().getSelectedItem().getLocalParameters(), mutatorParameters); -				}			 +				refreshParameters(mutatorCBox.getSelectionModel().getSelectedItem().getLocalParameters(), mutatorParameters);  			}  		}); @@ -189,22 +181,22 @@ public class SettingsPane extends AnchorPane {  		final VBox problemParameters = new VBox(2);  		problemParameters.setPadding(new Insets(0, 0, 4, 0)); -		if (jcgp.getProblem().getLocalParameters() != null) { -			refreshParameters(jcgp.getProblem().getLocalParameters(), problemParameters); -		} +		refreshParameters(jcgp.getProblem().getLocalParameters(), problemParameters);  		final HBox testCaseControlContainer = new HBox(2);  		final Button showTestCaseButton = makeTestCaseButton(); -		final Button loadTestCaseButton = makeLoadTestCaseButton(); +		final Button loadProblemDataButton = makeLoadTestCaseButton();  		HBox.setHgrow(showTestCaseButton, Priority.ALWAYS);  		showTestCaseButton.setMaxWidth(Double.MAX_VALUE); -		HBox.setHgrow(loadTestCaseButton, Priority.ALWAYS); -		loadTestCaseButton.setMaxWidth(Double.MAX_VALUE); +		HBox.setHgrow(loadProblemDataButton, Priority.ALWAYS); +		loadProblemDataButton.setMaxWidth(Double.MAX_VALUE);  		if (jcgp.getProblem() instanceof TestCaseProblem<?>) { -			testCaseControlContainer.getChildren().addAll(showTestCaseButton, loadTestCaseButton); +			testCaseControlContainer.getChildren().addAll(showTestCaseButton, loadProblemDataButton);  			remakeTestCaseTable(); +		} else { +			testCaseControlContainer.getChildren().add(loadProblemDataButton);  		}  		nodeFunctions = new VBox(2); @@ -215,16 +207,16 @@ public class SettingsPane extends AnchorPane {  			@Override  			public void handle(ActionEvent event) {  				jcgp.setProblem(problemCBox.getSelectionModel().getSelectedIndex()); -				if (jcgp.getProblem().getLocalParameters() != null) { -					refreshParameters(jcgp.getProblem().getLocalParameters(), problemParameters); -				} +				refreshParameters(jcgp.getProblem().getLocalParameters(), problemParameters);  				testCaseTable.close();  				gui.setEvaluating(false);  				refreshFunctions();  				testCaseControlContainer.getChildren().clear();  				if (jcgp.getProblem() instanceof TestCaseProblem) { -					testCaseControlContainer.getChildren().addAll(showTestCaseButton, loadTestCaseButton); +					testCaseControlContainer.getChildren().addAll(showTestCaseButton, loadProblemDataButton);  					remakeTestCaseTable(); +				} else { +					testCaseControlContainer.getChildren().add(loadProblemDataButton);  				}  				gui.reset();  			} @@ -236,17 +228,17 @@ public class SettingsPane extends AnchorPane {  	}  	private Button makeLoadTestCaseButton() { -		Button b = new Button("Load test cases"); +		Button b = new Button("Load problem data");  		b.setOnAction(new EventHandler<ActionEvent>() {  			@Override  			public void handle(ActionEvent event) {  				FileChooser fc = new FileChooser(); -				fc.setTitle("Open test case file..."); +				fc.setTitle("Open problem file...");  				fc.getExtensionFilters().add(new ExtensionFilter("CGP " + gui.getExperiment().getProblem() + " files", "*" + ((TestCaseProblem<?>) gui.getExperiment().getProblem()).getFileExtension()));  				fc.getExtensionFilters().add(new ExtensionFilter("All files", "*.*"));  				File chrFile = fc.showOpenDialog(gui.getStage());  				if (chrFile != null) { -					gui.getExperiment().loadTestCases(chrFile); +					gui.getExperiment().loadProblemData(chrFile);  					remakeTestCaseTable();  					gui.reDraw();  				} @@ -369,10 +361,12 @@ public class SettingsPane extends AnchorPane {  	private void refreshParameters(Parameter<?>[] newParameters, VBox vb) {  		parameters.removeAll(vb.getChildren());  		vb.getChildren().clear(); -		for (int i = 0; i < newParameters.length; i++) { -	        GUIParameter<?> gp = GUIParameter.create(newParameters[i], this); -	        parameters.add(gp); -        	vb.getChildren().add(gp); +		if (newParameters != null) { +			for (int i = 0; i < newParameters.length; i++) { +				GUIParameter<?> gp = GUIParameter.create(newParameters[i], this); +				parameters.add(gp); +				vb.getChildren().add(gp); +			}  		}  		revalidateParameters();  	} @@ -386,7 +380,7 @@ public class SettingsPane extends AnchorPane {  		CheckBox cb;  		final FunctionSet fs = gui.getExperiment().getResources().getFunctionSet();  		for (int i = 0; i < fs.getTotalFunctionCount(); i++) { -			cb = new CheckBox(fs.getFunction(i).getName()); +			cb = new CheckBox(fs.getFunction(i).toString());  			cb.setId(String.valueOf(i));  			cb.setSelected(fs.isEnabled(fs.getFunction(i)));  			final int index = i; diff --git a/src/jcgp/gui/settings/parameters/GUIBooleanParameter.java b/src/jcgp/gui/settings/parameters/GUIBooleanParameter.java index e708c53..cc7113d 100644 --- a/src/jcgp/gui/settings/parameters/GUIBooleanParameter.java +++ b/src/jcgp/gui/settings/parameters/GUIBooleanParameter.java @@ -62,7 +62,8 @@ public class GUIBooleanParameter extends GUIParameter<Boolean> {  			checkBox.setStyle(BASE_CHECKBOX_STYLE + INVALID_PARAMETER_STYLE);  			checkBox.setTooltip(tooltip);  			tooltip.setText(parameter.getStatus().getDetails()); -		} else if (parameter.getStatus() == ParameterStatus.WARNING || parameter.getStatus() ==  ParameterStatus.WARNING_RESET) { +		} else if (parameter.getStatus() == ParameterStatus.WARNING  +				|| parameter.getStatus() == ParameterStatus.WARNING_RESET) {  			checkBox.setStyle(BASE_CHECKBOX_STYLE + WARNING_PARAMETER_STYLE);  			checkBox.setTooltip(tooltip);  			tooltip.setText(parameter.getStatus().getDetails()); diff --git a/src/jcgp/gui/settings/parameters/GUIDoubleParameter.java b/src/jcgp/gui/settings/parameters/GUIDoubleParameter.java index f177ffa..777e739 100644 --- a/src/jcgp/gui/settings/parameters/GUIDoubleParameter.java +++ b/src/jcgp/gui/settings/parameters/GUIDoubleParameter.java @@ -36,6 +36,7 @@ public class GUIDoubleParameter extends GUIParameter<Number> {  	@Override  	protected Control makeControl() { +		// we use a text field, and a formatting class to enforce decimals  		decimalFormat = new DecimalFormat();  		decimalFormat.setMaximumFractionDigits(10);  		textField = new TextField(decimalFormat.format(parameter.get().doubleValue())); @@ -48,14 +49,16 @@ public class GUIDoubleParameter extends GUIParameter<Number> {  	@Override  	protected void setControlListeners() {  		/* pass the TextField value back to the parameter whenever it gets -		 * modified, provided it is not empty and the experiment isn't running */ +		 * modified, provided it is not empty, the experiment isn't running +		 * and it matches the double-precision regex filter */  		textField.textProperty().addListener(new ChangeListener<String>() {  			@Override  			public void changed(  					ObservableValue<? extends String> observable,  					String oldValue, String newValue) {  				if (!settingsPane.isExperimentRunning()) { -					if (newValue.matches("([0-9]*[.]*[0-9]*)")) { +					//if (newValue.matches("([0-9]*[.]?[0-9]*)")) { +					if (newValue.matches("^[-+]?[0-9]*\\.?[0-9]+$")) {  						if (!newValue.isEmpty()) {  							double value = Double.parseDouble(newValue);  							parameter.set(value); diff --git a/src/jcgp/gui/settings/parameters/GUIIntegerParameter.java b/src/jcgp/gui/settings/parameters/GUIIntegerParameter.java index e1b0b75..6e8b3f1 100644 --- a/src/jcgp/gui/settings/parameters/GUIIntegerParameter.java +++ b/src/jcgp/gui/settings/parameters/GUIIntegerParameter.java @@ -33,6 +33,7 @@ public class GUIIntegerParameter extends GUIParameter<Number> {  	@Override  	protected Control makeControl() { +		// this uses a text field  		textField = new TextField(String.valueOf(parameter.get()));  		textField.setStyle(VALID_PARAMETER_STYLE);  		textField.setAlignment(Pos.CENTER_RIGHT); @@ -44,7 +45,8 @@ public class GUIIntegerParameter extends GUIParameter<Number> {  	@Override  	protected void setControlListeners() {  		/* pass the TextField value back to the parameter whenever it gets -		 * modified, provided it is not empty and the experiment isn't running */ +		 * modified, provided it is not empty, the experiment isn't running +		 * and it matches the integer regex pattern */  		textField.textProperty().addListener(new ChangeListener<String>() {  			@Override  			public void changed( @@ -98,7 +100,7 @@ public class GUIIntegerParameter extends GUIParameter<Number> {  	@Override  	public void refreshValue() {  		if (!textField.isFocused()) { -			textField.setText(String.valueOf(parameter.get())); +			textField.setText(parameter.get().toString());  		}  	}  } diff --git a/src/jcgp/gui/settings/parameters/GUIParameter.java b/src/jcgp/gui/settings/parameters/GUIParameter.java index 79762ff..b675fb5 100644 --- a/src/jcgp/gui/settings/parameters/GUIParameter.java +++ b/src/jcgp/gui/settings/parameters/GUIParameter.java @@ -30,9 +30,8 @@ import jcgp.gui.settings.SettingsPane;   * Monitor parameters have their Control disabled so that no changed can be made via the GUI.   * Non-monitor parameters are updated automatically as well, but may be changed by the user   * if the program is not evolving. - * <br><br> - * For more information on how parameters work in JCGP, see {@link Parameter}.   *  + * @see Parameter   * @author Eduardo Pedroni   * @param <T> the parameter data type   */ @@ -174,7 +173,6 @@ public abstract class GUIParameter<T> extends HBox {  	 */  	public void validate() {  		parameter.validate(parameter.get()); -		//refreshValue();  		setValidityStyle();  	} | 
