iDynoOptimizer.MOEAFramework26.src.org.moeaframework.algorithm.AdaptiveTimeContinuation.java Source code

Java tutorial

Introduction

Here is the source code for iDynoOptimizer.MOEAFramework26.src.org.moeaframework.algorithm.AdaptiveTimeContinuation.java

Source

/* Copyright 2009-2015 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 iDynoOptimizer.MOEAFramework26.src.org.moeaframework.algorithm;

import java.io.NotSerializableException;
import java.io.Serializable;

import org.apache.commons.lang3.event.EventListenerSupport;
import iDynoOptimizer.MOEAFramework26.src.org.moeaframework.core.EvolutionaryAlgorithm;
import iDynoOptimizer.MOEAFramework26.src.org.moeaframework.core.NondominatedPopulation;
import iDynoOptimizer.MOEAFramework26.src.org.moeaframework.core.Population;
import iDynoOptimizer.MOEAFramework26.src.org.moeaframework.core.Selection;
import iDynoOptimizer.MOEAFramework26.src.org.moeaframework.core.Solution;
import iDynoOptimizer.MOEAFramework26.src.org.moeaframework.core.Variation;

/**
 * Decorator for {@link EvolutionaryAlgorithm}s to add time continuation
 * (restarts). Restarts occur if either
 * <ol>
 * <li>the number of fitness function evaluations since the last restart exceeds
 * {@code maxWindowSize}; or
 * <li>the population-to-archive ratio exceeds {@code populationRatio} by more
 * than {@code 25%}.
 * </ol>
 * If a restart occurs, the population is emptied, the population size is
 * adapted to maintain the {@code populationRatio}, the the new population is
 * filled with solutions selected from {@code algorithm.getArchive()} and
 * mutated using the specified {@link Selection} and {@link Variation}
 * operators.
 * <p>
 * References:
 * <ol>
 *   <li>Goldberg, D. E.  "Sizing Populations for Serial and Parallel Genetic 
 *       Algorithms."  In 3rd International Conference on Genetic Algorithms, 
 *       pp. 70-79, 1989.
 *   <li>Srivastava, R. P.  "Time Continuation in Genetic Algorithms."
 *       Technical report, Illinois Genetic Algorithm Laboratory, 2002.
 *   <li>Kollat, J. B., and Reed, P. M.  "Comparison of Multi-Objective 
 *       Evolutionary Algorithms for Long-Term Monitoring Design."  Advances in
 *       Water Resources, 29(6):792-807, 2006.
 * </ol>
 */
public class AdaptiveTimeContinuation extends PeriodicAction implements EvolutionaryAlgorithm {

    /**
     * The maximum number of iterations allowed since the last restart before 
     * forcing a restart.
     */
    private final int maxWindowSize;

    /**
     * The population-to-archive ratio.
     */
    private final double populationRatio;

    /**
     * The minimum size of the population.
     */
    private final int minimumPopulationSize;

    /**
     * The maximum size of the population.
     */
    private final int maximumPopulationSize;

    /**
     * The selection operator for selecting solutions from the archive during a
     * restart.
     */
    private final Selection selection;

    /**
     * The variation operator for mutating solutions selected from the archive
     * during a restart.
     */
    private final Variation variation;

    /**
     * The number of iterations at the last invocation of {@code restart}.
     */
    private int iterationAtLastRestart;

    /**
     * The collection of listeners notified when a restart occurs.
     */
    private final EventListenerSupport<RestartListener> listeners;

    /**
     * Decorates the specified algorithm with adaptive time continuation.
     * 
     * @param algorithm the algorithm being decorated
     * @param windowSize the number of iterations between invocations of
     *        {@code check}
     * @param maxWindowSize the maximum number of iterations allowed since the
     *        last restart before forcing a restart
     * @param populationRatio the population-to-archive ratio
     * @param minimumPopulationSize the minimum size of the population
     * @param maximumPopulationSize the maximum size of the population
     * @param selection the selection operator for selecting solutions from the
     *        archive during a restart
     * @param variation the variation operator for mutating solutions selected
     *        from the archive during a restart
     */
    public AdaptiveTimeContinuation(EvolutionaryAlgorithm algorithm, int windowSize, int maxWindowSize,
            double populationRatio, int minimumPopulationSize, int maximumPopulationSize, Selection selection,
            Variation variation) {
        super(algorithm, windowSize, FrequencyType.STEPS);
        this.maxWindowSize = maxWindowSize;
        this.populationRatio = populationRatio;
        this.minimumPopulationSize = minimumPopulationSize;
        this.maximumPopulationSize = maximumPopulationSize;
        this.selection = selection;
        this.variation = variation;

        listeners = EventListenerSupport.create(RestartListener.class);
    }

    /**
     * Adds a listener to be notified whenever a restart occurs.
     * 
     * @param listener the listener to be notified whenever a restart occurs
     */
    public void addRestartListener(RestartListener listener) {
        listeners.addListener(listener);
    }

    /**
     * Removes the specified listener so it no longer receives notifications
     * whenever a restart occurs.
     * 
     * @param listener the listener to be removed
     */
    public void removeRestartListener(RestartListener listener) {
        listeners.removeListener(listener);
    }

