From 383256f8cfcbf1de70f93a1d1ea0e7c972812af0 Mon Sep 17 00:00:00 2001 From: Gilles Sadowski Date: Sun, 12 Jun 2022 02:41:56 +0200 Subject: [PATCH] MATH-1618: Make "stopping condition" a "BiPredicate". Second argument is the generation count (as determined by the caller). --- .../mathfunctions/MathFunctionOptimizer2.java | 4 +-- .../math4/ga2/GeneticAlgorithmFactory.java | 13 +++++---- .../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> stop = + final BiPredicate, 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 implements Callable decoder; /** Criterion for stopping the evolution. */ - private final Predicate> stop; + private final BiPredicate, Integer> stop; /** Fitness calculator. */ private final FitnessService fitness; /** Chromosome selector. */ @@ -71,7 +71,7 @@ public final class GeneticAlgorithmFactory implements Callable init, Function decoder, - Predicate> stop, + BiPredicate, Integer> stop, FitnessService fitness, Selection selection, Map, ApplicationRate> operators, @@ -107,7 +107,7 @@ public final class GeneticAlgorithmFactory implements Callable Callable> create(Collection init, Function decoder, - Predicate> stop, + BiPredicate, Integer> stop, FitnessService fitness, Selection selection, Map, ApplicationRate> operators, @@ -147,7 +147,7 @@ public final class GeneticAlgorithmFactory implements Callable initFactory, int populationSize, Function decoder, - Predicate> stop, + BiPredicate, Integer> stop, FitnessService fitness, Selection selection, Map, ApplicationRate> operators, @@ -181,8 +181,7 @@ public final class GeneticAlgorithmFactory implements Callable 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 not thread-safe. + * Notes: + *
    + *
  • Class is not thread-safe.
  • + *
  • A new instance must created for each GA run (otherwise + * an {@link IllegalStateException} will be thrown).
  • + *
* * @param Genotype. * @param

Phenotype. */ -public class UnchangedFitness implements Predicate> { +public class UnchangedFitness implements BiPredicate, Integer> { /** Function that computes the reference value. */ private final ToDoubleFunction> 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 implements Predicate> { /** {@inheritDoc} */ @Override - public boolean test(Population population) { + public boolean test(Population 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; }