/*
* This file is part of JGAP.
*
* JGAP offers a dual license model containing the LGPL as well as the MPL.
*
* For licensing information please see the file license.txt included with JGAP
* or have a look at the top of class org.jgap.Chromosome which representatively
* includes the JGAP license policy applicable for any file delivered with JGAP.
*/
package org.jgap;
import java.util.*;
import gnu.trove.*;
/**
* The cached fitness function extends the original FitnessFunction
* functionality in order to reduce evaluating something twice.
*
* @author Dennis Fleurbaaij
* @author Klaus Meffert
* @author Tobias Getrost
* @since 3.2
*/
public abstract class CachedFitnessFunction
extends FitnessFunction {
/**@todo allow to restrict size of cache / age of entries*/
/** String containing the CVS revision. Read out via reflection!*/
private final static String CVS_REVISION = "$Revision: 1.4 $";
// Cache with the previous results
private Map<String, Double> cachedFitnessValues;
/**
* Default Constructor ensuring downward compatibility.
*
* @author Tobias Getrost
* @since 3.3.2
*/
public CachedFitnessFunction() {
this(new THashMap<String, Double> ());
}
/**
* Constructor that allows to use a custom <code>java.util.Map</code>
* implementation as cache.<br>
* E.g. for multi-threaded fitness calculations one could use one instance of
* <code>java.util.concurrent.ConcurrentHashMap</code> for all instances of
* the fitness function.
*
* @param cache <code>java.util.Map</code> data structure used to cache the
* fitness values
*
* @author Tobias Getrost
* @since 3.3.2
*/
public CachedFitnessFunction(Map<String, Double> cache) {
cachedFitnessValues = cache;
}
/**
* Cached fitness value function.
*
* @param a_subject the chromosome to evaluate
* @return fitness value, from cache if available
*
* @author Dennis Fleurbaaij
* @since 3.2
*/
@Override
public final double getFitnessValue(final IChromosome a_subject) {
// Retrieve business key of chromosome.
// ------------------------------------
String businessKey = getBusinessKey(a_subject);
if (businessKey == null) {
// Caching not possible.
// ---------------------
return super.getFitnessValue(a_subject);
}
// Evaluate cache.
// ---------------
Double fitnessValue = cachedFitnessValues.get(businessKey);
if (fitnessValue != null) {
// Return cached result.
// ---------------------
return fitnessValue.doubleValue();
}
// Compute fitness value for the first time.
// -----------------------------------------
double returnValue = super.getFitnessValue(a_subject);
// Put result into cache.
// ----------------------
cachedFitnessValues.put(businessKey, returnValue);
// Return result.
// --------------
return returnValue;
}
/**
* Retrieves the business key of a chromosome instance.
*
* @param a_subject the chromosome to retrieve the key for
* @return the business key of the chromosome
*
* @author Klaus Meffert
* @since 3.2
*/
protected String getBusinessKey(IChromosome a_subject) {
String result;
Class clazz = a_subject.getClass();
if (IBusinessKey.class.isAssignableFrom(clazz)) {
result = ( (IBusinessKey) a_subject).getBusinessKey();
}
else if (IPersistentRepresentation.class.isAssignableFrom(clazz)) {
result = ( (IPersistentRepresentation) a_subject).
getPersistentRepresentation();
}
else {
result = null;
}
return result;
}
}