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;
         }
 

Reply via email to