From 5c2fd7c6000d0ecb7914f9536da468fba482d43f Mon Sep 17 00:00:00 2001 From: Fedor Smirnov Date: Fri, 2 Mar 2018 19:53:31 +0100 Subject: [PATCH 01/20] Implemented the basic structure of the survivor- and the mating-selection --- .../org/opt4j/optimizers/ea/AeSeHCoupler.java | 106 ++++++++++++ .../opt4j/optimizers/ea/AeSeHSelector.java | 65 ++++++++ .../ea/DefaultSurvivorGeneration.java | 151 ++++++++++++++++++ .../ea/ESamplingSurvivorGeneration.java | 30 ++++ .../opt4j/optimizers/ea/EpsilonAdaption.java | 50 ++++++ .../opt4j/optimizers/ea/EpsilonMapping.java | 44 +++++ .../ea/EvolutionaryAlgorithmModule.java | 21 ++- .../optimizers/ea/NeighborhoodScheduler.java | 34 ++++ .../optimizers/ea/NonDominatedSorting.java | 44 +++++ 9 files changed, 543 insertions(+), 2 deletions(-) create mode 100644 opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHCoupler.java create mode 100644 opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHSelector.java create mode 100644 opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultSurvivorGeneration.java create mode 100644 opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/ESamplingSurvivorGeneration.java create mode 100644 opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonAdaption.java create mode 100644 opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonMapping.java create mode 100644 opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NeighborhoodScheduler.java create mode 100644 opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedSorting.java diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHCoupler.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHCoupler.java new file mode 100644 index 00000000..cb0e9531 --- /dev/null +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHCoupler.java @@ -0,0 +1,106 @@ +package org.opt4j.optimizers.ea; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; + +import org.opt4j.core.Individual; +import org.opt4j.core.Objective; +import org.opt4j.core.Objectives; +import org.opt4j.operators.crossover.Pair; + +import com.google.inject.Inject; + +/** + * This class implements a parent selection process based on + * epsilon-neighborhood. This technique was first proposed in the paper: + * + * Aguirre, Hernán, Akira Oyama, and Kiyoshi Tanaka. "Adaptive ε-sampling and + * ε-hood for evolutionary many-objective optimization." International + * Conference on Evolutionary Multi-Criterion Optimization. Springer, Berlin, + * Heidelberg, 2013. + * + * Please consider citing the paper if you use this class for a scientific + * publication. + * + * @author Fedor Smirnov + * + */ +public class AeSeHCoupler implements Coupler { + protected final EpsilonAdaption epsilonAdaption; + protected final EpsilonMapping epsilonMapping; + protected final Random random; + protected final int plannedNeighborhoodNumber; + protected final NeighborhoodScheduler scheduler; + + @Inject + public AeSeHCoupler(EpsilonMapping epsilonMapping, EpsilonAdaption epsilonAdaption, Random random, + int plannedNeighborhoodNumber, NeighborhoodScheduler scheduler) { + this.epsilonMapping = epsilonMapping; + this.epsilonAdaption = epsilonAdaption; + this.random = random; + this.plannedNeighborhoodNumber = plannedNeighborhoodNumber; + this.scheduler = scheduler; + } + + @Override + public Collection> getCouples(int size, List parents) { + if (size != parents.size() / 2) { + throw new IllegalArgumentException("The offspring number should be equal to the population size"); + } + Collection> result = new HashSet>(); + List> neighborhoods = createNeighborhoods(parents); + // adapt the epsilon + epsilonAdaption.adaptNeighborhoodEpsilon(neighborhoods.size() > plannedNeighborhoodNumber); + scheduler.init(neighborhoods); + for (int i = 0; i < size; i++){ + result.add(pickCouple(scheduler.next())); + } + return result; + } + + /** + * Pick a couple of parents from the given neighborhood. Here, we just pick two random individuals. + * + * @param neighborhood + * @return + */ + protected Pair pickCouple(Set neighborhood){ + List individualList = new ArrayList(neighborhood); + Individual first = individualList.remove(random.nextInt(individualList.size())); + Individual second = individualList.remove(random.nextInt(individualList.size())); + return new Pair(first, second); + } + + /** + * Apply the epsilon neighborhood creation. + * + * @param survivors + * @return + */ + protected List> createNeighborhoods(List survivors) { + List> neighborhoods = new ArrayList>(); + Map objectiveAmplitudes = epsilonMapping + .findObjectiveAmplitudes(new HashSet(survivors)); + while (!survivors.isEmpty()) { + // pick a random individual + int idx = random.nextInt(survivors.size()); + Individual reference = survivors.remove(idx); + Set neighborhood = new HashSet(); + Objectives epsilonEnhancedObjectives = epsilonMapping.mapObjectives(reference.getObjectives(), + epsilonAdaption.getNeighborhoodEspilon(), objectiveAmplitudes); + // put the individuals epsilon-dominated by the reference into its neighborhood + for (Individual candidate : survivors) { + if (epsilonEnhancedObjectives.dominates(candidate.getObjectives()))neighborhood.add(candidate); + } + survivors.removeAll(neighborhood); + neighborhood.add(reference); + neighborhoods.add(neighborhood); + } + return neighborhoods; + } +} diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHSelector.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHSelector.java new file mode 100644 index 00000000..54689eee --- /dev/null +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHSelector.java @@ -0,0 +1,65 @@ +package org.opt4j.optimizers.ea; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Random; +import java.util.Set; + +import org.opt4j.core.Individual; + +import com.google.inject.Inject; +import com.google.inject.Singleton; + +/** + * This class implements a selection process based on the epsilon-sampling + * presented in the paper: + * + * Aguirre, Hernán, Akira Oyama, and Kiyoshi Tanaka. "Adaptive ε-sampling and + * ε-hood for evolutionary many-objective optimization." International + * Conference on Evolutionary Multi-Criterion Optimization. Springer, Berlin, + * Heidelberg, 2013. + * + * Please consider citing the paper if you use this class for a scientific + * publication. + * + * @author Fedor Smirnov + * + */ +@Singleton +public class AeSeHSelector implements Selector { + + protected final NonDominatedSorting nonDominatedSorting; + protected final Random random; + protected final ESamplingSurvivorGeneration survivorGeneration; + + @Inject + public AeSeHSelector(NonDominatedSorting nonDominatedSorting, Random random, + ESamplingSurvivorGeneration survivorGeneration) { + this.nonDominatedSorting = nonDominatedSorting; + this.random = random; + this.survivorGeneration = survivorGeneration; + } + + @Override + public Collection getParents(int mu, Collection population) { + if (mu != population.size()){ + throw new IllegalArgumentException("The population should consist only of the parents by now."); + } + return population; + } + + @Override + public Collection getLames(int lambda, Collection population) { + int survivorNumber = population.size() - lambda; + Set survivors = survivorGeneration.getSurvivors(population, survivorNumber); + Set lames = new HashSet(population); + lames.removeAll(survivors); + return lames; + } + + @Override + public void init(int maxsize) { + // do nothing + } + +} diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultSurvivorGeneration.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultSurvivorGeneration.java new file mode 100644 index 00000000..3307a56c --- /dev/null +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultSurvivorGeneration.java @@ -0,0 +1,151 @@ +package org.opt4j.optimizers.ea; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; + +import org.opt4j.core.Individual; +import org.opt4j.core.Objective; +import org.opt4j.core.Objectives; + +import com.google.inject.Inject; + +/** + * The basic survivor selection used by the Adaptive ε-sampling and ε-hood for + * evolutionary many-objective optimization, without any extensions. + * + * @author Fedor Smirnov + * + */ +public class DefaultSurvivorGeneration implements ESamplingSurvivorGeneration { + + protected final NonDominatedSorting nonDominatedSorting; + protected final Random random; + protected final EpsilonMapping epsilonMapping; + protected final EpsilonAdaption epsilonAdaption; + + @Inject + public DefaultSurvivorGeneration(NonDominatedSorting nonDominatedSorting, Random random, + EpsilonMapping epsilonMapping, EpsilonAdaption epsilonAdaption) { + this.nonDominatedSorting = nonDominatedSorting; + this.random = random; + this.epsilonMapping = epsilonMapping; + this.epsilonAdaption = epsilonAdaption; + } + + @Override + public Set getSurvivors(Collection population, int survivorNumber) { + Set survivors = new HashSet(); + // get the non-dominated front and the extreme solutions + List> fronts = nonDominatedSorting.generateFronts(population); + Collection paretoSolutions = fronts.get(0); + Set extremeIndividuals = nonDominatedSorting.getExtremeIndividuals(paretoSolutions); + + if (paretoSolutions.size() > survivorNumber) { + // more non-dominated solutions than survivors => apply ε-sampling + applyEpsilonSampling(survivors, extremeIndividuals, paretoSolutions, survivorNumber); + } else { + addDominatedSurvivors(survivors, survivorNumber, fronts); + } + return survivors; + } + + /** + * Create the survivor pool by adding the epsilon-sampled individuals to the + * extreme individuals. + * + * @param survivors + * @param extremeIndividuals + * @param firstFront + * @param extremeObjectiveValues + * @param survivorNumber + */ + protected void applyEpsilonSampling(Set survivors, Collection extremeIndividuals, + Collection firstFront, int survivorNumber) { + List nonDominatedIndividuals = new ArrayList(firstFront); + // the extreme values always survive + survivors.addAll(extremeIndividuals); + nonDominatedIndividuals.removeAll(extremeIndividuals); + Map objectiveAmplitudes = epsilonMapping + .findObjectiveAmplitudes(new HashSet(nonDominatedIndividuals)); + Set epsilonDominantIndividuals = new HashSet(); + Set epsilonDominatedIndividuals = new HashSet(); + // apply epsilon sampling until the individual list is empty + while (!nonDominatedIndividuals.isEmpty()) { + // pick a random individual + Individual epsilonDominant = nonDominatedIndividuals.get(random.nextInt(nonDominatedIndividuals.size())); + Set epsilonDominated = new HashSet(); + nonDominatedIndividuals.remove(epsilonDominant); + Objectives epsilonEnhancedObjectives = epsilonMapping.mapObjectives(epsilonDominant.getObjectives(), + epsilonAdaption.getSamplingEpsilon(), objectiveAmplitudes); + // gather all individuals epsilon dominated by the picked individual + for (int i = 0; i < nonDominatedIndividuals.size(); i++) { + Individual comparisonIndividual = nonDominatedIndividuals.get(i); + if (epsilonEnhancedObjectives.dominates(comparisonIndividual.getObjectives())) { + epsilonDominated.add(comparisonIndividual); + } + } + nonDominatedIndividuals.removeAll(epsilonDominated); + epsilonDominantIndividuals.add(epsilonDominant); + epsilonDominatedIndividuals.addAll(epsilonDominated); + } + boolean tooManyEpsilonDominantIndividuals = (extremeIndividuals.size() + + epsilonDominantIndividuals.size()) > survivorNumber; + // adapt the sampling epsilon + epsilonAdaption.adaptSamplingEpsilon(tooManyEpsilonDominantIndividuals); + if (tooManyEpsilonDominantIndividuals) { + // add a random subset of the epsilon dominant individuals + List survivalCandidates = new ArrayList(epsilonDominantIndividuals); + while (survivors.size() < survivorNumber) { + int idx = random.nextInt(survivalCandidates.size()); + Individual survivor = survivalCandidates.get(idx); + survivors.add(survivor); + survivalCandidates.remove(idx); + } + } else { + // add a random subset from the epsilon dominated individuals + survivors.addAll(epsilonDominantIndividuals); + List survivorCandidates = new ArrayList(epsilonDominatedIndividuals); + while (survivors.size() < survivorNumber) { + int idx = random.nextInt(survivorCandidates.size()); + Individual survivor = survivorCandidates.get(idx); + survivorCandidates.remove(idx); + survivors.add(survivor); + } + } + } + + /** + * In the case where the first non-dominated front does not suffice to + * create enough survivors, dominated solutions are added to the survivor + * pool. + * + * @param survivors + * @param paretoSolutions + * @param survivorNumber + * @param fronts + */ + protected void addDominatedSurvivors(Set survivors, int survivorNumber, + List> fronts) { + // non-dominated solutions do not suffice to generate the number of + // survivors => add dominated solutions + survivors.addAll(fronts.get(0)); + int frontIndex = 1; + // Fill the survivors by iteratively adding the dominated fronts. + while (survivorNumber > fronts.get(frontIndex).size() + survivors.size()) { + survivors.addAll(fronts.get(frontIndex)); + frontIndex++; + } + List currentFront = new ArrayList(fronts.get(frontIndex)); + while (survivorNumber > survivors.size()) { + // choose a random survivor from the current front + Individual survivor = currentFront.get(random.nextInt(currentFront.size())); + survivors.add(survivor); + currentFront.remove(survivor); + } + } +} diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/ESamplingSurvivorGeneration.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/ESamplingSurvivorGeneration.java new file mode 100644 index 00000000..14a3c73e --- /dev/null +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/ESamplingSurvivorGeneration.java @@ -0,0 +1,30 @@ +package org.opt4j.optimizers.ea; + +import java.util.Collection; +import java.util.Set; + +import org.opt4j.core.Individual; + +/** + * + * Interface for the classes which generate the survivor pool during the + * selection implemented by {@link AeSeHSelector}. + * + * @author Fedor Smirnov + * + */ +public interface ESamplingSurvivorGeneration { + + /** + * Generate the survivors out of the input collection. + * + * @param population + * : the current population (union of the parent- and the + * offspring-sets from the current iteration) + * @param survivorNumber : The number of survivors to create + * @return : the survivors (used as the parent generation for the next + * iteration) + */ + public Set getSurvivors(Collection population, int survivorNumber); + +} diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonAdaption.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonAdaption.java new file mode 100644 index 00000000..85ca3817 --- /dev/null +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonAdaption.java @@ -0,0 +1,50 @@ +package org.opt4j.optimizers.ea; + +/** + * Interface for the classes that manage the adaptation of the epsilon value + * used for survivor selection by {@link AeSeHSelector}. + * + * @author Fedor Smirnov + * + */ +public interface EpsilonAdaption { + + /** + * Returns the current value of the sampling epsilon. + * + * @return Current epsilon_s + */ + public double getSamplingEpsilon(); + + /** + * Returns the current value of the epsilon used for the creation of the + * neighborhoods + * + * @return Current epsilon_h + */ + public double getNeighborhoodEspilon(); + + /** + * At the end of the selection process, the epsilon_s value is adjusted + * depending on the number of created epsilon-dominant survivors. The goal + * is to find an epsilon_s value that results in the creation of exactly + * alpha epsilon-dominant survivors, with alpha as the population size. + * + * @param tooManyEpsilonDominantIndividuals + * : TRUE => too many dominant survivors were created; FALSE => + * not enough dominant survivors were created + */ + public void adaptSamplingEpsilon(boolean tooManyEpsilonDominantIndividuals); + + /** + * At the end of the neighborhood creation, the epsilon_h value is adjusted + * depending on the number of created neighborhoods. The goal is to find a + * value where the number of neighborhoods is near a user-defined value. + * + * @param tooManyNeighborhoods + * : TRUE => too many neighborhoods created; FALSE => not enough + * neighborhoods created + */ + public void adaptNeighborhoodEpsilon(boolean tooManyNeighborhoods); + +} diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonMapping.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonMapping.java new file mode 100644 index 00000000..21d89597 --- /dev/null +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonMapping.java @@ -0,0 +1,44 @@ +package org.opt4j.optimizers.ea; + +import java.util.Map; +import java.util.Set; + +import org.opt4j.core.Individual; +import org.opt4j.core.Objective; +import org.opt4j.core.Objectives; + +/** + * Interface for the classes applying the epsilon mapping used by the + * {@link AeSeHSelector}. + * + * @author Fedor Smirnov + * + */ +public interface EpsilonMapping { + + /** + * Map the given objectives on the objectives used for the check of the + * epsilon dominance. + * + * @param original + * : the actual objectives of the individual + * @param epsilon + * : the epsilon value + * @param objectiveAmplitudes + * : a map containing the amplitude values of the objectives + * @return : objectives enhanced by the epsilon value + */ + public Objectives mapObjectives(final Objectives original, double epsilon, Map objectiveAmplitudes); + + /** + * Create a map mapping the objectives to their amplitudes (difference + * between maximal and minimal value). These extreme values are used during + * epsilon mapping to scale the delta according to the objective values of + * the individual group under consideration. + * + * @param individuals + * @return + */ + public Map findObjectiveAmplitudes(Set individuals); + +} diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java index 9a58cf18..2d764786 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java @@ -41,6 +41,10 @@ @Info("Multi-Objective Evolutionary Algorithm that performs a Crossover and Mutate for variation and uses a Selector for the environmental selection.") public class EvolutionaryAlgorithmModule extends OptimizerModule { + public enum MoeaType{ + NSGA2, AeSeH + } + @Info("The number of generations.") @Order(0) @MaxIterations @@ -68,7 +72,9 @@ public class EvolutionaryAlgorithmModule extends OptimizerModule { @Ignore protected CrossoverRateType crossoverRateType = CrossoverRateType.CONSTANT; - + + protected MoeaType moeaType = MoeaType.NSGA2; + /** * The {@link CrossoverRateType} allows to choose between different types of * crossover rates. @@ -82,6 +88,14 @@ public enum CrossoverRateType { */ CONSTANT; } + + public MoeaType getMoeaType() { + return moeaType; + } + + public void setMoeaType(MoeaType moeaType) { + this.moeaType = moeaType; + } /** * Returns the population size {@code alpha}. @@ -218,7 +232,10 @@ public void setCrossoverRate(double crossoverRate) { public void config() { bindIterativeOptimizer(EvolutionaryAlgorithm.class); - bind(CrossoverRate.class).to(ConstantCrossoverRate.class).in(SINGLETON); + if(moeaType.equals(MoeaType.AeSeH)){ + bind(Selector.class).to(AeSeHSelector.class); + bind(Coupler.class).to(AeSeHCoupler.class); + } } } diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NeighborhoodScheduler.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NeighborhoodScheduler.java new file mode 100644 index 00000000..bd99c552 --- /dev/null +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NeighborhoodScheduler.java @@ -0,0 +1,34 @@ +package org.opt4j.optimizers.ea; + +import java.util.List; +import java.util.Set; + +import org.opt4j.core.Individual; + +/** + * Interface for the classes that manage the schedule according to which the + * neighborhoods are chosen by the {@link AeSeHCoupler} to pick the crossover + * parent. + * + * @author Fedor Smirnov + * + */ +public interface NeighborhoodScheduler { + + /** + * Perform the operations specific to the current neighborhood that have to + * be done before the scheduling. + * + * @param neighborhoods + */ + public void init(List> neighborhoods); + + /** + * Return a copy of the neighborhood that shall be used for the creation of + * the next pair of parents. + * + * @return Copy of the neighborhood set. + */ + public Set next(); + +} diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedSorting.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedSorting.java new file mode 100644 index 00000000..0cc16aaf --- /dev/null +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedSorting.java @@ -0,0 +1,44 @@ +package org.opt4j.optimizers.ea; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import org.opt4j.core.Individual; + +/** + * Interface for the classes that sort given individuals based on objective + * dominance. + * + * @author Fedor Smirnov + * + */ +public interface NonDominatedSorting { + + /** + * Applies non-dominated sorting to an input collection of individuals. They + * are hereby sorted into so-called fronts. A front contains individuals + * that are dominated by a certain number of other individuals in the given + * collection. For example, the first front contains the Pareto-optimal + * solutions that are not dominated by any individuals. + * + * @param individuals + * : The input collection of individuals + * @return : A list of the shape [f_1, f_2, ... , f_n] with f_i being the + * individuals in the ith front and n being the number of fronts. + */ + public List> generateFronts(Collection individuals); + + /** + * Sweep the input collection of individuals (the first non-dominated front) + * and return a set of individuals with extreme objective values (in the + * optimization direction, i.e. the maxima of maximization objectives and + * the minima of the objectives that are to be minimized). + * + * @param firstFront + * : The input collection of individuals + * @return : The set of individuals with extreme values + */ + public Set getExtremeIndividuals(Collection firstFront); + +} From 6e114f722b16768897a81ca1ad0df9d75d693d45 Mon Sep 17 00:00:00 2001 From: Fedor Smirnov Date: Sat, 3 Mar 2018 19:20:05 +0100 Subject: [PATCH 02/20] implemented tests for the adaptive epsilon sampling EA --- build.gradle | 2 + opt4j-optimizers/build.gradle | 3 + .../optimizers/ea/AdditiveEpsilonMapping.java | 52 ++++++++ .../org/opt4j/optimizers/ea/AeSeHCoupler.java | 37 ++--- .../opt4j/optimizers/ea/AeSeHSelector.java | 11 +- .../ea/DefaultEpsilonAdaptation.java | 66 +++++++++ .../ea/DefaultSurvivorGeneration.java | 30 ++--- .../opt4j/optimizers/ea/EpsilonAdaption.java | 5 +- .../opt4j/optimizers/ea/EpsilonMapping.java | 2 +- .../optimizers/ea/NeighborhoodScheduler.java | 9 -- .../optimizers/ea/NonDominatedSorting.java | 126 +++++++++++++++--- .../java/org/opt4j/optimizers/ea/Nsga2.java | 74 +--------- .../optimizers/ea/RoundRobinScheduler.java | 30 +++++ .../ea/AdditiveEpsilonMappingTest.java | 76 +++++++++++ .../opt4j/optimizers/ea/AeSeHCouplerTest.java | 106 +++++++++++++++ .../optimizers/ea/AeSeHSelectorTest.java | 71 ++++++++++ .../ea/DefaultEpsilonAdaptationTest.java | 70 ++++++++++ .../ea/DefaultSurvivorGenerationTest.java | 118 ++++++++++++++++ .../ea/NonDominatedSortingTest.java | 85 ++++++++++++ .../ea/RoundRobinSchedulerTest.java | 42 ++++++ 20 files changed, 871 insertions(+), 144 deletions(-) create mode 100644 opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java create mode 100644 opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptation.java create mode 100644 opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/RoundRobinScheduler.java create mode 100644 opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AdditiveEpsilonMappingTest.java create mode 100644 opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHCouplerTest.java create mode 100644 opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHSelectorTest.java create mode 100644 opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptationTest.java create mode 100644 opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest.java create mode 100644 opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/NonDominatedSortingTest.java create mode 100644 opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/RoundRobinSchedulerTest.java diff --git a/build.gradle b/build.gradle index ab5696d0..52fdc4f2 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,6 @@ plugins { id 'com.github.kt3k.coveralls' version '2.6.3' + id "org.sonarqube" version "2.5" } apply plugin: 'base' apply plugin: 'application' @@ -21,6 +22,7 @@ allprojects { group = 'org.opt4j' repositories { + jcenter() mavenCentral() } diff --git a/opt4j-optimizers/build.gradle b/opt4j-optimizers/build.gradle index d159236d..b1a634e9 100644 --- a/opt4j-optimizers/build.gradle +++ b/opt4j-optimizers/build.gradle @@ -1,4 +1,7 @@ dependencies { compile project(':opt4j-core') compile project(':opt4j-operators') + + testCompile group: 'junit', name: 'junit', version: '[4.0,)' + testCompile "org.mockito:mockito-core:2.+" } \ No newline at end of file diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java new file mode 100644 index 00000000..b60517a1 --- /dev/null +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java @@ -0,0 +1,52 @@ +package org.opt4j.optimizers.ea; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.opt4j.core.Individual; +import org.opt4j.core.Objective; +import org.opt4j.core.Objective.Sign; +import org.opt4j.core.Objectives; + +/** + * Implements the evenly spaced adaptive epsilon function. + * + * @author Fedor Smirnov + * + */ +public class AdditiveEpsilonMapping implements EpsilonMapping { + + @Override + public Objectives mapObjectives(Objectives original, double epsilon, Map objectiveAmplitudes) { + Objectives result = new Objectives(); + for (Objective obj : original.getKeys()) { + double value = original.get(obj).getDouble(); + double delta = epsilon * objectiveAmplitudes.get(obj) * (obj.getSign().equals(Sign.MAX) ? 1 : -1); + result.add(obj, value + delta); + } + return result; + } + + @Override + public Map findObjectiveAmplitudes(Set individuals) { + Map maximumMap = new HashMap(); + Map minimumMap = new HashMap(); + Map amplitudeMap = new HashMap(); + for (Individual indi : individuals) { + for (Objective obj : indi.getObjectives().getKeys()) { + double value = indi.getObjectives().get(obj).getDouble(); + if (!maximumMap.containsKey(obj) || maximumMap.get(obj) < value) { + maximumMap.put(obj, value); + } + if (!minimumMap.containsKey(obj) || minimumMap.get(obj) > value) { + minimumMap.put(obj, value); + } + } + } + for (Objective obj : maximumMap.keySet()) { + amplitudeMap.put(obj, maximumMap.get(obj) - minimumMap.get(obj)); + } + return amplitudeMap; + } +} diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHCoupler.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHCoupler.java index cb0e9531..9111a912 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHCoupler.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHCoupler.java @@ -31,20 +31,19 @@ * */ public class AeSeHCoupler implements Coupler { + protected final EpsilonAdaption epsilonAdaption; protected final EpsilonMapping epsilonMapping; protected final Random random; protected final int plannedNeighborhoodNumber; - protected final NeighborhoodScheduler scheduler; @Inject public AeSeHCoupler(EpsilonMapping epsilonMapping, EpsilonAdaption epsilonAdaption, Random random, - int plannedNeighborhoodNumber, NeighborhoodScheduler scheduler) { + int plannedNeighborhoodNumber) { this.epsilonMapping = epsilonMapping; this.epsilonAdaption = epsilonAdaption; this.random = random; this.plannedNeighborhoodNumber = plannedNeighborhoodNumber; - this.scheduler = scheduler; } @Override @@ -54,22 +53,25 @@ public Collection> getCouples(int size, List parent } Collection> result = new HashSet>(); List> neighborhoods = createNeighborhoods(parents); - // adapt the epsilon - epsilonAdaption.adaptNeighborhoodEpsilon(neighborhoods.size() > plannedNeighborhoodNumber); - scheduler.init(neighborhoods); - for (int i = 0; i < size; i++){ + RoundRobinScheduler scheduler = new RoundRobinScheduler(neighborhoods); + for (int i = 0; i < size; i++) { result.add(pickCouple(scheduler.next())); } return result; } - + /** - * Pick a couple of parents from the given neighborhood. Here, we just pick two random individuals. + * Pick a couple of parents from the given neighborhood. Here, we just pick + * two random individuals. * * @param neighborhood - * @return + * @return The pair that was picked as parents for a crossover. */ - protected Pair pickCouple(Set neighborhood){ + protected Pair pickCouple(Set neighborhood) { + if (neighborhood.size() == 1) { + Individual hermit = neighborhood.iterator().next(); + return new Pair(hermit, hermit); + } List individualList = new ArrayList(neighborhood); Individual first = individualList.remove(random.nextInt(individualList.size())); Individual second = individualList.remove(random.nextInt(individualList.size())); @@ -80,7 +82,8 @@ protected Pair pickCouple(Set neighborhood){ * Apply the epsilon neighborhood creation. * * @param survivors - * @return + * @return a list of individual sets. Each set is considered as a + * neighborhood */ protected List> createNeighborhoods(List survivors) { List> neighborhoods = new ArrayList>(); @@ -92,15 +95,19 @@ protected List> createNeighborhoods(List survivors) Individual reference = survivors.remove(idx); Set neighborhood = new HashSet(); Objectives epsilonEnhancedObjectives = epsilonMapping.mapObjectives(reference.getObjectives(), - epsilonAdaption.getNeighborhoodEspilon(), objectiveAmplitudes); - // put the individuals epsilon-dominated by the reference into its neighborhood + epsilonAdaption.getNeighborhoodEpsilon(), objectiveAmplitudes); + // put the individuals epsilon-dominated by the reference into its + // neighborhood for (Individual candidate : survivors) { - if (epsilonEnhancedObjectives.dominates(candidate.getObjectives()))neighborhood.add(candidate); + if (epsilonEnhancedObjectives.dominates(candidate.getObjectives())) + neighborhood.add(candidate); } survivors.removeAll(neighborhood); neighborhood.add(reference); neighborhoods.add(neighborhood); } + // adapt the epsilon + epsilonAdaption.adaptNeighborhoodEpsilon(neighborhoods.size() > plannedNeighborhoodNumber); return neighborhoods; } } diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHSelector.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHSelector.java index 54689eee..d607f275 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHSelector.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHSelector.java @@ -2,7 +2,6 @@ import java.util.Collection; import java.util.HashSet; -import java.util.Random; import java.util.Set; import org.opt4j.core.Individual; @@ -28,21 +27,16 @@ @Singleton public class AeSeHSelector implements Selector { - protected final NonDominatedSorting nonDominatedSorting; - protected final Random random; protected final ESamplingSurvivorGeneration survivorGeneration; @Inject - public AeSeHSelector(NonDominatedSorting nonDominatedSorting, Random random, - ESamplingSurvivorGeneration survivorGeneration) { - this.nonDominatedSorting = nonDominatedSorting; - this.random = random; + public AeSeHSelector(ESamplingSurvivorGeneration survivorGeneration) { this.survivorGeneration = survivorGeneration; } @Override public Collection getParents(int mu, Collection population) { - if (mu != population.size()){ + if (mu != population.size()) { throw new IllegalArgumentException("The population should consist only of the parents by now."); } return population; @@ -61,5 +55,4 @@ public Collection getLames(int lambda, Collection popula public void init(int maxsize) { // do nothing } - } diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptation.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptation.java new file mode 100644 index 00000000..00f83864 --- /dev/null +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptation.java @@ -0,0 +1,66 @@ +package org.opt4j.optimizers.ea; + +public class DefaultEpsilonAdaptation implements EpsilonAdaption { + + protected double epsilon_sample; + protected double epsilon_sample_delta; + protected final double epsilon_sample_delta_max; + protected final double epsilon_sample_delta_min; + + protected double epsilon_neighborhood; + protected double epsilon_neighborhood_delta; + protected final double epsilon_neighborhood_delta_max; + protected final double epsilon_neighborhood_delta_min; + + public DefaultEpsilonAdaptation(double epsilon_sample, double epsilon_sample_delta, double epsilon_sample_delta_max, + double epsilon_sample_delta_min, double epsilon_neighborhood, double epsilon_neighborhood_delta, + double epsilon_neighborhood_delta_max, double epsilon_neighborhood_delta_min) { + if (epsilon_sample_delta < epsilon_sample_delta_min || epsilon_sample_delta > epsilon_sample_delta_max){ + throw new IllegalArgumentException("The start value for the epsilon_sample must lie within the provided bounds"); + } + if (epsilon_neighborhood_delta < epsilon_neighborhood_delta_min || epsilon_neighborhood_delta > epsilon_neighborhood_delta_max){ + throw new IllegalArgumentException("The start value for the epsilon_neighborhood must lie within the provided bounds"); + } + + this.epsilon_sample = epsilon_sample; + this.epsilon_sample_delta = epsilon_sample_delta; + this.epsilon_sample_delta_max = epsilon_sample_delta_max; + this.epsilon_sample_delta_min = epsilon_sample_delta_min; + this.epsilon_neighborhood = epsilon_neighborhood; + this.epsilon_neighborhood_delta = epsilon_neighborhood_delta; + this.epsilon_neighborhood_delta_max = epsilon_neighborhood_delta_max; + this.epsilon_neighborhood_delta_min = epsilon_neighborhood_delta_min; + } + + @Override + public double getSamplingEpsilon() { + return epsilon_sample; + } + + @Override + public double getNeighborhoodEpsilon() { + return epsilon_neighborhood; + } + + @Override + public void adaptSamplingEpsilon(boolean tooManyEpsilonDominantIndividuals) { + if (tooManyEpsilonDominantIndividuals){ + epsilon_sample = epsilon_sample + epsilon_sample_delta; + epsilon_sample_delta = Math.min(epsilon_sample_delta_max, 2 * epsilon_sample_delta); + }else{ + epsilon_sample = Math.max(0.0, epsilon_sample - epsilon_sample_delta); + epsilon_sample_delta = Math.max(epsilon_sample_delta_min, epsilon_sample_delta / 2); + } + } + + @Override + public void adaptNeighborhoodEpsilon(boolean tooManyNeighborhoods) { + if(tooManyNeighborhoods){ + epsilon_neighborhood = epsilon_neighborhood + epsilon_neighborhood_delta; + epsilon_neighborhood_delta = Math.min(epsilon_neighborhood_delta_max, 2 * epsilon_neighborhood_delta); + }else{ + epsilon_neighborhood = Math.max(0.0, epsilon_neighborhood - epsilon_neighborhood_delta); + epsilon_neighborhood_delta = Math.max(epsilon_neighborhood_delta_min, epsilon_neighborhood_delta / 2); + } + } +} diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultSurvivorGeneration.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultSurvivorGeneration.java index 3307a56c..13e8697c 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultSurvivorGeneration.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultSurvivorGeneration.java @@ -23,15 +23,12 @@ */ public class DefaultSurvivorGeneration implements ESamplingSurvivorGeneration { - protected final NonDominatedSorting nonDominatedSorting; protected final Random random; protected final EpsilonMapping epsilonMapping; protected final EpsilonAdaption epsilonAdaption; @Inject - public DefaultSurvivorGeneration(NonDominatedSorting nonDominatedSorting, Random random, - EpsilonMapping epsilonMapping, EpsilonAdaption epsilonAdaption) { - this.nonDominatedSorting = nonDominatedSorting; + public DefaultSurvivorGeneration(Random random, EpsilonMapping epsilonMapping, EpsilonAdaption epsilonAdaption) { this.random = random; this.epsilonMapping = epsilonMapping; this.epsilonAdaption = epsilonAdaption; @@ -39,17 +36,17 @@ public DefaultSurvivorGeneration(NonDominatedSorting nonDominatedSorting, Random @Override public Set getSurvivors(Collection population, int survivorNumber) { - Set survivors = new HashSet(); + Set survivors; // get the non-dominated front and the extreme solutions - List> fronts = nonDominatedSorting.generateFronts(population); + List> fronts = NonDominatedSorting.generateFronts(population); Collection paretoSolutions = fronts.get(0); - Set extremeIndividuals = nonDominatedSorting.getExtremeIndividuals(paretoSolutions); + Set extremeIndividuals = NonDominatedSorting.getExtremeIndividuals(paretoSolutions); if (paretoSolutions.size() > survivorNumber) { // more non-dominated solutions than survivors => apply ε-sampling - applyEpsilonSampling(survivors, extremeIndividuals, paretoSolutions, survivorNumber); + survivors = applyEpsilonSampling(extremeIndividuals, paretoSolutions, survivorNumber); } else { - addDominatedSurvivors(survivors, survivorNumber, fronts); + survivors = addDominatedSurvivors(survivorNumber, fronts); } return survivors; } @@ -58,14 +55,13 @@ public Set getSurvivors(Collection population, int survi * Create the survivor pool by adding the epsilon-sampled individuals to the * extreme individuals. * - * @param survivors * @param extremeIndividuals * @param firstFront - * @param extremeObjectiveValues * @param survivorNumber */ - protected void applyEpsilonSampling(Set survivors, Collection extremeIndividuals, + protected Set applyEpsilonSampling(Collection extremeIndividuals, Collection firstFront, int survivorNumber) { + Set survivors = new HashSet(); List nonDominatedIndividuals = new ArrayList(firstFront); // the extreme values always survive survivors.addAll(extremeIndividuals); @@ -117,6 +113,7 @@ protected void applyEpsilonSampling(Set survivors, Collection survivors, Collection survivors, int survivorNumber, - List> fronts) { + protected Set addDominatedSurvivors(int survivorNumber, List> fronts) { + Set survivors = new HashSet(); // non-dominated solutions do not suffice to generate the number of // survivors => add dominated solutions survivors.addAll(fronts.get(0)); @@ -140,12 +135,13 @@ protected void addDominatedSurvivors(Set survivors, int survivorNumb survivors.addAll(fronts.get(frontIndex)); frontIndex++; } - List currentFront = new ArrayList(fronts.get(frontIndex)); + List currentFront = fronts.get(frontIndex); while (survivorNumber > survivors.size()) { // choose a random survivor from the current front Individual survivor = currentFront.get(random.nextInt(currentFront.size())); survivors.add(survivor); currentFront.remove(survivor); } + return survivors; } } diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonAdaption.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonAdaption.java index 85ca3817..41cb019b 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonAdaption.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonAdaption.java @@ -1,5 +1,7 @@ package org.opt4j.optimizers.ea; +import com.google.inject.ImplementedBy; + /** * Interface for the classes that manage the adaptation of the epsilon value * used for survivor selection by {@link AeSeHSelector}. @@ -7,6 +9,7 @@ * @author Fedor Smirnov * */ +@ImplementedBy(DefaultEpsilonAdaptation.class) public interface EpsilonAdaption { /** @@ -22,7 +25,7 @@ public interface EpsilonAdaption { * * @return Current epsilon_h */ - public double getNeighborhoodEspilon(); + public double getNeighborhoodEpsilon(); /** * At the end of the selection process, the epsilon_s value is adjusted diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonMapping.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonMapping.java index 21d89597..f997fba1 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonMapping.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonMapping.java @@ -37,7 +37,7 @@ public interface EpsilonMapping { * the individual group under consideration. * * @param individuals - * @return + * @return map mapping each objective onto ist amplitude */ public Map findObjectiveAmplitudes(Set individuals); diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NeighborhoodScheduler.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NeighborhoodScheduler.java index bd99c552..1177373b 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NeighborhoodScheduler.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NeighborhoodScheduler.java @@ -1,6 +1,5 @@ package org.opt4j.optimizers.ea; -import java.util.List; import java.util.Set; import org.opt4j.core.Individual; @@ -15,14 +14,6 @@ */ public interface NeighborhoodScheduler { - /** - * Perform the operations specific to the current neighborhood that have to - * be done before the scheduling. - * - * @param neighborhoods - */ - public void init(List> neighborhoods); - /** * Return a copy of the neighborhood that shall be used for the creation of * the next pair of parents. diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedSorting.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedSorting.java index 0cc16aaf..d4601ec9 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedSorting.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedSorting.java @@ -1,44 +1,130 @@ package org.opt4j.optimizers.ea; +import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import org.opt4j.core.Individual; +import org.opt4j.core.Objective; +import org.opt4j.core.Objective.Sign; +import org.opt4j.core.Objectives; /** - * Interface for the classes that sort given individuals based on objective - * dominance. + * Class used for the non-dominated sorting. During non-dominated sorting, the + * evaluated individuals are sorted into fronts based on the number of + * individuals they are dominated by. The first front consists of points that + * are not dominated at all and so on. * * @author Fedor Smirnov * */ -public interface NonDominatedSorting { +public class NonDominatedSorting { + + private NonDominatedSorting() { + } /** - * Applies non-dominated sorting to an input collection of individuals. They - * are hereby sorted into so-called fronts. A front contains individuals - * that are dominated by a certain number of other individuals in the given - * collection. For example, the first front contains the Pareto-optimal - * solutions that are not dominated by any individuals. + * Sort the given individuals into non-dominated fronts * * @param individuals - * : The input collection of individuals - * @return : A list of the shape [f_1, f_2, ... , f_n] with f_i being the - * individuals in the ith front and n being the number of fronts. + * @return an ordered list of the non-dominated front. The first entry is + * made up by the first front, that is by the Pareto-optimal + * solutions */ - public List> generateFronts(Collection individuals); + public static List> generateFronts(Collection individuals) { + // assign an id to each individual that corresponds to its index in an + // array + List pop = new ArrayList(individuals); + Map id = new HashMap(); + for (int i = 0; i < pop.size(); i++) { + id.put(pop.get(i), i); + } + List> fronts = new ArrayList>(); + // Initialize a map where an individual is assigned to the individuals + // that it dominates + Map> S = new HashMap>(); + // n is an array where for each individual, the number of individuals + // that dominate it is stored + int[] n = new int[pop.size()]; + for (Individual e : pop) { + S.put(e, new ArrayList()); + n[id.get(e)] = 0; + } + // compare each individual with each other individual + for (int i = 0; i < pop.size(); i++) { + for (int j = i + 1; j < pop.size(); j++) { + Individual p = pop.get(i); + Individual q = pop.get(j); + Objectives po = p.getObjectives(); + Objectives qo = q.getObjectives(); + + if (po.dominates(qo)) { + S.get(p).add(q); + n[id.get(q)]++; + } else if (qo.dominates(po)) { + S.get(q).add(p); + n[id.get(p)]++; + } + } + } + // The first front consists of individuals that are dominated by zero + // other individuals + List f1 = new ArrayList(); + for (Individual i : pop) { + if (n[id.get(i)] == 0) { + f1.add(i); + } + } + fronts.add(f1); + List fi = f1; + // Create the subsequent fronts. Front f_i is made up by individuals + // that + // are not dominated if all individuals from fronts f_j with j < i are + // removed. + while (!fi.isEmpty()) { + List h = new ArrayList(); + for (Individual p : fi) { + for (Individual q : S.get(p)) { + n[id.get(q)]--; + if (n[id.get(q)] == 0) { + h.add(q); + } + } + } + if (!h.isEmpty()) + fronts.add(h); + fi = h; + } + return fronts; + } /** - * Sweep the input collection of individuals (the first non-dominated front) - * and return a set of individuals with extreme objective values (in the - * optimization direction, i.e. the maxima of maximization objectives and - * the minima of the objectives that are to be minimized). + * Return the individuals with the best values for the individual objectives * * @param firstFront - * : The input collection of individuals - * @return : The set of individuals with extreme values + * @return the set of the extreme individuals. */ - public Set getExtremeIndividuals(Collection firstFront); - + public static Set getExtremeIndividuals(Collection firstFront) { + Map bestIndis = new HashMap(); + for (Individual indi : firstFront) { + for (Objective o : indi.getObjectives().getKeys()) { + double value = indi.getObjectives().get(o).getDouble(); + Sign sign = o.getSign(); + if (!bestIndis.containsKey(o)) { + bestIndis.put(o, indi); + } else { + double storedValue = bestIndis.get(o).getObjectives().get(o).getDouble(); + if ((storedValue < value && sign.equals(Sign.MAX)) + || storedValue > value && sign.equals(Sign.MIN)) { + bestIndis.put(o, indi); + } + } + } + } + return new HashSet(bestIndis.values()); + } } diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/Nsga2.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/Nsga2.java index 9eb6e4cd..758a81d9 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/Nsga2.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/Nsga2.java @@ -19,7 +19,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. *******************************************************************************/ - package org.opt4j.optimizers.ea; @@ -33,7 +32,6 @@ import java.util.Random; import org.opt4j.core.Individual; -import org.opt4j.core.Objectives; import org.opt4j.core.common.archive.FrontDensityIndicator; import org.opt4j.core.common.random.Rand; import org.opt4j.core.start.Constant; @@ -93,7 +91,7 @@ public Collection getParents(int mu, Collection populati List all = new ArrayList(population); List parents = new ArrayList(); - List> fronts = fronts(all); + List> fronts = NonDominatedSorting.generateFronts(all); Map rank = getRank(fronts); Map distance = new HashMap(); @@ -138,7 +136,7 @@ public Collection getParents(int mu, Collection populati public Collection getLames(int size, Collection population) { List lames = new ArrayList(); - List> fronts = fronts(population); + List> fronts = NonDominatedSorting.generateFronts(population); Collections.reverse(fronts); for (List front : fronts) { @@ -174,72 +172,4 @@ protected Map getRank(List> fronts) { } return ranks; } - - /** - * Evaluate the fronts and set the correspondent rank values. - * - * @param individuals - * the individuals - * @return the fronts - */ - public List> fronts(Collection individuals) { - - List pop = new ArrayList(individuals); - Map id = new HashMap(); - for (int i = 0; i < pop.size(); i++) { - id.put(pop.get(i), i); - } - - List> fronts = new ArrayList>(); - - Map> S = new HashMap>(); - int[] n = new int[pop.size()]; - - for (Individual e : pop) { - S.put(e, new ArrayList()); - n[id.get(e)] = 0; - } - - for (int i = 0; i < pop.size(); i++) { - for (int j = i + 1; j < pop.size(); j++) { - Individual p = pop.get(i); - Individual q = pop.get(j); - - Objectives po = p.getObjectives(); - Objectives qo = q.getObjectives(); - - if (po.dominates(qo)) { - S.get(p).add(q); - n[id.get(q)]++; - } else if (qo.dominates(po)) { - S.get(q).add(p); - n[id.get(p)]++; - } - } - } - - List f1 = new ArrayList(); - for (Individual i : pop) { - if (n[id.get(i)] == 0) { - f1.add(i); - } - } - fronts.add(f1); - List fi = f1; - while (!fi.isEmpty()) { - List h = new ArrayList(); - for (Individual p : fi) { - for (Individual q : S.get(p)) { - n[id.get(q)]--; - if (n[id.get(q)] == 0) { - h.add(q); - } - } - } - fronts.add(h); - fi = h; - } - return fronts; - } - } diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/RoundRobinScheduler.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/RoundRobinScheduler.java new file mode 100644 index 00000000..2d3b8b59 --- /dev/null +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/RoundRobinScheduler.java @@ -0,0 +1,30 @@ +package org.opt4j.optimizers.ea; + +import java.util.List; +import java.util.Set; + +import org.opt4j.core.Individual; + +/** + * A scheduler that schedules the neighborhoods in a simple round-robin fashion. + * + * @author Fedor Smirnov + * + */ +public class RoundRobinScheduler implements NeighborhoodScheduler { + + protected final List> neighborhoods; + protected int nextIdx; + + public RoundRobinScheduler(List> neighborhoods) { + this.neighborhoods = neighborhoods; + this.nextIdx = 0; + } + + @Override + public Set next() { + Set neighborhood = neighborhoods.get(nextIdx); + nextIdx = (nextIdx + 1) % neighborhoods.size(); + return neighborhood; + } +} diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AdditiveEpsilonMappingTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AdditiveEpsilonMappingTest.java new file mode 100644 index 00000000..6eb73643 --- /dev/null +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AdditiveEpsilonMappingTest.java @@ -0,0 +1,76 @@ +package org.opt4j.optimizers.ea; + +import static org.junit.Assert.*; + +import org.junit.Test; +import org.opt4j.core.Individual; +import org.opt4j.core.Objective; +import org.opt4j.core.Objective.Sign; +import org.opt4j.core.Objectives; + +import static org.mockito.Mockito.*; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class AdditiveEpsilonMappingTest { + + protected static final Objective first = new Objective("first", Sign.MAX); + protected static final Objective second = new Objective("second", Sign.MIN); + + protected static Set getIndividualSet() { + Objectives firstObj = new Objectives(); + firstObj.add(first, 4); + firstObj.add(second, 3); + + Objectives secondObj = new Objectives(); + secondObj.add(first, 1); + secondObj.add(second, 1); + + Objectives thirdObj = new Objectives(); + thirdObj.add(first, 2); + thirdObj.add(second, 2); + + Individual first = mock(Individual.class); + when(first.getObjectives()).thenReturn(firstObj); + Individual second = mock(Individual.class); + when(second.getObjectives()).thenReturn(secondObj); + Individual third = mock(Individual.class); + when(third.getObjectives()).thenReturn(thirdObj); + + Set indis = new HashSet(); + indis.add(first); + indis.add(second); + indis.add(third); + return indis; + } + + @Test + public void testMapObjectives() { + Set indis = getIndividualSet(); + AdditiveEpsilonMapping epsilonMapping = new AdditiveEpsilonMapping(); + Map amplitudeMap = epsilonMapping.findObjectiveAmplitudes(indis); + + Objectives objectives = new Objectives(); + objectives.add(first, 0); + objectives.add(second, 0); + double epsilon = 0.5; + + Objectives epsilonEnhanced = epsilonMapping.mapObjectives(objectives, epsilon, amplitudeMap); + assertEquals(1.5, epsilonEnhanced.get(first).getDouble(), 0.0); + assertEquals(-1.0, epsilonEnhanced.get(second).getDouble(), 0.0); + } + + @Test + public void testFindAmplitudes() { + Set indis = getIndividualSet(); + AdditiveEpsilonMapping epsilonMapping = new AdditiveEpsilonMapping(); + Map amplitudeMap = epsilonMapping.findObjectiveAmplitudes(indis); + assertTrue(amplitudeMap.containsKey(first)); + assertTrue(amplitudeMap.containsKey(second)); + assertEquals(3.0, amplitudeMap.get(first), 0.0); + assertEquals(2.0, amplitudeMap.get(second), 0.0); + } + +} diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHCouplerTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHCouplerTest.java new file mode 100644 index 00000000..1c0ead5e --- /dev/null +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHCouplerTest.java @@ -0,0 +1,106 @@ +package org.opt4j.optimizers.ea; + +import static org.junit.Assert.*; + +import org.junit.Test; +import org.opt4j.core.Individual; +import org.opt4j.core.Objective; +import org.opt4j.core.Objectives; +import org.opt4j.core.Objective.Sign; +import org.opt4j.operators.crossover.Pair; + +import static org.mockito.Mockito.*; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; + +public class AeSeHCouplerTest { + + protected static EpsilonAdaption mockAdaption = mock(DefaultEpsilonAdaptation.class); + + protected static Objective firstObj = new Objective("first", Sign.MAX); + protected static Objective secondObj = new Objective("second", Sign.MAX); + + protected static Individual first = mock(Individual.class); + protected static Individual second = mock(Individual.class); + protected static Individual third = mock(Individual.class); + protected static Individual fourth = mock(Individual.class); + + protected static List getSurvivors() { + List survivors = new ArrayList(); + when(first.getObjectives()).thenReturn(getObj(5, 1)); + survivors.add(first); + when(second.getObjectives()).thenReturn(getObj(3, 3)); + survivors.add(second); + when(third.getObjectives()).thenReturn(getObj(1, 4)); + survivors.add(third); + when(fourth.getObjectives()).thenReturn(getObj(3, 3)); + survivors.add(fourth); + return survivors; + } + + protected static Objectives getObj(int firstValue, int secondValue) { + Objectives result = new Objectives(); + result.add(firstObj, firstValue); + result.add(secondObj, secondValue); + return result; + } + + @Test + public void testGetCouples() { + AeSeHCoupler coupler = new AeSeHCoupler(new AdditiveEpsilonMapping(), mockAdaption, new Random(), 2); + Collection> couples = coupler.getCouples(2, getSurvivors()); + assertEquals(2, couples.size()); + } + + @Test + public void testCreateNeighborhoods() { + AeSeHCoupler coupler = new AeSeHCoupler(new AdditiveEpsilonMapping(), mockAdaption, new Random(), 2); + Map amplitudeMap = new HashMap(); + amplitudeMap.put(firstObj, 0.001); + amplitudeMap.put(secondObj, 0.001); + List survivors = getSurvivors(); + when(mockAdaption.getNeighborhoodEpsilon()).thenReturn(0.0001); + List> neighborhoods = coupler.createNeighborhoods(survivors); + assertEquals(3, neighborhoods.size()); + verify(mockAdaption).adaptNeighborhoodEpsilon(true); + coupler = new AeSeHCoupler(new AdditiveEpsilonMapping(), mockAdaption, new Random(), 5); + neighborhoods = coupler.createNeighborhoods(survivors); + verify(mockAdaption).adaptNeighborhoodEpsilon(false); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetCouplesWrongCoupleNumber() { + AeSeHCoupler coupler = new AeSeHCoupler(new AdditiveEpsilonMapping(), mockAdaption, new Random(), 2); + Individual first = mock(Individual.class); + Individual second = mock(Individual.class); + List indiSet = new ArrayList(); + indiSet.add(first); + indiSet.add(second); + coupler.getCouples(3, indiSet); + } + + @Test + public void testGetCouple() { + AeSeHCoupler coupler = new AeSeHCoupler(new AdditiveEpsilonMapping(), mockAdaption, new Random(), 2); + Individual first = mock(Individual.class); + Individual second = mock(Individual.class); + Set indiSet = new HashSet(); + indiSet.add(first); + indiSet.add(second); + Pair couple = coupler.pickCouple(indiSet); + assertTrue(couple.getFirst().equals(first) || couple.getSecond().equals(first)); + assertTrue(couple.getFirst().equals(second) || couple.getSecond().equals(second)); + indiSet.remove(first); + couple = coupler.pickCouple(indiSet); + assertTrue(couple.getFirst().equals(second)); + assertTrue(couple.getSecond().equals(second)); + } + +} diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHSelectorTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHSelectorTest.java new file mode 100644 index 00000000..c7b6fadf --- /dev/null +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHSelectorTest.java @@ -0,0 +1,71 @@ +package org.opt4j.optimizers.ea; + +import static org.junit.Assert.*; + +import org.junit.Test; +import org.opt4j.core.Individual; +import org.opt4j.core.optimizer.Population; + +import static org.mockito.Mockito.*; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +public class AeSeHSelectorTest { + + @Test(expected=IllegalArgumentException.class) + public void testGetParentsWrongCall(){ + ESamplingSurvivorGeneration survivorGeneration = mock(DefaultSurvivorGeneration.class); + AeSeHSelector selector = new AeSeHSelector(survivorGeneration); + Individual first = mock(Individual.class); + Individual second = mock(Individual.class); + Individual third = mock(Individual.class); + Population population = new Population(); + population.add(first); + population.add(second); + population.add(third); + selector.getParents(2, population); + } + + @Test + public void testGetParents(){ + ESamplingSurvivorGeneration survivorGeneration = mock(DefaultSurvivorGeneration.class); + AeSeHSelector selector = new AeSeHSelector(survivorGeneration); + Individual first = mock(Individual.class); + Individual second = mock(Individual.class); + Individual third = mock(Individual.class); + Population population = new Population(); + population.add(first); + population.add(second); + population.add(third); + Collection parents = selector.getParents(3, population); + assertEquals(population, parents); + } + + @Test + public void testGetLames() { + ESamplingSurvivorGeneration survivorGeneration = mock(DefaultSurvivorGeneration.class); + AeSeHSelector selector = new AeSeHSelector(survivorGeneration); + + Individual first = mock(Individual.class); + Individual second = mock(Individual.class); + Individual third = mock(Individual.class); + + Set survivors = new HashSet(); + survivors.add(first); + survivors.add(second); + + Population population = new Population(); + population.add(first); + population.add(second); + population.add(third); + + when(survivorGeneration.getSurvivors(population, 2)).thenReturn(survivors); + Collection result = selector.getLames(1, population); + verify(survivorGeneration).getSurvivors(population, 2); + assertEquals(1, result.size()); + assertTrue(result.contains(third)); + } + +} diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptationTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptationTest.java new file mode 100644 index 00000000..10e6feb0 --- /dev/null +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptationTest.java @@ -0,0 +1,70 @@ +package org.opt4j.optimizers.ea; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class DefaultEpsilonAdaptationTest { + + protected double eps_start = 0.0; + protected double eps_delta_start = 0.5; + protected double eps_delta_max = 1.5; + protected double eps_delta_min = 0.4; + + @Test + public void testEpsilonNeighborhood() { + DefaultEpsilonAdaptation adaptation = new DefaultEpsilonAdaptation(0, 0, 0, 0, eps_start, eps_delta_start, + eps_delta_max, eps_delta_min); + assertEquals(eps_start, adaptation.getNeighborhoodEpsilon(), 0.0); + adaptation.adaptNeighborhoodEpsilon(true); + assertEquals(0.5, adaptation.getNeighborhoodEpsilon(), 0.0); + adaptation.adaptNeighborhoodEpsilon(true); + assertEquals(1.5, adaptation.epsilon_neighborhood_delta, 0.0); + assertEquals(1.5, adaptation.getNeighborhoodEpsilon(), 0.0); + adaptation.adaptNeighborhoodEpsilon(false); + assertEquals(0.0, adaptation.getNeighborhoodEpsilon(), 0.0); + assertEquals(0.75, adaptation.epsilon_neighborhood_delta, 0.0); + adaptation.adaptNeighborhoodEpsilon(false); + assertEquals(0.0, adaptation.getNeighborhoodEpsilon(), 0.0); + assertEquals(0.4, adaptation.epsilon_neighborhood_delta, 0.0); + } + + @Test + public void testEpsilonSample() { + DefaultEpsilonAdaptation adaptation = new DefaultEpsilonAdaptation(eps_start, eps_delta_start, eps_delta_max, + eps_delta_min, 0, 0, 0, 0); + assertEquals(eps_start, adaptation.getSamplingEpsilon(), 0.0); + adaptation.adaptSamplingEpsilon(true); + assertEquals(0.5, adaptation.getSamplingEpsilon(), 0.0); + adaptation.adaptSamplingEpsilon(true); + assertEquals(1.5, adaptation.epsilon_sample_delta, 0.0); + assertEquals(1.5, adaptation.getSamplingEpsilon(), 0.0); + adaptation.adaptSamplingEpsilon(false); + assertEquals(0.0, adaptation.getSamplingEpsilon(), 0.0); + assertEquals(0.75, adaptation.epsilon_sample_delta, 0.0); + adaptation.adaptSamplingEpsilon(false); + assertEquals(0.0, adaptation.getSamplingEpsilon(), 0.0); + assertEquals(0.4, adaptation.epsilon_sample_delta, 0.0); + } + + @Test(expected = IllegalArgumentException.class) + public void testEpsilonNeighborhoodWrongBoundsMax() { + new DefaultEpsilonAdaptation(0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.9, 0.8); + } + + @Test(expected = IllegalArgumentException.class) + public void testEpsilonNeighborhoodWrongBoundsMin() { + new DefaultEpsilonAdaptation(0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 1.1); + } + + @Test(expected = IllegalArgumentException.class) + public void testEpsilonSampleWrongBoundsMin() { + new DefaultEpsilonAdaptation(0.0, 1.0, 2.0, 1.1, 0.0, 0.0, 0.0, 0.0); + } + + @Test(expected = IllegalArgumentException.class) + public void testEpsilonSampleWrongBoundsMax() { + new DefaultEpsilonAdaptation(0.0, 1.0, 0.5, 0.4, 0.0, 0.0, 0.0, 0.0); + } + +} diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest.java new file mode 100644 index 00000000..b585471f --- /dev/null +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest.java @@ -0,0 +1,118 @@ +package org.opt4j.optimizers.ea; + +import static org.junit.Assert.*; + +import org.junit.Test; +import org.opt4j.core.Individual; +import org.opt4j.core.Objective; +import org.opt4j.core.Objectives; + +import static org.mockito.Mockito.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; + +public class DefaultSurvivorGenerationTest { + + protected static Individual extremeIndividual = mock(Individual.class); + + protected static Objectives dominant = mock(Objectives.class); + protected static Objectives dominated = mock(Objectives.class); + + protected static Individual first = mock(Individual.class); + protected static Individual second = mock(Individual.class); + protected static Individual third = mock(Individual.class); + protected static Individual fourth = mock(Individual.class); + protected static Individual fifth = mock(Individual.class); + + public static List getFirstFront() { + List result = new ArrayList(); + result.add(extremeIndividual); + + when(dominant.dominates(dominated)).thenReturn(true); + when(dominant.dominates(dominant)).thenReturn(false); + when(dominated.dominates(dominated)).thenReturn(false); + when(dominated.dominates(dominated)).thenReturn(false); + + when(first.getObjectives()).thenReturn(dominant); + when(second.getObjectives()).thenReturn(dominant); + when(third.getObjectives()).thenReturn(dominated); + when(fourth.getObjectives()).thenReturn(dominated); + when(fifth.getObjectives()).thenReturn(dominated); + + result.add(first); + result.add(second); + result.add(third); + result.add(fourth); + result.add(fifth); + return result; + } + + @SuppressWarnings("unchecked") + @Test + public void testApplyEpsilonSampling(){ + EpsilonMapping mockMapping = mock(AdditiveEpsilonMapping.class); + EpsilonAdaption mockAdaption = mock(DefaultEpsilonAdaptation.class); + Map amplitudeMap = new HashMap(); + when(mockMapping.findObjectiveAmplitudes(any(HashSet.class))).thenReturn(amplitudeMap); + when(mockAdaption.getSamplingEpsilon()).thenReturn(0.0); + when(mockMapping.mapObjectives(dominant, 0.0, amplitudeMap)).thenReturn(dominant); + when(mockMapping.mapObjectives(dominated, 0.0, amplitudeMap)).thenReturn(dominated); + Set extremes = new HashSet(); + extremes.add(extremeIndividual); + DefaultSurvivorGeneration survivorGeneration = new DefaultSurvivorGeneration(new Random(), mockMapping, mockAdaption); + Set survivors = survivorGeneration.applyEpsilonSampling(extremes, getFirstFront(), 4); + assertTrue(survivors.containsAll(extremes)); + assertTrue(survivors.contains(first)); + assertTrue(survivors.contains(second)); + verify(mockAdaption).adaptSamplingEpsilon(false); + survivorGeneration.applyEpsilonSampling(extremes, getFirstFront(), 2); + verify(mockAdaption).adaptSamplingEpsilon(true); + } + + public static List> getFronts() { + Individual first = mock(Individual.class); + Individual second = mock(Individual.class); + Individual third = mock(Individual.class); + Individual fourth = mock(Individual.class); + Individual fifth = mock(Individual.class); + Individual sixth = mock(Individual.class); + + List> fronts = new ArrayList>(); + List firstFront = new ArrayList(); + firstFront.add(first); + firstFront.add(second); + firstFront.add(third); + List secondFront = new ArrayList(); + secondFront.add(fourth); + List thirdFront = new ArrayList(); + thirdFront.add(fifth); + thirdFront.add(sixth); + fronts.add(firstFront); + fronts.add(secondFront); + fronts.add(thirdFront); + return fronts; + } + + @Test + public void testAddDominatedSurvivors() { + Random mockRandom = mock(Random.class); + when(mockRandom.nextInt(2)).thenReturn(0); + EpsilonAdaption mockAdaption = mock(DefaultEpsilonAdaptation.class); + DefaultSurvivorGeneration survivorGeneration = new DefaultSurvivorGeneration(mockRandom, + new AdditiveEpsilonMapping(), mockAdaption); + List> fronts = getFronts(); + Set survivors = survivorGeneration.addDominatedSurvivors(5, fronts); + assertEquals(5, survivors.size()); + assertTrue(survivors.containsAll(fronts.get(0))); + assertTrue(survivors.containsAll(fronts.get(1))); + verify(mockRandom).nextInt(2); + + } + +} diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/NonDominatedSortingTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/NonDominatedSortingTest.java new file mode 100644 index 00000000..b27d9378 --- /dev/null +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/NonDominatedSortingTest.java @@ -0,0 +1,85 @@ +package org.opt4j.optimizers.ea; + +import static org.junit.Assert.*; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.junit.Test; +import org.opt4j.core.Individual; +import org.opt4j.core.Objective; +import org.opt4j.core.Objective.Sign; +import org.opt4j.core.Objectives; + +import static org.mockito.Mockito.*; + +public class NonDominatedSortingTest { + + protected static final Objective firstObj = new Objective("first", Sign.MAX); + protected static final Objective secondObj = new Objective("second", Sign.MAX); + + protected static Individual first = mock(Individual.class); + protected static Individual second = mock(Individual.class); + protected static Individual third = mock(Individual.class); + protected static Individual fourth = mock(Individual.class); + protected static Individual fifth = mock(Individual.class); + + protected static Set getIndividualSet() { + Set result = new HashSet(); + + when(first.getObjectives()).thenReturn(getObjectives(5, 1)); + when(second.getObjectives()).thenReturn(getObjectives(3, 3)); + when(third.getObjectives()).thenReturn(getObjectives(1, 4)); + when(fourth.getObjectives()).thenReturn(getObjectives(3, 2)); + when(fifth.getObjectives()).thenReturn(getObjectives(1, 1)); + + when(first.toString()).thenReturn("first"); + when(second.toString()).thenReturn("second"); + when(third.toString()).thenReturn("third"); + when(fourth.toString()).thenReturn("fourth"); + when(fifth.toString()).thenReturn("fifth"); + + result.add(first); + result.add(second); + result.add(third); + result.add(fourth); + result.add(fifth); + + return result; + } + + protected static Objectives getObjectives(int f, int s) { + Objectives result = new Objectives(); + result.add(firstObj, f); + result.add(secondObj, s); + return result; + } + + @Test + public void testGetExtremeIndividuals() { + Set extremes = NonDominatedSorting + .getExtremeIndividuals(NonDominatedSorting.generateFronts(getIndividualSet()).get(0)); + assertEquals(2, extremes.size()); + assertTrue(extremes.contains(first)); + assertTrue(extremes.contains(third)); + } + + @Test + public void testGenerateFronts() { + List> fronts = NonDominatedSorting.generateFronts(getIndividualSet()); + assertEquals(3, fronts.size()); + + assertEquals(3, fronts.get(0).size()); + assertTrue(fronts.get(0).contains(first)); + assertTrue(fronts.get(0).contains(second)); + assertTrue(fronts.get(0).contains(third)); + + assertEquals(1, fronts.get(1).size()); + assertTrue(fronts.get(1).contains(fourth)); + + assertEquals(1, fronts.get(2).size()); + assertTrue(fronts.get(2).contains(fifth)); + } + +} diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/RoundRobinSchedulerTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/RoundRobinSchedulerTest.java new file mode 100644 index 00000000..878ac771 --- /dev/null +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/RoundRobinSchedulerTest.java @@ -0,0 +1,42 @@ +package org.opt4j.optimizers.ea; + +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.junit.Test; +import org.opt4j.core.Individual; + +public class RoundRobinSchedulerTest { + + @SuppressWarnings("serial") + class MockNeighborhood extends HashSet{ + protected final String name; + public MockNeighborhood(String name){ + this.name = name; + } + @Override + public String toString() { + return name; + } + } + + @Test + public void test() { + MockNeighborhood first = new MockNeighborhood("first"); + MockNeighborhood second = new MockNeighborhood("second"); + MockNeighborhood third = new MockNeighborhood("third"); + List> neighborhoods = new ArrayList>(); + neighborhoods.add(first); + neighborhoods.add(second); + neighborhoods.add(third); + RoundRobinScheduler scheduler = new RoundRobinScheduler(neighborhoods); + assertEquals(scheduler.next().toString(), "first"); + assertEquals(scheduler.next().toString(), "second"); + assertEquals(scheduler.next().toString(), "third"); + assertEquals(scheduler.next().toString(), "first"); + } +} From 4f14f945f3c7cdc39b49765a6dde18d096119a6d Mon Sep 17 00:00:00 2001 From: Fedor Smirnov Date: Sun, 4 Mar 2018 08:41:18 +0100 Subject: [PATCH 03/20] Integrated the AeSeH into the EA Gui --- .../org/opt4j/optimizers/ea/AeSeHCoupler.java | 3 +- .../ea/DefaultEpsilonAdaptation.java | 38 ++-- .../ea/ESamplingSurvivorGeneration.java | 3 + .../opt4j/optimizers/ea/EpsilonMapping.java | 3 + .../ea/EvolutionaryAlgorithmModule.java | 170 +++++++++++++++--- 5 files changed, 176 insertions(+), 41 deletions(-) diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHCoupler.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHCoupler.java index 9111a912..7fe28003 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHCoupler.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHCoupler.java @@ -11,6 +11,7 @@ import org.opt4j.core.Individual; import org.opt4j.core.Objective; import org.opt4j.core.Objectives; +import org.opt4j.core.start.Constant; import org.opt4j.operators.crossover.Pair; import com.google.inject.Inject; @@ -39,7 +40,7 @@ public class AeSeHCoupler implements Coupler { @Inject public AeSeHCoupler(EpsilonMapping epsilonMapping, EpsilonAdaption epsilonAdaption, Random random, - int plannedNeighborhoodNumber) { + @Constant(value = "neighborhoodNumber", namespace = AeSeHCoupler.class) int plannedNeighborhoodNumber) { this.epsilonMapping = epsilonMapping; this.epsilonAdaption = epsilonAdaption; this.random = random; diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptation.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptation.java index 00f83864..7a8b5ca7 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptation.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptation.java @@ -1,5 +1,9 @@ package org.opt4j.optimizers.ea; +import org.opt4j.core.start.Constant; + +import com.google.inject.Inject; + public class DefaultEpsilonAdaptation implements EpsilonAdaption { protected double epsilon_sample; @@ -12,16 +16,26 @@ public class DefaultEpsilonAdaptation implements EpsilonAdaption { protected final double epsilon_neighborhood_delta_max; protected final double epsilon_neighborhood_delta_min; - public DefaultEpsilonAdaptation(double epsilon_sample, double epsilon_sample_delta, double epsilon_sample_delta_max, - double epsilon_sample_delta_min, double epsilon_neighborhood, double epsilon_neighborhood_delta, - double epsilon_neighborhood_delta_max, double epsilon_neighborhood_delta_min) { - if (epsilon_sample_delta < epsilon_sample_delta_min || epsilon_sample_delta > epsilon_sample_delta_max){ - throw new IllegalArgumentException("The start value for the epsilon_sample must lie within the provided bounds"); + @Inject + public DefaultEpsilonAdaptation( + @Constant(value = "epsilonSample", namespace = DefaultEpsilonAdaptation.class) double epsilon_sample, + @Constant(value = "epsilonSampleDelta", namespace = DefaultEpsilonAdaptation.class) double epsilon_sample_delta, + @Constant(value = "epsilonSampleDeltaMax", namespace = DefaultEpsilonAdaptation.class) double epsilon_sample_delta_max, + @Constant(value = "epsilonSampleDeltaMin", namespace = DefaultEpsilonAdaptation.class) double epsilon_sample_delta_min, + @Constant(value = "epsilonNeighborhood", namespace = DefaultEpsilonAdaptation.class) double epsilon_neighborhood, + @Constant(value = "epsilonNeighborhoodDelta", namespace = DefaultEpsilonAdaptation.class) double epsilon_neighborhood_delta, + @Constant(value = "epsilonNeighborhoodDeltaMax", namespace = DefaultEpsilonAdaptation.class) double epsilon_neighborhood_delta_max, + @Constant(value = "epsilonNeighborhoodDeltaMin", namespace = DefaultEpsilonAdaptation.class) double epsilon_neighborhood_delta_min) { + if (epsilon_sample_delta < epsilon_sample_delta_min || epsilon_sample_delta > epsilon_sample_delta_max) { + throw new IllegalArgumentException( + "The start value for the epsilon_sample must lie within the provided bounds"); } - if (epsilon_neighborhood_delta < epsilon_neighborhood_delta_min || epsilon_neighborhood_delta > epsilon_neighborhood_delta_max){ - throw new IllegalArgumentException("The start value for the epsilon_neighborhood must lie within the provided bounds"); + if (epsilon_neighborhood_delta < epsilon_neighborhood_delta_min + || epsilon_neighborhood_delta > epsilon_neighborhood_delta_max) { + throw new IllegalArgumentException( + "The start value for the epsilon_neighborhood must lie within the provided bounds"); } - + this.epsilon_sample = epsilon_sample; this.epsilon_sample_delta = epsilon_sample_delta; this.epsilon_sample_delta_max = epsilon_sample_delta_max; @@ -44,10 +58,10 @@ public double getNeighborhoodEpsilon() { @Override public void adaptSamplingEpsilon(boolean tooManyEpsilonDominantIndividuals) { - if (tooManyEpsilonDominantIndividuals){ + if (tooManyEpsilonDominantIndividuals) { epsilon_sample = epsilon_sample + epsilon_sample_delta; epsilon_sample_delta = Math.min(epsilon_sample_delta_max, 2 * epsilon_sample_delta); - }else{ + } else { epsilon_sample = Math.max(0.0, epsilon_sample - epsilon_sample_delta); epsilon_sample_delta = Math.max(epsilon_sample_delta_min, epsilon_sample_delta / 2); } @@ -55,10 +69,10 @@ public void adaptSamplingEpsilon(boolean tooManyEpsilonDominantIndividuals) { @Override public void adaptNeighborhoodEpsilon(boolean tooManyNeighborhoods) { - if(tooManyNeighborhoods){ + if (tooManyNeighborhoods) { epsilon_neighborhood = epsilon_neighborhood + epsilon_neighborhood_delta; epsilon_neighborhood_delta = Math.min(epsilon_neighborhood_delta_max, 2 * epsilon_neighborhood_delta); - }else{ + } else { epsilon_neighborhood = Math.max(0.0, epsilon_neighborhood - epsilon_neighborhood_delta); epsilon_neighborhood_delta = Math.max(epsilon_neighborhood_delta_min, epsilon_neighborhood_delta / 2); } diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/ESamplingSurvivorGeneration.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/ESamplingSurvivorGeneration.java index 14a3c73e..f9678f46 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/ESamplingSurvivorGeneration.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/ESamplingSurvivorGeneration.java @@ -5,6 +5,8 @@ import org.opt4j.core.Individual; +import com.google.inject.ImplementedBy; + /** * * Interface for the classes which generate the survivor pool during the @@ -13,6 +15,7 @@ * @author Fedor Smirnov * */ +@ImplementedBy(DefaultSurvivorGeneration.class) public interface ESamplingSurvivorGeneration { /** diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonMapping.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonMapping.java index f997fba1..b2938f10 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonMapping.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonMapping.java @@ -7,6 +7,8 @@ import org.opt4j.core.Objective; import org.opt4j.core.Objectives; +import com.google.inject.ImplementedBy; + /** * Interface for the classes applying the epsilon mapping used by the * {@link AeSeHSelector}. @@ -14,6 +16,7 @@ * @author Fedor Smirnov * */ +@ImplementedBy(AdditiveEpsilonMapping.class) public interface EpsilonMapping { /** diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java index 2d764786..29fff8d2 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java @@ -19,13 +19,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. *******************************************************************************/ - package org.opt4j.optimizers.ea; import org.opt4j.core.config.annotations.Ignore; import org.opt4j.core.config.annotations.Info; import org.opt4j.core.config.annotations.Order; +import org.opt4j.core.config.annotations.Required; import org.opt4j.core.optimizer.MaxIterations; import org.opt4j.core.optimizer.OptimizerModule; import org.opt4j.core.start.Constant; @@ -41,40 +41,76 @@ @Info("Multi-Objective Evolutionary Algorithm that performs a Crossover and Mutate for variation and uses a Selector for the environmental selection.") public class EvolutionaryAlgorithmModule extends OptimizerModule { - public enum MoeaType{ + public enum MoeaType { NSGA2, AeSeH } - + @Info("The number of generations.") @Order(0) @MaxIterations protected int generations = 1000; @Constant(value = "alpha", namespace = EvolutionaryAlgorithm.class) - @Info("The size of the population.") + @Info("Alph - The size of the population.") @Order(1) - protected int alpha = 100; + protected int populationSize = 100; - @Constant(value = "mu", namespace = EvolutionaryAlgorithm.class) - @Info("The number of parents per generation.") + @Info("Mu - The number of parents per generation.") + @Required(property = "moeaType", elements = { "NSGA2" }) @Order(2) - protected int mu = 25; + protected int parentsPerGeneration = 25; - @Constant(value = "lambda", namespace = EvolutionaryAlgorithm.class) - @Info("The number of offspring per generation.") + @Info("Lambda The number of offspring per generation.") + @Required(property = "moeaType", elements = { "NSGA2" }) @Order(3) - protected int lambda = 25; + protected int offspringsPerGeneration = 25; @Info("Performs a crossover operation with this given rate.") @Order(4) @Constant(value = "rate", namespace = ConstantCrossoverRate.class) protected double crossoverRate = 0.95; + @Required(property = "moeaType", elements = { "AeSeH" }) + @Constant(value = "epsilonSample", namespace = DefaultEpsilonAdaptation.class) + protected double epsilonSample = 0.0; + + @Required(property = "moeaType", elements = { "AeSeH" }) + @Constant(value = "epsilonSampleDelta", namespace = DefaultEpsilonAdaptation.class) + protected double epsilonSampleDelta = 0.005; + + @Required(property = "moeaType", elements = { "AeSeH" }) + @Constant(value = "epsilonSampleDeltaMax", namespace = DefaultEpsilonAdaptation.class) + protected double epsilonSampleDeltaMax = 0.005; + + @Required(property = "moeaType", elements = { "AeSeH" }) + @Constant(value = "epsilonSampleDeltaMin", namespace = DefaultEpsilonAdaptation.class) + protected double epsilonSampleDeltaMin = 0.0001; + + @Required(property = "moeaType", elements = { "AeSeH" }) + @Constant(value = "epsilonNeighborhood", namespace = DefaultEpsilonAdaptation.class) + protected double epsilonNeighborhood = 0.0; + + @Required(property = "moeaType", elements = { "AeSeH" }) + @Constant(value = "epsilonNeighborhoodDelta", namespace = DefaultEpsilonAdaptation.class) + protected double epsilonNeighborhoodDelta = 0.005; + + @Required(property = "moeaType", elements = { "AeSeH" }) + @Constant(value = "epsilonNeighborhoodDeltaMax", namespace = DefaultEpsilonAdaptation.class) + protected double epsilonNeighborhoodDeltaMax = 0.005; + + @Required(property = "moeaType", elements = { "AeSeH" }) + @Constant(value = "epsilonNeighborhoodDeltaMin", namespace = DefaultEpsilonAdaptation.class) + protected double epsilonNeighborhoodDeltaMin = 0.0001; + + @Required(property = "moeaType", elements = { "AeSeH" }) + @Constant(value = "neighborhoodNumber", namespace = AeSeHCoupler.class) + protected int neighborhoodNumber = 5; + @Ignore protected CrossoverRateType crossoverRateType = CrossoverRateType.CONSTANT; - + protected MoeaType moeaType = MoeaType.NSGA2; - + /** * The {@link CrossoverRateType} allows to choose between different types of * crossover rates. @@ -88,7 +124,15 @@ public enum CrossoverRateType { */ CONSTANT; } - + + public int getNeighborhoodNumber() { + return neighborhoodNumber; + } + + public void setNeighborhoodNumber(int neighborhoodNumber) { + this.neighborhoodNumber = neighborhoodNumber; + } + public MoeaType getMoeaType() { return moeaType; } @@ -97,14 +141,78 @@ public void setMoeaType(MoeaType moeaType) { this.moeaType = moeaType; } + public double getEpsilonSample() { + return epsilonSample; + } + + public void setEpsilonSample(double epsilonSample) { + this.epsilonSample = epsilonSample; + } + + public double getEpsilonSampleDelta() { + return epsilonSampleDelta; + } + + public void setEpsilonSampleDelta(double epsilonSampleDelta) { + this.epsilonSampleDelta = epsilonSampleDelta; + } + + public double getEpsilonSampleDeltaMax() { + return epsilonSampleDeltaMax; + } + + public void setEpsilonSampleDeltaMax(double epsilonSampleDeltaMax) { + this.epsilonSampleDeltaMax = epsilonSampleDeltaMax; + } + + public double getEpsilonSampleDeltaMin() { + return epsilonSampleDeltaMin; + } + + public void setEpsilonSampleDeltaMin(double epsilonSampleDeltaMin) { + this.epsilonSampleDeltaMin = epsilonSampleDeltaMin; + } + + public double getEpsilonNeighborhood() { + return epsilonNeighborhood; + } + + public void setEpsilonNeighborhood(double epsilonNeighborhood) { + this.epsilonNeighborhood = epsilonNeighborhood; + } + + public double getEpsilonNeighborhoodDelta() { + return epsilonNeighborhoodDelta; + } + + public void setEpsilonNeighborhoodDelta(double epsilonNeighborhoodDelta) { + this.epsilonNeighborhoodDelta = epsilonNeighborhoodDelta; + } + + public double getEpsilonNeighborhoodDeltaMax() { + return epsilonNeighborhoodDeltaMax; + } + + public void setEpsilonNeighborhoodDeltaMax(double epsilonNeighborhoodDeltaMax) { + this.epsilonNeighborhoodDeltaMax = epsilonNeighborhoodDeltaMax; + } + + public double getEpsilonNeighborhoodDeltaMin() { + return epsilonNeighborhoodDeltaMin; + } + + public void setEpsilonNeighborhoodDeltaMin(double epsilonNeighborhoodDeltaMin) { + this.epsilonNeighborhoodDeltaMin = epsilonNeighborhoodDeltaMin; + } + /** * Returns the population size {@code alpha}. * * @see #setAlpha * @return the population size */ - public int getAlpha() { - return alpha; + public int getPopulationSize() { + return populationSize; } /** @@ -114,8 +222,8 @@ public int getAlpha() { * @param alpha * the population size to set */ - public void setAlpha(int alpha) { - this.alpha = alpha; + public void setPopulationSize(int alpha) { + this.populationSize = alpha; } /** @@ -145,8 +253,8 @@ public void setGenerations(int generations) { * @see #setLambda * @return the number of children */ - public int getLambda() { - return lambda; + public int getOffspringsPerGeneration() { + return offspringsPerGeneration; } /** @@ -156,8 +264,8 @@ public int getLambda() { * @param lambda * the number of children */ - public void setLambda(int lambda) { - this.lambda = lambda; + public void setOffspringsPerGeneration(int lambda) { + this.offspringsPerGeneration = lambda; } /** @@ -166,8 +274,8 @@ public void setLambda(int lambda) { * @see #setMu * @return the number of parents */ - public int getMu() { - return mu; + public int getParentsPerGeneration() { + return parentsPerGeneration; } /** @@ -177,8 +285,8 @@ public int getMu() { * @param mu * the number of parents */ - public void setMu(int mu) { - this.mu = mu; + public void setParentsPerGeneration(int mu) { + this.parentsPerGeneration = mu; } /** @@ -230,12 +338,18 @@ public void setCrossoverRate(double crossoverRate) { */ @Override public void config() { - bindIterativeOptimizer(EvolutionaryAlgorithm.class); bind(CrossoverRate.class).to(ConstantCrossoverRate.class).in(SINGLETON); - if(moeaType.equals(MoeaType.AeSeH)){ + if (moeaType.equals(MoeaType.AeSeH)) { + bindConstant("lambda", EvolutionaryAlgorithm.class).to(populationSize); + bindConstant("mu", EvolutionaryAlgorithm.class).to(populationSize); + parentsPerGeneration = populationSize; + offspringsPerGeneration = populationSize; bind(Selector.class).to(AeSeHSelector.class); bind(Coupler.class).to(AeSeHCoupler.class); + }else{ + bindConstant("lambda", EvolutionaryAlgorithm.class).to(offspringsPerGeneration); + bindConstant("mu", EvolutionaryAlgorithm.class).to(parentsPerGeneration); } } } From 5500531ebb62d9c7ba49bd95ee8a3d37c6a60a65 Mon Sep 17 00:00:00 2001 From: Fedor Smirnov Date: Wed, 7 Mar 2018 10:03:48 +0100 Subject: [PATCH 04/20] separated the modules of NSGA and AeSeH; made AeSeH more flexible towards different parent and offspring numbers --- .../org/opt4j/optimizers/ea/AeSeHModule.java | 252 ++++++++++++++++++ .../opt4j/optimizers/ea/AeSeHSelector.java | 5 +- .../ea/EvolutionaryAlgorithmModule.java | 149 +---------- .../opt4j/optimizers/ea/AeSeHCouplerTest.java | 11 - .../optimizers/ea/AeSeHSelectorTest.java | 26 +- .../ea/DefaultSurvivorGenerationTest.java | 26 -- 6 files changed, 268 insertions(+), 201 deletions(-) create mode 100644 opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHModule.java diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHModule.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHModule.java new file mode 100644 index 00000000..956765f3 --- /dev/null +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHModule.java @@ -0,0 +1,252 @@ +package org.opt4j.optimizers.ea; + +import org.opt4j.core.config.annotations.Info; +import org.opt4j.core.config.annotations.Order; +import org.opt4j.core.optimizer.MaxIterations; +import org.opt4j.core.optimizer.OptimizerModule; +import org.opt4j.core.start.Constant; + +/** + * Module to bind the AeSeH evolutionary algorithm as optimizer. + * + * @author Fedor Smirnov + * + */ + +@Info("Multi-objective evolutionary algorithm where the survival selection and the creation of neighborhoods is based on epsilon-dominance. The selection of parents is done within the created neighborhoods.") +public class AeSeHModule extends OptimizerModule { + + @Info("The number of generations.") + @Order(0) + @MaxIterations + protected int generations = 1000; + + @Constant(value = "alpha", namespace = EvolutionaryAlgorithm.class) + @Info("Alph - The size of the population.") + @Order(1) + protected int populationSize = 100; + + @Info("Mu - The number of parents per generation.") + @Order(2) + protected int parentsPerGeneration = 25; + + @Info("Lambda The number of offsprings per generation.") + @Order(3) + protected int offspringsPerGeneration = 25; + + @Info("Performs a crossover operation with this given rate.") + @Order(4) + @Constant(value = "rate", namespace = ConstantCrossoverRate.class) + protected double crossoverRate = 0.95; + + @Info("The start value used for the epsilon value which is applied during the survivor selection.") + @Constant(value = "epsilonSample", namespace = DefaultEpsilonAdaptation.class) + protected double epsilonSample = 0.0; + + @Info("The start value used for the adaption of the epsilon value which is applied during the survivor selection.") + @Constant(value = "epsilonSampleDelta", namespace = DefaultEpsilonAdaptation.class) + protected double epsilonSampleDelta = 0.005; + + @Info("The maximal value used for the epsilon value which is applied during the survivor selection.") + @Constant(value = "epsilonSampleDeltaMax", namespace = DefaultEpsilonAdaptation.class) + protected double epsilonSampleDeltaMax = 0.005; + + @Info("The minimal value used for the epsilon value which is applied during the survivor selection.") + @Constant(value = "epsilonSampleDeltaMin", namespace = DefaultEpsilonAdaptation.class) + protected double epsilonSampleDeltaMin = 0.0001; + + @Info("The start value used for the epsilon value which is applied during the neighborhood creation.") + @Constant(value = "epsilonNeighborhood", namespace = DefaultEpsilonAdaptation.class) + protected double epsilonNeighborhood = 0.0; + + @Info("The start value used for the adaptation of the epsilon value which is applied during the neighborhood creation.") + @Constant(value = "epsilonNeighborhoodDelta", namespace = DefaultEpsilonAdaptation.class) + protected double epsilonNeighborhoodDelta = 0.005; + + @Info("The maximal value used for the epsilon value which is applied during the neighborhood creation.") + @Constant(value = "epsilonNeighborhoodDeltaMax", namespace = DefaultEpsilonAdaptation.class) + protected double epsilonNeighborhoodDeltaMax = 0.005; + + @Info("The minimal value used for the epsilon value which is applied during the neighborhood creation.") + @Constant(value = "epsilonNeighborhoodDeltaMin", namespace = DefaultEpsilonAdaptation.class) + protected double epsilonNeighborhoodDeltaMin = 0.0001; + + @Info("The reference value for the number of neighborhoods. The epsilon_h value is adapted to create a similar number of neighborhoods.") + @Constant(value = "neighborhoodNumber", namespace = AeSeHCoupler.class) + protected int neighborhoodNumber = 5; + + public int getNeighborhoodNumber() { + return neighborhoodNumber; + } + + public void setNeighborhoodNumber(int neighborhoodNumber) { + this.neighborhoodNumber = neighborhoodNumber; + } + + public double getEpsilonSample() { + return epsilonSample; + } + + public void setEpsilonSample(double epsilonSample) { + this.epsilonSample = epsilonSample; + } + + public double getEpsilonSampleDelta() { + return epsilonSampleDelta; + } + + public void setEpsilonSampleDelta(double epsilonSampleDelta) { + this.epsilonSampleDelta = epsilonSampleDelta; + } + + public double getEpsilonSampleDeltaMax() { + return epsilonSampleDeltaMax; + } + + public void setEpsilonSampleDeltaMax(double epsilonSampleDeltaMax) { + this.epsilonSampleDeltaMax = epsilonSampleDeltaMax; + } + + public double getEpsilonSampleDeltaMin() { + return epsilonSampleDeltaMin; + } + + public void setEpsilonSampleDeltaMin(double epsilonSampleDeltaMin) { + this.epsilonSampleDeltaMin = epsilonSampleDeltaMin; + } + + public double getEpsilonNeighborhood() { + return epsilonNeighborhood; + } + + public void setEpsilonNeighborhood(double epsilonNeighborhood) { + this.epsilonNeighborhood = epsilonNeighborhood; + } + + public double getEpsilonNeighborhoodDelta() { + return epsilonNeighborhoodDelta; + } + + public void setEpsilonNeighborhoodDelta(double epsilonNeighborhoodDelta) { + this.epsilonNeighborhoodDelta = epsilonNeighborhoodDelta; + } + + public double getEpsilonNeighborhoodDeltaMax() { + return epsilonNeighborhoodDeltaMax; + } + + public void setEpsilonNeighborhoodDeltaMax(double epsilonNeighborhoodDeltaMax) { + this.epsilonNeighborhoodDeltaMax = epsilonNeighborhoodDeltaMax; + } + + public double getEpsilonNeighborhoodDeltaMin() { + return epsilonNeighborhoodDeltaMin; + } + + public void setEpsilonNeighborhoodDeltaMin(double epsilonNeighborhoodDeltaMin) { + this.epsilonNeighborhoodDeltaMin = epsilonNeighborhoodDeltaMin; + } + + /** + * Returns the population size {@code alpha}. + * + * @return the population size + */ + public int getPopulationSize() { + return populationSize; + } + + /** + * Sets the population size {@code alpha}. + * + * @param alpha + * the population size to set + */ + public void setPopulationSize(int alpha) { + this.populationSize = alpha; + } + + /** + * Returns the number of generations. + * + * @return the number of generations + */ + public int getGenerations() { + return generations; + } + + /** + * Sets the number of generations. + * + * @param generations + * the number of generations + */ + public void setGenerations(int generations) { + this.generations = generations; + } + + /** + * Returns the number of children {@code lambda}. + * + * @return the number of children + */ + public int getOffspringsPerGeneration() { + return offspringsPerGeneration; + } + + /** + * Sets the number of children {@code lambda}. + * + * @param lambda + * the number of children + */ + public void setOffspringsPerGeneration(int lambda) { + this.offspringsPerGeneration = lambda; + } + + /** + * Returns the number of parents {@code mu}. + * + * @return the number of parents + */ + public int getParentsPerGeneration() { + return parentsPerGeneration; + } + + /** + * Sets the number of parents {@code mu}. + * + * @param mu + * the number of parents + */ + public void setParentsPerGeneration(int mu) { + this.parentsPerGeneration = mu; + } + + /** + * Returns the used crossover rate. + * + * @return the crossoverRate + */ + public double getCrossoverRate() { + return crossoverRate; + } + + /** + * Sets the crossover rate. + * + * @param crossoverRate + * the crossoverRate to set + */ + public void setCrossoverRate(double crossoverRate) { + this.crossoverRate = crossoverRate; + } + + @Override + protected void config() { + bindIterativeOptimizer(EvolutionaryAlgorithm.class); + bind(CrossoverRate.class).to(ConstantCrossoverRate.class).in(SINGLETON); + bind(Selector.class).to(AeSeHSelector.class); + bind(Coupler.class).to(AeSeHCoupler.class); + } +} diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHSelector.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHSelector.java index d607f275..3c803bea 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHSelector.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHSelector.java @@ -36,9 +36,8 @@ public AeSeHSelector(ESamplingSurvivorGeneration survivorGeneration) { @Override public Collection getParents(int mu, Collection population) { - if (mu != population.size()) { - throw new IllegalArgumentException("The population should consist only of the parents by now."); - } + // do nothing: In the AeSeH algorithm, all survivors are considered as possible + // parents return population; } diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java index 29fff8d2..ee6c9b2d 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java @@ -25,7 +25,6 @@ import org.opt4j.core.config.annotations.Ignore; import org.opt4j.core.config.annotations.Info; import org.opt4j.core.config.annotations.Order; -import org.opt4j.core.config.annotations.Required; import org.opt4j.core.optimizer.MaxIterations; import org.opt4j.core.optimizer.OptimizerModule; import org.opt4j.core.start.Constant; @@ -41,10 +40,6 @@ @Info("Multi-Objective Evolutionary Algorithm that performs a Crossover and Mutate for variation and uses a Selector for the environmental selection.") public class EvolutionaryAlgorithmModule extends OptimizerModule { - public enum MoeaType { - NSGA2, AeSeH - } - @Info("The number of generations.") @Order(0) @MaxIterations @@ -56,12 +51,10 @@ public enum MoeaType { protected int populationSize = 100; @Info("Mu - The number of parents per generation.") - @Required(property = "moeaType", elements = { "NSGA2" }) @Order(2) protected int parentsPerGeneration = 25; - @Info("Lambda The number of offspring per generation.") - @Required(property = "moeaType", elements = { "NSGA2" }) + @Info("Lambda The number of offsprings per generation.") @Order(3) protected int offspringsPerGeneration = 25; @@ -70,47 +63,9 @@ public enum MoeaType { @Constant(value = "rate", namespace = ConstantCrossoverRate.class) protected double crossoverRate = 0.95; - @Required(property = "moeaType", elements = { "AeSeH" }) - @Constant(value = "epsilonSample", namespace = DefaultEpsilonAdaptation.class) - protected double epsilonSample = 0.0; - - @Required(property = "moeaType", elements = { "AeSeH" }) - @Constant(value = "epsilonSampleDelta", namespace = DefaultEpsilonAdaptation.class) - protected double epsilonSampleDelta = 0.005; - - @Required(property = "moeaType", elements = { "AeSeH" }) - @Constant(value = "epsilonSampleDeltaMax", namespace = DefaultEpsilonAdaptation.class) - protected double epsilonSampleDeltaMax = 0.005; - - @Required(property = "moeaType", elements = { "AeSeH" }) - @Constant(value = "epsilonSampleDeltaMin", namespace = DefaultEpsilonAdaptation.class) - protected double epsilonSampleDeltaMin = 0.0001; - - @Required(property = "moeaType", elements = { "AeSeH" }) - @Constant(value = "epsilonNeighborhood", namespace = DefaultEpsilonAdaptation.class) - protected double epsilonNeighborhood = 0.0; - - @Required(property = "moeaType", elements = { "AeSeH" }) - @Constant(value = "epsilonNeighborhoodDelta", namespace = DefaultEpsilonAdaptation.class) - protected double epsilonNeighborhoodDelta = 0.005; - - @Required(property = "moeaType", elements = { "AeSeH" }) - @Constant(value = "epsilonNeighborhoodDeltaMax", namespace = DefaultEpsilonAdaptation.class) - protected double epsilonNeighborhoodDeltaMax = 0.005; - - @Required(property = "moeaType", elements = { "AeSeH" }) - @Constant(value = "epsilonNeighborhoodDeltaMin", namespace = DefaultEpsilonAdaptation.class) - protected double epsilonNeighborhoodDeltaMin = 0.0001; - - @Required(property = "moeaType", elements = { "AeSeH" }) - @Constant(value = "neighborhoodNumber", namespace = AeSeHCoupler.class) - protected int neighborhoodNumber = 5; - @Ignore protected CrossoverRateType crossoverRateType = CrossoverRateType.CONSTANT; - protected MoeaType moeaType = MoeaType.NSGA2; - /** * The {@link CrossoverRateType} allows to choose between different types of * crossover rates. @@ -125,90 +80,9 @@ public enum CrossoverRateType { CONSTANT; } - public int getNeighborhoodNumber() { - return neighborhoodNumber; - } - - public void setNeighborhoodNumber(int neighborhoodNumber) { - this.neighborhoodNumber = neighborhoodNumber; - } - - public MoeaType getMoeaType() { - return moeaType; - } - - public void setMoeaType(MoeaType moeaType) { - this.moeaType = moeaType; - } - - public double getEpsilonSample() { - return epsilonSample; - } - - public void setEpsilonSample(double epsilonSample) { - this.epsilonSample = epsilonSample; - } - - public double getEpsilonSampleDelta() { - return epsilonSampleDelta; - } - - public void setEpsilonSampleDelta(double epsilonSampleDelta) { - this.epsilonSampleDelta = epsilonSampleDelta; - } - - public double getEpsilonSampleDeltaMax() { - return epsilonSampleDeltaMax; - } - - public void setEpsilonSampleDeltaMax(double epsilonSampleDeltaMax) { - this.epsilonSampleDeltaMax = epsilonSampleDeltaMax; - } - - public double getEpsilonSampleDeltaMin() { - return epsilonSampleDeltaMin; - } - - public void setEpsilonSampleDeltaMin(double epsilonSampleDeltaMin) { - this.epsilonSampleDeltaMin = epsilonSampleDeltaMin; - } - - public double getEpsilonNeighborhood() { - return epsilonNeighborhood; - } - - public void setEpsilonNeighborhood(double epsilonNeighborhood) { - this.epsilonNeighborhood = epsilonNeighborhood; - } - - public double getEpsilonNeighborhoodDelta() { - return epsilonNeighborhoodDelta; - } - - public void setEpsilonNeighborhoodDelta(double epsilonNeighborhoodDelta) { - this.epsilonNeighborhoodDelta = epsilonNeighborhoodDelta; - } - - public double getEpsilonNeighborhoodDeltaMax() { - return epsilonNeighborhoodDeltaMax; - } - - public void setEpsilonNeighborhoodDeltaMax(double epsilonNeighborhoodDeltaMax) { - this.epsilonNeighborhoodDeltaMax = epsilonNeighborhoodDeltaMax; - } - - public double getEpsilonNeighborhoodDeltaMin() { - return epsilonNeighborhoodDeltaMin; - } - - public void setEpsilonNeighborhoodDeltaMin(double epsilonNeighborhoodDeltaMin) { - this.epsilonNeighborhoodDeltaMin = epsilonNeighborhoodDeltaMin; - } - /** * Returns the population size {@code alpha}. * - * @see #setAlpha * @return the population size */ public int getPopulationSize() { @@ -218,7 +92,6 @@ public int getPopulationSize() { /** * Sets the population size {@code alpha}. * - * @see #getAlpha * @param alpha * the population size to set */ @@ -229,7 +102,6 @@ public void setPopulationSize(int alpha) { /** * Returns the number of generations. * - * @see #setGenerations * @return the number of generations */ public int getGenerations() { @@ -250,7 +122,6 @@ public void setGenerations(int generations) { /** * Returns the number of children {@code lambda}. * - * @see #setLambda * @return the number of children */ public int getOffspringsPerGeneration() { @@ -260,7 +131,6 @@ public int getOffspringsPerGeneration() { /** * Sets the number of children {@code lambda}. * - * @see #getLambda * @param lambda * the number of children */ @@ -271,7 +141,6 @@ public void setOffspringsPerGeneration(int lambda) { /** * Returns the number of parents {@code mu}. * - * @see #setMu * @return the number of parents */ public int getParentsPerGeneration() { @@ -281,7 +150,6 @@ public int getParentsPerGeneration() { /** * Sets the number of parents {@code mu}. * - * @see #getMu * @param mu * the number of parents */ @@ -292,7 +160,6 @@ public void setParentsPerGeneration(int mu) { /** * Returns the type of crossover rate that is used. * - * @see #setCrossoverRateType * @return the crossoverRateType */ public CrossoverRateType getCrossoverRateType() { @@ -302,7 +169,6 @@ public CrossoverRateType getCrossoverRateType() { /** * Sets the type of crossover rate to use. * - * @see #getCrossoverRateType * @param crossoverRateType * the crossoverRateType to set */ @@ -313,7 +179,6 @@ public void setCrossoverRateType(CrossoverRateType crossoverRateType) { /** * Returns the used crossover rate. * - * @see #setCrossoverRate * @return the crossoverRate */ public double getCrossoverRate() { @@ -323,7 +188,6 @@ public double getCrossoverRate() { /** * Sets the crossover rate. * - * @see #getCrossoverRate * @param crossoverRate * the crossoverRate to set */ @@ -340,16 +204,5 @@ public void setCrossoverRate(double crossoverRate) { public void config() { bindIterativeOptimizer(EvolutionaryAlgorithm.class); bind(CrossoverRate.class).to(ConstantCrossoverRate.class).in(SINGLETON); - if (moeaType.equals(MoeaType.AeSeH)) { - bindConstant("lambda", EvolutionaryAlgorithm.class).to(populationSize); - bindConstant("mu", EvolutionaryAlgorithm.class).to(populationSize); - parentsPerGeneration = populationSize; - offspringsPerGeneration = populationSize; - bind(Selector.class).to(AeSeHSelector.class); - bind(Coupler.class).to(AeSeHCoupler.class); - }else{ - bindConstant("lambda", EvolutionaryAlgorithm.class).to(offspringsPerGeneration); - bindConstant("mu", EvolutionaryAlgorithm.class).to(parentsPerGeneration); - } } } diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHCouplerTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHCouplerTest.java index 1c0ead5e..fe22ec9c 100644 --- a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHCouplerTest.java +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHCouplerTest.java @@ -75,17 +75,6 @@ public void testCreateNeighborhoods() { verify(mockAdaption).adaptNeighborhoodEpsilon(false); } - @Test(expected = IllegalArgumentException.class) - public void testGetCouplesWrongCoupleNumber() { - AeSeHCoupler coupler = new AeSeHCoupler(new AdditiveEpsilonMapping(), mockAdaption, new Random(), 2); - Individual first = mock(Individual.class); - Individual second = mock(Individual.class); - List indiSet = new ArrayList(); - indiSet.add(first); - indiSet.add(second); - coupler.getCouples(3, indiSet); - } - @Test public void testGetCouple() { AeSeHCoupler coupler = new AeSeHCoupler(new AdditiveEpsilonMapping(), mockAdaption, new Random(), 2); diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHSelectorTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHSelectorTest.java index c7b6fadf..a325b032 100644 --- a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHSelectorTest.java +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHSelectorTest.java @@ -14,19 +14,19 @@ public class AeSeHSelectorTest { - @Test(expected=IllegalArgumentException.class) - public void testGetParentsWrongCall(){ - ESamplingSurvivorGeneration survivorGeneration = mock(DefaultSurvivorGeneration.class); - AeSeHSelector selector = new AeSeHSelector(survivorGeneration); - Individual first = mock(Individual.class); - Individual second = mock(Individual.class); - Individual third = mock(Individual.class); - Population population = new Population(); - population.add(first); - population.add(second); - population.add(third); - selector.getParents(2, population); - } +// @Test(expected=IllegalArgumentException.class) +// public void testGetParentsWrongCall(){ +// ESamplingSurvivorGeneration survivorGeneration = mock(DefaultSurvivorGeneration.class); +// AeSeHSelector selector = new AeSeHSelector(survivorGeneration); +// Individual first = mock(Individual.class); +// Individual second = mock(Individual.class); +// Individual third = mock(Individual.class); +// Population population = new Population(); +// population.add(first); +// population.add(second); +// population.add(third); +// selector.getParents(2, population); +// } @Test public void testGetParents(){ diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest.java index b585471f..af00ce84 100644 --- a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest.java +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest.java @@ -4,16 +4,12 @@ import org.junit.Test; import org.opt4j.core.Individual; -import org.opt4j.core.Objective; import org.opt4j.core.Objectives; import static org.mockito.Mockito.*; import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Random; import java.util.Set; @@ -53,28 +49,6 @@ public static List getFirstFront() { return result; } - @SuppressWarnings("unchecked") - @Test - public void testApplyEpsilonSampling(){ - EpsilonMapping mockMapping = mock(AdditiveEpsilonMapping.class); - EpsilonAdaption mockAdaption = mock(DefaultEpsilonAdaptation.class); - Map amplitudeMap = new HashMap(); - when(mockMapping.findObjectiveAmplitudes(any(HashSet.class))).thenReturn(amplitudeMap); - when(mockAdaption.getSamplingEpsilon()).thenReturn(0.0); - when(mockMapping.mapObjectives(dominant, 0.0, amplitudeMap)).thenReturn(dominant); - when(mockMapping.mapObjectives(dominated, 0.0, amplitudeMap)).thenReturn(dominated); - Set extremes = new HashSet(); - extremes.add(extremeIndividual); - DefaultSurvivorGeneration survivorGeneration = new DefaultSurvivorGeneration(new Random(), mockMapping, mockAdaption); - Set survivors = survivorGeneration.applyEpsilonSampling(extremes, getFirstFront(), 4); - assertTrue(survivors.containsAll(extremes)); - assertTrue(survivors.contains(first)); - assertTrue(survivors.contains(second)); - verify(mockAdaption).adaptSamplingEpsilon(false); - survivorGeneration.applyEpsilonSampling(extremes, getFirstFront(), 2); - verify(mockAdaption).adaptSamplingEpsilon(true); - } - public static List> getFronts() { Individual first = mock(Individual.class); Individual second = mock(Individual.class); From 069159a34207aa6401430c9e0cc3adf7fea57e99 Mon Sep 17 00:00:00 2001 From: Fedor Smirnov Date: Wed, 7 Mar 2018 10:21:59 +0100 Subject: [PATCH 05/20] fixed module bug --- .../src/main/java/org/opt4j/optimizers/ea/AeSeHCoupler.java | 3 --- .../src/main/java/org/opt4j/optimizers/ea/AeSeHModule.java | 2 ++ .../org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java | 2 ++ 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHCoupler.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHCoupler.java index 7fe28003..d2a05807 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHCoupler.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHCoupler.java @@ -49,9 +49,6 @@ public AeSeHCoupler(EpsilonMapping epsilonMapping, EpsilonAdaption epsilonAdapti @Override public Collection> getCouples(int size, List parents) { - if (size != parents.size() / 2) { - throw new IllegalArgumentException("The offspring number should be equal to the population size"); - } Collection> result = new HashSet>(); List> neighborhoods = createNeighborhoods(parents); RoundRobinScheduler scheduler = new RoundRobinScheduler(neighborhoods); diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHModule.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHModule.java index 956765f3..e4086d59 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHModule.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHModule.java @@ -26,10 +26,12 @@ public class AeSeHModule extends OptimizerModule { @Order(1) protected int populationSize = 100; + @Constant(value = "mu", namespace = EvolutionaryAlgorithm.class) @Info("Mu - The number of parents per generation.") @Order(2) protected int parentsPerGeneration = 25; + @Constant(value = "lambda", namespace = EvolutionaryAlgorithm.class) @Info("Lambda The number of offsprings per generation.") @Order(3) protected int offspringsPerGeneration = 25; diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java index ee6c9b2d..fc617e3e 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java @@ -50,10 +50,12 @@ public class EvolutionaryAlgorithmModule extends OptimizerModule { @Order(1) protected int populationSize = 100; + @Constant(value = "mu", namespace = EvolutionaryAlgorithm.class) @Info("Mu - The number of parents per generation.") @Order(2) protected int parentsPerGeneration = 25; + @Constant(value = "lambda", namespace = EvolutionaryAlgorithm.class) @Info("Lambda The number of offsprings per generation.") @Order(3) protected int offspringsPerGeneration = 25; From 9820bea76ccad1d4a43c4dce83bc43b0e68ad174 Mon Sep 17 00:00:00 2001 From: Fedor Smirnov Date: Thu, 8 Mar 2018 18:18:06 +0100 Subject: [PATCH 06/20] tests for AeSeH; addressed code smells of AeSeH --- .../optimizers/ea/AdditiveEpsilonMapping.java | 10 +- .../org/opt4j/optimizers/ea/AeSeHModule.java | 11 +- .../ea/DefaultEpsilonAdaptation.java | 74 ++++----- .../ea/DefaultSurvivorGeneration.java | 65 ++++---- .../ea/DefaultEpsilonAdaptationTest.java | 12 +- ...va => DefaultSurvivorGenerationTest1.java} | 4 +- .../ea/DefaultSurvivorGenerationTest2.java | 143 ++++++++++++++++++ 7 files changed, 244 insertions(+), 75 deletions(-) rename opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/{DefaultSurvivorGenerationTest.java => DefaultSurvivorGenerationTest1.java} (98%) create mode 100644 opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest2.java diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java index b60517a1..e0bd2396 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java @@ -2,6 +2,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import org.opt4j.core.Individual; @@ -38,14 +39,17 @@ public Map findObjectiveAmplitudes(Set individual double value = indi.getObjectives().get(obj).getDouble(); if (!maximumMap.containsKey(obj) || maximumMap.get(obj) < value) { maximumMap.put(obj, value); - } + } if (!minimumMap.containsKey(obj) || minimumMap.get(obj) > value) { minimumMap.put(obj, value); } } } - for (Objective obj : maximumMap.keySet()) { - amplitudeMap.put(obj, maximumMap.get(obj) - minimumMap.get(obj)); + for (Entry maxEntry : maximumMap.entrySet()) { + Objective obj = maxEntry.getKey(); + Double maximum = maxEntry.getValue(); + Double minimum = minimumMap.get(obj); + amplitudeMap.put(obj, maximum - minimum); } return amplitudeMap; } diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHModule.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHModule.java index e4086d59..12a19432 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHModule.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHModule.java @@ -7,7 +7,16 @@ import org.opt4j.core.start.Constant; /** - * Module to bind the AeSeH evolutionary algorithm as optimizer. + * Module to bind the AeSeH evolutionary algorithm as optimizer. This algorithm + * was first introduced in the paper: + * + * Aguirre, Hernán, Akira Oyama, and Kiyoshi Tanaka. "Adaptive ε-sampling and + * ε-hood for evolutionary many-objective optimization." International + * Conference on Evolutionary Multi-Criterion Optimization. Springer, Berlin, + * Heidelberg, 2013. + * + * Please consider citing the paper if you use this class for a scientific + * publication. * * @author Fedor Smirnov * diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptation.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptation.java index 7a8b5ca7..64cd32d5 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptation.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptation.java @@ -6,75 +6,75 @@ public class DefaultEpsilonAdaptation implements EpsilonAdaption { - protected double epsilon_sample; - protected double epsilon_sample_delta; - protected final double epsilon_sample_delta_max; - protected final double epsilon_sample_delta_min; + protected double epsilonSample; + protected double epsilonSampleDelta; + protected final double epsilonSampleDeltaMax; + protected final double epsilonSampleDeltaMin; - protected double epsilon_neighborhood; - protected double epsilon_neighborhood_delta; - protected final double epsilon_neighborhood_delta_max; - protected final double epsilon_neighborhood_delta_min; + protected double epsilonNeighborhood; + protected double epsilonNeighborhoodDelta; + protected final double epsilonNeighborhoodDeltaMax; + protected final double epsilonNeighborhoodDeltaMin; @Inject public DefaultEpsilonAdaptation( - @Constant(value = "epsilonSample", namespace = DefaultEpsilonAdaptation.class) double epsilon_sample, - @Constant(value = "epsilonSampleDelta", namespace = DefaultEpsilonAdaptation.class) double epsilon_sample_delta, - @Constant(value = "epsilonSampleDeltaMax", namespace = DefaultEpsilonAdaptation.class) double epsilon_sample_delta_max, - @Constant(value = "epsilonSampleDeltaMin", namespace = DefaultEpsilonAdaptation.class) double epsilon_sample_delta_min, - @Constant(value = "epsilonNeighborhood", namespace = DefaultEpsilonAdaptation.class) double epsilon_neighborhood, - @Constant(value = "epsilonNeighborhoodDelta", namespace = DefaultEpsilonAdaptation.class) double epsilon_neighborhood_delta, - @Constant(value = "epsilonNeighborhoodDeltaMax", namespace = DefaultEpsilonAdaptation.class) double epsilon_neighborhood_delta_max, - @Constant(value = "epsilonNeighborhoodDeltaMin", namespace = DefaultEpsilonAdaptation.class) double epsilon_neighborhood_delta_min) { - if (epsilon_sample_delta < epsilon_sample_delta_min || epsilon_sample_delta > epsilon_sample_delta_max) { + @Constant(value = "epsilonSample", namespace = DefaultEpsilonAdaptation.class) double epsilonSample, + @Constant(value = "epsilonSampleDelta", namespace = DefaultEpsilonAdaptation.class) double epsilonSampleDelta, + @Constant(value = "epsilonSampleDeltaMax", namespace = DefaultEpsilonAdaptation.class) double epsilonSampleDeltaMax, + @Constant(value = "epsilonSampleDeltaMin", namespace = DefaultEpsilonAdaptation.class) double epsilonSampleDeltaMin, + @Constant(value = "epsilonNeighborhood", namespace = DefaultEpsilonAdaptation.class) double epsilonNeighborhood, + @Constant(value = "epsilonNeighborhoodDelta", namespace = DefaultEpsilonAdaptation.class) double epsilonNeighborhoodDelta, + @Constant(value = "epsilonNeighborhoodDeltaMax", namespace = DefaultEpsilonAdaptation.class) double epsilonNeighborhoodDeltaMax, + @Constant(value = "epsilonNeighborhoodDeltaMin", namespace = DefaultEpsilonAdaptation.class) double epsilonNeighborhoodDeltaMin) { + if (epsilonSampleDelta < epsilonSampleDeltaMin || epsilonSampleDelta > epsilonSampleDeltaMax) { throw new IllegalArgumentException( "The start value for the epsilon_sample must lie within the provided bounds"); } - if (epsilon_neighborhood_delta < epsilon_neighborhood_delta_min - || epsilon_neighborhood_delta > epsilon_neighborhood_delta_max) { + if (epsilonNeighborhoodDelta < epsilonNeighborhoodDeltaMin + || epsilonNeighborhoodDelta > epsilonNeighborhoodDeltaMax) { throw new IllegalArgumentException( "The start value for the epsilon_neighborhood must lie within the provided bounds"); } - this.epsilon_sample = epsilon_sample; - this.epsilon_sample_delta = epsilon_sample_delta; - this.epsilon_sample_delta_max = epsilon_sample_delta_max; - this.epsilon_sample_delta_min = epsilon_sample_delta_min; - this.epsilon_neighborhood = epsilon_neighborhood; - this.epsilon_neighborhood_delta = epsilon_neighborhood_delta; - this.epsilon_neighborhood_delta_max = epsilon_neighborhood_delta_max; - this.epsilon_neighborhood_delta_min = epsilon_neighborhood_delta_min; + this.epsilonSample = epsilonSample; + this.epsilonSampleDelta = epsilonSampleDelta; + this.epsilonSampleDeltaMax = epsilonSampleDeltaMax; + this.epsilonSampleDeltaMin = epsilonSampleDeltaMin; + this.epsilonNeighborhood = epsilonNeighborhood; + this.epsilonNeighborhoodDelta = epsilonNeighborhoodDelta; + this.epsilonNeighborhoodDeltaMax = epsilonNeighborhoodDeltaMax; + this.epsilonNeighborhoodDeltaMin = epsilonNeighborhoodDeltaMin; } @Override public double getSamplingEpsilon() { - return epsilon_sample; + return epsilonSample; } @Override public double getNeighborhoodEpsilon() { - return epsilon_neighborhood; + return epsilonNeighborhood; } @Override public void adaptSamplingEpsilon(boolean tooManyEpsilonDominantIndividuals) { if (tooManyEpsilonDominantIndividuals) { - epsilon_sample = epsilon_sample + epsilon_sample_delta; - epsilon_sample_delta = Math.min(epsilon_sample_delta_max, 2 * epsilon_sample_delta); + epsilonSample = epsilonSample + epsilonSampleDelta; + epsilonSampleDelta = Math.min(epsilonSampleDeltaMax, 2 * epsilonSampleDelta); } else { - epsilon_sample = Math.max(0.0, epsilon_sample - epsilon_sample_delta); - epsilon_sample_delta = Math.max(epsilon_sample_delta_min, epsilon_sample_delta / 2); + epsilonSample = Math.max(0.0, epsilonSample - epsilonSampleDelta); + epsilonSampleDelta = Math.max(epsilonSampleDeltaMin, epsilonSampleDelta / 2); } } @Override public void adaptNeighborhoodEpsilon(boolean tooManyNeighborhoods) { if (tooManyNeighborhoods) { - epsilon_neighborhood = epsilon_neighborhood + epsilon_neighborhood_delta; - epsilon_neighborhood_delta = Math.min(epsilon_neighborhood_delta_max, 2 * epsilon_neighborhood_delta); + epsilonNeighborhood = epsilonNeighborhood + epsilonNeighborhoodDelta; + epsilonNeighborhoodDelta = Math.min(epsilonNeighborhoodDeltaMax, 2 * epsilonNeighborhoodDelta); } else { - epsilon_neighborhood = Math.max(0.0, epsilon_neighborhood - epsilon_neighborhood_delta); - epsilon_neighborhood_delta = Math.max(epsilon_neighborhood_delta_min, epsilon_neighborhood_delta / 2); + epsilonNeighborhood = Math.max(0.0, epsilonNeighborhood - epsilonNeighborhoodDelta); + epsilonNeighborhoodDelta = Math.max(epsilonNeighborhoodDeltaMin, epsilonNeighborhoodDelta / 2); } } } diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultSurvivorGeneration.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultSurvivorGeneration.java index 13e8697c..9bfb2a51 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultSurvivorGeneration.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultSurvivorGeneration.java @@ -44,7 +44,7 @@ public Set getSurvivors(Collection population, int survi if (paretoSolutions.size() > survivorNumber) { // more non-dominated solutions than survivors => apply ε-sampling - survivors = applyEpsilonSampling(extremeIndividuals, paretoSolutions, survivorNumber); + survivors = addNonDominatedSurvivors(extremeIndividuals, paretoSolutions, survivorNumber); } else { survivors = addDominatedSurvivors(survivorNumber, fronts); } @@ -59,36 +59,16 @@ public Set getSurvivors(Collection population, int survi * @param firstFront * @param survivorNumber */ - protected Set applyEpsilonSampling(Collection extremeIndividuals, + protected Set addNonDominatedSurvivors(Collection extremeIndividuals, Collection firstFront, int survivorNumber) { Set survivors = new HashSet(); List nonDominatedIndividuals = new ArrayList(firstFront); // the extreme values always survive survivors.addAll(extremeIndividuals); nonDominatedIndividuals.removeAll(extremeIndividuals); - Map objectiveAmplitudes = epsilonMapping - .findObjectiveAmplitudes(new HashSet(nonDominatedIndividuals)); Set epsilonDominantIndividuals = new HashSet(); Set epsilonDominatedIndividuals = new HashSet(); - // apply epsilon sampling until the individual list is empty - while (!nonDominatedIndividuals.isEmpty()) { - // pick a random individual - Individual epsilonDominant = nonDominatedIndividuals.get(random.nextInt(nonDominatedIndividuals.size())); - Set epsilonDominated = new HashSet(); - nonDominatedIndividuals.remove(epsilonDominant); - Objectives epsilonEnhancedObjectives = epsilonMapping.mapObjectives(epsilonDominant.getObjectives(), - epsilonAdaption.getSamplingEpsilon(), objectiveAmplitudes); - // gather all individuals epsilon dominated by the picked individual - for (int i = 0; i < nonDominatedIndividuals.size(); i++) { - Individual comparisonIndividual = nonDominatedIndividuals.get(i); - if (epsilonEnhancedObjectives.dominates(comparisonIndividual.getObjectives())) { - epsilonDominated.add(comparisonIndividual); - } - } - nonDominatedIndividuals.removeAll(epsilonDominated); - epsilonDominantIndividuals.add(epsilonDominant); - epsilonDominatedIndividuals.addAll(epsilonDominated); - } + applyEpsilonSampling(nonDominatedIndividuals, epsilonDominantIndividuals, epsilonDominatedIndividuals, epsilonAdaption.getSamplingEpsilon()); boolean tooManyEpsilonDominantIndividuals = (extremeIndividuals.size() + epsilonDominantIndividuals.size()) > survivorNumber; // adapt the sampling epsilon @@ -117,9 +97,42 @@ protected Set applyEpsilonSampling(Collection extremeInd } /** - * In the case where the first non-dominated front does not suffice to - * create enough survivors, dominated solutions are added to the survivor - * pool. + * Apply epsilon sampling by dividing the given individuals into the two sets of epsilon-dominant and epsilon-dominated individuals. + * + * @param firstFront : The input individuals who constitute the first non-dominated front of the current population. + * @param epsilonDominantIndividuals : The set that will be filled with the epsilon-dominant individuals. + * @param epsilonDominatedIndividuals : The set that will be filled with epsilon-dominated individuals + * @param samplingEpsilon : The value used for the epsilon sampling. + */ + protected void applyEpsilonSampling(List firstFront, Set epsilonDominantIndividuals, + Set epsilonDominatedIndividuals, double samplingEpsilon) { + // apply epsilon sampling until the individual list is empty + List nonDominatedIndividuals = new ArrayList(firstFront); + Map objectiveAmplitudes = epsilonMapping + .findObjectiveAmplitudes(new HashSet(nonDominatedIndividuals)); + while (!nonDominatedIndividuals.isEmpty()) { + // pick a random individual + Individual epsilonDominant = nonDominatedIndividuals.get(random.nextInt(nonDominatedIndividuals.size())); + Set epsilonDominated = new HashSet(); + nonDominatedIndividuals.remove(epsilonDominant); + Objectives epsilonEnhancedObjectives = epsilonMapping.mapObjectives(epsilonDominant.getObjectives(), + samplingEpsilon, objectiveAmplitudes); + // gather all individuals epsilon dominated by the picked individual + for (int i = 0; i < nonDominatedIndividuals.size(); i++) { + Individual comparisonIndividual = nonDominatedIndividuals.get(i); + if (epsilonEnhancedObjectives.dominates(comparisonIndividual.getObjectives())) { + epsilonDominated.add(comparisonIndividual); + } + } + nonDominatedIndividuals.removeAll(epsilonDominated); + epsilonDominantIndividuals.add(epsilonDominant); + epsilonDominatedIndividuals.addAll(epsilonDominated); + } + } + + /** + * In the case where the first non-dominated front does not suffice to create + * enough survivors, dominated solutions are added to the survivor pool. * * @param survivorNumber * @param fronts diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptationTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptationTest.java index 10e6feb0..4d52c9c8 100644 --- a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptationTest.java +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptationTest.java @@ -19,14 +19,14 @@ public void testEpsilonNeighborhood() { adaptation.adaptNeighborhoodEpsilon(true); assertEquals(0.5, adaptation.getNeighborhoodEpsilon(), 0.0); adaptation.adaptNeighborhoodEpsilon(true); - assertEquals(1.5, adaptation.epsilon_neighborhood_delta, 0.0); + assertEquals(1.5, adaptation.epsilonNeighborhoodDelta, 0.0); assertEquals(1.5, adaptation.getNeighborhoodEpsilon(), 0.0); adaptation.adaptNeighborhoodEpsilon(false); assertEquals(0.0, adaptation.getNeighborhoodEpsilon(), 0.0); - assertEquals(0.75, adaptation.epsilon_neighborhood_delta, 0.0); + assertEquals(0.75, adaptation.epsilonNeighborhoodDelta, 0.0); adaptation.adaptNeighborhoodEpsilon(false); assertEquals(0.0, adaptation.getNeighborhoodEpsilon(), 0.0); - assertEquals(0.4, adaptation.epsilon_neighborhood_delta, 0.0); + assertEquals(0.4, adaptation.epsilonNeighborhoodDelta, 0.0); } @Test @@ -37,14 +37,14 @@ public void testEpsilonSample() { adaptation.adaptSamplingEpsilon(true); assertEquals(0.5, adaptation.getSamplingEpsilon(), 0.0); adaptation.adaptSamplingEpsilon(true); - assertEquals(1.5, adaptation.epsilon_sample_delta, 0.0); + assertEquals(1.5, adaptation.epsilonSampleDelta, 0.0); assertEquals(1.5, adaptation.getSamplingEpsilon(), 0.0); adaptation.adaptSamplingEpsilon(false); assertEquals(0.0, adaptation.getSamplingEpsilon(), 0.0); - assertEquals(0.75, adaptation.epsilon_sample_delta, 0.0); + assertEquals(0.75, adaptation.epsilonSampleDelta, 0.0); adaptation.adaptSamplingEpsilon(false); assertEquals(0.0, adaptation.getSamplingEpsilon(), 0.0); - assertEquals(0.4, adaptation.epsilon_sample_delta, 0.0); + assertEquals(0.4, adaptation.epsilonSampleDelta, 0.0); } @Test(expected = IllegalArgumentException.class) diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest1.java similarity index 98% rename from opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest.java rename to opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest1.java index af00ce84..dc24df53 100644 --- a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest.java +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest1.java @@ -13,7 +13,7 @@ import java.util.Random; import java.util.Set; -public class DefaultSurvivorGenerationTest { +public class DefaultSurvivorGenerationTest1 { protected static Individual extremeIndividual = mock(Individual.class); @@ -72,7 +72,7 @@ public static List> getFronts() { fronts.add(thirdFront); return fronts; } - + @Test public void testAddDominatedSurvivors() { Random mockRandom = mock(Random.class); diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest2.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest2.java new file mode 100644 index 00000000..9fc2bdec --- /dev/null +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest2.java @@ -0,0 +1,143 @@ +package org.opt4j.optimizers.ea; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; +import org.opt4j.core.Individual; +import org.opt4j.core.Objective; +import org.opt4j.core.Objective.Sign; +import org.opt4j.core.Objectives; + +import static org.mockito.Mockito.*; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; + +public class DefaultSurvivorGenerationTest2 { + + protected Objective firstObj = new Objective("first", Sign.MAX); + protected Objective secondObj = new Objective("second", Sign.MAX); + + protected List nonDominated; + + protected Individual firstIndi; + protected Individual secondIndi; + protected Individual thirdIndi; + protected Individual fourthIndi; + + protected Random rand; + + protected EpsilonMapping mapping; + + protected EpsilonAdaption adaptation; + + protected Individual getIndividual(double firstValue, double secondValue) { + Individual result = mock(Individual.class); + Objectives objectives = new Objectives(); + objectives.add(firstObj, firstValue); + objectives.add(secondObj, secondValue); + when(result.getObjectives()).thenReturn(objectives); + return result; + } + + @Before + public void init() { + nonDominated = new ArrayList(); + firstIndi = getIndividual(1.0, 5.0); + secondIndi = getIndividual(1.1, 3.0); + thirdIndi = getIndividual(3.0, 1.1); + fourthIndi = getIndividual(5.0, 1.0); + nonDominated.add(firstIndi); + nonDominated.add(fourthIndi); + nonDominated.add(secondIndi); + nonDominated.add(thirdIndi); + + rand = mock(Random.class); + when(rand.nextInt(anyInt())).thenReturn(0); + + adaptation = mock(EpsilonAdaption.class); + when(adaptation.getSamplingEpsilon()).thenReturn(0.2); + mapping = new AdditiveEpsilonMapping(); + } + + @Test + public void testGetSurvivors() { + Set extremes = new HashSet(); + Individual firstExtreme = getIndividual(0.0, 6.0); + Individual secondExtreme = getIndividual(6.0, 0.0); + Individual dominated = getIndividual(1.0, 1.0); + extremes.add(firstExtreme); + extremes.add(secondExtreme); + Set population = new HashSet(nonDominated); + population.addAll(extremes); + population.add(dominated); + DefaultSurvivorGeneration survivorGeneration = new DefaultSurvivorGeneration(rand, mapping, adaptation); + Set survivors = survivorGeneration.getSurvivors(population, 3); + assertEquals(3, survivors.size()); + assertTrue(survivors.contains(firstExtreme)); + assertTrue(survivors.contains(secondExtreme)); + assertFalse(survivors.contains(dominated)); + + survivors = survivorGeneration.getSurvivors(population, 7); + assertEquals(7, survivors.size()); + assertTrue(survivors.contains(firstExtreme)); + assertTrue(survivors.contains(secondExtreme)); + assertTrue(survivors.contains(dominated)); + } + + @Test + public void addNonDominatedSurvivorsTestTooFewSurvivors() { + Set extremes = new HashSet(); + Individual firstExtreme = getIndividual(0.0, 6.0); + Individual secondExtreme = getIndividual(6.0, 0.0); + // make sure we always have epsilon-dominance + Individual addition = getIndividual(1.2, 2.9); + extremes.add(firstExtreme); + extremes.add(secondExtreme); + Set firstFront = new HashSet(nonDominated); + firstFront.addAll(extremes); + firstFront.add(addition); + DefaultSurvivorGeneration survivorGeneration = new DefaultSurvivorGeneration(rand, mapping, adaptation); + Set survivors = survivorGeneration.addNonDominatedSurvivors(extremes, firstFront, 7); + assertEquals(7, survivors.size()); + assertTrue(survivors.contains(firstExtreme)); + assertTrue(survivors.contains(secondExtreme)); + verify(adaptation).adaptSamplingEpsilon(false); + } + + @Test + public void addNonDominatedSurvivorsTestTooManySurvivors() { + Set extremes = new HashSet(); + Individual firstExtreme = getIndividual(0.0, 6.0); + Individual secondExtreme = getIndividual(6.0, 0.0); + extremes.add(firstExtreme); + extremes.add(secondExtreme); + Set firstFront = new HashSet(nonDominated); + firstFront.addAll(extremes); + DefaultSurvivorGeneration survivorGeneration = new DefaultSurvivorGeneration(rand, mapping, adaptation); + Set survivors = survivorGeneration.addNonDominatedSurvivors(extremes, firstFront, 3); + assertEquals(3, survivors.size()); + assertTrue(survivors.contains(firstExtreme)); + assertTrue(survivors.contains(secondExtreme)); + verify(adaptation).adaptSamplingEpsilon(true); + } + + @Test + public void testApplyEpsilonSampling() { + DefaultSurvivorGeneration survivorGeneration = new DefaultSurvivorGeneration(rand, mapping, adaptation); + Set dominant = new HashSet(); + Set dominated = new HashSet(); + survivorGeneration.applyEpsilonSampling(nonDominated, dominant, dominated, 0.05); + assertEquals(2, dominant.size()); + assertEquals(2, dominated.size()); + assertTrue(dominant.contains(firstIndi)); + assertTrue(dominant.contains(fourthIndi)); + assertTrue(dominated.contains(secondIndi)); + assertTrue(dominated.contains(thirdIndi)); + } + +} From 24345a451b1a529a163b61019096e36509074a92 Mon Sep 17 00:00:00 2001 From: Fedor Smirnov Date: Fri, 9 Mar 2018 11:49:20 +0100 Subject: [PATCH 07/20] changed the way the sampling accesses objective values to cope with null values --- .../org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java index e0bd2396..409aeec0 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java @@ -1,6 +1,7 @@ package org.opt4j.optimizers.ea; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -35,8 +36,12 @@ public Map findObjectiveAmplitudes(Set individual Map minimumMap = new HashMap(); Map amplitudeMap = new HashMap(); for (Individual indi : individuals) { - for (Objective obj : indi.getObjectives().getKeys()) { - double value = indi.getObjectives().get(obj).getDouble(); + Objectives objectives = indi.getObjectives(); + Iterator iterator = objectives.getKeys().iterator(); + double[] values = objectives.array(); + for (int i = 0; i < objectives.size(); i++) { + Objective obj = iterator.next(); + double value = values[i]; if (!maximumMap.containsKey(obj) || maximumMap.get(obj) < value) { maximumMap.put(obj, value); } From 519c44d940dba981c05cbcd853df82b24dda4478 Mon Sep 17 00:00:00 2001 From: Fedor Smirnov Date: Fri, 9 Mar 2018 12:08:19 +0100 Subject: [PATCH 08/20] fixed the value access for the epsilon mapping function --- .../org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java index 409aeec0..e724739f 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java @@ -22,8 +22,11 @@ public class AdditiveEpsilonMapping implements EpsilonMapping { @Override public Objectives mapObjectives(Objectives original, double epsilon, Map objectiveAmplitudes) { Objectives result = new Objectives(); - for (Objective obj : original.getKeys()) { - double value = original.get(obj).getDouble(); + Iterator iterator = original.getKeys().iterator(); + double[] values = original.array(); + for (int i = 0; i < original.size(); i++) { + Objective obj = iterator.next(); + double value = values[i] * (obj.getSign().equals(Sign.MIN) ? 1 : -1); double delta = epsilon * objectiveAmplitudes.get(obj) * (obj.getSign().equals(Sign.MAX) ? 1 : -1); result.add(obj, value + delta); } From 4608ebc75846ef3112770af7d2dcb655e9da7e3e Mon Sep 17 00:00:00 2001 From: Fedor Smirnov Date: Fri, 9 Mar 2018 17:38:25 +0100 Subject: [PATCH 09/20] refactored the non-dominated sorting --- .../optimizers/ea/NonDominatedSorting.java | 137 ++++++++++++------ 1 file changed, 93 insertions(+), 44 deletions(-) diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedSorting.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedSorting.java index d4601ec9..30a52b47 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedSorting.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedSorting.java @@ -31,75 +31,124 @@ private NonDominatedSorting() { * Sort the given individuals into non-dominated fronts * * @param individuals - * @return an ordered list of the non-dominated front. The first entry is - * made up by the first front, that is by the Pareto-optimal - * solutions + * @return an ordered list of the non-dominated front. The first entry is made + * up by the first front, that is by the Pareto-optimal solutions */ public static List> generateFronts(Collection individuals) { // assign an id to each individual that corresponds to its index in an // array - List pop = new ArrayList(individuals); - Map id = new HashMap(); - for (int i = 0; i < pop.size(); i++) { - id.put(pop.get(i), i); + List individualList = new ArrayList(individuals); + Map indexMap = new HashMap(); + for (int i = 0; i < individualList.size(); i++) { + indexMap.put(individualList.get(i), i); } List> fronts = new ArrayList>(); // Initialize a map where an individual is assigned to the individuals // that it dominates - Map> S = new HashMap>(); + Map> dominatedIndividualsMap = new HashMap>(); // n is an array where for each individual, the number of individuals // that dominate it is stored - int[] n = new int[pop.size()]; - for (Individual e : pop) { - S.put(e, new ArrayList()); - n[id.get(e)] = 0; - } - // compare each individual with each other individual - for (int i = 0; i < pop.size(); i++) { - for (int j = i + 1; j < pop.size(); j++) { - Individual p = pop.get(i); - Individual q = pop.get(j); - Objectives po = p.getObjectives(); - Objectives qo = q.getObjectives(); - - if (po.dominates(qo)) { - S.get(p).add(q); - n[id.get(q)]++; - } else if (qo.dominates(po)) { - S.get(q).add(p); - n[id.get(p)]++; - } - } + int[] dominatingIndividualNumber = new int[individualList.size()]; + for (Individual e : individualList) { + dominatedIndividualsMap.put(e, new ArrayList()); + dominatingIndividualNumber[indexMap.get(e)] = 0; } + determineDomination(individualList, dominatedIndividualsMap, dominatingIndividualNumber, indexMap); // The first front consists of individuals that are dominated by zero // other individuals List f1 = new ArrayList(); - for (Individual i : pop) { - if (n[id.get(i)] == 0) { + for (Individual i : individualList) { + if (dominatingIndividualNumber[indexMap.get(i)] == 0) { f1.add(i); } } fronts.add(f1); - List fi = f1; + List currentFront = f1; // Create the subsequent fronts. Front f_i is made up by individuals // that // are not dominated if all individuals from fronts f_j with j < i are // removed. - while (!fi.isEmpty()) { - List h = new ArrayList(); - for (Individual p : fi) { - for (Individual q : S.get(p)) { - n[id.get(q)]--; - if (n[id.get(q)] == 0) { - h.add(q); - } + while (!currentFront.isEmpty()) { + List nextFront = getNextFront(currentFront, dominatedIndividualsMap, dominatingIndividualNumber, indexMap); + if (!nextFront.isEmpty()) + fronts.add(nextFront); + currentFront = nextFront; + } + return fronts; + } + + /** + * Find the next non-dominated front by processing the current non-dominated + * front. The individuals found therein are removed from consideration. The + * individuals that are then not dominated form the next non-dominated front. + * + * @param currentFront + * : The list of individuals forming the current non-dominated front + * @param dominatedIndividualsMap + * : map mapping an individual on the collection of individuals that + * it dominates + * @param dominatingIndividualNumber + * : an array where the number of dominating individuals is stored + * for each individual + * @param individual2IndexMap + * : a map storing the indices of the individuals used to access the + * dominatingIndividualNumber + * @return The list of individuals forming the next non-dominated front. + */ + protected static List getNextFront(List currentFront, + Map> dominatedIndividualsMap, int[] dominatingIndividualNumber, + Map individual2IndexMap) { + List nextFront = new ArrayList(); + for (Individual dominant : currentFront) { + for (Individual dominated : dominatedIndividualsMap.get(dominant)) { + dominatingIndividualNumber[individual2IndexMap.get(dominated)]--; + if (dominatingIndividualNumber[individual2IndexMap.get(dominated)] == 0) { + nextFront.add(dominated); + } + } + } + return nextFront; + } + + /** + * Compare all possible individual pairs. For each individual, store 1) the + * number of individuals it is dominated by and 2) the set of individuals it + * dominates. + * + * @param individualList + * : A list of the individuals + * @param dominatedIndividualsMap + * : A map that is filled during the execution of the method. Each + * individual is mapped onto the set of individuals that are + * dominated by this individual. + * @param dominatingIndividualNumber + * : An integer array (initialized with zeros) that is filled during + * the execution of this method. Each individual is associated with + * an entry of this array. The integer therein is the number of + * individuals this individual is dominated by. + * @param individual2IndexMap + * : A map mapping each individual onto its index in the + * dominatingIndividualNumber - array. + */ + protected static void determineDomination(List individualList, + Map> dominatedIndividualsMap, int[] dominatingIndividualNumber, + Map individual2IndexMap) { + // compare each individual with each other individual + for (int i = 0; i < individualList.size(); i++) { + for (int j = i + 1; j < individualList.size(); j++) { + Individual p = individualList.get(i); + Individual q = individualList.get(j); + Objectives po = p.getObjectives(); + Objectives qo = q.getObjectives(); + if (po.dominates(qo)) { + dominatedIndividualsMap.get(p).add(q); + dominatingIndividualNumber[individual2IndexMap.get(q)]++; + } else if (qo.dominates(po)) { + dominatedIndividualsMap.get(q).add(p); + dominatingIndividualNumber[individual2IndexMap.get(p)]++; } } - if (!h.isEmpty()) - fronts.add(h); - fi = h; } - return fronts; } /** From a17788feca97476216a60b5d543e0b15c099233d Mon Sep 17 00:00:00 2001 From: Fedor Smirnov Date: Sun, 11 Mar 2018 15:16:17 +0100 Subject: [PATCH 10/20] fixed typos --- .../src/main/java/org/opt4j/optimizers/ea/AeSeHModule.java | 2 +- .../org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHModule.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHModule.java index 12a19432..75bc0ee5 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHModule.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHModule.java @@ -31,7 +31,7 @@ public class AeSeHModule extends OptimizerModule { protected int generations = 1000; @Constant(value = "alpha", namespace = EvolutionaryAlgorithm.class) - @Info("Alph - The size of the population.") + @Info("Alpha - The size of the population.") @Order(1) protected int populationSize = 100; diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java index fc617e3e..011ef7ad 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java @@ -46,7 +46,7 @@ public class EvolutionaryAlgorithmModule extends OptimizerModule { protected int generations = 1000; @Constant(value = "alpha", namespace = EvolutionaryAlgorithm.class) - @Info("Alph - The size of the population.") + @Info("Alpha - The size of the population.") @Order(1) protected int populationSize = 100; From 0551a69c776e4889e0a82dd7f1972b6b46d6997d Mon Sep 17 00:00:00 2001 From: Fedor Smirnov Date: Sun, 11 Mar 2018 16:02:12 +0100 Subject: [PATCH 11/20] added a check for infeasible objectives; adjusted the test cases accordingly --- .../optimizers/ea/AdditiveEpsilonMapping.java | 2 ++ .../optimizers/ea/NonDominatedSorting.java | 26 +++++++++---------- .../ea/AdditiveEpsilonMappingTest.java | 7 +++++ .../optimizers/ea/AeSeHSelectorTest.java | 14 ---------- .../ea/NonDominatedSortingTest.java | 13 ++++++++-- 5 files changed, 33 insertions(+), 29 deletions(-) diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java index e724739f..0aae2d85 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java @@ -44,6 +44,8 @@ public Map findObjectiveAmplitudes(Set individual double[] values = objectives.array(); for (int i = 0; i < objectives.size(); i++) { Objective obj = iterator.next(); + if (objectives.get(obj).getValue() == Objective.INFEASIBLE) + continue; double value = values[i]; if (!maximumMap.containsKey(obj) || maximumMap.get(obj) < value) { maximumMap.put(obj, value); diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedSorting.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedSorting.java index 30a52b47..feb7862f 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedSorting.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedSorting.java @@ -10,7 +10,6 @@ import org.opt4j.core.Individual; import org.opt4j.core.Objective; -import org.opt4j.core.Objective.Sign; import org.opt4j.core.Objectives; /** @@ -159,18 +158,19 @@ protected static void determineDomination(List individualList, */ public static Set getExtremeIndividuals(Collection firstFront) { Map bestIndis = new HashMap(); - for (Individual indi : firstFront) { - for (Objective o : indi.getObjectives().getKeys()) { - double value = indi.getObjectives().get(o).getDouble(); - Sign sign = o.getSign(); - if (!bestIndis.containsKey(o)) { - bestIndis.put(o, indi); - } else { - double storedValue = bestIndis.get(o).getObjectives().get(o).getDouble(); - if ((storedValue < value && sign.equals(Sign.MAX)) - || storedValue > value && sign.equals(Sign.MIN)) { - bestIndis.put(o, indi); - } + Map extremeValues = new HashMap(); + Individual firstIndi = firstFront.iterator().next(); + List objList = new ArrayList(firstIndi.getObjectives().getKeys()); + // iterate the individuals + for (Individual indi : firstFront){ + // iterate the objectives and their values + double[] values = indi.getObjectives().array(); + for (int i = 0; i < objList.size(); i++){ + Objective obj = objList.get(i); + double value = values[i]; + if(!bestIndis.containsKey(obj) || extremeValues.get(obj) > value){ + bestIndis.put(obj, indi); + extremeValues.put(obj, value); } } } diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AdditiveEpsilonMappingTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AdditiveEpsilonMappingTest.java index 6eb73643..d98e2bc9 100644 --- a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AdditiveEpsilonMappingTest.java +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AdditiveEpsilonMappingTest.java @@ -31,6 +31,10 @@ protected static Set getIndividualSet() { Objectives thirdObj = new Objectives(); thirdObj.add(first, 2); thirdObj.add(second, 2); + + Objectives infeasibleObj = new Objectives(); + infeasibleObj.add(first, Objective.INFEASIBLE); + infeasibleObj.add(second, Objective.INFEASIBLE); Individual first = mock(Individual.class); when(first.getObjectives()).thenReturn(firstObj); @@ -38,11 +42,14 @@ protected static Set getIndividualSet() { when(second.getObjectives()).thenReturn(secondObj); Individual third = mock(Individual.class); when(third.getObjectives()).thenReturn(thirdObj); + Individual infeasible = mock(Individual.class); + when(infeasible.getObjectives()).thenReturn(infeasibleObj); Set indis = new HashSet(); indis.add(first); indis.add(second); indis.add(third); + indis.add(infeasible); return indis; } diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHSelectorTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHSelectorTest.java index a325b032..df78b100 100644 --- a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHSelectorTest.java +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHSelectorTest.java @@ -14,20 +14,6 @@ public class AeSeHSelectorTest { -// @Test(expected=IllegalArgumentException.class) -// public void testGetParentsWrongCall(){ -// ESamplingSurvivorGeneration survivorGeneration = mock(DefaultSurvivorGeneration.class); -// AeSeHSelector selector = new AeSeHSelector(survivorGeneration); -// Individual first = mock(Individual.class); -// Individual second = mock(Individual.class); -// Individual third = mock(Individual.class); -// Population population = new Population(); -// population.add(first); -// population.add(second); -// population.add(third); -// selector.getParents(2, population); -// } - @Test public void testGetParents(){ ESamplingSurvivorGeneration survivorGeneration = mock(DefaultSurvivorGeneration.class); diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/NonDominatedSortingTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/NonDominatedSortingTest.java index b27d9378..5bbf90a3 100644 --- a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/NonDominatedSortingTest.java +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/NonDominatedSortingTest.java @@ -10,6 +10,7 @@ import org.opt4j.core.Individual; import org.opt4j.core.Objective; import org.opt4j.core.Objective.Sign; + import org.opt4j.core.Objectives; import static org.mockito.Mockito.*; @@ -24,6 +25,7 @@ public class NonDominatedSortingTest { protected static Individual third = mock(Individual.class); protected static Individual fourth = mock(Individual.class); protected static Individual fifth = mock(Individual.class); + protected static Individual infeasible = mock(Individual.class); protected static Set getIndividualSet() { Set result = new HashSet(); @@ -34,17 +36,24 @@ protected static Set getIndividualSet() { when(fourth.getObjectives()).thenReturn(getObjectives(3, 2)); when(fifth.getObjectives()).thenReturn(getObjectives(1, 1)); + Objectives insfeasibleObjectives = new Objectives(); + insfeasibleObjectives.add(firstObj, Objective.INFEASIBLE); + insfeasibleObjectives.add(secondObj, Objective.INFEASIBLE); + when(infeasible.getObjectives()).thenReturn(insfeasibleObjectives); + when(first.toString()).thenReturn("first"); when(second.toString()).thenReturn("second"); when(third.toString()).thenReturn("third"); when(fourth.toString()).thenReturn("fourth"); when(fifth.toString()).thenReturn("fifth"); + when(infeasible.toString()).thenReturn("infeasible"); result.add(first); result.add(second); result.add(third); result.add(fourth); result.add(fifth); + result.add(infeasible); return result; } @@ -59,7 +68,7 @@ protected static Objectives getObjectives(int f, int s) { @Test public void testGetExtremeIndividuals() { Set extremes = NonDominatedSorting - .getExtremeIndividuals(NonDominatedSorting.generateFronts(getIndividualSet()).get(0)); + .getExtremeIndividuals(getIndividualSet()); assertEquals(2, extremes.size()); assertTrue(extremes.contains(first)); assertTrue(extremes.contains(third)); @@ -68,7 +77,7 @@ public void testGetExtremeIndividuals() { @Test public void testGenerateFronts() { List> fronts = NonDominatedSorting.generateFronts(getIndividualSet()); - assertEquals(3, fronts.size()); + assertEquals(4, fronts.size()); assertEquals(3, fronts.get(0).size()); assertTrue(fronts.get(0).contains(first)); From 03e83db70b7c3a5a29c29b8ddc03a34d09f87658 Mon Sep 17 00:00:00 2001 From: Fedor Smirnov Date: Fri, 16 Mar 2018 12:44:54 +0100 Subject: [PATCH 12/20] created an extra package for the classes of the AeSeH MOEA --- .../optimizers/ea/{ => aeseh}/AdditiveEpsilonMapping.java | 2 +- .../org/opt4j/optimizers/ea/{ => aeseh}/AeSeHCoupler.java | 3 ++- .../org/opt4j/optimizers/ea/{ => aeseh}/AeSeHModule.java | 7 ++++++- .../opt4j/optimizers/ea/{ => aeseh}/AeSeHSelector.java | 3 ++- .../ea/{ => aeseh}/DefaultEpsilonAdaptation.java | 2 +- .../ea/{ => aeseh}/DefaultSurvivorGeneration.java | 3 ++- .../ea/{ => aeseh}/ESamplingSurvivorGeneration.java | 2 +- .../opt4j/optimizers/ea/{ => aeseh}/EpsilonAdaption.java | 2 +- .../opt4j/optimizers/ea/{ => aeseh}/EpsilonMapping.java | 2 +- .../optimizers/ea/{ => aeseh}/NeighborhoodScheduler.java | 2 +- .../optimizers/ea/{ => aeseh}/RoundRobinScheduler.java | 2 +- .../java/org/opt4j/optimizers/ea/aeseh/package-info.java | 8 ++++++++ .../opt4j/optimizers/ea/AdditiveEpsilonMappingTest.java | 1 + .../java/org/opt4j/optimizers/ea/AeSeHCouplerTest.java | 4 ++++ .../java/org/opt4j/optimizers/ea/AeSeHSelectorTest.java | 3 +++ .../opt4j/optimizers/ea/DefaultEpsilonAdaptationTest.java | 1 + .../optimizers/ea/DefaultSurvivorGenerationTest1.java | 4 ++++ .../optimizers/ea/DefaultSurvivorGenerationTest2.java | 4 ++++ .../org/opt4j/optimizers/ea/RoundRobinSchedulerTest.java | 1 + 19 files changed, 45 insertions(+), 11 deletions(-) rename opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/{ => aeseh}/AdditiveEpsilonMapping.java (98%) rename opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/{ => aeseh}/AeSeHCoupler.java (98%) rename opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/{ => aeseh}/AeSeHModule.java (96%) rename opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/{ => aeseh}/AeSeHSelector.java (95%) rename opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/{ => aeseh}/DefaultEpsilonAdaptation.java (98%) rename opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/{ => aeseh}/DefaultSurvivorGeneration.java (98%) rename opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/{ => aeseh}/ESamplingSurvivorGeneration.java (95%) rename opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/{ => aeseh}/EpsilonAdaption.java (97%) rename opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/{ => aeseh}/EpsilonMapping.java (97%) rename opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/{ => aeseh}/NeighborhoodScheduler.java (92%) rename opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/{ => aeseh}/RoundRobinScheduler.java (94%) create mode 100644 opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/package-info.java diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AdditiveEpsilonMapping.java similarity index 98% rename from opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java rename to opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AdditiveEpsilonMapping.java index 0aae2d85..da027eb8 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AdditiveEpsilonMapping.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AdditiveEpsilonMapping.java @@ -1,4 +1,4 @@ -package org.opt4j.optimizers.ea; +package org.opt4j.optimizers.ea.aeseh; import java.util.HashMap; import java.util.Iterator; diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHCoupler.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHCoupler.java similarity index 98% rename from opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHCoupler.java rename to opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHCoupler.java index d2a05807..bda570c1 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHCoupler.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHCoupler.java @@ -1,4 +1,4 @@ -package org.opt4j.optimizers.ea; +package org.opt4j.optimizers.ea.aeseh; import java.util.ArrayList; import java.util.Collection; @@ -13,6 +13,7 @@ import org.opt4j.core.Objectives; import org.opt4j.core.start.Constant; import org.opt4j.operators.crossover.Pair; +import org.opt4j.optimizers.ea.Coupler; import com.google.inject.Inject; diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHModule.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHModule.java similarity index 96% rename from opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHModule.java rename to opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHModule.java index 75bc0ee5..78bd9562 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHModule.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHModule.java @@ -1,10 +1,15 @@ -package org.opt4j.optimizers.ea; +package org.opt4j.optimizers.ea.aeseh; import org.opt4j.core.config.annotations.Info; import org.opt4j.core.config.annotations.Order; import org.opt4j.core.optimizer.MaxIterations; import org.opt4j.core.optimizer.OptimizerModule; import org.opt4j.core.start.Constant; +import org.opt4j.optimizers.ea.ConstantCrossoverRate; +import org.opt4j.optimizers.ea.Coupler; +import org.opt4j.optimizers.ea.CrossoverRate; +import org.opt4j.optimizers.ea.EvolutionaryAlgorithm; +import org.opt4j.optimizers.ea.Selector; /** * Module to bind the AeSeH evolutionary algorithm as optimizer. This algorithm diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHSelector.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHSelector.java similarity index 95% rename from opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHSelector.java rename to opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHSelector.java index 3c803bea..ab819fdb 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/AeSeHSelector.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHSelector.java @@ -1,10 +1,11 @@ -package org.opt4j.optimizers.ea; +package org.opt4j.optimizers.ea.aeseh; import java.util.Collection; import java.util.HashSet; import java.util.Set; import org.opt4j.core.Individual; +import org.opt4j.optimizers.ea.Selector; import com.google.inject.Inject; import com.google.inject.Singleton; diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptation.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/DefaultEpsilonAdaptation.java similarity index 98% rename from opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptation.java rename to opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/DefaultEpsilonAdaptation.java index 64cd32d5..4d785741 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptation.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/DefaultEpsilonAdaptation.java @@ -1,4 +1,4 @@ -package org.opt4j.optimizers.ea; +package org.opt4j.optimizers.ea.aeseh; import org.opt4j.core.start.Constant; diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultSurvivorGeneration.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/DefaultSurvivorGeneration.java similarity index 98% rename from opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultSurvivorGeneration.java rename to opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/DefaultSurvivorGeneration.java index 9bfb2a51..60c21f44 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/DefaultSurvivorGeneration.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/DefaultSurvivorGeneration.java @@ -1,4 +1,4 @@ -package org.opt4j.optimizers.ea; +package org.opt4j.optimizers.ea.aeseh; import java.util.ArrayList; import java.util.Collection; @@ -11,6 +11,7 @@ import org.opt4j.core.Individual; import org.opt4j.core.Objective; import org.opt4j.core.Objectives; +import org.opt4j.optimizers.ea.NonDominatedSorting; import com.google.inject.Inject; diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/ESamplingSurvivorGeneration.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/ESamplingSurvivorGeneration.java similarity index 95% rename from opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/ESamplingSurvivorGeneration.java rename to opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/ESamplingSurvivorGeneration.java index f9678f46..ef72d4a2 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/ESamplingSurvivorGeneration.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/ESamplingSurvivorGeneration.java @@ -1,4 +1,4 @@ -package org.opt4j.optimizers.ea; +package org.opt4j.optimizers.ea.aeseh; import java.util.Collection; import java.util.Set; diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonAdaption.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/EpsilonAdaption.java similarity index 97% rename from opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonAdaption.java rename to opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/EpsilonAdaption.java index 41cb019b..9691c3b2 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonAdaption.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/EpsilonAdaption.java @@ -1,4 +1,4 @@ -package org.opt4j.optimizers.ea; +package org.opt4j.optimizers.ea.aeseh; import com.google.inject.ImplementedBy; diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonMapping.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/EpsilonMapping.java similarity index 97% rename from opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonMapping.java rename to opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/EpsilonMapping.java index b2938f10..d139631f 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EpsilonMapping.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/EpsilonMapping.java @@ -1,4 +1,4 @@ -package org.opt4j.optimizers.ea; +package org.opt4j.optimizers.ea.aeseh; import java.util.Map; import java.util.Set; diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NeighborhoodScheduler.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/NeighborhoodScheduler.java similarity index 92% rename from opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NeighborhoodScheduler.java rename to opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/NeighborhoodScheduler.java index 1177373b..42787ed2 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NeighborhoodScheduler.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/NeighborhoodScheduler.java @@ -1,4 +1,4 @@ -package org.opt4j.optimizers.ea; +package org.opt4j.optimizers.ea.aeseh; import java.util.Set; diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/RoundRobinScheduler.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/RoundRobinScheduler.java similarity index 94% rename from opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/RoundRobinScheduler.java rename to opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/RoundRobinScheduler.java index 2d3b8b59..02a448e1 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/RoundRobinScheduler.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/RoundRobinScheduler.java @@ -1,4 +1,4 @@ -package org.opt4j.optimizers.ea; +package org.opt4j.optimizers.ea.aeseh; import java.util.List; import java.util.Set; diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/package-info.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/package-info.java new file mode 100644 index 00000000..f6e0cff7 --- /dev/null +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/package-info.java @@ -0,0 +1,8 @@ +/** + * Package for the classes of the Adaptive ε-Sampling ε-Hood MOEA. + */ +/** + * @author Fedor Smirnov + * + */ +package org.opt4j.optimizers.ea.aeseh; \ No newline at end of file diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AdditiveEpsilonMappingTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AdditiveEpsilonMappingTest.java index d98e2bc9..93910501 100644 --- a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AdditiveEpsilonMappingTest.java +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AdditiveEpsilonMappingTest.java @@ -6,6 +6,7 @@ import org.opt4j.core.Individual; import org.opt4j.core.Objective; import org.opt4j.core.Objective.Sign; +import org.opt4j.optimizers.ea.aeseh.AdditiveEpsilonMapping; import org.opt4j.core.Objectives; import static org.mockito.Mockito.*; diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHCouplerTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHCouplerTest.java index fe22ec9c..a3b09ff9 100644 --- a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHCouplerTest.java +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHCouplerTest.java @@ -8,6 +8,10 @@ import org.opt4j.core.Objectives; import org.opt4j.core.Objective.Sign; import org.opt4j.operators.crossover.Pair; +import org.opt4j.optimizers.ea.aeseh.AdditiveEpsilonMapping; +import org.opt4j.optimizers.ea.aeseh.AeSeHCoupler; +import org.opt4j.optimizers.ea.aeseh.DefaultEpsilonAdaptation; +import org.opt4j.optimizers.ea.aeseh.EpsilonAdaption; import static org.mockito.Mockito.*; diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHSelectorTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHSelectorTest.java index df78b100..64dae726 100644 --- a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHSelectorTest.java +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHSelectorTest.java @@ -5,6 +5,9 @@ import org.junit.Test; import org.opt4j.core.Individual; import org.opt4j.core.optimizer.Population; +import org.opt4j.optimizers.ea.aeseh.AeSeHSelector; +import org.opt4j.optimizers.ea.aeseh.DefaultSurvivorGeneration; +import org.opt4j.optimizers.ea.aeseh.ESamplingSurvivorGeneration; import static org.mockito.Mockito.*; diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptationTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptationTest.java index 4d52c9c8..938c91d5 100644 --- a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptationTest.java +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptationTest.java @@ -3,6 +3,7 @@ import static org.junit.Assert.*; import org.junit.Test; +import org.opt4j.optimizers.ea.aeseh.DefaultEpsilonAdaptation; public class DefaultEpsilonAdaptationTest { diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest1.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest1.java index dc24df53..5bfb86a1 100644 --- a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest1.java +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest1.java @@ -5,6 +5,10 @@ import org.junit.Test; import org.opt4j.core.Individual; import org.opt4j.core.Objectives; +import org.opt4j.optimizers.ea.aeseh.AdditiveEpsilonMapping; +import org.opt4j.optimizers.ea.aeseh.DefaultEpsilonAdaptation; +import org.opt4j.optimizers.ea.aeseh.DefaultSurvivorGeneration; +import org.opt4j.optimizers.ea.aeseh.EpsilonAdaption; import static org.mockito.Mockito.*; diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest2.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest2.java index 9fc2bdec..3bdb7eab 100644 --- a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest2.java +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest2.java @@ -7,6 +7,10 @@ import org.opt4j.core.Individual; import org.opt4j.core.Objective; import org.opt4j.core.Objective.Sign; +import org.opt4j.optimizers.ea.aeseh.AdditiveEpsilonMapping; +import org.opt4j.optimizers.ea.aeseh.DefaultSurvivorGeneration; +import org.opt4j.optimizers.ea.aeseh.EpsilonAdaption; +import org.opt4j.optimizers.ea.aeseh.EpsilonMapping; import org.opt4j.core.Objectives; import static org.mockito.Mockito.*; diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/RoundRobinSchedulerTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/RoundRobinSchedulerTest.java index 878ac771..9866c150 100644 --- a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/RoundRobinSchedulerTest.java +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/RoundRobinSchedulerTest.java @@ -9,6 +9,7 @@ import org.junit.Test; import org.opt4j.core.Individual; +import org.opt4j.optimizers.ea.aeseh.RoundRobinScheduler; public class RoundRobinSchedulerTest { From 051805b517c6594e5d42ebeec4ed190bdd23b611 Mon Sep 17 00:00:00 2001 From: Fedor Smirnov Date: Fri, 16 Mar 2018 12:46:29 +0100 Subject: [PATCH 13/20] moved the tests to the new package as well --- .../optimizers/ea/{ => aeseh}/AdditiveEpsilonMappingTest.java | 2 +- .../org/opt4j/optimizers/ea/{ => aeseh}/AeSeHCouplerTest.java | 2 +- .../org/opt4j/optimizers/ea/{ => aeseh}/AeSeHSelectorTest.java | 2 +- .../optimizers/ea/{ => aeseh}/DefaultEpsilonAdaptationTest.java | 2 +- .../ea/{ => aeseh}/DefaultSurvivorGenerationTest1.java | 2 +- .../ea/{ => aeseh}/DefaultSurvivorGenerationTest2.java | 2 +- .../optimizers/ea/{ => aeseh}/RoundRobinSchedulerTest.java | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) rename opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/{ => aeseh}/AdditiveEpsilonMappingTest.java (98%) rename opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/{ => aeseh}/AeSeHCouplerTest.java (98%) rename opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/{ => aeseh}/AeSeHSelectorTest.java (97%) rename opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/{ => aeseh}/DefaultEpsilonAdaptationTest.java (98%) rename opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/{ => aeseh}/DefaultSurvivorGenerationTest1.java (98%) rename opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/{ => aeseh}/DefaultSurvivorGenerationTest2.java (99%) rename opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/{ => aeseh}/RoundRobinSchedulerTest.java (96%) diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AdditiveEpsilonMappingTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/aeseh/AdditiveEpsilonMappingTest.java similarity index 98% rename from opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AdditiveEpsilonMappingTest.java rename to opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/aeseh/AdditiveEpsilonMappingTest.java index 93910501..49a30a1d 100644 --- a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AdditiveEpsilonMappingTest.java +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/aeseh/AdditiveEpsilonMappingTest.java @@ -1,4 +1,4 @@ -package org.opt4j.optimizers.ea; +package org.opt4j.optimizers.ea.aeseh; import static org.junit.Assert.*; diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHCouplerTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/aeseh/AeSeHCouplerTest.java similarity index 98% rename from opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHCouplerTest.java rename to opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/aeseh/AeSeHCouplerTest.java index a3b09ff9..1365ccf4 100644 --- a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHCouplerTest.java +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/aeseh/AeSeHCouplerTest.java @@ -1,4 +1,4 @@ -package org.opt4j.optimizers.ea; +package org.opt4j.optimizers.ea.aeseh; import static org.junit.Assert.*; diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHSelectorTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/aeseh/AeSeHSelectorTest.java similarity index 97% rename from opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHSelectorTest.java rename to opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/aeseh/AeSeHSelectorTest.java index 64dae726..4ee04071 100644 --- a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/AeSeHSelectorTest.java +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/aeseh/AeSeHSelectorTest.java @@ -1,4 +1,4 @@ -package org.opt4j.optimizers.ea; +package org.opt4j.optimizers.ea.aeseh; import static org.junit.Assert.*; diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptationTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/aeseh/DefaultEpsilonAdaptationTest.java similarity index 98% rename from opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptationTest.java rename to opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/aeseh/DefaultEpsilonAdaptationTest.java index 938c91d5..e72f5a1f 100644 --- a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultEpsilonAdaptationTest.java +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/aeseh/DefaultEpsilonAdaptationTest.java @@ -1,4 +1,4 @@ -package org.opt4j.optimizers.ea; +package org.opt4j.optimizers.ea.aeseh; import static org.junit.Assert.*; diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest1.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/aeseh/DefaultSurvivorGenerationTest1.java similarity index 98% rename from opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest1.java rename to opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/aeseh/DefaultSurvivorGenerationTest1.java index 5bfb86a1..cf677616 100644 --- a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest1.java +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/aeseh/DefaultSurvivorGenerationTest1.java @@ -1,4 +1,4 @@ -package org.opt4j.optimizers.ea; +package org.opt4j.optimizers.ea.aeseh; import static org.junit.Assert.*; diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest2.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/aeseh/DefaultSurvivorGenerationTest2.java similarity index 99% rename from opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest2.java rename to opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/aeseh/DefaultSurvivorGenerationTest2.java index 3bdb7eab..94fda509 100644 --- a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/DefaultSurvivorGenerationTest2.java +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/aeseh/DefaultSurvivorGenerationTest2.java @@ -1,4 +1,4 @@ -package org.opt4j.optimizers.ea; +package org.opt4j.optimizers.ea.aeseh; import static org.junit.Assert.*; diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/RoundRobinSchedulerTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/aeseh/RoundRobinSchedulerTest.java similarity index 96% rename from opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/RoundRobinSchedulerTest.java rename to opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/aeseh/RoundRobinSchedulerTest.java index 9866c150..9e008499 100644 --- a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/RoundRobinSchedulerTest.java +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/aeseh/RoundRobinSchedulerTest.java @@ -1,4 +1,4 @@ -package org.opt4j.optimizers.ea; +package org.opt4j.optimizers.ea.aeseh; import static org.junit.Assert.*; From c5a6b87b46848703b0eb0723db3a60581d14f314 Mon Sep 17 00:00:00 2001 From: Fedor Smirnov Date: Fri, 16 Mar 2018 12:48:24 +0100 Subject: [PATCH 14/20] restored the build.gradle file --- build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle b/build.gradle index 52fdc4f2..93473742 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,5 @@ plugins { id 'com.github.kt3k.coveralls' version '2.6.3' - id "org.sonarqube" version "2.5" } apply plugin: 'base' apply plugin: 'application' From 35e74a6a41c93d98085c4760aa4a95af0794597b Mon Sep 17 00:00:00 2001 From: Fedor Smirnov Date: Fri, 16 Mar 2018 13:46:23 +0100 Subject: [PATCH 15/20] Implemented non dominated sorting in a non-static way --- .../ea/{NonDominatedSorting.java => NonDominatedFronts.java} | 0 .../{NonDominatedSortingTest.java => NonDominatedFrontsTest.java} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/{NonDominatedSorting.java => NonDominatedFronts.java} (100%) rename opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/{NonDominatedSortingTest.java => NonDominatedFrontsTest.java} (100%) diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedSorting.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedFronts.java similarity index 100% rename from opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedSorting.java rename to opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedFronts.java diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/NonDominatedSortingTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/NonDominatedFrontsTest.java similarity index 100% rename from opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/NonDominatedSortingTest.java rename to opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/NonDominatedFrontsTest.java From fb152ff1d36f9e7216ffa47e4e85107a822a6b3d Mon Sep 17 00:00:00 2001 From: Fedor Smirnov Date: Fri, 16 Mar 2018 13:47:07 +0100 Subject: [PATCH 16/20] forgot to add stuff before committing --- .../ea/EvolutionaryAlgorithmModule.java | 6 +-- .../optimizers/ea/NonDominatedFronts.java | 38 ++++++++++--------- .../java/org/opt4j/optimizers/ea/Nsga2.java | 4 +- .../optimizers/ea/aeseh/AeSeHCoupler.java | 2 +- .../optimizers/ea/aeseh/AeSeHModule.java | 8 ++-- .../ea/aeseh/DefaultSurvivorGeneration.java | 25 +++++++----- .../ea/aeseh/ESamplingSurvivorGeneration.java | 8 ++-- .../optimizers/ea/aeseh/EpsilonAdaption.java | 18 ++++----- .../optimizers/ea/NonDominatedFrontsTest.java | 8 ++-- 9 files changed, 61 insertions(+), 56 deletions(-) diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java index 011ef7ad..3172fb5e 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/EvolutionaryAlgorithmModule.java @@ -46,17 +46,17 @@ public class EvolutionaryAlgorithmModule extends OptimizerModule { protected int generations = 1000; @Constant(value = "alpha", namespace = EvolutionaryAlgorithm.class) - @Info("Alpha - The size of the population.") + @Info("The size of the population α.") @Order(1) protected int populationSize = 100; @Constant(value = "mu", namespace = EvolutionaryAlgorithm.class) - @Info("Mu - The number of parents per generation.") + @Info("The number of parents per generation μ.") @Order(2) protected int parentsPerGeneration = 25; @Constant(value = "lambda", namespace = EvolutionaryAlgorithm.class) - @Info("Lambda The number of offsprings per generation.") + @Info("The number of offsprings per generation λ.") @Order(3) protected int offspringsPerGeneration = 25; diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedFronts.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedFronts.java index feb7862f..847f6bcd 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedFronts.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedFronts.java @@ -13,17 +13,19 @@ import org.opt4j.core.Objectives; /** - * Class used for the non-dominated sorting. During non-dominated sorting, the - * evaluated individuals are sorted into fronts based on the number of - * individuals they are dominated by. The first front consists of points that - * are not dominated at all and so on. + * The NonDominatedFronts sorts each evaluated individual into fronts based on + * the number of other individuals it is dominated by. The first front consists + * of points that are not dominated at all and so on. * * @author Fedor Smirnov * */ -public class NonDominatedSorting { +public class NonDominatedFronts extends ArrayList> { - private NonDominatedSorting() { + private static final long serialVersionUID = -7008617060878292974L; + + public NonDominatedFronts(Collection individuals) { + generateFronts(individuals); } /** @@ -33,7 +35,7 @@ private NonDominatedSorting() { * @return an ordered list of the non-dominated front. The first entry is made * up by the first front, that is by the Pareto-optimal solutions */ - public static List> generateFronts(Collection individuals) { + public void generateFronts(Collection individuals) { // assign an id to each individual that corresponds to its index in an // array List individualList = new ArrayList(individuals); @@ -41,7 +43,6 @@ public static List> generateFronts(Collection indiv for (int i = 0; i < individualList.size(); i++) { indexMap.put(individualList.get(i), i); } - List> fronts = new ArrayList>(); // Initialize a map where an individual is assigned to the individuals // that it dominates Map> dominatedIndividualsMap = new HashMap>(); @@ -61,19 +62,19 @@ public static List> generateFronts(Collection indiv f1.add(i); } } - fronts.add(f1); + add(f1); List currentFront = f1; // Create the subsequent fronts. Front f_i is made up by individuals // that // are not dominated if all individuals from fronts f_j with j < i are // removed. while (!currentFront.isEmpty()) { - List nextFront = getNextFront(currentFront, dominatedIndividualsMap, dominatingIndividualNumber, indexMap); + List nextFront = getNextFront(currentFront, dominatedIndividualsMap, dominatingIndividualNumber, + indexMap); if (!nextFront.isEmpty()) - fronts.add(nextFront); + add(nextFront); currentFront = nextFront; } - return fronts; } /** @@ -94,7 +95,7 @@ public static List> generateFronts(Collection indiv * dominatingIndividualNumber * @return The list of individuals forming the next non-dominated front. */ - protected static List getNextFront(List currentFront, + protected List getNextFront(List currentFront, Map> dominatedIndividualsMap, int[] dominatingIndividualNumber, Map individual2IndexMap) { List nextFront = new ArrayList(); @@ -129,7 +130,7 @@ protected static List getNextFront(List currentFront, * : A map mapping each individual onto its index in the * dominatingIndividualNumber - array. */ - protected static void determineDomination(List individualList, + protected void determineDomination(List individualList, Map> dominatedIndividualsMap, int[] dominatingIndividualNumber, Map individual2IndexMap) { // compare each individual with each other individual @@ -156,19 +157,20 @@ protected static void determineDomination(List individualList, * @param firstFront * @return the set of the extreme individuals. */ - public static Set getExtremeIndividuals(Collection firstFront) { + public Set getExtremeIndividuals() { Map bestIndis = new HashMap(); Map extremeValues = new HashMap(); + List firstFront = get(0); Individual firstIndi = firstFront.iterator().next(); List objList = new ArrayList(firstIndi.getObjectives().getKeys()); // iterate the individuals - for (Individual indi : firstFront){ + for (Individual indi : firstFront) { // iterate the objectives and their values double[] values = indi.getObjectives().array(); - for (int i = 0; i < objList.size(); i++){ + for (int i = 0; i < objList.size(); i++) { Objective obj = objList.get(i); double value = values[i]; - if(!bestIndis.containsKey(obj) || extremeValues.get(obj) > value){ + if (!bestIndis.containsKey(obj) || extremeValues.get(obj) > value) { bestIndis.put(obj, indi); extremeValues.put(obj, value); } diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/Nsga2.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/Nsga2.java index 758a81d9..228a93bf 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/Nsga2.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/Nsga2.java @@ -91,7 +91,7 @@ public Collection getParents(int mu, Collection populati List all = new ArrayList(population); List parents = new ArrayList(); - List> fronts = NonDominatedSorting.generateFronts(all); + List> fronts = new NonDominatedFronts(all); Map rank = getRank(fronts); Map distance = new HashMap(); @@ -136,7 +136,7 @@ public Collection getParents(int mu, Collection populati public Collection getLames(int size, Collection population) { List lames = new ArrayList(); - List> fronts = NonDominatedSorting.generateFronts(population); + List> fronts = new NonDominatedFronts(population); Collections.reverse(fronts); for (List front : fronts) { diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHCoupler.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHCoupler.java index bda570c1..1f6a12f0 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHCoupler.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHCoupler.java @@ -64,7 +64,7 @@ public Collection> getCouples(int size, List parent * two random individuals. * * @param neighborhood - * @return The pair that was picked as parents for a crossover. + * @return the pair that was picked as parents for a crossover */ protected Pair pickCouple(Set neighborhood) { if (neighborhood.size() == 1) { diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHModule.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHModule.java index 78bd9562..cf5e7fc3 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHModule.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHModule.java @@ -24,9 +24,7 @@ * publication. * * @author Fedor Smirnov - * */ - @Info("Multi-objective evolutionary algorithm where the survival selection and the creation of neighborhoods is based on epsilon-dominance. The selection of parents is done within the created neighborhoods.") public class AeSeHModule extends OptimizerModule { @@ -36,17 +34,17 @@ public class AeSeHModule extends OptimizerModule { protected int generations = 1000; @Constant(value = "alpha", namespace = EvolutionaryAlgorithm.class) - @Info("Alpha - The size of the population.") + @Info("The size of the population α.") @Order(1) protected int populationSize = 100; @Constant(value = "mu", namespace = EvolutionaryAlgorithm.class) - @Info("Mu - The number of parents per generation.") + @Info("The number of parents per generation μ.") @Order(2) protected int parentsPerGeneration = 25; @Constant(value = "lambda", namespace = EvolutionaryAlgorithm.class) - @Info("Lambda The number of offsprings per generation.") + @Info("The number of offsprings per generation λ.") @Order(3) protected int offspringsPerGeneration = 25; diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/DefaultSurvivorGeneration.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/DefaultSurvivorGeneration.java index 60c21f44..fe71389b 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/DefaultSurvivorGeneration.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/DefaultSurvivorGeneration.java @@ -11,7 +11,7 @@ import org.opt4j.core.Individual; import org.opt4j.core.Objective; import org.opt4j.core.Objectives; -import org.opt4j.optimizers.ea.NonDominatedSorting; +import org.opt4j.optimizers.ea.NonDominatedFronts; import com.google.inject.Inject; @@ -39,9 +39,9 @@ public DefaultSurvivorGeneration(Random random, EpsilonMapping epsilonMapping, E public Set getSurvivors(Collection population, int survivorNumber) { Set survivors; // get the non-dominated front and the extreme solutions - List> fronts = NonDominatedSorting.generateFronts(population); + NonDominatedFronts fronts = new NonDominatedFronts(population); Collection paretoSolutions = fronts.get(0); - Set extremeIndividuals = NonDominatedSorting.getExtremeIndividuals(paretoSolutions); + Set extremeIndividuals = fronts.getExtremeIndividuals(); if (paretoSolutions.size() > survivorNumber) { // more non-dominated solutions than survivors => apply ε-sampling @@ -69,7 +69,8 @@ protected Set addNonDominatedSurvivors(Collection extrem nonDominatedIndividuals.removeAll(extremeIndividuals); Set epsilonDominantIndividuals = new HashSet(); Set epsilonDominatedIndividuals = new HashSet(); - applyEpsilonSampling(nonDominatedIndividuals, epsilonDominantIndividuals, epsilonDominatedIndividuals, epsilonAdaption.getSamplingEpsilon()); + applyEpsilonSampling(nonDominatedIndividuals, epsilonDominantIndividuals, epsilonDominatedIndividuals, + epsilonAdaption.getSamplingEpsilon()); boolean tooManyEpsilonDominantIndividuals = (extremeIndividuals.size() + epsilonDominantIndividuals.size()) > survivorNumber; // adapt the sampling epsilon @@ -98,12 +99,18 @@ protected Set addNonDominatedSurvivors(Collection extrem } /** - * Apply epsilon sampling by dividing the given individuals into the two sets of epsilon-dominant and epsilon-dominated individuals. + * Apply epsilon sampling by dividing the given individuals into the two sets of + * epsilon-dominant and epsilon-dominated individuals. * - * @param firstFront : The input individuals who constitute the first non-dominated front of the current population. - * @param epsilonDominantIndividuals : The set that will be filled with the epsilon-dominant individuals. - * @param epsilonDominatedIndividuals : The set that will be filled with epsilon-dominated individuals - * @param samplingEpsilon : The value used for the epsilon sampling. + * @param firstFront + * the input individuals which constitute the first non-dominated front + * of the current population + * @param epsilonDominantIndividuals + * the set that will be filled with the epsilon-dominant individuals + * @param epsilonDominatedIndividuals + * the set that will be filled with epsilon-dominated individuals + * @param samplingEpsilon + * the value used for the epsilon sampling */ protected void applyEpsilonSampling(List firstFront, Set epsilonDominantIndividuals, Set epsilonDominatedIndividuals, double samplingEpsilon) { diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/ESamplingSurvivorGeneration.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/ESamplingSurvivorGeneration.java index ef72d4a2..f496617c 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/ESamplingSurvivorGeneration.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/ESamplingSurvivorGeneration.java @@ -22,11 +22,11 @@ public interface ESamplingSurvivorGeneration { * Generate the survivors out of the input collection. * * @param population - * : the current population (union of the parent- and the + * the current population (union of the parent- and the * offspring-sets from the current iteration) - * @param survivorNumber : The number of survivors to create - * @return : the survivors (used as the parent generation for the next - * iteration) + * @param survivorNumber + * the number of survivors to create + * @return the survivors (used as the parent generation for the next iteration) */ public Set getSurvivors(Collection population, int survivorNumber); diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/EpsilonAdaption.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/EpsilonAdaption.java index 9691c3b2..cdbf0e98 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/EpsilonAdaption.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/EpsilonAdaption.java @@ -13,7 +13,7 @@ public interface EpsilonAdaption { /** - * Returns the current value of the sampling epsilon. + * returns the current value of the sampling epsilon. * * @return Current epsilon_s */ @@ -29,24 +29,22 @@ public interface EpsilonAdaption { /** * At the end of the selection process, the epsilon_s value is adjusted - * depending on the number of created epsilon-dominant survivors. The goal - * is to find an epsilon_s value that results in the creation of exactly - * alpha epsilon-dominant survivors, with alpha as the population size. + * depending on the number of created epsilon-dominant survivors. The goal is to + * find an epsilon_s value that results in the creation of exactly alpha + * epsilon-dominant survivors, with alpha as the population size. * * @param tooManyEpsilonDominantIndividuals - * : TRUE => too many dominant survivors were created; FALSE => - * not enough dominant survivors were created + * {@code true} if too many individuals have been created */ public void adaptSamplingEpsilon(boolean tooManyEpsilonDominantIndividuals); /** * At the end of the neighborhood creation, the epsilon_h value is adjusted - * depending on the number of created neighborhoods. The goal is to find a - * value where the number of neighborhoods is near a user-defined value. + * depending on the number of created neighborhoods. The goal is to find a value + * where the number of neighborhoods is near a user-defined value. * * @param tooManyNeighborhoods - * : TRUE => too many neighborhoods created; FALSE => not enough - * neighborhoods created + * {@code true} if too many individuals have been created */ public void adaptNeighborhoodEpsilon(boolean tooManyNeighborhoods); diff --git a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/NonDominatedFrontsTest.java b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/NonDominatedFrontsTest.java index 5bbf90a3..70005193 100644 --- a/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/NonDominatedFrontsTest.java +++ b/opt4j-optimizers/src/test/java/org/opt4j/optimizers/ea/NonDominatedFrontsTest.java @@ -15,7 +15,7 @@ import static org.mockito.Mockito.*; -public class NonDominatedSortingTest { +public class NonDominatedFrontsTest { protected static final Objective firstObj = new Objective("first", Sign.MAX); protected static final Objective secondObj = new Objective("second", Sign.MAX); @@ -67,8 +67,8 @@ protected static Objectives getObjectives(int f, int s) { @Test public void testGetExtremeIndividuals() { - Set extremes = NonDominatedSorting - .getExtremeIndividuals(getIndividualSet()); + NonDominatedFronts fronts = new NonDominatedFronts(getIndividualSet()); + Set extremes = fronts.getExtremeIndividuals(); assertEquals(2, extremes.size()); assertTrue(extremes.contains(first)); assertTrue(extremes.contains(third)); @@ -76,7 +76,7 @@ public void testGetExtremeIndividuals() { @Test public void testGenerateFronts() { - List> fronts = NonDominatedSorting.generateFronts(getIndividualSet()); + List> fronts = new NonDominatedFronts(getIndividualSet()); assertEquals(4, fronts.size()); assertEquals(3, fronts.get(0).size()); From 82914851bdf1c22d4a24dfce4467f7666e980cc3 Mon Sep 17 00:00:00 2001 From: Fedor Smirnov Date: Fri, 16 Mar 2018 13:48:12 +0100 Subject: [PATCH 17/20] changed the build to get mockito from maven --- build.gradle | 2 +- opt4j-optimizers/build.gradle | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 93473742..3212766e 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,6 @@ plugins { id 'com.github.kt3k.coveralls' version '2.6.3' + } apply plugin: 'base' apply plugin: 'application' @@ -21,7 +22,6 @@ allprojects { group = 'org.opt4j' repositories { - jcenter() mavenCentral() } diff --git a/opt4j-optimizers/build.gradle b/opt4j-optimizers/build.gradle index b1a634e9..c7090d01 100644 --- a/opt4j-optimizers/build.gradle +++ b/opt4j-optimizers/build.gradle @@ -2,6 +2,6 @@ dependencies { compile project(':opt4j-core') compile project(':opt4j-operators') - testCompile group: 'junit', name: 'junit', version: '[4.0,)' - testCompile "org.mockito:mockito-core:2.+" + testCompile group: 'junit', name: 'junit', version: '[4.0,)' + testCompile group: 'org.mockito', name: 'mockito-all', version: '1.9.5' } \ No newline at end of file From 92973243e706672dfb56a5bbd4d5c26b0691c378 Mon Sep 17 00:00:00 2001 From: Fedor Smirnov Date: Fri, 16 Mar 2018 18:15:29 +0100 Subject: [PATCH 18/20] cleaned up the comments --- .../optimizers/ea/NonDominatedFronts.java | 28 +++++++++---------- .../ea/aeseh/AdditiveEpsilonMapping.java | 2 +- .../optimizers/ea/aeseh/AeSeHCoupler.java | 13 ++++----- .../ea/aeseh/DefaultSurvivorGeneration.java | 6 ++-- .../ea/aeseh/ESamplingSurvivorGeneration.java | 5 ++-- .../optimizers/ea/aeseh/EpsilonAdaption.java | 27 +++++++++--------- .../optimizers/ea/aeseh/EpsilonMapping.java | 20 ++++++------- .../ea/aeseh/NeighborhoodScheduler.java | 8 +++--- 8 files changed, 54 insertions(+), 55 deletions(-) diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedFronts.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedFronts.java index 847f6bcd..686cb9c3 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedFronts.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedFronts.java @@ -29,11 +29,11 @@ public NonDominatedFronts(Collection individuals) { } /** - * Sort the given individuals into non-dominated fronts + * sort the given individuals into non-dominated fronts * * @param individuals * @return an ordered list of the non-dominated front. The first entry is made - * up by the first front, that is by the Pareto-optimal solutions + * up by the first front, that is by the Pareto-optimal solutions. */ public void generateFronts(Collection individuals) { // assign an id to each individual that corresponds to its index in an @@ -83,17 +83,17 @@ public void generateFronts(Collection individuals) { * individuals that are then not dominated form the next non-dominated front. * * @param currentFront - * : The list of individuals forming the current non-dominated front + * the list of individuals forming the current non-dominated front * @param dominatedIndividualsMap - * : map mapping an individual on the collection of individuals that + * map mapping an individual on the collection of individuals that * it dominates * @param dominatingIndividualNumber - * : an array where the number of dominating individuals is stored + * an array where the number of dominating individuals is stored * for each individual * @param individual2IndexMap - * : a map storing the indices of the individuals used to access the + * a map storing the indices of the individuals used to access the * dominatingIndividualNumber - * @return The list of individuals forming the next non-dominated front. + * @return the list of individuals forming the next non-dominated front */ protected List getNextFront(List currentFront, Map> dominatedIndividualsMap, int[] dominatingIndividualNumber, @@ -116,19 +116,19 @@ protected List getNextFront(List currentFront, * dominates. * * @param individualList - * : A list of the individuals + * a list of the individuals * @param dominatedIndividualsMap - * : A map that is filled during the execution of the method. Each + * A map that is filled during the execution of the method. Each * individual is mapped onto the set of individuals that are * dominated by this individual. * @param dominatingIndividualNumber - * : An integer array (initialized with zeros) that is filled during + * An integer array (initialized with zeros) that is filled during * the execution of this method. Each individual is associated with * an entry of this array. The integer therein is the number of * individuals this individual is dominated by. * @param individual2IndexMap - * : A map mapping each individual onto its index in the - * dominatingIndividualNumber - array. + * a map mapping each individual onto its index in the + * dominatingIndividualNumber - array */ protected void determineDomination(List individualList, Map> dominatedIndividualsMap, int[] dominatingIndividualNumber, @@ -152,10 +152,10 @@ protected void determineDomination(List individualList, } /** - * Return the individuals with the best values for the individual objectives + * returns the individuals with the best values for the individual objectives * * @param firstFront - * @return the set of the extreme individuals. + * @return the set of the extreme individuals */ public Set getExtremeIndividuals() { Map bestIndis = new HashMap(); diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AdditiveEpsilonMapping.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AdditiveEpsilonMapping.java index da027eb8..c08b7ff3 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AdditiveEpsilonMapping.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AdditiveEpsilonMapping.java @@ -12,7 +12,7 @@ import org.opt4j.core.Objectives; /** - * Implements the evenly spaced adaptive epsilon function. + * Implements the evenly spaced adaptive ε function. * * @author Fedor Smirnov * diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHCoupler.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHCoupler.java index 1f6a12f0..7d286c4b 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHCoupler.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHCoupler.java @@ -18,8 +18,8 @@ import com.google.inject.Inject; /** - * This class implements a parent selection process based on - * epsilon-neighborhood. This technique was first proposed in the paper: + * Implements a parent selection process based on epsilon-neighborhood. This + * technique was first proposed in the paper: * * Aguirre, Hernán, Akira Oyama, and Kiyoshi Tanaka. "Adaptive ε-sampling and * ε-hood for evolutionary many-objective optimization." International @@ -60,8 +60,8 @@ public Collection> getCouples(int size, List parent } /** - * Pick a couple of parents from the given neighborhood. Here, we just pick - * two random individuals. + * Picks a couple of parents from the given neighborhood. Here, we just pick two + * random individuals. * * @param neighborhood * @return the pair that was picked as parents for a crossover @@ -78,11 +78,10 @@ protected Pair pickCouple(Set neighborhood) { } /** - * Apply the epsilon neighborhood creation. + * Applies the epsilon neighborhood creation. * * @param survivors - * @return a list of individual sets. Each set is considered as a - * neighborhood + * @return a list of individual sets. Each set is considered as a neighborhood. */ protected List> createNeighborhoods(List survivors) { List> neighborhoods = new ArrayList>(); diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/DefaultSurvivorGeneration.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/DefaultSurvivorGeneration.java index fe71389b..fdb3824f 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/DefaultSurvivorGeneration.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/DefaultSurvivorGeneration.java @@ -53,7 +53,7 @@ public Set getSurvivors(Collection population, int survi } /** - * Create the survivor pool by adding the epsilon-sampled individuals to the + * Creates the survivor pool by adding the ε-sampled individuals to the * extreme individuals. * * @param extremeIndividuals @@ -99,8 +99,8 @@ protected Set addNonDominatedSurvivors(Collection extrem } /** - * Apply epsilon sampling by dividing the given individuals into the two sets of - * epsilon-dominant and epsilon-dominated individuals. + * Applies ε-sampling by dividing the given individuals into the two sets of + * ε-dominant and ε-dominated individuals. * * @param firstFront * the input individuals which constitute the first non-dominated front diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/ESamplingSurvivorGeneration.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/ESamplingSurvivorGeneration.java index f496617c..5bb14611 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/ESamplingSurvivorGeneration.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/ESamplingSurvivorGeneration.java @@ -19,14 +19,15 @@ public interface ESamplingSurvivorGeneration { /** - * Generate the survivors out of the input collection. + * generates the survivors out of the input collection * * @param population * the current population (union of the parent- and the * offspring-sets from the current iteration) * @param survivorNumber * the number of survivors to create - * @return the survivors (used as the parent generation for the next iteration) + * @return the survivors (used as the pool for the parent candidates for the + * next generation) */ public Set getSurvivors(Collection population, int survivorNumber); diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/EpsilonAdaption.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/EpsilonAdaption.java index cdbf0e98..eb228358 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/EpsilonAdaption.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/EpsilonAdaption.java @@ -3,8 +3,8 @@ import com.google.inject.ImplementedBy; /** - * Interface for the classes that manage the adaptation of the epsilon value - * used for survivor selection by {@link AeSeHSelector}. + * Interface for the classes that manage the adaptation of the ε-value used for + * survivor selection by {@link AeSeHSelector}. * * @author Fedor Smirnov * @@ -13,25 +13,24 @@ public interface EpsilonAdaption { /** - * returns the current value of the sampling epsilon. + * returns the current value of the sampling epsilon * - * @return Current epsilon_s + * @return current ε used for the sampling */ public double getSamplingEpsilon(); /** - * Returns the current value of the epsilon used for the creation of the - * neighborhoods + * returns the current value of the ε used for the creation of the neighborhoods * - * @return Current epsilon_h + * @return current ε for the neighborhood creation */ public double getNeighborhoodEpsilon(); /** - * At the end of the selection process, the epsilon_s value is adjusted - * depending on the number of created epsilon-dominant survivors. The goal is to - * find an epsilon_s value that results in the creation of exactly alpha - * epsilon-dominant survivors, with alpha as the population size. + * At the end of the selection process, the sampling ε value is adjusted + * depending on the number of created ε-dominant survivors. The goal is to find + * an ε-value that results in the creation of exactly α ε-dominant survivors, + * with α as the population size. * * @param tooManyEpsilonDominantIndividuals * {@code true} if too many individuals have been created @@ -39,9 +38,9 @@ public interface EpsilonAdaption { public void adaptSamplingEpsilon(boolean tooManyEpsilonDominantIndividuals); /** - * At the end of the neighborhood creation, the epsilon_h value is adjusted - * depending on the number of created neighborhoods. The goal is to find a value - * where the number of neighborhoods is near a user-defined value. + * At the end of the neighborhood creation, the neighborhood ε value is adjusted + * depending on the number of created neighborhoods. The goal is to find an + * ε-value where the number of neighborhoods is near a user-defined value. * * @param tooManyNeighborhoods * {@code true} if too many individuals have been created diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/EpsilonMapping.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/EpsilonMapping.java index d139631f..ebb10172 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/EpsilonMapping.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/EpsilonMapping.java @@ -10,7 +10,7 @@ import com.google.inject.ImplementedBy; /** - * Interface for the classes applying the epsilon mapping used by the + * Interface for the classes applying the ε mapping used by the * {@link AeSeHSelector}. * * @author Fedor Smirnov @@ -20,27 +20,27 @@ public interface EpsilonMapping { /** - * Map the given objectives on the objectives used for the check of the - * epsilon dominance. + * maps the given objectives on the objectives used for the check of the + * ε dominance. * * @param original - * : the actual objectives of the individual + * the actual objectives of the individual * @param epsilon - * : the epsilon value + * the ε value * @param objectiveAmplitudes - * : a map containing the amplitude values of the objectives - * @return : objectives enhanced by the epsilon value + * a map containing the amplitude values of the objectives + * @return objectives enhanced by the epsilon value */ public Objectives mapObjectives(final Objectives original, double epsilon, Map objectiveAmplitudes); /** - * Create a map mapping the objectives to their amplitudes (difference + * Creates a map mapping the objectives to their amplitudes (difference * between maximal and minimal value). These extreme values are used during - * epsilon mapping to scale the delta according to the objective values of + * ε mapping to scale the delta according to the objective values of * the individual group under consideration. * * @param individuals - * @return map mapping each objective onto ist amplitude + * @return map mapping each objective onto its amplitude */ public Map findObjectiveAmplitudes(Set individuals); diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/NeighborhoodScheduler.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/NeighborhoodScheduler.java index 42787ed2..c8e00103 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/NeighborhoodScheduler.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/NeighborhoodScheduler.java @@ -7,7 +7,7 @@ /** * Interface for the classes that manage the schedule according to which the * neighborhoods are chosen by the {@link AeSeHCoupler} to pick the crossover - * parent. + * parents. * * @author Fedor Smirnov * @@ -15,10 +15,10 @@ public interface NeighborhoodScheduler { /** - * Return a copy of the neighborhood that shall be used for the creation of - * the next pair of parents. + * returns a copy of the neighborhood that shall be used for the creation of + * the next pair of parents * - * @return Copy of the neighborhood set. + * @return copy of the neighborhood set */ public Set next(); From dabe519275bccd90d73bce6dc2edca90b09c7d72 Mon Sep 17 00:00:00 2001 From: Fedor Smirnov Date: Mon, 19 Mar 2018 10:08:11 +0100 Subject: [PATCH 19/20] fixed infeasible objectives bug --- .../java/org/opt4j/optimizers/ea/NonDominatedFronts.java | 3 --- .../opt4j/optimizers/ea/aeseh/AdditiveEpsilonMapping.java | 7 +++++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedFronts.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedFronts.java index 686cb9c3..19dd1c71 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedFronts.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/NonDominatedFronts.java @@ -32,8 +32,6 @@ public NonDominatedFronts(Collection individuals) { * sort the given individuals into non-dominated fronts * * @param individuals - * @return an ordered list of the non-dominated front. The first entry is made - * up by the first front, that is by the Pareto-optimal solutions. */ public void generateFronts(Collection individuals) { // assign an id to each individual that corresponds to its index in an @@ -154,7 +152,6 @@ protected void determineDomination(List individualList, /** * returns the individuals with the best values for the individual objectives * - * @param firstFront * @return the set of the extreme individuals */ public Set getExtremeIndividuals() { diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AdditiveEpsilonMapping.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AdditiveEpsilonMapping.java index c08b7ff3..41568efd 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AdditiveEpsilonMapping.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AdditiveEpsilonMapping.java @@ -27,8 +27,11 @@ public Objectives mapObjectives(Objectives original, double epsilon, Map Date: Wed, 21 Mar 2018 15:09:47 +0100 Subject: [PATCH 20/20] used the citation-annotation and removed the comments --- .../opt4j/optimizers/ea/aeseh/AeSeHCoupler.java | 11 +---------- .../opt4j/optimizers/ea/aeseh/AeSeHModule.java | 15 +++++---------- .../opt4j/optimizers/ea/aeseh/AeSeHSelector.java | 9 --------- 3 files changed, 6 insertions(+), 29 deletions(-) diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHCoupler.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHCoupler.java index 7d286c4b..a9ea5e05 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHCoupler.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHCoupler.java @@ -18,16 +18,7 @@ import com.google.inject.Inject; /** - * Implements a parent selection process based on epsilon-neighborhood. This - * technique was first proposed in the paper: - * - * Aguirre, Hernán, Akira Oyama, and Kiyoshi Tanaka. "Adaptive ε-sampling and - * ε-hood for evolutionary many-objective optimization." International - * Conference on Evolutionary Multi-Criterion Optimization. Springer, Berlin, - * Heidelberg, 2013. - * - * Please consider citing the paper if you use this class for a scientific - * publication. + * Implements a parent selection process based on epsilon-neighborhood. * * @author Fedor Smirnov * diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHModule.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHModule.java index cf5e7fc3..d6a07a40 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHModule.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHModule.java @@ -1,5 +1,8 @@ package org.opt4j.optimizers.ea.aeseh; +import static org.opt4j.core.config.annotations.Citation.PublicationMonth.UNKNOWN; + +import org.opt4j.core.config.annotations.Citation; import org.opt4j.core.config.annotations.Info; import org.opt4j.core.config.annotations.Order; import org.opt4j.core.optimizer.MaxIterations; @@ -12,20 +15,12 @@ import org.opt4j.optimizers.ea.Selector; /** - * Module to bind the AeSeH evolutionary algorithm as optimizer. This algorithm - * was first introduced in the paper: - * - * Aguirre, Hernán, Akira Oyama, and Kiyoshi Tanaka. "Adaptive ε-sampling and - * ε-hood for evolutionary many-objective optimization." International - * Conference on Evolutionary Multi-Criterion Optimization. Springer, Berlin, - * Heidelberg, 2013. - * - * Please consider citing the paper if you use this class for a scientific - * publication. + * Module to bind the AeSeH evolutionary algorithm as optimizer. * * @author Fedor Smirnov */ @Info("Multi-objective evolutionary algorithm where the survival selection and the creation of neighborhoods is based on epsilon-dominance. The selection of parents is done within the created neighborhoods.") +@Citation(authors = "Hernán Aguirre, Akira Oyama, and Kiyoshi Tanaka", title = "Adaptive ε-sampling and ε-hood for evolutionary many-objective optimization.", journal = "Evolutionary Multi-Criterion Optimization (EMO)", pageFirst = 322, pageLast = 336, year = 2013, month = UNKNOWN) public class AeSeHModule extends OptimizerModule { @Info("The number of generations.") diff --git a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHSelector.java b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHSelector.java index ab819fdb..532d6d54 100644 --- a/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHSelector.java +++ b/opt4j-optimizers/src/main/java/org/opt4j/optimizers/ea/aeseh/AeSeHSelector.java @@ -12,15 +12,6 @@ /** * This class implements a selection process based on the epsilon-sampling - * presented in the paper: - * - * Aguirre, Hernán, Akira Oyama, and Kiyoshi Tanaka. "Adaptive ε-sampling and - * ε-hood for evolutionary many-objective optimization." International - * Conference on Evolutionary Multi-Criterion Optimization. Springer, Berlin, - * Heidelberg, 2013. - * - * Please consider citing the paper if you use this class for a scientific - * publication. * * @author Fedor Smirnov *