This is an automated email from the ASF dual-hosted git repository. erans pushed a commit to branch feature__MATH-1563__genetic_algorithm in repository https://gitbox.apache.org/repos/asf/commons-math.git
commit 383256f8cfcbf1de70f93a1d1ea0e7c972812af0 Author: Gilles Sadowski <gillese...@gmail.com> AuthorDate: Sun Jun 12 02:41:56 2022 +0200 MATH-1618: Make "stopping condition" a "BiPredicate". Second argument is the generation count (as determined by the caller). --- .../ga/mathfunctions/MathFunctionOptimizer2.java | 4 ++-- .../commons/math4/ga2/GeneticAlgorithmFactory.java | 13 +++++------ .../commons/math4/ga2/stop/UnchangedFitness.java | 27 +++++++++++++++------- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/MathFunctionOptimizer2.java b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/MathFunctionOptimizer2.java index 96ea5087b..ac128d89e 100644 --- a/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/MathFunctionOptimizer2.java +++ b/commons-math-examples/examples-ga/examples-ga-math-functions/src/main/java/org/apache/commons/math4/examples/ga/mathfunctions/MathFunctionOptimizer2.java @@ -23,7 +23,7 @@ import java.util.HashMap; import java.util.List; import java.util.function.Function; import java.util.function.ToDoubleFunction; -import java.util.function.Predicate; +import java.util.function.BiPredicate; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import java.util.concurrent.Callable; @@ -100,7 +100,7 @@ public final class MathFunctionOptimizer2 { }; // Stopping condition (not thread-safe). - final Predicate<Population<Chromosome, Coordinates>> stop = + final BiPredicate<Population<Chromosome, Coordinates>, Integer> stop = new UnchangedFitness(UnchangedFitness.Type.BEST, numGeneration); diff --git a/commons-math-ga2/src/main/java/org/apache/commons/math4/ga2/GeneticAlgorithmFactory.java b/commons-math-ga2/src/main/java/org/apache/commons/math4/ga2/GeneticAlgorithmFactory.java index 40ec98249..9386e5617 100644 --- a/commons-math-ga2/src/main/java/org/apache/commons/math4/ga2/GeneticAlgorithmFactory.java +++ b/commons-math-ga2/src/main/java/org/apache/commons/math4/ga2/GeneticAlgorithmFactory.java @@ -23,7 +23,7 @@ import java.util.ArrayList; import java.util.Map; import java.util.concurrent.Callable; import java.util.function.Function; -import java.util.function.Predicate; +import java.util.function.BiPredicate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.commons.rng.simple.RandomSource; @@ -43,7 +43,7 @@ public final class GeneticAlgorithmFactory<G, P> implements Callable<Population< /** Genotype to phenotype converter. */ private final Function<G, P> decoder; /** Criterion for stopping the evolution. */ - private final Predicate<Population<G, P>> stop; + private final BiPredicate<Population<G, P>, Integer> stop; /** Fitness calculator. */ private final FitnessService<G, P> fitness; /** Chromosome selector. */ @@ -71,7 +71,7 @@ public final class GeneticAlgorithmFactory<G, P> implements Callable<Population< */ private GeneticAlgorithmFactory(Collection<G> init, Function<G, P> decoder, - Predicate<Population<G, P>> stop, + BiPredicate<Population<G, P>, Integer> stop, FitnessService<G, P> fitness, Selection<G, P> selection, Map<GeneticOperator<G>, ApplicationRate> operators, @@ -107,7 +107,7 @@ public final class GeneticAlgorithmFactory<G, P> implements Callable<Population< */ public static <G, P> Callable<Population<G, P>> create(Collection<G> init, Function<G, P> decoder, - Predicate<Population<G, P>> stop, + BiPredicate<Population<G, P>, Integer> stop, FitnessService<G, P> fitness, Selection<G, P> selection, Map<GeneticOperator<G>, ApplicationRate> operators, @@ -147,7 +147,7 @@ public final class GeneticAlgorithmFactory<G, P> implements Callable<Population< ChromosomeFactory<G> initFactory, int populationSize, Function<G, P> decoder, - Predicate<Population<G, P>> stop, + BiPredicate<Population<G, P>, Integer> stop, FitnessService<G, P> fitness, Selection<G, P> selection, Map<GeneticOperator<G>, ApplicationRate> operators, @@ -181,8 +181,7 @@ public final class GeneticAlgorithmFactory<G, P> implements Callable<Population< currentGen.add(init); final UniformRandomProvider rng = random.create(); - while (!stop.test(currentGen)) { - ++generation; + while (!stop.test(currentGen, ++generation)) { final Population<G, P> nextGen = new Population<>(popSize, decoder, fitness); applyElitism(currentGen, nextGen); diff --git a/commons-math-ga2/src/main/java/org/apache/commons/math4/ga2/stop/UnchangedFitness.java b/commons-math-ga2/src/main/java/org/apache/commons/math4/ga2/stop/UnchangedFitness.java index c261c434f..228abd9aa 100644 --- a/commons-math-ga2/src/main/java/org/apache/commons/math4/ga2/stop/UnchangedFitness.java +++ b/commons-math-ga2/src/main/java/org/apache/commons/math4/ga2/stop/UnchangedFitness.java @@ -18,25 +18,30 @@ package org.apache.commons.math4.ga2.stop; import java.util.Map; import java.util.function.ToDoubleFunction; -import java.util.function.Predicate; +import java.util.function.BiPredicate; import org.apache.commons.math4.ga2.Population; /** * Criterion for asserting convergence of a population. - * Note: Class is <em>not</em> thread-safe. + * Notes: + * <ul> + * <li>Class is <em>not</em> thread-safe.</li> + * <li>A <em>new</em> instance must created for each GA run (otherwise + * an {@link IllegalStateException} will be thrown).</li> + * </ul> * * @param <G> Genotype. * @param <P> Phenotype. */ -public class UnchangedFitness<G, P> implements Predicate<Population<G, P>> { +public class UnchangedFitness<G, P> implements BiPredicate<Population<G, P>, Integer> { /** Function that computes the reference value. */ private final ToDoubleFunction<Population<G, P>> calculator; /** Number of generations during which no change has happened. */ private final int maxGenerations; /** Value for previous population. */ private double previousFitness = Double.NaN; - /** Number of generations without changes. */ - private int generations = 0; + /** Generation at which the last change has occurred. */ + private int updatedGeneration = 0; /** What needs to be unchanged. */ public enum Type { @@ -71,14 +76,20 @@ public class UnchangedFitness<G, P> implements Predicate<Population<G, P>> { /** {@inheritDoc} */ @Override - public boolean test(Population<G, P> population) { + public boolean test(Population<G, P> population, + Integer generationCounter) { + final int genDiff = generationCounter - updatedGeneration; + if (genDiff < 0) { + throw new IllegalStateException("Incorrect usage"); + } + final double fitness = calculator.applyAsDouble(population); if (fitness == previousFitness) { - if (++generations > maxGenerations) { + if (genDiff > maxGenerations) { return true; } } else { - generations = 0; + updatedGeneration = generationCounter; previousFitness = fitness; }