/*
* 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.io.*;
import java.util.*;
import org.apache.commons.lang.builder.*;
import org.jgap.audit.*;
import org.jgap.data.config.*;
import org.jgap.event.*;
import org.jgap.impl.*;
import org.jgap.util.*;
/**
* The Configuration class represents the current configuration of
* plugins and parameters necessary to execute the genetic algorithm (such
* as fitness function, natural selector, genetic operators, and so on).
* <p>
* Note that, while during setup, the settings, flags, and other
* values may be set multiple times. But once the lockSettings() method
* is invoked, they cannot be changed. The default behavior of the
* Genotype constructor is to invoke this method, meaning that
* once a Configuration object is passed to a Genotype, it cannot
* be subsequently modified. There is no mechanism for unlocking
* the settings once they are locked.
* <p>
* Not all configuration options are required. See the documentation
* for each of the respective mutator methods to determine whether
* it is required to provide a value for that setting, and what the
* setting will default to if not.
*
* @author Neil Rotstan
* @author Klaus Meffert
* @since 1.0
*/
public class Configuration
implements Configurable, Serializable, ICloneable, Comparable {
/** String containing the CVS revision. Read out via reflection!*/
private final static String CVS_REVISION = "$Revision: 1.101 $";
/**
* Constant for class name of JGAP Factory to use. Use as:
* System.setProperty(PROPERTY_JGAPFACTORY_CLASS, "myJGAPFactory");
* If none such property set, class JGAPFactory will be used.
*/
public static final String PROPERTY_JGAPFACTORY_CLASS = "JGAPFACTORYCLASS";
public static final String PROPERTY_FITFUNC_INST = "JGAPFITFUNCINST";
public static final String PROPERTY_BFITFNC_INST = "JGAPBFITFNCINST";
public static final String PROPERTY_FITEVAL_INST = "JGAPFITEVALINST";
public static final String PROPERTY_SAMPLE_CHROM_INST = "JGAPSAMPLECHRMINST";
public static final String PROPERTY_EVENT_MGR_INST = "JGAPEVNTMGRINST";
/**
* Constants for toString()
*/
public static final String S_CONFIGURATION = "Configuration";
public static final String S_CONFIGURATION_NAME = "Configuration name";
public static final String S_POPULATION_SIZE = "Population size";
public static final String S_MINPOPSIZE = "Minimum pop. size [%]";
public static final String S_CHROMOSOME_SIZE = "Chromosome size";
public static final String S_SAMPLE_CHROM = "Sample Chromosome";
public static final String S_SIZE = "Size";
public static final String S_TOSTRING = "toString";
public static final String S_RANDOM_GENERATOR = "Random generator";
public static final String S_EVENT_MANAGER = "Event manager";
public static final String S_NONE = "none";
public static final String S_CONFIGURATION_HANDLER = "Configuration handler";
public static final String S_FITNESS_FUNCTION = "Fitness function";
public static final String S_FITNESS_EVALUATOR = "Fitness evaluator";
// public static final String S_POPCONSTANT_SELECTOR = "Constant Population Selector";
public static final String S_GENETIC_OPERATORS = "Genetic operators";
public static final String S_NATURAL_SELECTORS = "Natural Selectors";
public static final String S_PRE = "pre";
public static final String S_POST = "post";
/**
* Contains a bag of custom properties. Can be empty.
* A custom property is such that is not included in the standard JGAP
* configuration.
*
* @since 3.3.1
*/
// private Map m_propertyBag;
private ConfigurationConfigurable m_config = new ConfigurationConfigurable();
/**
* References the current fitness function that will be used to evaluate
* chromosomes during the natural selection process. Note that only this
* or the bulk fitness function may be set - the two are mutually exclusive.
*
* @author Neil Rotstan
* @since 1.0
*/
private FitnessFunction m_objectiveFunction;
/**
* The fitness evaluator. See interface class FitnessEvaluator for details.
*
* @since 2.0 (since 1.1 in class Genotype)
*/
private FitnessEvaluator m_fitnessEvaluator;
/**
* Performs the evolution.
*/
private IBreeder m_breeder;
/**
* Minimum size guaranteed for population. If zero or below then no ensurance.
*
* @author Klaus Meffert
*/
private int m_minPercentageSizePopulation;
/**
* References the current bulk fitness function that will be used to
* evaluate chromosomes (in bulk) during the natural selection
* process. Note that only this or the normal fitness function
* may be set - the two are mutually exclusive.
*
* @author Neil Rotstan
* @since 1.0
*/
private BulkFitnessFunction m_bulkObjectiveFunction;
// /**
// * If population size should be kept constant then this selector determines
// * which of the chromosomes to select into the next generation.
// *
// * @author Klaus Meffert
// * @since 3.2.2
// */
// private INaturalSelector m_popConstantSelector;
/**
* References a Chromosome that serves as a sample of the Gene setup
* that is to be used. Each gene in the Chromosome should be represented
* with the desired Gene type.
*
* @author Neil Rotstan
* @since 1.0
*/
private IChromosome m_sampleChromosome;
/**
* References the random number generator implementation that is to be
* used for the generation of any random numbers during the various
* genetic operations and processes.
*
* @author Neil Rotstan
* @since 1.0
*/
private RandomGenerator m_randomGenerator;
/**
* References the event manager that is to be used for the notification
* of genetic events and the management of event subscribers.
*
* @author Neil Rotstan
* @since 1.0
*/
private IEventManager m_eventManager;
/**
* References the chromosome pool, if any, that is to be used to pool
* discarded Chromosome instances so that they may be recycled later,
* thereby saving memory and the time to construct them from scratch.
*
* @author Neil Rotstan
* @since 1.0
*/
private transient IChromosomePool m_chromosomePool;
/**
* Stores all of the GeneticOperator implementations that are to be used
* to operate upon the chromosomes of a population prior to natural
* selection. Operators will be executed in the order that they are
* added to this list.
*
* @author Klaus Meffert
* @since 1.1
*/
private List m_geneticOperators;
/**
* The number of genes that will be stored in each chromosome in the
* population.
*/
private int m_chromosomeSize;
/**
* Indicates whether the settings of this Configuration instance have
* been locked. Prior to locking, the settings may be set and reset
* as desired. Once this flag is set to true, no settings may be
* altered.
*/
private boolean m_settingsLocked;
/**
* Ordered chain of NaturalSelector's which will be executed before applying
* Genetic Operators.
*
* @author Klaus Meffert
* @since 1.1
*/
private ChainOfSelectors m_preSelectors;
/**
* Ordered chain of NaturalSelector's which will be executed after applying
* Genetic Operators.
*
* @author Klaus Meffert
* @since 1.1
*/
private ChainOfSelectors m_postSelectors;
/**
* Should the fittest chromosome in the population be preserved to the next
* generation when evolving (in Genotype.evolve()) ?
*/
private boolean m_preserveFittestIndividual;
/**
* How many chromosomes should be selected from previous generation?
* The missing chromosomes will be filled up with randomly created new
* ones.
* 1 = all
*/
private double m_selectFromPrevGen;
/**
* Indicates how many times the evolve()-method in class Genotype has been
* called. Represents the number of the current population.
*
* @author Klaus Meffert
* @since 2.2
*/
private int m_generationNr;
/**
* The Configuration handler for this Configurable.
*
* @author Siddhartha Azad
* @since 2.3
*/
private transient RootConfigurationHandler m_conHandler;
/**
* Informative name for output.
*
* @author Klaus Meffert
* @since 2.3
*/
private String m_name;
/**
* True: population size will be kept constant at specified size in
* configuration. False: population size will grow dependently on used
* NaturalSelector's and GeneticOperator's.
* Default is TRUE
*
* @author Klaus Meffert
* @since 2.4
*/
private boolean m_keepPopulationSizeConstant;
/**
* Holds the central configurable factory for creating default objects.
*
* @author Klaus Meffert
* @since 2.6
*/
private IJGAPFactory m_factory;
/**
* See Chromosome class, field m_alwaysCalculate, for description
*
* @author Klaus Meffert
* @since 3.2.2
*/
private boolean m_alwaysCalculateFitness;
private transient String threadKey;
/**
* True: Use unique keys, especially in Chromosomes, to allow tracking and
* monitoring of evolution progress.
*
* @author Klaus Meffert
* @since 3.5
*/
private boolean m_uniqueKeysActive;
/**
* Unique ID for a configuration to distinguish it from other configurations
* instantiated within the same thread.
*
* @author Klaus Meffert
* @since 3.01
*/
private String m_id;
/**
*
* @author Klaus Meffert
* @since 3.5
*/
private IEvolutionMonitor m_monitor;
public Configuration() {
this("", null);
}
/**
* Initialize with default values.
*
* @param a_id unique id for the configuration within the current thread
* @param a_name informative name of the configuration, may be null
*
* @author Neil Rotstan
* @author Klaus Meffert
* @since 1.0
*/
public Configuration(String a_id, String a_name) {
// m_propertyBag = new Hashtable();
m_id = a_id;
setName(a_name);
makeThreadKey();
m_preSelectors = new ChainOfSelectors(this);
m_postSelectors = new ChainOfSelectors(this);
m_selectFromPrevGen = 1.0d;
// Use synchronized list for distributed computing.
// ------------------------------------------------
m_geneticOperators = new Vector();
m_conHandler = new RootConfigurationHandler();
m_conHandler.setConfigurable(this);
m_keepPopulationSizeConstant = true;
m_alwaysCalculateFitness = false;
// Create factory for being able to configure the used default objects,
// like random generators or fitness evaluators.
// --------------------------------------------------------------------
String clazz = System.getProperty(PROPERTY_JGAPFACTORY_CLASS);
if (clazz != null && clazz.length() > 0) {
try {
m_factory = (IJGAPFactory) Class.forName(clazz).newInstance();
} catch (Throwable ex) {
throw new RuntimeException("Class " + clazz
+ " could not be instantiated"
+ " as type IJGAPFactory", ex);
}
}
else {
m_factory = new JGAPFactory(false);
}
}
/**
* Constructs a configuration with an informative name but without a unique
* ID. This practically prevents more than one configurations to be
* instantiated within the same thread.
*
* @param a_name informative name of the configuration, may be null
*
* @author Klaus Meffert
*/
public Configuration(final String a_name) {
this();
setName(a_name);
}
/**
* Reads in the configuration from the given file.
*
* @param a_configFileName the config file from which to load the
* configuration
* @param a_ignore just there to create distinct signatures :-(
*
* @throws ConfigException
* @throws InvalidConfigurationException
*
* @author Siddhartha Azad
* @since 2.3
*/
public Configuration(final String a_configFileName, boolean a_ignore)
throws ConfigException, InvalidConfigurationException {
this();
ConfigFileReader.instance().setFileName(a_configFileName);
// Set the configuration statically for constructing classes by the
// default constructor.
// ----------------------------------------------------------------
Genotype.setStaticConfiguration(this);
// Read in the config, thus creating instances of configurable classes
// by invoking their default constructor.
// -------------------------------------------------------------------
getConfigurationHandler().readConfig();
}
/**
* SHOULD NOT BE NECESSARY TO CALL UNDER NORMAL CIRCUMSTANCES. May be useful
* for unit tests.<p>
* Reset the configuration so that re-setting parameters such as fitness
* function is possible (without calling this method, an overwriting of a
* previously set fitness function results in a RuntimeException).
*
* @author Klaus Meffert
* @since 3.0
*/
public static void reset() {
reset("");
}
/**
* Reset the configuration so that re-setting parameters such as fitness
* function is possible (without calling this method, an overwriting of a
* previously set fitness function results in a RuntimeException).
*
* @param a_id a hopefully unique id of the configuration
*
* @author Klaus Meffert
* @since 3.0
*/
public static void reset(final String a_id) {
String threadKey = getThreadKey(Thread.currentThread(), a_id);
System.setProperty(threadKey + Configuration.PROPERTY_FITFUNC_INST, "");
System.setProperty(threadKey + Configuration.PROPERTY_BFITFNC_INST, "");
System.setProperty(threadKey + Configuration.PROPERTY_FITEVAL_INST, "");
System.setProperty(threadKey + Configuration.PROPERTY_SAMPLE_CHROM_INST, "");
System.setProperty(threadKey + Configuration.PROPERTY_EVENT_MGR_INST, "");
}
/**
* See Configuration.reset().
* @param a_propName the property to reset
*
* @author Klaus Meffert
* @since 3.0
*/
public static void resetProperty(final String a_propName) {
resetProperty(a_propName, "");
}
public static void resetProperty(final String a_propName, final String a_id) {
String threadKey = getThreadKey(Thread.currentThread(), a_id);
System.setProperty(threadKey + a_propName, "");
}
/**
* @param a_name informative name of the configuration
*
* @author Klaus Meffert
* @since 2.3
*/
public void setName(final String a_name) {
m_name = a_name;
}
/**
* @return informative name of the configuration
*
* @author Klaus Meffert
* @since 2.3
*/
public String getName() {
return m_name;
}
/**
* Sets the fitness function to be used for this genetic algorithm.
* The fitness function is responsible for evaluating a given Chromosome and
* returning a positive integer that represents its worth as a candidate
* solution. These values are used as a guide by the natural to determine
* which Chromosome instances will be allowed to move on to the next round of
* evolution, and which will instead be eliminated.
*
* Note that it is illegal to set both this fitness function and a bulk
* fitness function. Although one or the other must be set, the two are
* mutually exclusive.
*
* @param a_functionToSet fitness function to be used
*
* @throws InvalidConfigurationException if the fitness function is null, a
* bulk fitness function has already been set, or if this Configuration
* object is locked.
*
* @author Neil Rotstan
* @since 1.1
*/
public synchronized void setFitnessFunction(final FitnessFunction
a_functionToSet)
throws InvalidConfigurationException {
verifyChangesAllowed();
// Sanity check: Make sure that the given fitness function isn't null.
// -------------------------------------------------------------------
if (a_functionToSet == null) {
throw new InvalidConfigurationException(
"The FitnessFunction instance must not be null.");
}
// Make sure the bulk fitness function hasn't already been set.
// ------------------------------------------------------------
if (m_bulkObjectiveFunction != null) {
throw new InvalidConfigurationException(
"The bulk fitness function and normal fitness function " +
"may not both be set.");
}
// Ensure that no other fitness function has been set in a different
// configuration object within the same thread!
// -----------------------------------------------------------------
checkProperty(PROPERTY_FITFUNC_INST, a_functionToSet, m_objectiveFunction,
"Fitness function has already been set differently.");
m_objectiveFunction = a_functionToSet;
}
/**
* Verifies that a property is not set. If not set, set it, otherwise throw
* a RuntimeException with a_errmsg as text.
* @param a_propname the property to check (the current thread will be
* considered as a part of the property's name, too)
* @param a_obj the object that should be set in charge of the property
* @param a_oldObj the old object that is set until now. Not used yet
* @param a_errmsg the error message to throw in case the property is already
* set for the current thread
*
* @author Klaus Meffert
* @since 3.0
*/
protected void checkProperty(final String a_propname, final Object a_obj,
final Object a_oldObj, final String a_errmsg) {
String instanceHash = System.getProperty(threadKey + a_propname, null);
String key = makeKey(a_obj);
if (instanceHash == null || instanceHash.length() < 1) {
System.setProperty(threadKey + a_propname, key);
}
else if (!instanceHash.equals(key)) {
throw new RuntimeException(a_errmsg + "\nIf you want to set or construct"
+
" a configuration multiple times, please call"
+
" static method Configuration.reset() before"
+ " each setting!");
}
}
/**
* @param a_obj the object to make a key for, must not be null
* @return key produced for the object (hashCode() is used, so it should be
* implemented properly!)
*
* @author Klaus Meffert
* @since 3.0
*/
protected String makeKey(final Object a_obj) {
String key = String.valueOf(a_obj.hashCode())
+ a_obj.getClass().getName();
return key;
}
/**
* Retrieves the fitness function previously setup in this Configuration
* object.
*
* @return the fitness function
*
* @author Neil Rotstan
* @since 1.0
*/
public synchronized FitnessFunction getFitnessFunction() {
return m_objectiveFunction;
}
/**
* Sets the bulk fitness function to be used for this genetic algorithm.
* The bulk fitness function may be used to evaluate and assign fitness
* values to the entire group of candidate Chromosomes in a single batch.
* This can be useful in cases where it's difficult to assign fitness
* values to a Chromosome in isolation from the other candidate
* Chromosomes.
* <p>
* Note that it is illegal to set both a bulk fitness function and a
* normal fitness function. Although one or the other is required, the
* two are mutually exclusive.
*
* @param a_functionToSet bulk fitness function to be used
*
* @throws InvalidConfigurationException if the bulk fitness function is
* null, the normal fitness function has already been set, or if this
* Configuration object is locked
*
* @author Neil Rotstan
* @author Klaus Meffert
* @since 1.0
*/
public synchronized void setBulkFitnessFunction(
final BulkFitnessFunction a_functionToSet)
throws InvalidConfigurationException {
verifyChangesAllowed();
// Sanity check: Make sure that the given bulk fitness function
// isn't null.
// ------------------------------------------------------------
if (a_functionToSet == null) {
throw new InvalidConfigurationException(
"The BulkFitnessFunction instance must not be null.");
}
// Make sure a normal fitness function hasn't already been set.
// ------------------------------------------------------------
if (m_objectiveFunction != null) {
throw new InvalidConfigurationException(
"The bulk fitness function and normal fitness function " +
"must not both be set.");
}
// Ensure that no other bulk fitness function has been set in a
// different configuration object within the same thread!
// ------------------------------------------------------------
checkProperty(PROPERTY_BFITFNC_INST, a_functionToSet,m_bulkObjectiveFunction,
"Bulk fitness function has already been set differently.");
m_bulkObjectiveFunction = a_functionToSet;
}
/**
* Retrieves the bulk fitness function previously setup in this
* Configuration object.
*
* @return the bulk fitness function
*
* @author Neil Rotstan
* @since 1.0
*/
public synchronized BulkFitnessFunction getBulkFitnessFunction() {
return m_bulkObjectiveFunction;
}
/**
* Sets the sample Chromosome that is to be used as a guide for the
* construction of other Chromosomes. The Chromosome should be setup
* with each gene represented by the desired concrete Gene implementation
* for that gene position (locus). Anytime a new Chromosome is created,
* it will be constructed with the same Gene setup as that provided in
* this sample Chromosome.
*
* @param a_sampleChromosomeToSet Chromosome to be used as the sample
* @throws InvalidConfigurationException if the given Chromosome is null or
* this Configuration object is locked
*
* @author Neil Rotstan
* @since 1.0
*/
public void setSampleChromosome(final IChromosome a_sampleChromosomeToSet)
throws InvalidConfigurationException {
verifyChangesAllowed();
// Sanity check: Make sure that the given chromosome isn't null.
// -----------------------------------------------------------
if (a_sampleChromosomeToSet == null) {
throw new InvalidConfigurationException(
"The sample chromosome instance must not be null.");
}
if (a_sampleChromosomeToSet.getConfiguration() == null) {
throw new InvalidConfigurationException(
"The sample chromosome's configuration must not be null.");
}
// Ensure that no other sample chromosome has been set in a
// different configuration object within the same thread!
// --------------------------------------------------------
checkProperty(PROPERTY_SAMPLE_CHROM_INST, a_sampleChromosomeToSet,
m_sampleChromosome, "Sample chromosome has already been set differently.");
m_sampleChromosome = a_sampleChromosomeToSet;
m_chromosomeSize = m_sampleChromosome.size();
}
/**
* Retrieves the sample Chromosome that contains the desired Gene setup
* for each respective gene position (locus).
*
* @return sample Chromosome instance
*
* @author Neil Rotstan
* @since 1.0
*/
public IChromosome getSampleChromosome() {
return m_sampleChromosome;
}
/**
* Retrieves the chromosome size being used by this genetic
* algorithm. This value is set automatically when the sample chromosome
* is provided.
*
* @return chromosome size used in this configuration
*
* @author Neil Rotstan
* @since 1.0
*/
public int getChromosomeSize() {
return m_chromosomeSize;
}
/**
* Sets the natural selector to be used for this genetic algorithm.
* The natural selector is responsible for actually selecting
* which Chromosome instances are allowed to move on to the next
* round of evolution (usually guided by the fitness values
* provided by the fitness function). This setting is required.
*
* @param a_selectorToSet the natural selector to be used
*
* @throws InvalidConfigurationException if the natural selector is null or
* this Configuration object is locked
*
* @author Neil Rotstan
* @since 1.0
* @deprecated use addNaturalSelector(false) instead
*/
public synchronized void setNaturalSelector(final NaturalSelector
a_selectorToSet)
throws InvalidConfigurationException {
addNaturalSelector(a_selectorToSet, false);
}
/**
* Retrieves the natural selector setup in this Configuration instance.
*
* @return the natural selector
*
* @author Neil Rotstan
* @since 1.0
* @deprecated use getNaturalSelectors(true) or getNaturalSelectors(false)
* to obtain the relevant chain of NaturalSelector's and then call the
* chain's get(index) method
*/
public synchronized NaturalSelector getNaturalSelector() {
if (getNaturalSelectors(false).size() < 1) {
return null;
}
return getNaturalSelectors(false).get(0);
}
/**
* @param a_processBeforeGeneticOperators true: retrieve selector that is
* registered to be executed before genetic operators, false: get the one
* that is registered to be executed after genetic operators
* @param a_index index of the selector to get
* @return NaturalSelector
*
* @author Klaus Meffert
* @since 1.1
*/
public synchronized NaturalSelector getNaturalSelector(final boolean
a_processBeforeGeneticOperators, final int a_index) {
if (a_processBeforeGeneticOperators) {
return m_preSelectors.get(a_index);
}
else {
return m_postSelectors.get(a_index);
}
}
/**
* Only use for read-only access! Especially don't call clear() for the
* returned ChainOfSelectors object!
*
* @param a_processBeforeGeneticOperators true: retrieve selector that is
* registered to be executed before genetic operators, false: get the one
* that is registered to be executed after genetic operators
* @return ChainOfSelectors
*
* @author Klaus Meffert
* @since 1.1
*/
public ChainOfSelectors getNaturalSelectors(final boolean
a_processBeforeGeneticOperators) {
if (a_processBeforeGeneticOperators) {
return m_preSelectors;
}
else {
return m_postSelectors;
}
}
/**
* @param a_processBeforeGeneticOperators true: retrieve selector that is
* registered to be executed before genetic operators, false: get the one
* that is registered to be executed after genetic operators
* @return size of selector list (distinct by a_processBeforeGeneticOperators)
*
* @author Klaus Meffert
* @since 1.1
*/
public int getNaturalSelectorsSize(final boolean
a_processBeforeGeneticOperators) {
if (a_processBeforeGeneticOperators) {
return m_preSelectors.size();
}
else {
return m_postSelectors.size();
}
}
/**
* Removes all natural selectors (either pre or post ones).
*
* @param a_processBeforeGeneticOperators true: remove all selectors
* processed before genetic operators, false: remove the ones processed
* afterwards
*
* @author Klaus Meffert
* @since 2.3
*/
public void removeNaturalSelectors(final boolean
a_processBeforeGeneticOperators) {
if (a_processBeforeGeneticOperators) {
getNaturalSelectors(true).clear();
}
else {
getNaturalSelectors(false).clear();
}
}
/**
* Sets the random generator to be used for this genetic algorithm.
* The random generator is responsible for generating random numbers,
* which are used throughout the process of genetic evolution and
* selection. This setting is required.
*
* @param a_generatorToSet random generator to be used
*
* @throws InvalidConfigurationException if the random generator is null or
* this object is locked
*
* @author Neil Rotstan
* @since 1.0
*/
public synchronized void setRandomGenerator(final RandomGenerator
a_generatorToSet)
throws InvalidConfigurationException {
verifyChangesAllowed();
// Sanity check: Make sure that the given random generator isn't null.
// -------------------------------------------------------------------
if (a_generatorToSet == null) {
throw new InvalidConfigurationException(
"The RandomGenerator instance may not be null.");
}
m_randomGenerator = a_generatorToSet;
}
/**
* Retrieves the random generator setup in this Configuration instance.
*
* @return the random generator
*
* @author Neil Rotstan
* @since 1.0
*/
public synchronized RandomGenerator getRandomGenerator() {
return m_randomGenerator;
}
/**
* Adds a genetic operator for use in this algorithm. Genetic operators
* represent evolutionary steps that, when combined, make up the
* evolutionary process. Examples of genetic operators are reproduction,
* crossover, and mutation. During the evolution process, all of the
* genetic operators added via this method are invoked in the order
* they were added. At least one genetic operator must be provided.
*
* @param a_operatorToAdd the genetic operator to add.
*
* @throws InvalidConfigurationException if the genetic operator is null or
* if this Configuration object is locked
*
* @author Neil Rotstan
* @since 1.0
*/
public synchronized void addGeneticOperator(final GeneticOperator
a_operatorToAdd)
throws InvalidConfigurationException {
verifyChangesAllowed();
// Sanity check: Make sure that the given genetic operator isn't null.
// -------------------------------------------------------------------
if (a_operatorToAdd == null) {
throw new InvalidConfigurationException(
"The GeneticOperator instance must not be null.");
}
m_geneticOperators.add(a_operatorToAdd);
}
/**
* Retrieves the genetic operators setup in this Configuration instance.
* Note that once this Configuration instance is locked, a new, immutable list
* of operators is used and any lists previously retrieved with this method
* will no longer reflect the actual list in use.
*
* @return the list of genetic operators
*
* @author Neil Rotstan
* @since 1.0
*/
public List getGeneticOperators() {
return m_geneticOperators;
}
/**
* Sets the population size to be used for this genetic algorithm.
* The population size is a fixed value that represents the
* number of Chromosomes contained within the Genotype (population).
* This setting is required.
*
* @param a_sizeOfPopulation population size to be used
*
* @throws InvalidConfigurationException if the population size is not
* positive or this object is locked
*
* @author Neil Rotstan
* @since 1.0
*/
public synchronized void setPopulationSize(final int a_sizeOfPopulation)
throws InvalidConfigurationException {
verifyChangesAllowed();
// Sanity check: Make sure the population size is positive.
// --------------------------------------------------------
if (a_sizeOfPopulation < 1) {
throw new InvalidConfigurationException(
"The population size must be positive.");
}
m_config.m_populationSize = a_sizeOfPopulation;
}
/**
* Retrieves the population size setup in this Configuration instance.
*
* @return population size
*/
public synchronized int getPopulationSize() {
return m_config.m_populationSize;
}
/**
* Sets the event manager that is to be associated with this configuration.
* The event manager is responsible for the management of event subscribers
* and event notifications.
*
* @param a_eventManagerToSet the EventManager instance to use in this
* configuration
*
* @throws InvalidConfigurationException if the event manager is null
* or this Configuration object is locked
*
* @author Neil Rotstan
* @since 1.0
*/
public void setEventManager(final IEventManager a_eventManagerToSet)
throws InvalidConfigurationException {
verifyChangesAllowed();
// Sanity check: Make sure that the given event manager isn't null.
// ----------------------------------------------------------------
if (a_eventManagerToSet == null) {
throw new InvalidConfigurationException(
"The event manager instance must not be null.");
}
// Ensure that no other event manager has been set in a different
// configuration object within the same thread!
// --------------------------------------------------------------
checkProperty(PROPERTY_EVENT_MGR_INST, a_eventManagerToSet,m_eventManager,
"Event manager has already been set differently.");
m_eventManager = a_eventManagerToSet;
}
/**
* Retrieves the event manager associated with this configuration. The event
* manager is responsible for the management of event subscribers
* and event notifications.
*
* @return the actively configured event manager instance
*
* @since 1.0
*/
public IEventManager getEventManager() {
return m_eventManager;
}
/**
* Sets the ChromosomePool that is to be associated with this
* configuration. The ChromosomePool is used to pool discarded Chromosome
* instances so that they may be recycled later, thereby saving memory and
* the time to construct them from scratch. The presence of a ChromosomePool
* is optional. If none exists, then a new Chromosome will be constructed
* each time one is needed.
*
* @param a_chromosomePoolToSet the ChromosomePool instance to use
* @throws InvalidConfigurationException if this object is locked
*
* @author Neil Rotstan
* @since 1.0
*/
public void setChromosomePool(final IChromosomePool a_chromosomePoolToSet)
throws InvalidConfigurationException {
verifyChangesAllowed();
m_chromosomePool = a_chromosomePoolToSet;
}
/**
* Retrieves the ChromosomePool instance, if any, that is associated with
* this configuration. The ChromosomePool is used to pool discarded
* Chromosome instances so that they may be recycled later, thereby
* saving memory and the time to construct them from scratch. The presence
* of a ChromosomePool instance is optional. If none exists, then new
* Chromosomes should be constructed each time one is needed.
*
* @return the ChromosomePool instance associated this configuration, or
* null if none has been provided
*
* @author Neil Rotstan
* @since 1.0
*/
public IChromosomePool getChromosomePool() {
return m_chromosomePool;
}
/**
* Locks all of the settings in this configuration object. Once
* this method is successfully invoked, none of the settings may
* be changed. There is no way to unlock this object once it is locked.
* <p>
* Prior to returning successfully, this method will first invoke the
* verifyStateIsValid() method to make sure that any required configuration
* options have been properly set. If it detects a problem, it will
* throw an InvalidConfigurationException and leave the object unlocked.
* <p>
* It's possible to test whether this object is locked through the
* isLocked() method.
* <p>
* It is ok to lock an object more than once. In that case, this method
* does nothing and simply returns.
*
* @throws InvalidConfigurationException if this Configuration object is
* in an invalid state at the time of invocation
*
* @author Neil Rotstan
* @since 1.0
*/
public synchronized void lockSettings()
throws InvalidConfigurationException {
if (!m_settingsLocked) {
verifyStateIsValid();
// // Make genetic operators list immutable.
// // --------------------------------------
// m_geneticOperators = Collections.unmodifiableList(m_geneticOperators);
m_settingsLocked = true;
}
}
/**
* Retrieves the lock status of this object.
*
* @return true if this object has been locked by a previous successful
* call to the lockSettings() method, false otherwise
*
* @author Neil Rotstan
* @since 1.0
*/
public boolean isLocked() {
return m_settingsLocked;
}
/**
* Tests the state of this Configuration object to make sure it's valid.
* This generally consists of verifying that required settings have, in
* fact, been set. If this object is not in a valid state, then an
* exception will be thrown detailing the reason the state is not valid.
*
* @throws InvalidConfigurationException if the state of this Configuration
* is not valid. The error message in the exception will detail the reason
* for invalidity
*
* @author Neil Rotstan
* @since 1.0
*/
public synchronized void verifyStateIsValid()
throws InvalidConfigurationException {
// First, make sure all of the required fields have been set to
// appropriate values.
// ------------------------------------------------------------
if (m_objectiveFunction == null && m_bulkObjectiveFunction == null) {
throw new InvalidConfigurationException(
"A desired fitness function or bulk fitness function must " +
"be specified in the active configuration.");
}
if (m_sampleChromosome == null) {
throw new InvalidConfigurationException(
"A sample instance of the desired Chromosome " +
"setup must be specified in the active configuration.");
}
if (m_preSelectors.size() == 0 && m_postSelectors.size() == 0) {
throw new InvalidConfigurationException(
"At least one desired natural selector must be specified in the"
+ " active configuration.");
}
if (m_randomGenerator == null) {
throw new InvalidConfigurationException(
"A desired random number generator must be specified in the " +
"active configuration.");
}
if (m_eventManager == null) {
throw new InvalidConfigurationException(
"A desired event manager must be specified in the active " +
"configuration.");
}
if (m_geneticOperators.isEmpty()) {
throw new InvalidConfigurationException(
"At least one genetic operator must be specified in the " +
"configuration.");
}
if (m_chromosomeSize <= 0) {
throw new InvalidConfigurationException(
"A chromosome size greater than zero must be specified in " +
"the active configuration.");
}
if (m_config.m_populationSize <= 0) {
throw new InvalidConfigurationException(
"A population size greater than zero must be specified in " +
"the active configuration.");
}
if (m_fitnessEvaluator == null) {
throw new IllegalArgumentException(
"The fitness evaluator must not be null.");
}
// Next, it's critical that each Gene implementation in the sample
// Chromosome has a working equals() method, or else the genetic
// engine will end up failing in mysterious and unpredictable ways.
// We therefore verify right here that this method is working properly
// in each of the Gene implementations used in the sample Chromosome.
// -------------------------------------------------------------------
Gene[] sampleGenes = m_sampleChromosome.getGenes();
for (int i = 0; i < sampleGenes.length; i++) {
Gene sampleCopy = sampleGenes[i].newGene();
sampleCopy.setAllele(sampleGenes[i].getAllele());
if (! (sampleCopy.equals(sampleGenes[i]))) {
throw new InvalidConfigurationException(
"The sample Gene at gene position (locus) "
+ i
+ " does not appear to have a working equals() or compareTo()"
+ " method.\n"
+ "It could also be that you forgot to implement method"
+ " newGene() in your Gene implementation.\n"
+ "When tested, the method returned false when comparing "
+ "the sample gene with a gene of the same type and "
+ "possessing the same value (allele).");
}
}
}
/**
* Makes sure that this Configuration object isn't locked. If it is, then
* an exception is thrown with an appropriate message indicating
* that settings in this object may not be altered. This method
* should be invoked by any mutator method in this object prior
* to making any state alterations.
*
* @throws InvalidConfigurationException if this Configuration object is
* locked
*
* @author Neil Rotstan
* @since 1.0
*/
protected void verifyChangesAllowed()
throws InvalidConfigurationException {
if (m_settingsLocked) {
throw new InvalidConfigurationException(
"This Configuration object is locked. Settings may not be " +
"altered.");
}
}
/**
* Adds a NaturalSelector to the ordered chain of registered
* NaturalSelector's. It's possible to execute the NaturalSelector before
* or after (registered) genetic operations have been applied.
* Normally, you would add a selector that is applied after the genetic
* operators are processed (a_processBeforeGeneticOperators = false).
*
* @param a_selector the selector to be added to the chain
* @param a_processBeforeGeneticOperators true: execute NaturalSelector
* before any genetic operator will be applied, false: .. after..
* @throws InvalidConfigurationException
*
* @author Klaus Meffert
* @since 1.1
*/
public void addNaturalSelector(NaturalSelector a_selector,
boolean a_processBeforeGeneticOperators)
throws InvalidConfigurationException {
verifyChangesAllowed();
if (a_processBeforeGeneticOperators) {
m_preSelectors.addNaturalSelector(a_selector);
}
else {
m_postSelectors.addNaturalSelector(a_selector);
}
}
/**
* Minimum size guaranteed for population. This is significant during
* evolution as natural selectors could select fewer chromosomes for the next
* generation than the initial population size was.
* @param a_minimumSizeGuaranteedPercent if zero or below then no ensurance
* for size given, see Genotype.evolve()
*
* @author Klaus Meffert
*/
public void setMinimumPopSizePercent(int a_minimumSizeGuaranteedPercent) {
m_minPercentageSizePopulation = a_minimumSizeGuaranteedPercent;
}
public int getMinimumPopSizePercent() {
return m_minPercentageSizePopulation;
}
/**
* @return the assigned FitnessEvaluator
*
* @author Klaus Meffert
* @since 2.0
*/
public FitnessEvaluator getFitnessEvaluator() {
return m_fitnessEvaluator;
}
/**
* Set the fitness evaluator (deciding if a given fitness value is better
* when it's higher or better when it's lower).
* @param a_fitnessEvaluator the FitnessEvaluator to be used
*
* @author Klaus Meffert
* @since 2.0
*/
public void setFitnessEvaluator(FitnessEvaluator a_fitnessEvaluator) {
if (a_fitnessEvaluator == null) {
throw new IllegalStateException(
"The fitness evaluator object must not be null!");
}
// Ensure that no other fitness evaluator has been set in a
// different configuration object within the same thread!
// --------------------------------------------------------
checkProperty(PROPERTY_FITEVAL_INST, a_fitnessEvaluator,m_fitnessEvaluator,
"Fitness evaluator has already been set differently.");
m_fitnessEvaluator = a_fitnessEvaluator;
}
/**
* @return true: fittest chromosome should always be transferred to next
* generation
*
* @author Klaus Meffert
* @since 2.1
*/
public boolean isPreserveFittestIndividual() {
return m_preserveFittestIndividual;
}
/**
* Determines whether to save (keep) the fittest individual.
* @param a_preserveFittest true: always transfer fittest chromosome to next
* generation
*
* @author Klaus Meffert
* @since 2.1
*/
public void setPreservFittestIndividual(boolean a_preserveFittest) {
m_preserveFittestIndividual = a_preserveFittest;
}
public void incrementGenerationNr() {
m_generationNr++;
}
public int getGenerationNr() {
return m_generationNr;
}
/**
* Implementation of the Configurable interface.
* @return ConfigurationHandler
* @throws ConfigException
*
* @author Siddhartha Azad
*/
public ConfigurationHandler getConfigurationHandler() {
return m_conHandler;
}
/**
* @return string representation of the configuration containing all
* configurable elements
*
* @author Klaus Meffert
* @since 2.3
*/
public String toString() {
String result = S_CONFIGURATION + ":";
// Basic parameters.
// -----------------
result += "\n " + S_CONFIGURATION_NAME + ": " + getName();
result += "\n " + S_POPULATION_SIZE + ": " + getPopulationSize();
result += "\n " + S_MINPOPSIZE + ": " + getMinimumPopSizePercent();
result += "\n " + S_CHROMOSOME_SIZE + ": " + getChromosomeSize();
// Sample chromosome.
// ------------------
result += "\n " + S_SAMPLE_CHROM + ":\n";
if (getSampleChromosome() == null) {
result += "\n null";
}
else {
result += "\n " + S_SIZE + ": " + getSampleChromosome().size();
result += "\n " + S_TOSTRING + ": " + getSampleChromosome().toString();
}
// Random generator.
// -----------------
result += "\n " + S_RANDOM_GENERATOR + ": ";
if (getRandomGenerator() != null) {
result += getRandomGenerator().getClass().getName();
}
else {
result += S_NONE;
}
result += "\n " + S_EVENT_MANAGER + ": ";
// Event manager.
// --------------
if (getEventManager() == null) {
result += S_NONE;
}
else {
result += getEventManager().getClass().getName();
}
// Configuration handler.
// ----------------------
result += "\n " + S_CONFIGURATION_HANDLER + ": ";
if (getConfigurationHandler() == null) {
result += "null";
}
else {
result += getConfigurationHandler().getName();
}
// Fitness function.
// -----------------
result += "\n " + S_FITNESS_FUNCTION + ": ";
if (getFitnessFunction() == null) {
result += "null";
}
else {
result += getFitnessFunction().getClass().getName();
}
// Fitness evaluator.
// ------------------
result += "\n " + S_FITNESS_EVALUATOR + ": ";
if (getFitnessEvaluator() == null) {
result += "null";
}
else {
result += getFitnessEvaluator().getClass().getName();
}
// Genetic operators.
// ------------------
result += "\n " + S_GENETIC_OPERATORS + ": ";
if (getGeneticOperators() == null) {
result += "null";
}
else {
int gensize = getGeneticOperators().size();
if (gensize < 1) {
result += S_NONE;
}
else {
for (int i = 0; i < gensize; i++) {
if (i > 0) {
result += "; ";
}
result += " " + getGeneticOperators().get(i).getClass().getName();
}
}
}
// Natural selectors (pre).
// ------------------------
int natsize = getNaturalSelectors(true).size();
result += "\n " + S_NATURAL_SELECTORS + "(" + S_PRE + "): ";
if (natsize < 1) {
result += S_NONE;
}
else {
for (int i = 0; i < natsize; i++) {
if (i > 0) {
result += "; ";
}
result += " " + getNaturalSelectors(true).get(i).getClass().getName();
}
}
// Natural selectors (post).
// -------------------------
natsize = getNaturalSelectors(false).size();
result += "\n " + S_NATURAL_SELECTORS + "(" + S_POST + "): ";
if (natsize < 1) {
result += "none";
}
else {
for (int i = 0; i < natsize; i++) {
if (i > 0) {
result += "; ";
}
result += " " + getNaturalSelectors(false).get(i).getClass().getName();
}
}
// String popSelector;
// if (m_popConstantSelector == null) {
// popSelector = "null";
// }
// else {
// popSelector = m_popConstantSelector.getClass().getName();
// }
// result += "\n " + S_POPCONSTANT_SELECTOR + ": "
// + popSelector;
return result;
}
/**
* See setKeepPopulationSizeConstant and
* GABreeder#evolve(Population, Configuration) for detailled explanation.
* @return true: population size will always be the same size
* (as given with Configuration.setPopulationSize(int)
*
* @author Klaus Meffert
* @since 2.4
*/
public boolean isKeepPopulationSizeConstant() {
return m_keepPopulationSizeConstant;
}
/**
* Allows to keep the population size constant during one evolution, even if
* there is no appropriate instance of NaturalSelector (such as
* WeightedRouletteSelector) registered with the Configuration.<p>
* See setKeepPopulationSizeConstant and
* GABreeder#evolve(Population, Configuration) for detailled explanation.
*
* @param a_keepPopSizeConstant true: population size will always be
* the same size (as given with Configuration.setPopulationSize(int)
*
* @author Klaus Meffert
* @since 2.4
*/
public void setKeepPopulationSizeConstant(boolean a_keepPopSizeConstant) {
m_keepPopulationSizeConstant = a_keepPopSizeConstant;
}
public void setSelectFromPrevGen(double a_percentage) {
if (a_percentage < 0 || a_percentage > 1.00) {
throw new IllegalArgumentException("Argument must be between 0 and 1");
}
m_selectFromPrevGen = a_percentage;
}
public double getSelectFromPrevGen() {
return m_selectFromPrevGen;
}
/**
* @return the JGAP factory registered
*
* @author Klaus Meffert
*/
public IJGAPFactory getJGAPFactory() {
return m_factory;
}
public class ConfigurationConfigurable
implements Serializable {
/**
* The number of chromosomes that will be stored in the Genotype.
*/
int m_populationSize;
}
/**
* Builds a string considering the current thread and the given id.
*
* @param current the current Thread
* @param a_id a hopefully unique id of the configuration
*
* @return string built up
*
* @author Klaus Meffert
* @since 3.01
*/
protected static String getThreadKey(Thread current, String a_id) {
return current.toString() + "|" + a_id + "|";
}
/**
* @param a_factory the IJGAPFactory to use
*
* @author Klaus Meffert
* @since 3.01
*/
public void setJGAPFactory(IJGAPFactory a_factory) {
m_factory = a_factory;
}
/**
* @param a_breeder the breeder to use
*
* @author Klaus Meffert
* @since 3.2
*/
public void setBreeder(IBreeder a_breeder) {
assert(a_breeder != null);
m_breeder = a_breeder;
}
/**
* @return the breeder set or new standard breeder instance in case no breeder
* was set before.
*
* @author Klaus Meffert
* @since 3.2
*/
public IBreeder getBreeder() {
if (m_breeder == null) {
m_breeder = new GABreeder();
}
return m_breeder;
}
// /**
// * If population size should be kept constant then this selector determines
// * which of the chromosomes to select into the next generation.
// *
// * @param a_popConstantSelector the selector to use
// * @throws InvalidConfigurationException
// *
// * @author Klaus Meffert
// * @since 3.2.2
// */
// public void setKeepPopConstantSelector(INaturalSelector a_popConstantSelector)
// throws InvalidConfigurationException {
// verifyChangesAllowed();
// m_popConstantSelector = a_popConstantSelector;
// }
// /**
// * @return the registered selector to keep population size constant. If none
// * is set, the NewestChromosomesSelector is instantiated, assigned and
// * returned
// *
// * @throws InvalidConfigurationException
// *
// * @author Klaus Meffert
// * @since 3.2.2
// */
// public INaturalSelector getKeepPopConstantSelector()
// throws InvalidConfigurationException{
// if (m_popConstantSelector == null) {
// m_popConstantSelector = new NewestChromosomesSelector(this);
// }
// return m_popConstantSelector;
// }
/**
* @param a_alwaysCalculate true: Chromosome.getFitnessValue() will always
* (re-)calculate the fitness value. This may be necessary in case of
* environments where the state changes without the chromosome to notice.
*
* @author Klaus Meffert
* @since 3.2.2
*/
public void setAlwaysCaculateFitness(boolean a_alwaysCalculate) {
m_alwaysCalculateFitness = a_alwaysCalculate;
}
/**
* @return true: Chromosome.getFitnessValue() will always (re-)calculate the
* fitness value. This may be necessary in case of environments where the
* state changes without the chromosome to notice.
*
* @author Klaus Meffert
* @since 3.2.2
*/
public boolean isAlwaysCalculateFitness() {
return m_alwaysCalculateFitness;
}
protected String makeThreadKey() {
Thread current = Thread.currentThread();
threadKey = getThreadKey(current, m_id);
return threadKey;
}
/**
* Sets a property in the bag.
*
* Be aware that setting in unserializable value here leads to problems with
* distributed computing or other scenarios based on serialization!
*
* Be aware that cloning may also lead to conflicts
* in case you use unsupported object types!
*
* @param a_propName name of the property to se the value for
* @param a_value value of the property
*
* @author Klaus Meffert
* @since 3.3.1
*/
// public void setPropertyInBag(String a_propName, Object a_value) {
// m_propertyBag.put(a_propName, a_value);
// }
/**
*
* @param a_propName name of the property to retrieve the value from
* @return value of the property
*
* @author Klaus Meffert
* @since 3.3.1
*/
// public Object getPropertyFromBag(String a_propName) {
// return m_propertyBag.get(a_propName);
// }
/**
* Deserialize the object. Needed to provide a unique ID for each thread the
* object is used in.
*
* @param a_inputStream the ObjectInputStream provided for deserialzation
* @throws ClassNotFoundException
* @throws IOException
*
* @author Klaus Meffert
* @since 3.01
*/
private void readObject(ObjectInputStream a_inputStream)
throws ClassNotFoundException, IOException {
// Always perform the default de-serialization first.
// --------------------------------------------------
a_inputStream.defaultReadObject();
makeThreadKey();
}
/**
* @return the id of the configuration set
*
* @author Klaus Meffert
* @since 3.1
*/
public String getId() {
return m_id;
}
/**
* Only to be called by sub classes, such as GPConfiguration.
*
* @param a_id the id to set
*
* @author Klaus Meffert
* @since 3.2
*/
protected void setId(String a_id) {
m_id = a_id;
}
/**
* @return deep clone of this instance
*
* @author Klaus Meffert
* @since 3.2
*/
public Object clone() {
return newInstance(m_id, m_name);
}
/**
* Creates a new Configuration instance by cloning. Allows to preset the
* ID and the name.
*
* @param a_id new ID for clone
* @param a_name new name for clone
* @return deep clone of this instance
*
* @author Klaus Meffert
* @since 3.2
*/
public Configuration newInstance(String a_id, String a_name) {
try {
Configuration result = new Configuration(m_name);
// Clone JGAPFactory first because it helps in cloning other objects.
// ------------------------------------------------------------------
if (m_factory instanceof ICloneable) {
result.m_factory = (IJGAPFactory)((ICloneable)m_factory).clone();
}
else {
// We must fallback to a standardized solution.
// --------------------------------------------
m_factory = new JGAPFactory(false);
result.m_factory = (IJGAPFactory)((JGAPFactory)m_factory).clone();
}
if (m_breeder != null) {
result.m_breeder = (IBreeder)doClone(m_breeder);
}
if (m_bulkObjectiveFunction != null) {
result.m_bulkObjectiveFunction = m_bulkObjectiveFunction;
}
result.m_chromosomeSize = m_chromosomeSize;
// result.m_chromosomePool = m_chromosomePool.clone();
// result.m_conHandler = m_conHandler.clone();
result.m_eventManager = (IEventManager)doClone(m_eventManager);
result.m_fitnessEvaluator = (FitnessEvaluator)doClone(m_fitnessEvaluator);
result.m_generationNr = 0;
result.m_geneticOperators = (List)doClone(m_geneticOperators);
result.m_keepPopulationSizeConstant = m_keepPopulationSizeConstant;
result.m_minPercentageSizePopulation = m_minPercentageSizePopulation;
result.m_selectFromPrevGen = m_selectFromPrevGen;
result.m_objectiveFunction = (FitnessFunction)doClone(m_objectiveFunction);
// result.m_popConstantSelector = (INaturalSelector)doClone(m_popConstantSelector);
result.m_postSelectors = (ChainOfSelectors)doClone(m_postSelectors);
result.m_preSelectors = (ChainOfSelectors)doClone(m_preSelectors);
result.m_preserveFittestIndividual = m_preserveFittestIndividual;
result.m_randomGenerator = (RandomGenerator)doClone(m_randomGenerator);
if (m_sampleChromosome != null) {
result.m_sampleChromosome = (IChromosome) m_sampleChromosome.clone();
}
result.m_alwaysCalculateFitness = m_alwaysCalculateFitness;
result.m_settingsLocked = m_settingsLocked;
// result.m_propertyBag = (Map)doClone(m_propertyBag);
// Configurable data.
// ------------------
result.m_config = new ConfigurationConfigurable();
result.m_config.m_populationSize = m_config.m_populationSize;
// Identificative data.
// --------------------
result.m_name = a_name;
result.m_id = a_id;
result.makeThreadKey();// Must be called after m_id is set
return result;
} catch (Throwable t) {
throw new CloneException(t);
}
}
/**
* Helper called from clone.
*
* @param a_objToClone the object to clone
* @return cloned object or null, if cloning not possible
* @throws Exception
*
* @author Klaus Meffert
* @since 3.2
*/
protected Object doClone(Object a_objToClone) throws Exception {
if (a_objToClone != null) {
ICloneHandler handler = getJGAPFactory().getCloneHandlerFor(
a_objToClone, null);
if (handler != null) {
return handler.perform(a_objToClone, null, null);
}
}
return null;
}
/**
* The equals-method.
*
* @param a_other the other object to compare
* @return true if seen as equal
*
* @author Klaus Meffert
* @since 3.2
*/
public boolean equals(Object a_other) {
return compareTo(a_other) == 0;
}
/**
* The compareTo-method.
*
* @param a_other the other object to compare
* @return -1, 0, 1
*
* @author Klaus Meffert
* @since 3.2
*/
public int compareTo(Object a_other) {
if (a_other == null) {
return 1;
}
else {
Configuration other = (Configuration) a_other;
try {
return new CompareToBuilder()
.append(m_config.m_populationSize, other.m_config.m_populationSize)
.append(m_factory, other.m_factory)
.append(m_breeder, other.m_breeder)
.append(m_objectiveFunction, other.m_objectiveFunction)
.append(m_fitnessEvaluator, other.m_fitnessEvaluator)
.append(m_bulkObjectiveFunction, other.m_bulkObjectiveFunction)
.append(m_sampleChromosome, other.m_sampleChromosome)
.append(m_randomGenerator, other.m_randomGenerator)
// .append(m_eventManager, other.m_eventManager)
// .append(m_chromosomePool, other.m_chromosomePool)
.append(m_geneticOperators.toArray(), other.m_geneticOperators.toArray())
.append(m_chromosomeSize, other.m_chromosomeSize)
.append(m_preSelectors, other.m_preSelectors)
.append(m_postSelectors, other.m_postSelectors)
// .append(m_popConstantSelector, other.m_popConstantSelector)
.append(m_preserveFittestIndividual,
other.m_preserveFittestIndividual)
// .append(m_conHandler, other.m_conHandler)
.append(threadKey, other.threadKey)
.append(m_keepPopulationSizeConstant,
other.m_keepPopulationSizeConstant)
.append(m_alwaysCalculateFitness, other.m_alwaysCalculateFitness)
.append(m_minPercentageSizePopulation,
other.m_minPercentageSizePopulation)
.append(m_selectFromPrevGen,other.m_selectFromPrevGen)
.append(m_generationNr, other.m_generationNr)
.append(m_name, other.m_name)
// .append(m_propertyBag, other.m_propertyBag)
.append(m_settingsLocked, other.m_settingsLocked)
.toComparison();
} catch (ClassCastException cex) {
throw new RuntimeException("Cannot compare all objects within"
+ " org.jgap.Configuration, because at"
+ " least one does not implement interface"
+ " java.lang.Comparable!");
}
}
}
/**
* Sets a monitor for auditing evolution progress.
*
* @param a_monitor the monitor to use
*
* @author Klaus Meffert
* @since 3.5
*/
public void setMonitor(IEvolutionMonitor a_monitor) {
m_monitor = a_monitor;
if(m_monitor != null) {
setUniqueKeysActive(true);
}
}
/**
* @return the monitor uses for auditing the evolution progress.
*
* @author Klaus Meffert
* @since 3.5
*/
public IEvolutionMonitor getMonitor() {
return m_monitor;
}
/**
* @param a_active true: use unique keys to allow tracking and monitoring
*
* @author Klaus Meffert
* @since 3.5
*/
public void setUniqueKeysActive(boolean a_active) {
m_uniqueKeysActive = a_active;
}
/**
* @return true: use unique keys to allow tracking and monitoring
*
* @author Klaus Meffert
* @since 3.5
*/
public boolean isUniqueKeysActive() {
return m_uniqueKeysActive;
}
}