/* 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 java.util.Arrays;
import org.moeaframework.core.Algorithm;
import org.moeaframework.core.Problem;
import org.moeaframework.core.Solution;
/**
* Abstract class providing default implementations for several
* {@link Algorithm} methods. All method extending this class must use the
* {@link #evaluate} method to evaluate a solution. This is mandatory to ensure
* the {@link #getNumberOfEvaluations()} method returns the correct result.
* <p>
* Subclasses should avoid overriding the {@link #step()} method and instead
* override the {@link #initialize()} and {@link #iterate()} methods
* individually.
*/
public abstract class AbstractAlgorithm implements Algorithm {
/**
* The problem being solved.
*/
protected final Problem problem;
/**
* The number of times the {@link #evaluate} method was invoked.
*/
protected int numberOfEvaluations;
/**
* {@code true} if the {@link #initialize()} method has been invoked;
* {@code false} otherwise.
*/
protected boolean initialized;
/**
* {@code true} if the {@link #terminate()} method has been invoked;
* {@code false} otherwise.
*/
protected boolean terminated;
/**
* Constructs an abstract algorithm for solving the specified problem.
*
* @param problem the problem being solved
*/
public AbstractAlgorithm(Problem problem) {
super();
this.problem = problem;
}
/**
* Evaluates the specified solutions. This method calls
* {@link #evaluate(Solution)} on each of the solutions. Subclasses should
* prefer calling this method over {@code evaluate} whenever possible,
* as this ensures the solutions can be evaluated in parallel.
*
* @param solutions the solutions to evaluate
*/
public void evaluateAll(Iterable<Solution> solutions) {
for (Solution solution : solutions) {
evaluate(solution);
}
}
/**
* Evaluates the specified solutions. This method is equivalent to
* {@code evaluateAll(Arrays.asList(solutions))}.
*
* @param solutions the solutions to evaluate
*/
public void evaluateAll(Solution[] solutions) {
evaluateAll(Arrays.asList(solutions));
}
@Override
public void evaluate(Solution solution) {
problem.evaluate(solution);
numberOfEvaluations++;
}
@Override
public int getNumberOfEvaluations() {
return numberOfEvaluations;
}
@Override
public Problem getProblem() {
return problem;
}
/**
* Performs any initialization that is required by this algorithm. This
* method is called automatically by the first invocation of
* {@link #step()}, but may also be called manually prior to any invocations
* of {@code step}. Implementations should always invoke
* {@code super.initialize()} to ensure the hierarchy is initialized
* correctly.
*
* @throws AlgorithmInitializationException if the algorithm has already
* been initialized
*/
protected void initialize() {
if (initialized) {
throw new AlgorithmInitializationException(this,
"algorithm already initialized");
}
initialized = true;
}
/**
* Returns {@code true} if the {@link #initialize()} method has been
* invoked; {@code false} otherwise.
*
* @return {@code true} if the {@link #initialize()} method has been
* invoked; {@code false} otherwise
*/
public boolean isInitialized() {
return initialized;
}
/**
* This method first checks if the algorithm is initialized. If not, the
* {@link #initialize()} method is invoked. If initialized, all calls to
* {@code step} invoke {@link #iterate()}. Implementations should override
* the {@code initialize} and {@code iterate} methods in preference to
* modifying this method.
*
* @throws AlgorithmTerminationException if the algorithm has already
* terminated
*/
@Override
public void step() {
if (isTerminated()) {
throw new AlgorithmTerminationException(this,
"algorithm already terminated");
} else if (!isInitialized()) {
initialize();
} else {
iterate();
}
}
/**
* Performs one iteration of the algorithm. This method should be
* overridden by implementations to perform each logical iteration of the
* algorithm.
*/
protected abstract void iterate();
@Override
public boolean isTerminated() {
return terminated;
}
/**
* Implementations should always invoke {@code super.terminate()} to ensure
* the hierarchy is terminated correctly. This method is automatically
* invoked during finalization, and need only be called directly if
* non-Java resources are in use.
*
* @throws AlgorithmTerminationException if the algorithm has already
* terminated
*/
@Override
public void terminate() {
if (terminated) {
throw new AlgorithmTerminationException(this,
"algorithm already terminated");
}
terminated = true;
}
@Override
protected void finalize() throws Throwable {
try {
if (!isTerminated()) {
terminate();
}
} finally {
super.finalize();
}
}
@Override
public Serializable getState() throws NotSerializableException {
throw new NotSerializableException(getClass().getName());
}
@Override
public void setState(Object state) throws NotSerializableException {
throw new NotSerializableException(getClass().getName());
}
}