/* 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.io.NotSerializableException; import java.io.Serializable; import org.moeaframework.core.Algorithm; import org.moeaframework.core.NondominatedPopulation; import org.moeaframework.core.Problem; import org.moeaframework.core.Solution; /** * Decorates an algorithm to perform some action periodically throughout the * execution of the algorithm. Note that due to the underlying implementation * of the algorithm, the action may be invoked less frequently than requested * or not at all. */ public abstract class PeriodicAction implements Algorithm { /** * Defines the type of frequency. */ public enum FrequencyType { /** * The frequency measures the number of objective function evaluations. */ EVALUATIONS, /** * The frequency measures the number of invocations of * {@link Algorithm#step()}. */ STEPS } /** * The underlying algorithm being decorated. */ protected final Algorithm algorithm; /** * The frequency that the {@link #doAction()} method is invoked. */ protected final int frequency; /** * The type of frequency. */ protected final FrequencyType frequencyType; /** * The number of invocations of the {@link Algorithm#step()} method. Only * used if the frequency type is {@code STEPS}. */ protected int iteration; /** * The last invocation {@link #doAction()} was invoked. Only used if the * frequency type is {@code STEPS}. */ protected int lastInvocation; /** * Decorates an algorithm to perform a period action. * * @param algorithm the algorithm being decorated * @param frequency the frequency the {@link #doAction()} method is invoked * @param frequencyType the type of frequency */ public PeriodicAction(Algorithm algorithm, int frequency, FrequencyType frequencyType) { super(); this.algorithm = algorithm; this.frequency = frequency; this.frequencyType = frequencyType; } @Override public Problem getProblem() { return algorithm.getProblem(); } @Override public NondominatedPopulation getResult() { return algorithm.getResult(); } @Override public void step() { algorithm.step(); if (frequencyType.equals(FrequencyType.EVALUATIONS)) { if ((getNumberOfEvaluations() - lastInvocation) >= frequency) { doAction(); lastInvocation = getNumberOfEvaluations(); } } else if (frequencyType.equals(FrequencyType.STEPS)) { iteration++; if ((iteration - lastInvocation) >= frequency) { doAction(); lastInvocation = iteration; } } else { throw new IllegalStateException(); } } @Override public void evaluate(Solution solution) { algorithm.evaluate(solution); } @Override public int getNumberOfEvaluations() { return algorithm.getNumberOfEvaluations(); } @Override public boolean isTerminated() { return algorithm.isTerminated(); } @Override public void terminate() { algorithm.terminate(); } /** * Invoked periodically by this class to perform some function. This * function should not depend on the frequency that it is invoked, since * it is not guaranteed that this method is invoked at any specific * frequency and, in some cases, may not be invoked at all. */ public abstract void doAction(); /** * Proxy for serializing and deserializing the state of a * {@code PeriodicAction}. This proxy supports saving * the underlying algorithm state, {@code iteration} and * {@code lastInvocation}. */ private static class PeriodicActionState implements Serializable { private static final long serialVersionUID = -8654866332843263225L; /** * The state of the underlying algorithm. */ private final Serializable algorithmState; /** * The {@code iteration} value of the {@code PeriodicAction}. */ private final int iteration; /** * The {@code lastInvocation} value of the {@code PeriodicAction}. */ private final int lastInvocation; /** * Constructs a proxy for storing the state of a {@code PeriodicAction}. * * @param algorithmState the state of the underlying algorithm * @param iteration the {@code iteration} value of the * {@code PeriodicAction} * @param lastInvocation the {@code lastInvocation} value of the * {@code PeriodicAction} */ public PeriodicActionState(Serializable algorithmState, int iteration, int lastInvocation) { super(); this.algorithmState = algorithmState; this.iteration = iteration; this.lastInvocation = lastInvocation; } /** * Returns the underlying algorithm state. * * @return the underlying algorithm state */ public Serializable getAlgorithmState() { return algorithmState; } /** * Returns the {@code iteration} value of the {@code PeriodicAction}. * * @return the {@code iteration} value of the {@code PeriodicAction} */ public int getIteration() { return iteration; } /** * Returns the {@code lastInvocation} value of the * {@code PeriodicAction}. * * @return the {@code lastInvocation} value of the * {@code PeriodicAction} */ public int getLastInvocation() { return lastInvocation; } } @Override public Serializable getState() throws NotSerializableException { return new PeriodicActionState(algorithm.getState(), iteration, lastInvocation); } @Override public void setState(Object state) throws NotSerializableException { PeriodicActionState periodicActionState = (PeriodicActionState)state; algorithm.setState(periodicActionState.getAlgorithmState()); iteration = periodicActionState.getIteration(); lastInvocation = periodicActionState.getLastInvocation(); } }