/* Copyright 2009-2016 David Hadka * * This file is part of the MOEA Framework. * * The MOEA Framework is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * The MOEA Framework is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the MOEA Framework. If not, see <http://www.gnu.org/licenses/>. */ package org.moeaframework.algorithm; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang3.ArrayUtils; import org.moeaframework.core.EpsilonBoxDominanceArchive; import org.moeaframework.core.EpsilonBoxEvolutionaryAlgorithm; import org.moeaframework.core.Initialization; import org.moeaframework.core.PRNG; import org.moeaframework.core.Population; import org.moeaframework.core.Problem; import org.moeaframework.core.Selection; import org.moeaframework.core.Solution; import org.moeaframework.core.Variation; import org.moeaframework.core.comparator.DominanceComparator; import org.moeaframework.core.comparator.ParetoDominanceComparator; /** * Implementation of the ε-MOEA algorithm. The ε-MOEA is a * steady-state algorithm, meaning only one individual in the population is * evolved per step, and uses an ε-dominance archive to maintain a * well-spread set of Pareto-optimal solutions. * <p> * References: * <ol> * <li>Deb et al. "A Fast Multi-Objective Evolutionary Algorithm for Finding * Well-Spread Pareto-Optimal Solutions." KanGAL Report No 2003002. Feb 2003. * </ol> */ public class EpsilonMOEA extends AbstractEvolutionaryAlgorithm implements EpsilonBoxEvolutionaryAlgorithm { /** * The dominance comparator used for updating the population. */ private final DominanceComparator dominanceComparator; /** * The selection operator. */ private final Selection selection; /** * The variation operator. */ private final Variation variation; /** * Constructs the ε-MOEA algorithm with the specified components. * * @param problem the problem being solved * @param population the population used to store solutions * @param archive the archive used to store the result * @param selection the selection operator * @param variation the variation operator * @param initialization the initialization method */ public EpsilonMOEA(Problem problem, Population population, EpsilonBoxDominanceArchive archive, Selection selection, Variation variation, Initialization initialization) { this(problem, population, archive, selection, variation, initialization, new ParetoDominanceComparator()); } /** * Constructs the ε-MOEA algorithm with the specified components. * * @param problem the problem being solved * @param population the population used to store solutions * @param archive the archive used to store the result * @param selection the selection operator * @param variation the variation operator * @param initialization the initialization method * @param dominanceComparator the dominance comparator used by the * {@link #addToPopulation} method */ public EpsilonMOEA(Problem problem, Population population, EpsilonBoxDominanceArchive archive, Selection selection, Variation variation, Initialization initialization, DominanceComparator dominanceComparator) { super(problem, population, archive, initialization); this.variation = variation; this.selection = selection; this.dominanceComparator = dominanceComparator; } @Override public void iterate() { Solution[] parents = null; if (archive.size() <= 1) { parents = selection.select(variation.getArity(), population); } else { parents = ArrayUtils.add( selection.select(variation.getArity() - 1, population), archive.get(PRNG.nextInt(archive.size()))); } PRNG.shuffle(parents); Solution[] children = variation.evolve(parents); for (Solution child : children) { evaluate(child); addToPopulation(child); archive.add(child); } } /** * Adds the new solution to the population if is non-dominated with the * current population, removing either a randomly-selected dominated * solution or a non-dominated solution. * * @param newSolution the new solution being added to the population */ protected void addToPopulation(Solution newSolution) { List<Integer> dominates = new ArrayList<Integer>(); boolean dominated = false; for (int i = 0; i < population.size(); i++) { int flag = dominanceComparator.compare(newSolution, population.get(i)); if (flag < 0) { dominates.add(i); } else if (flag > 0) { dominated = true; } } if (!dominates.isEmpty()) { population.remove(dominates.get(PRNG.nextInt(dominates.size()))); population.add(newSolution); } else if (!dominated) { population.remove(PRNG.nextInt(population.size())); population.add(newSolution); } } @Override public EpsilonBoxDominanceArchive getArchive() { return (EpsilonBoxDominanceArchive)super.getArchive(); } }