From 7a54a44b01f1b4ac5b39dc5d7a9d4e62d066982b Mon Sep 17 00:00:00 2001
From: Eduardo Pedroni <ep625@york.ac.uk>
Date: Sat, 10 May 2014 10:30:20 +0100
Subject: Fixed digital problem with more than one test case, improved
 mu+lambda to be more like CGP

---
 src/jcgp/backend/modules/es/MuPlusLambda.java      | 66 ++++++++++++++++++++--
 .../modules/problem/DigitalCircuitProblem.java     |  8 ++-
 2 files changed, 67 insertions(+), 7 deletions(-)

(limited to 'src/jcgp/backend/modules')

diff --git a/src/jcgp/backend/modules/es/MuPlusLambda.java b/src/jcgp/backend/modules/es/MuPlusLambda.java
index 3743ee6..6a6870f 100644
--- a/src/jcgp/backend/modules/es/MuPlusLambda.java
+++ b/src/jcgp/backend/modules/es/MuPlusLambda.java
@@ -77,21 +77,77 @@ public class MuPlusLambda extends EvolutionaryStrategy {
 
 	@Override
 	public void evolve(Population population, Mutator mutator) {	
-		// sort the population in order of best fitness
-		population.sort();
+		// sort the population neutrally
+		sort(population);
 		
-		// population is now sorted in ascending order of fitness, the last chromosomes are the fittest
+		// population is now sorted such that the new parents are in the last mu positions
 		for (int i = 0; i < getResources().populationSize() - mu.get(); i++) {
-			// select a random parent out of the lambda offspring individuals
+			// select a random parent out of the mu population parents
 			int randomParent = getResources().populationSize() - 1 - getResources().getRandomInt(mu.get());
 			if (report.get()) getResources().reportln("[ES] Copying Chr " + randomParent + " to population position " + i);
+			
+			// copy it into the offspring position
 			population.copyChromosome(randomParent, i);
 
-			// mutate selected chromosome
+			// mutate the new offspring chromosome
 			if (report.get()) getResources().reportln("[ES] Mutating copied chromosome");
 			mutator.mutate(population.get(i));
 		}
 
 		if (report.get()) getResources().reportln("[ES] Generation is complete");
 	}
+
+	/**
+	 * Neutrally sorts the specified population. 
+	 * <br><br>
+	 * Optimised sorting methods tend to be stable, meaning 
+	 * the order of elements which are already ordered is not
+	 * changed. While performing faster, such sorting algorithms
+	 * do not promote neutral drift, an important aspect of CGP.
+	 * <br><br>
+	 * This sort iterates through the population offspring (first lambda
+	 * elements) and compares each with each of the parents (last mu
+	 * elements), overwriting the parent if the offspring's fitness
+	 * is greater than or equal to the parent's. 
+	 * It is biased towards offspring: parents are replaced with
+	 * equally fit offspring as often as possible. 
+	 * 
+	 * @param population the population to sort.
+	 */
+	private void sort(Population population) {
+		/* Create an array with the index of each of the current parents.
+		 * This is done to speed up the sort. No deep chromosome copies are
+		 * made until the algorithm is finished; instead, only indices are copied.
+		 */
+		int[] parents = new int[mu.get()];
+		for (int i = 0; i < parents.length; i++) {
+			parents[i] = lambda.get() + i;
+		}
+		
+		// cycle through the offspring, i.e. the first lambda elements of the population
+		for (int o = 0; o < getResources().populationSize() - mu.get(); o++) {
+			// compare each offspring with each parent, as stored in parents
+			for (int p = 0; p < parents.length; p++) {
+				/* replace parent if the offspring fitness and greater than or equal to its own
+				 * if it is equal to, only replace if it is an old parent, if it is greater than,
+				 * replace regardless
+				 */
+				if ((population.get(o).getFitness() == population.get(parents[p]).getFitness() && parents[p] >= lambda.get())
+						|| population.get(o).getFitness() >= population.get(parents[p]).getFitness()) {
+					parents[p] = o;
+					// offspring has been selected, check the next one
+					break;
+				}
+			}
+		}
+		
+		/* selection is complete, parents now contains the indices of each selected offspring
+		 * time to perform the deep copies
+		 */
+		for (int c = 0; c < parents.length; c++) {
+			// copy each selected index in parent to each parent position in the population
+			population.copyChromosome(parents[c], lambda.get() + c);
+		}
+		
+	}
 }
diff --git a/src/jcgp/backend/modules/problem/DigitalCircuitProblem.java b/src/jcgp/backend/modules/problem/DigitalCircuitProblem.java
index b615675..e2f17c3 100644
--- a/src/jcgp/backend/modules/problem/DigitalCircuitProblem.java
+++ b/src/jcgp/backend/modules/problem/DigitalCircuitProblem.java
@@ -45,13 +45,17 @@ public class DigitalCircuitProblem extends TestCaseProblem<UnsignedInteger> {
 					Integer output = ((UnsignedInteger) population.get(i).getOutput(o).calculate()).get();
 					Integer matches = ~(output ^ testCases.get(t).getOutput(o).get());
 					// check only the relevant bits
-					int bits = (int) Math.pow(2.0, (double) resources.inputs());
+					int bits;
+					if (resources.inputs() < 5) {
+						bits = (int) Math.pow(2.0, (double) resources.inputs());
+					} else {
+						bits = 32;
+					}
 					for (int b = 0; b < bits; b++) {
 						fitness += (matches >>> b) & 1;
 					}
 				}
 			}
-
 			// assign the resulting fitness to the respective individual
 			population.get(i).setFitness(fitness);
 		}
-- 
cgit v1.2.3