/* 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 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();
}
}