    /**
     * Performs a check to determine if a restart should occur. Returns
     * {@code RestartType.NONE} if no restart should occur; or
     * {@code RestartType.HARD} if the population-to-archive ratio exceeds 
     * {@code populationRatio} by more than {@code 25%} or the number of fitness
     * evaluations since the last restart exceeds {@code maxWindowSize}.
     * 
     * @return {@code RestartType.NONE} if no restart should occur; or
     *         {@code RestartType.HARD} if the population-to-archive ratio
     *         exceeds {@code populationRatio} by more than {@code 25%} or
     *         if the number of fitness evaluations since the last restart 
     *         exceeds {@code maxWindowSize}
     */
    protected RestartType check() {
        int populationSize = getPopulation().size();
        double targetSize = populationRatio * getArchive().size();

        if (iteration - iterationAtLastRestart >= maxWindowSize) {
            return RestartType.HARD;
        } else if ((targetSize >= minimumPopulationSize) && (targetSize <= maximumPopulationSize)
                && (Math.abs(populationSize - targetSize) > (0.25 * targetSize))) {
            return RestartType.HARD;
        } else {
            return RestartType.NONE;
        }
    }

    /**
     * Performs a restart. If the type is {@code RestartType.HARD}, the
     * population is emptied, resized and filled with solutions selected and
     * mutated from the archive. If the type is {@code RestartType.SOFT}, the
     * population is not emptied; new solutions are only added to fill any empty
     * slots.
     * 
     * @param type the type of restart
     */
    protected void restart(RestartType type) {
        Population population = getPopulation();
        NondominatedPopulation archive = getArchive();

        if (type.equals(RestartType.HARD)) {
            population.clear();
            population.addAll(archive);
        }

        int newPopulationSize = (int) (populationRatio * archive.size());

        if (newPopulationSize < minimumPopulationSize) {
            newPopulationSize = minimumPopulationSize;
        } else if (newPopulationSize > maximumPopulationSize) {
            newPopulationSize = maximumPopulationSize;
        }

        while (population.size() < newPopulationSize) {
            Solution[] parents = selection.select(variation.getArity(), archive);
            Solution[] children = variation.evolve(parents);

            for (Solution child : children) {
                algorithm.evaluate(child);
                population.add(child);
                archive.add(child);
            }
        }

        if (type.equals(RestartType.HARD)) {
            iterationAtLastRestart = iteration;
        }

        listeners.fire().restarted(new RestartEvent(this, type));
    }

    @Override
    public void doAction() {
        RestartType type = check();

        if ((type != null) && !type.equals(RestartType.NONE)) {
            restart(type);
        }
    }

    @Override
    public Population getPopulation() {
        return ((EvolutionaryAlgorithm) algorithm).getPopulation();
    }

    @Override
    public NondominatedPopulation getArchive() {
        return ((EvolutionaryAlgorithm) algorithm).getArchive();
    }

    /**
     * Proxy for serializing and deserializing the state of an
     * {@code AdaptiveTimeContinuation} instance. This proxy supports saving
     * the underlying algorithm state and {@code iterationAtLastRestart}.
     */
    private static class AdaptiveTimeContinuationState implements Serializable {

        private static final long serialVersionUID = -4773227519517581809L;

        /**
         * The state of the underlying algorithm.
         */
        private final Serializable algorithmState;

        /**
         * The {@code iterationAtLastRestart} value of the
         * {@code AdaptiveTimeContinuation} instance.
         */
        private final int iterationAtLastRestart;

        /**
         * Constructs a proxy for storing the state of an
         * {@code AdaptiveTimeContinuation} instance.
         * 
         * @param algorithmState the state of the underlying algorithm
         * @param iterationAtLastRestart the {@code iterationAtLastRestart}
         *        value of the {@code AdaptiveTimeContinuation} instance
         */
        public AdaptiveTimeContinuationState(Serializable algorithmState, int iterationAtLastRestart) {
            super();
            this.algorithmState = algorithmState;
            this.iterationAtLastRestart = iterationAtLastRestart;
        }

        /**
         * Returns the underlying algorithm state.
         * 
         * @return the underlying algorithm state
         */
        public Serializable getAlgorithmState() {
            return algorithmState;
        }

        /**
         * Returns the {@code iterationAtLastRestart} value of the
         * {@code AdaptiveTimeContinuation} instance.
         * 
         * @return the {@code iterationAtLastRestart} value of the
         *         {@code AdaptiveTimeContinuation} instance
         */
        public int getIterationAtLastRestart() {
            return iterationAtLastRestart;
        }

    }

    @Override
    public Serializable getState() throws NotSerializableException {
        return new AdaptiveTimeContinuationState(super.getState(), iterationAtLastRestart);
    }

    @Override
    public void setState(Object objState) throws NotSerializableException {
        AdaptiveTimeContinuationState state = (AdaptiveTimeContinuationState) objState;

        super.setState(state.getAlgorithmState());
        iterationAtLastRestart = state.getIterationAtLastRestart();
    }

}