diff --git a/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/comparator/ParetoOptimisationValue.java b/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/comparator/ParetoOptimisationValue.java index 9ca49b3c2e2664d2804f26e945392d2d22d59c3c..5edbe0f629ebd5b7530d3f5b013b443ae0d45c73 100644 --- a/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/comparator/ParetoOptimisationValue.java +++ b/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/comparator/ParetoOptimisationValue.java @@ -1,8 +1,12 @@ package de.evoal.core.ea.main.comparator; import java.util.Arrays; +import java.util.Comparator; +import java.util.function.ToIntFunction; import de.evoal.core.api.optimisation.OptimisationValue; +import io.jenetics.ext.moea.ElementComparator; +import io.jenetics.ext.moea.ElementDistance; import io.jenetics.ext.moea.Vec; import lombok.NonNull; @@ -50,4 +54,20 @@ public class ParetoOptimisationValue implements OptimisationValue { return result; } + + public static ElementComparator<ParetoOptimisationValue> compare() { + return (u, v, i) -> u.fitnessValues.compare(v.fitnessValues, i); + } + + public static Comparator<ParetoOptimisationValue> dominance() { + return (u, v) -> Vec.dominance(u.fitnessValues.data(), v.fitnessValues.data()); + } + + public static ElementDistance<ParetoOptimisationValue> distance() { + return (u, v, i) -> u.fitnessValues.distance(v.fitnessValues, i); + } + + public static ToIntFunction<ParetoOptimisationValue> dimension() { + return u -> u.fitnessValues.length(); + } } diff --git a/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/producer/SelectorFactory.java b/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/producer/SelectorFactory.java index 69d9fe1da43441a8c83a40251d6285b0e63300ef..b71ee34329e80efa72afd8228b58fbeabfeddac0 100644 --- a/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/producer/SelectorFactory.java +++ b/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/producer/SelectorFactory.java @@ -3,8 +3,10 @@ package de.evoal.core.ea.main.producer; import de.evoal.core.api.board.CoreBlackboardEntries; import de.evoal.core.api.cdi.ConfigurationValue; import de.evoal.core.api.utils.LanguageHelper; +import de.evoal.core.ea.main.comparator.ParetoOptimisationValue; import de.evoal.languages.model.base.Instance; import io.jenetics.*; +import io.jenetics.ext.moea.NSGA2Selector; import lombok.extern.slf4j.Slf4j; import javax.enterprise.context.ApplicationScoped; @@ -45,6 +47,8 @@ public class SelectorFactory { case "tournament-selector": return createTournamentSelector(config); case "truncation-selector": return createTruncationSelector(config); + case "nsga2-selector": return createNSGA2Selector(config); + /* probability-based selectors */ case "boltzmann-selector": return createBoltzmannSelector(config); case "exponential-rank-selector": return createExponentialRankSelector(config); @@ -64,6 +68,14 @@ public class SelectorFactory { throw new IllegalStateException("Selector '" + name + "' is unknown."); } + private <G extends Gene<?, G>, C extends Comparable<? super C>> Selector<G, C> createNSGA2Selector(final Instance config) { + return (Selector<G, C>) new NSGA2Selector<>(ParetoOptimisationValue.dominance(), + ParetoOptimisationValue.compare(), + ParetoOptimisationValue.distance(), + ParetoOptimisationValue.dimension() + ); + } + private <G extends Gene<?, G>, C extends Comparable<? super C>> Selector<G,C> createRouletteWheelSelector(final Instance config) { return (Selector<G,C>) new RouletteWheelSelector<>(); } diff --git a/src/core/de.evoal.core.ea/src/main/resources/de/evoal/core/ea/optimisation.dl b/src/core/de.evoal.core.ea/src/main/resources/de/evoal/core/ea/optimisation.dl index 9a78c38654849994b3fd36334b8a620def25b054..3086bdd7dcf4916a4247454b8dee70671f2821ba 100644 --- a/src/core/de.evoal.core.ea/src/main/resources/de/evoal/core/ea/optimisation.dl +++ b/src/core/de.evoal.core.ea/src/main/resources/de/evoal/core/ea/optimisation.dl @@ -72,6 +72,19 @@ module de.evoal.core.ea.optimisation { abstract type selector { } + + /** + * This NSGA2 selector chooses <i>count</i> elements of the population. Therefore, the population is sorted using + * the Crowded-Comparison Operator first. For details, please read the original publication: + * + * K. Deb, A. Pratap, S. Agarwal, and T. Meyarivan. <i>A fast and elitist multiobjective genetic algorithm: + * NSGA-II</i>. Transactions on Evolutionary Computation, 6, 2, 182-197, April 2002. DOI: 10.1109/4235.996017. + * + * When using this selector, you have to ensure that you are using the ParetoComparator. Otherwise, the selector + * breaks. + */ + type 'nsga2-selector' extends selector { + } type 'roulette-wheel-selector' extends selector { }