summaryrefslogtreecommitdiffstats
path: root/watchmaker/framework/src/java/main/org/uncommons/watchmaker/framework/termination/Stagnation.java
diff options
context:
space:
mode:
Diffstat (limited to 'watchmaker/framework/src/java/main/org/uncommons/watchmaker/framework/termination/Stagnation.java')
-rw-r--r--watchmaker/framework/src/java/main/org/uncommons/watchmaker/framework/termination/Stagnation.java113
1 files changed, 113 insertions, 0 deletions
diff --git a/watchmaker/framework/src/java/main/org/uncommons/watchmaker/framework/termination/Stagnation.java b/watchmaker/framework/src/java/main/org/uncommons/watchmaker/framework/termination/Stagnation.java
new file mode 100644
index 0000000..b0bab4a
--- /dev/null
+++ b/watchmaker/framework/src/java/main/org/uncommons/watchmaker/framework/termination/Stagnation.java
@@ -0,0 +1,113 @@
+//=============================================================================
+// Copyright 2006-2010 Daniel W. Dyer
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//=============================================================================
+package org.uncommons.watchmaker.framework.termination;
+
+import org.uncommons.watchmaker.framework.PopulationData;
+import org.uncommons.watchmaker.framework.TerminationCondition;
+
+/**
+ * A {@link TerminationCondition} that halts evolution if no improvement in fitness
+ * is observed within a specified number of generations.
+ * @author Daniel Dyer
+ */
+public class Stagnation implements TerminationCondition
+{
+ private final int generationLimit;
+ private final boolean naturalFitness;
+ private final boolean usePopulationAverage;
+
+ private double bestFitness;
+ private int fittestGeneration;
+
+ /**
+ * Creates a {@link TerminationCondition} that will halt evolution after the
+ * specified number of generations passes without any improvement in the population's
+ * fittest individual.
+ * @param generationLimit The number of generations without improvement that
+ * will lead to termination.
+ * @param naturalFitness True if higher fitness scores are better, false otherwise.
+ */
+ public Stagnation(int generationLimit,
+ boolean naturalFitness)
+ {
+ this(generationLimit, naturalFitness, false);
+ }
+
+
+ /**
+ * Creates a {@link TerminationCondition} that will halt evolution after the
+ * specified number of generations passes without any improvement in the population's
+ * fitness (either the fittest individual or the mean fitness of the entire population,
+ * depending on the final parameter).
+ * @param generationLimit The number of generations without improvement that
+ * will lead to termination.
+ * @param naturalFitness True if higher fitness scores are better, false otherwise.
+ * @param usePopulationAverage If true uses the mean fitness of the population as the
+ * criteria, otherwise uses the fittest individual.
+ */
+ public Stagnation(int generationLimit,
+ boolean naturalFitness,
+ boolean usePopulationAverage)
+ {
+ this.generationLimit = generationLimit;
+ this.naturalFitness = naturalFitness;
+ this.usePopulationAverage = usePopulationAverage;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean shouldTerminate(PopulationData<?> populationData)
+ {
+ double fitness = getFitness(populationData);
+ if (populationData.getGenerationNumber() == 0 || hasFitnessImproved(fitness))
+ {
+ bestFitness = fitness;
+ fittestGeneration = populationData.getGenerationNumber();
+ }
+
+ return populationData.getGenerationNumber() - fittestGeneration >= generationLimit;
+ }
+
+
+ /**
+ * Determines the fitness of the current population (either best fitness or
+ * mean fitness depending on how the termination condition is configured).
+ * @param populationData Data about the current generation.
+ * @return The fitness measure used to decide whether the evolution has stagnated
+ * or not.
+ */
+ private double getFitness(PopulationData<?> populationData)
+ {
+ return usePopulationAverage
+ ? populationData.getMeanFitness()
+ : populationData.getBestCandidateFitness();
+ }
+
+
+ /**
+ * Determine whether the population fitness is better than the best seen so far.
+ * @param fitness The fitness of the current population (either best fitness or mean
+ * fitness depending on how the termination condition is configured).
+ * @return True if the fitness has improved in the current generation, false otherwise.
+ */
+ private boolean hasFitnessImproved(double fitness)
+ {
+ return (naturalFitness && fitness > bestFitness)
+ || (!naturalFitness && fitness < bestFitness);
+ }
+}