/*
* 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.audit;
import java.util.*;
import org.jgap.*;
import org.jgap.eval.*;
/**
* Monitors the evolution and stops it if evolution does not make a progress
* as desired.
* For usage of this monitor class, see class examples.audit.EvolutionMonitorExample.
*
* @author Klaus Meffert
* @since 3.4.4
*/
public class FitnessImprovementMonitor
implements IEvolutionMonitor {
/** String containing the CVS revision. Read out via reflection!*/
private final static String CVS_REVISION = "$Revision: 1.4 $";
private int m_initialWaitSeconds;
private int m_checkIntervalSeconds;
private double m_improvedFitnessExpected;
private long m_startMillis;
private long m_lastCheckMillis;
private double m_bestFitnessPreviously;
private int m_checks;
/**
* Constructor.
*
* @param a_initialWaitSeconds number of seconds to wait until first check
* @param a_checkIntervalSeconds number of seconds to wait after the previous
* check (except for the first check, where a_initialWaitSeconds is taken)
* @param a_improvedFitnessExpected number of fitness units the current best
* solution evolved is better than the best solution from the previously check
*
* @author Klaus Meffert
* @since 3.4.4
*/
public FitnessImprovementMonitor(int a_initialWaitSeconds,
int a_checkIntervalSeconds,
double a_improvedFitnessExpected) {
m_initialWaitSeconds = a_initialWaitSeconds;
m_checkIntervalSeconds = a_checkIntervalSeconds;
m_improvedFitnessExpected = a_improvedFitnessExpected;
m_bestFitnessPreviously = FitnessFunction.NO_FITNESS_VALUE;
}
/**
* Called after another evolution cycle has been executed.
*
* @param a_pop the currently evolved population
* @param a_messages the monitor can append messages to indicate why it asks
* evolution to stop
* @return true: continue with the evolution; false: stop evolution
*
* @author Klaus Meffert
* @since 3.4.4
*/
public boolean nextCycle(Population a_pop, List<String> a_messages) {
long currentMillis = System.currentTimeMillis();
boolean doCheck = false;
if (m_checks == 0) {
if (currentMillis - m_startMillis >= m_initialWaitSeconds * 1000) {
doCheck = true;
}
}
else {
if (currentMillis - m_lastCheckMillis >= m_checkIntervalSeconds * 1000) {
doCheck = true;
}
}
if (doCheck) {
// Let's verify the progress since our last check.
// -----------------------------------------------
IChromosome best = a_pop.determineFittestChromosome();
if (best != null) {
// A best solution exists.
// -----------------------
if (Math.abs(m_bestFitnessPreviously - FitnessFunction.NO_FITNESS_VALUE) <
FitnessFunction.DELTA) {
// There was no previous best solution.
// ------------------------------------
m_bestFitnessPreviously = best.getFitnessValue();
}
else {
// Is the current best solution better than the previous one?
// ----------------------------------------------------------
if (Math.abs(best.getFitnessValue() - m_bestFitnessPreviously) <
m_improvedFitnessExpected) {
// Bad luck, not enough progress.
// ------------------------------
a_messages.add("Not enough progress was made after initial delay");
return false;
}
else {
m_bestFitnessPreviously = best.getFitnessValue();
}
}
}
else {
if (m_checks > 0) {
// No result evolved during two check cycles.
// ------------------------------------------
a_messages.add(
"No solution at all was evolved during two check cycles.");
return false;
}
}
m_lastCheckMillis = System.currentTimeMillis();
m_checks++;
}
// No check needed yet.
// --------------------
return true;
}
/**
* Called just before the evolution starts.
*
* @param a_config the configuration used
*
* @author Klaus Meffert
* @since 3.4.4
*/
public void start(Configuration a_config) {
m_startMillis = System.currentTimeMillis();
}
/**
* Called whenever it's worth monitoring.
*
* @param a_monitorEvent see constants at top of class IEvolutionMonitor
* @param a_evolutionNo the index of the evolution round (1, 2, ...)
* @param a_information event-specific information
*
* @author Klaus Meffert
* @since 3.5
*/
public void event(String a_monitorEvent, int a_evolutionNo,
Object[] a_information) {
// Just a sample implemetation here to show how to react to the specific
// monitor events that are supported.
// ---------------------------------------------------------------------
if (a_monitorEvent == null) {
// Should never happen.
// --------------------
return;
}
if (a_information == null) {
return;
}
// The events are queried in the chronological order they do appear.
// -----------------------------------------------------------------
if (a_monitorEvent.equals(IEvolutionMonitor.MONITOR_EVENT_REMOVE_CHROMOSOME)) {
Population pop = (Population) a_information[0];
Integer chromosomeIndex = (Integer) a_information[1];
}
if (a_monitorEvent.equals(IEvolutionMonitor.
MONITOR_EVENT_BEFORE_UPDATE_CHROMOSOMES1)) {
Population pop = (Population) a_information[0];
}
if (a_monitorEvent.equals(IEvolutionMonitor.
MONITOR_EVENT_AFTER_UPDATE_CHROMOSOMES1)) {
Population pop = (Population) a_information[0];
}
if (a_monitorEvent.equals(IEvolutionMonitor.MONITOR_EVENT_BEFORE_SELECT)) {
NaturalSelector selector = (NaturalSelector) a_information[0];
Population pop = (Population) a_information[1];
int selectionSize = (Integer) a_information[2];
boolean a_processBeforeGeneticOperators = (Boolean) a_information[3];
/*
* a_processBeforeGeneticOperators = true:
* called after MONITOR_EVENT_AFTER_UPDATE_CHROMOSOMES1
* a_processBeforeGeneticOperators = false:
* called after MONITOR_EVENT_AFTER_UPDATE_CHROMOSOMES2
*/
}
if (a_monitorEvent.equals(IEvolutionMonitor.MONITOR_EVENT_AFTER_SELECT)) {
NaturalSelector selector = (NaturalSelector) a_information[0];
Population pop = (Population) a_information[1];
Population newPop = (Population) a_information[2];
int selectionSize = (Integer) a_information[3];
boolean a_processBeforeGeneticOperators = (Boolean) a_information[4];
/*
* a_processBeforeGeneticOperators = true:
* called after MONITOR_EVENT_AFTER_UPDATE_CHROMOSOMES1
* a_processBeforeGeneticOperators = false:
* called after MONITOR_EVENT_AFTER_UPDATE_CHROMOSOMES2
*/
}
if (a_monitorEvent.equals(IEvolutionMonitor.MONITOR_EVENT_BEFORE_OPERATE)) {
GeneticOperator operator = (GeneticOperator) a_information[0];
Population pop = (Population) a_information[1];
List<IChromosome> chromosomes = (List<IChromosome>) a_information[2];
}
if (a_monitorEvent.equals(IEvolutionMonitor.MONITOR_EVENT_AFTER_OPERATE)) {
GeneticOperator operator = (GeneticOperator) a_information[0];
Population pop = (Population) a_information[1];
List<IChromosome> chromosomes = (List<IChromosome>) a_information[2];
}
if (a_monitorEvent.equals(IEvolutionMonitor.MONITOR_EVENT_BEFORE_BULK_EVAL)) {
BulkFitnessFunction bulkFitnessFunction = (BulkFitnessFunction)
a_information[0];
Population pop = (Population) a_information[1];
}
if (a_monitorEvent.equals(IEvolutionMonitor.MONITOR_EVENT_AFTER_BULK_EVAL)) {
BulkFitnessFunction bulkFitnessFunction = (BulkFitnessFunction)
a_information[0];
Population pop = (Population) a_information[1];
}
if (a_monitorEvent.equals(IEvolutionMonitor.
MONITOR_EVENT_BEFORE_UPDATE_CHROMOSOMES2)) {
Population pop = (Population) a_information[0];
}
if (a_monitorEvent.equals(IEvolutionMonitor.
MONITOR_EVENT_AFTER_UPDATE_CHROMOSOMES2)) {
Population pop = (Population) a_information[0];
}
if (a_monitorEvent.equals(IEvolutionMonitor.
MONITOR_EVENT_BEFORE_ADD_CHROMOSOME)) {
Population pop = (Population) a_information[0];
IChromosome newChromosome = (IChromosome) a_information[1];
}
if (a_monitorEvent.equals(IEvolutionMonitor.MONITOR_EVENT_READD_FITTEST)) {
Population pop = (Population) a_information[0];
IChromosome fittest = (IChromosome) a_information[1];
}
}
/**
* @return null as no data is gathered by this monitor
*
* @author Klaus Meffert
* @since 3.5
*/
public PopulationHistoryIndexed getPopulations() {
return null;
}
}