0001: /*
0002: * This file is part of JGAP.
0003: *
0004: * JGAP offers a dual license model containing the LGPL as well as the MPL.
0005: *
0006: * For licensing information please see the file license.txt included with JGAP
0007: * or have a look at the top of class org.jgap.Chromosome which representatively
0008: * includes the JGAP license policy applicable for any file delivered with JGAP.
0009: */
0010: package org.jgap;
0011:
0012: import java.io.*;
0013: import java.util.*;
0014:
0015: import org.apache.commons.lang.builder.*;
0016: import org.jgap.data.config.*;
0017: import org.jgap.event.*;
0018: import org.jgap.impl.*;
0019: import org.jgap.util.*;
0020:
0021: /**
0022: * The Configuration class represents the current configuration of
0023: * plugins and parameters necessary to execute the genetic algorithm (such
0024: * as fitness function, natural selector, genetic operators, and so on).
0025: * <p>
0026: * Note that, while during setup, the settings, flags, and other
0027: * values may be set multiple times. But once the lockSettings() method
0028: * is invoked, they cannot be changed. The default behavior of the
0029: * Genotype constructor is to invoke this method, meaning that
0030: * once a Configuration object is passed to a Genotype, it cannot
0031: * be subsequently modified. There is no mechanism for unlocking
0032: * the settings once they are locked.
0033: * <p>
0034: * Not all configuration options are required. See the documentation
0035: * for each of the respective mutator methods to determine whether
0036: * it is required to provide a value for that setting, and what the
0037: * setting will default to if not.
0038: *
0039: * @author Neil Rotstan
0040: * @author Klaus Meffert
0041: * @since 1.0
0042: */
0043: public class Configuration implements Configurable, Serializable,
0044: ICloneable, Comparable {
0045: /** String containing the CVS revision. Read out via reflection!*/
0046: private final static String CVS_REVISION = "$Revision: 1.93 $";
0047:
0048: /**
0049: * Constant for class name of JGAP Factory to use. Use as:
0050: * System.setProperty(PROPERTY_JGAPFACTORY_CLASS, "myJGAPFactory");
0051: * If none such property set, class JGAPFactory will be used.
0052: */
0053: public static final String PROPERTY_JGAPFACTORY_CLASS = "JGAPFACTORYCLASS";
0054:
0055: public static final String PROPERTY_FITFUNC_INST = "JGAPFITFUNCINST";
0056:
0057: public static final String PROPERTY_BFITFNC_INST = "JGAPBFITFNCINST";
0058:
0059: public static final String PROPERTY_FITEVAL_INST = "JGAPFITEVALINST";
0060:
0061: public static final String PROPERTY_SAMPLE_CHROM_INST = "JGAPSAMPLECHRMINST";
0062:
0063: public static final String PROPERTY_EVENT_MGR_INST = "JGAPEVNTMGRINST";
0064:
0065: /**
0066: * Constants for toString()
0067: */
0068: public static final String S_CONFIGURATION = "Configuration";
0069:
0070: public static final String S_CONFIGURATION_NAME = "Configuration name";
0071:
0072: public static final String S_POPULATION_SIZE = "Population size";
0073:
0074: public static final String S_MINPOPSIZE = "Minimum pop. size [%]";
0075:
0076: public static final String S_CHROMOSOME_SIZE = "Chromosome size";
0077:
0078: public static final String S_SAMPLE_CHROM = "Sample Chromosome";
0079:
0080: public static final String S_SIZE = "Size";
0081:
0082: public static final String S_TOSTRING = "toString";
0083:
0084: public static final String S_RANDOM_GENERATOR = "Random generator";
0085:
0086: public static final String S_EVENT_MANAGER = "Event manager";
0087:
0088: public static final String S_NONE = "none";
0089:
0090: public static final String S_CONFIGURATION_HANDLER = "Configuration handler";
0091:
0092: public static final String S_FITNESS_FUNCTION = "Fitness function";
0093:
0094: public static final String S_FITNESS_EVALUATOR = "Fitness evaluator";
0095:
0096: // public static final String S_POPCONSTANT_SELECTOR = "Constant Population Selector";
0097:
0098: public static final String S_GENETIC_OPERATORS = "Genetic operators";
0099:
0100: public static final String S_NATURAL_SELECTORS = "Natural Selectors";
0101:
0102: public static final String S_PRE = "pre";
0103:
0104: public static final String S_POST = "post";
0105:
0106: /**
0107: * Contains a bag of custom properties. Can be empty.
0108: * A custom property is such that is not included in the standard JGAP
0109: * configuration.
0110: *
0111: * @since 3.3.1
0112: */
0113: // private Map m_propertyBag;
0114: private ConfigurationConfigurable m_config = new ConfigurationConfigurable();
0115:
0116: /**
0117: * References the current fitness function that will be used to evaluate
0118: * chromosomes during the natural selection process. Note that only this
0119: * or the bulk fitness function may be set - the two are mutually exclusive.
0120: *
0121: * @author Neil Rotstan
0122: * @since 1.0
0123: */
0124: private FitnessFunction m_objectiveFunction;
0125:
0126: /**
0127: * The fitness evaluator. See interface class FitnessEvaluator for details.
0128: *
0129: * @since 2.0 (since 1.1 in class Genotype)
0130: */
0131: private FitnessEvaluator m_fitnessEvaluator;
0132:
0133: /**
0134: * Performs the evolution.
0135: */
0136: private IBreeder m_breeder;
0137:
0138: /**
0139: * Minimum size guaranteed for population. If zero or below then no ensurance.
0140: *
0141: * @author Klaus Meffert
0142: */
0143: private int m_minPercentageSizePopulation;
0144:
0145: /**
0146: * References the current bulk fitness function that will be used to
0147: * evaluate chromosomes (in bulk) during the natural selection
0148: * process. Note that only this or the normal fitness function
0149: * may be set - the two are mutually exclusive.
0150: *
0151: * @author Neil Rotstan
0152: * @since 1.0
0153: */
0154: private BulkFitnessFunction m_bulkObjectiveFunction;
0155:
0156: // /**
0157: // * If population size should be kept constant then this selector determines
0158: // * which of the chromosomes to select into the next generation.
0159: // *
0160: // * @author Klaus Meffert
0161: // * @since 3.2.2
0162: // */
0163: // private INaturalSelector m_popConstantSelector;
0164:
0165: /**
0166: * References a Chromosome that serves as a sample of the Gene setup
0167: * that is to be used. Each gene in the Chromosome should be represented
0168: * with the desired Gene type.
0169: *
0170: * @author Neil Rotstan
0171: * @since 1.0
0172: */
0173: private IChromosome m_sampleChromosome;
0174:
0175: /**
0176: * References the random number generator implementation that is to be
0177: * used for the generation of any random numbers during the various
0178: * genetic operations and processes.
0179: *
0180: * @author Neil Rotstan
0181: * @since 1.0
0182: */
0183: private RandomGenerator m_randomGenerator;
0184:
0185: /**
0186: * References the event manager that is to be used for the notification
0187: * of genetic events and the management of event subscribers.
0188: *
0189: * @author Neil Rotstan
0190: * @since 1.0
0191: */
0192: private IEventManager m_eventManager;
0193:
0194: /**
0195: * References the chromosome pool, if any, that is to be used to pool
0196: * discarded Chromosome instances so that they may be recycled later,
0197: * thereby saving memory and the time to construct them from scratch.
0198: *
0199: * @author Neil Rotstan
0200: * @since 1.0
0201: */
0202: private transient IChromosomePool m_chromosomePool;
0203:
0204: /**
0205: * Stores all of the GeneticOperator implementations that are to be used
0206: * to operate upon the chromosomes of a population prior to natural
0207: * selection. Operators will be executed in the order that they are
0208: * added to this list.
0209: *
0210: * @author Klaus Meffert
0211: * @since 1.1
0212: */
0213: private List m_geneticOperators;
0214:
0215: /**
0216: * The number of genes that will be stored in each chromosome in the
0217: * population.
0218: */
0219: private int m_chromosomeSize;
0220:
0221: /**
0222: * Indicates whether the settings of this Configuration instance have
0223: * been locked. Prior to locking, the settings may be set and reset
0224: * as desired. Once this flag is set to true, no settings may be
0225: * altered.
0226: */
0227: private boolean m_settingsLocked;
0228:
0229: /**
0230: * Ordered chain of NaturalSelector's which will be executed before applying
0231: * Genetic Operators.
0232: *
0233: * @author Klaus Meffert
0234: * @since 1.1
0235: */
0236: private ChainOfSelectors m_preSelectors;
0237:
0238: /**
0239: * Ordered chain of NaturalSelector's which will be executed after applying
0240: * Genetic Operators.
0241: *
0242: * @author Klaus Meffert
0243: * @since 1.1
0244: */
0245: private ChainOfSelectors m_postSelectors;
0246:
0247: /**
0248: * Should the fittest chromosome in the population be preserved to the next
0249: * generation when evolving (in Genotype.evolve()) ?
0250: */
0251: private boolean m_preserveFittestIndividual;
0252:
0253: /**
0254: * How many chromosomes should be selected from previous generation?
0255: * The missing chromosomes will be filled up with randomly created new
0256: * ones.
0257: * 1 = all
0258: */
0259: private double m_selectFromPrevGen;
0260:
0261: /**
0262: * Indicates how many times the evolve()-method in class Genotype has been
0263: * called. Represents the number of the current population.
0264: *
0265: * @author Klaus Meffert
0266: * @since 2.2
0267: */
0268: private int m_generationNr;
0269:
0270: /**
0271: * The Configuration handler for this Configurable.
0272: *
0273: * @author Siddhartha Azad
0274: * @since 2.3
0275: */
0276: private transient RootConfigurationHandler m_conHandler;
0277:
0278: /**
0279: * Informative name for output.
0280: *
0281: * @author Klaus Meffert
0282: * @since 2.3
0283: */
0284: private String m_name;
0285:
0286: /**
0287: * True: population size will be kept constant at specified size in
0288: * configuration. False: population size will grow dependently on used
0289: * NaturalSelector's and GeneticOperator's.
0290: * Default is TRUE
0291: *
0292: * @author Klaus Meffert
0293: * @since 2.4
0294: */
0295: private boolean m_keepPopulationSizeConstant;
0296:
0297: /**
0298: * Holds the central configurable factory for creating default objects.
0299: *
0300: * @author Klaus Meffert
0301: * @since 2.6
0302: */
0303: private IJGAPFactory m_factory;
0304:
0305: /**
0306: * See Chromosome class, field m_alwaysCalculate, for description
0307: *
0308: * @author Klaus Meffert
0309: * @since 3.2.2
0310: */
0311: private boolean m_alwaysCalculateFitness;
0312:
0313: private transient String threadKey;
0314:
0315: /**
0316: * Unique ID for a configuration to distinguish it from other configurations
0317: * instantiated within the same thread.
0318: *
0319: * @author Klaus Meffert
0320: * @since 3.01
0321: */
0322: private String m_id;
0323:
0324: public Configuration() {
0325: this ("", null);
0326: }
0327:
0328: /**
0329: * Initialize with default values.
0330: *
0331: * @param a_id unique id for the configuration within the current thread
0332: * @param a_name informative name of the configuration, may be null
0333: *
0334: * @author Neil Rotstan
0335: * @author Klaus Meffert
0336: * @since 1.0
0337: */
0338: public Configuration(String a_id, String a_name) {
0339: // m_propertyBag = new Hashtable();
0340: m_id = a_id;
0341: setName(a_name);
0342: makeThreadKey();
0343: m_preSelectors = new ChainOfSelectors(this );
0344: m_postSelectors = new ChainOfSelectors(this );
0345: m_selectFromPrevGen = 1.0d;
0346: // Use synchronized list for distributed computing.
0347: // ------------------------------------------------
0348: m_geneticOperators = new Vector();
0349: m_conHandler = new RootConfigurationHandler();
0350: m_conHandler.setConfigurable(this );
0351: m_keepPopulationSizeConstant = true;
0352: m_alwaysCalculateFitness = false;
0353: // Create factory for being able to configure the used default objects,
0354: // like random generators or fitness evaluators.
0355: // --------------------------------------------------------------------
0356: String clazz = System.getProperty(PROPERTY_JGAPFACTORY_CLASS);
0357: if (clazz != null && clazz.length() > 0) {
0358: try {
0359: m_factory = (IJGAPFactory) Class.forName(clazz)
0360: .newInstance();
0361: } catch (Throwable ex) {
0362: throw new RuntimeException("Class " + clazz
0363: + " could not be instantiated"
0364: + " as type IJGAPFactory", ex);
0365: }
0366: } else {
0367: m_factory = new JGAPFactory(false);
0368: }
0369: }
0370:
0371: /**
0372: * Constructs a configuration with an informative name but without a unique
0373: * ID. This practically prevents more than one configurations to be
0374: * instantiated within the same thread.
0375: *
0376: * @param a_name informative name of the configuration, may be null
0377: *
0378: * @author Klaus Meffert
0379: */
0380: public Configuration(final String a_name) {
0381: this ();
0382: setName(a_name);
0383: }
0384:
0385: /**
0386: * Reads in the configuration from the given file.
0387: *
0388: * @param a_configFileName the config file from which to load the
0389: * configuration
0390: * @param a_ignore just there to create distinct signatures :-(
0391: *
0392: * @throws ConfigException
0393: * @throws InvalidConfigurationException
0394: *
0395: * @author Siddhartha Azad
0396: * @since 2.3
0397: */
0398: public Configuration(final String a_configFileName, boolean a_ignore)
0399: throws ConfigException, InvalidConfigurationException {
0400: this ();
0401: ConfigFileReader.instance().setFileName(a_configFileName);
0402: // Set the configuration statically for constructing classes by the
0403: // default constructor.
0404: // ----------------------------------------------------------------
0405: Genotype.setStaticConfiguration(this );
0406: // Read in the config, thus creating instances of configurable classes
0407: // by invoking their default constructor.
0408: // -------------------------------------------------------------------
0409: getConfigurationHandler().readConfig();
0410: }
0411:
0412: /**
0413: * SHOULD NOT BE NECESSARY TO CALL UNDER NORMAL CIRCUMSTANCES. May be useful
0414: * for unit tests.<p>
0415: * Reset the configuration so that re-setting parameters such as fitness
0416: * function is possible (without calling this method, an overwriting of a
0417: * previously set fitness function results in a RuntimeException).
0418: *
0419: * @author Klaus Meffert
0420: * @since 3.0
0421: */
0422: public static void reset() {
0423: reset("");
0424: }
0425:
0426: /**
0427: * Reset the configuration so that re-setting parameters such as fitness
0428: * function is possible (without calling this method, an overwriting of a
0429: * previously set fitness function results in a RuntimeException).
0430: *
0431: * @param a_id a hopefully unique id of the configuration
0432: *
0433: * @author Klaus Meffert
0434: * @since 3.0
0435: */
0436: public static void reset(final String a_id) {
0437: String threadKey = getThreadKey(Thread.currentThread(), a_id);
0438: System.setProperty(threadKey
0439: + Configuration.PROPERTY_FITFUNC_INST, "");
0440: System.setProperty(threadKey
0441: + Configuration.PROPERTY_BFITFNC_INST, "");
0442: System.setProperty(threadKey
0443: + Configuration.PROPERTY_FITEVAL_INST, "");
0444: System.setProperty(threadKey
0445: + Configuration.PROPERTY_SAMPLE_CHROM_INST, "");
0446: System.setProperty(threadKey
0447: + Configuration.PROPERTY_EVENT_MGR_INST, "");
0448: }
0449:
0450: /**
0451: * See Configuration.reset().
0452: * @param a_propName the property to reset
0453: *
0454: * @author Klaus Meffert
0455: * @since 3.0
0456: */
0457: public static void resetProperty(final String a_propName) {
0458: resetProperty(a_propName, "");
0459: }
0460:
0461: public static void resetProperty(final String a_propName,
0462: final String a_id) {
0463: String threadKey = getThreadKey(Thread.currentThread(), a_id);
0464: System.setProperty(threadKey + a_propName, "");
0465: }
0466:
0467: /**
0468: * @param a_name informative name of the configuration
0469: *
0470: * @author Klaus Meffert
0471: * @since 2.3
0472: */
0473: public void setName(final String a_name) {
0474: m_name = a_name;
0475: }
0476:
0477: /**
0478: * @return informative name of the configuration
0479: *
0480: * @author Klaus Meffert
0481: * @since 2.3
0482: */
0483: public String getName() {
0484: return m_name;
0485: }
0486:
0487: /**
0488: * Sets the fitness function to be used for this genetic algorithm.
0489: * The fitness function is responsible for evaluating a given Chromosome and
0490: * returning a positive integer that represents its worth as a candidate
0491: * solution. These values are used as a guide by the natural to determine
0492: * which Chromosome instances will be allowed to move on to the next round of
0493: * evolution, and which will instead be eliminated.
0494: *
0495: * Note that it is illegal to set both this fitness function and a bulk
0496: * fitness function. Although one or the other must be set, the two are
0497: * mutually exclusive.
0498: *
0499: * @param a_functionToSet fitness function to be used
0500: *
0501: * @throws InvalidConfigurationException if the fitness function is null, a
0502: * bulk fitness function has already been set, or if this Configuration
0503: * object is locked.
0504: *
0505: * @author Neil Rotstan
0506: * @since 1.1
0507: */
0508: public synchronized void setFitnessFunction(
0509: final FitnessFunction a_functionToSet)
0510: throws InvalidConfigurationException {
0511: verifyChangesAllowed();
0512: // Sanity check: Make sure that the given fitness function isn't null.
0513: // -------------------------------------------------------------------
0514: if (a_functionToSet == null) {
0515: throw new InvalidConfigurationException(
0516: "The FitnessFunction instance may not be null.");
0517: }
0518: // Make sure the bulk fitness function hasn't already been set.
0519: // ------------------------------------------------------------
0520: if (m_bulkObjectiveFunction != null) {
0521: throw new InvalidConfigurationException(
0522: "The bulk fitness function and normal fitness function "
0523: + "may not both be set.");
0524: }
0525: // Ensure that no other fitness function has been set in a different
0526: // configuration object within the same thread!
0527: // -----------------------------------------------------------------
0528: checkProperty(PROPERTY_FITFUNC_INST, a_functionToSet,
0529: m_objectiveFunction,
0530: "Fitness function has already been set differently.");
0531: m_objectiveFunction = a_functionToSet;
0532: }
0533:
0534: /**
0535: * Verifies that a property is not set. If not set, set it, otherwise throw
0536: * a RuntimeException with a_errmsg as text.
0537: * @param a_propname the property to check (the current thread will be
0538: * considered as a part of the property's name, too)
0539: * @param a_obj the object that should be set in charge of the property
0540: * @param a_oldObj the old object that is set until now. Not used yet
0541: * @param a_errmsg the error message to throw in case the property is already
0542: * set for the current thread
0543: *
0544: * @author Klaus Meffert
0545: * @since 3.0
0546: */
0547: protected void checkProperty(final String a_propname,
0548: final Object a_obj, final Object a_oldObj,
0549: final String a_errmsg) {
0550: String instanceHash = System.getProperty(
0551: threadKey + a_propname, null);
0552: String key = makeKey(a_obj);
0553: if (instanceHash == null || instanceHash.length() < 1) {
0554: System.setProperty(threadKey + a_propname, key);
0555: } else if (!instanceHash.equals(key)) {
0556: throw new RuntimeException(a_errmsg
0557: + "\nIf you want to set or construct"
0558: + " a configuration multiple times, please call"
0559: + " static method Configuration.reset() before"
0560: + " each setting!");
0561: }
0562: }
0563:
0564: /**
0565: * @param a_obj the object to make a key for, must not be null
0566: * @return key produced for the object (hashCode() is used, so it should be
0567: * implemented properly!)
0568: *
0569: * @author Klaus Meffert
0570: * @since 3.0
0571: */
0572: protected String makeKey(final Object a_obj) {
0573: String key = String.valueOf(a_obj.hashCode())
0574: + a_obj.getClass().getName();
0575: return key;
0576: }
0577:
0578: /**
0579: * Retrieves the fitness function previously setup in this Configuration
0580: * object.
0581: *
0582: * @return the fitness function
0583: *
0584: * @author Neil Rotstan
0585: * @since 1.0
0586: */
0587: public synchronized FitnessFunction getFitnessFunction() {
0588: return m_objectiveFunction;
0589: }
0590:
0591: /**
0592: * Sets the bulk fitness function to be used for this genetic algorithm.
0593: * The bulk fitness function may be used to evaluate and assign fitness
0594: * values to the entire group of candidate Chromosomes in a single batch.
0595: * This can be useful in cases where it's difficult to assign fitness
0596: * values to a Chromosome in isolation from the other candidate
0597: * Chromosomes.
0598: * <p>
0599: * Note that it is illegal to set both a bulk fitness function and a
0600: * normal fitness function. Although one or the other is required, the
0601: * two are mutually exclusive.
0602: *
0603: * @param a_functionToSet bulk fitness function to be used
0604: *
0605: * @throws InvalidConfigurationException if the bulk fitness function is
0606: * null, the normal fitness function has already been set, or if this
0607: * Configuration object is locked
0608: *
0609: * @author Neil Rotstan
0610: * @author Klaus Meffert
0611: * @since 1.0
0612: */
0613: public synchronized void setBulkFitnessFunction(
0614: final BulkFitnessFunction a_functionToSet)
0615: throws InvalidConfigurationException {
0616: verifyChangesAllowed();
0617: // Sanity check: Make sure that the given bulk fitness function
0618: // isn't null.
0619: // ------------------------------------------------------------
0620: if (a_functionToSet == null) {
0621: throw new InvalidConfigurationException(
0622: "The BulkFitnessFunction instance may not be null.");
0623: }
0624: // Make sure a normal fitness function hasn't already been set.
0625: // ------------------------------------------------------------
0626: if (m_objectiveFunction != null) {
0627: throw new InvalidConfigurationException(
0628: "The bulk fitness function and normal fitness function "
0629: + "may not both be set.");
0630: }
0631: // Ensure that no other bulk fitness function has been set in a
0632: // different configuration object within the same thread!
0633: // ------------------------------------------------------------
0634: checkProperty(PROPERTY_BFITFNC_INST, a_functionToSet,
0635: m_bulkObjectiveFunction,
0636: "Bulk fitness function has already been set differently.");
0637: m_bulkObjectiveFunction = a_functionToSet;
0638: }
0639:
0640: /**
0641: * Retrieves the bulk fitness function previously setup in this
0642: * Configuration object.
0643: *
0644: * @return the bulk fitness function
0645: *
0646: * @author Neil Rotstan
0647: * @since 1.0
0648: */
0649: public synchronized BulkFitnessFunction getBulkFitnessFunction() {
0650: return m_bulkObjectiveFunction;
0651: }
0652:
0653: /**
0654: * Sets the sample Chromosome that is to be used as a guide for the
0655: * construction of other Chromosomes. The Chromosome should be setup
0656: * with each gene represented by the desired concrete Gene implementation
0657: * for that gene position (locus). Anytime a new Chromosome is created,
0658: * it will be constructed with the same Gene setup as that provided in
0659: * this sample Chromosome.
0660: *
0661: * @param a_sampleChromosomeToSet Chromosome to be used as the sample
0662: * @throws InvalidConfigurationException if the given Chromosome is null or
0663: * this Configuration object is locked
0664: *
0665: * @author Neil Rotstan
0666: * @since 1.0
0667: */
0668: public void setSampleChromosome(
0669: final IChromosome a_sampleChromosomeToSet)
0670: throws InvalidConfigurationException {
0671: verifyChangesAllowed();
0672: // Sanity check: Make sure that the given chromosome isn't null.
0673:
0674: // -----------------------------------------------------------
0675: if (a_sampleChromosomeToSet == null) {
0676: throw new InvalidConfigurationException(
0677: "The sample chromosome instance may not be null.");
0678: }
0679: if (a_sampleChromosomeToSet.getConfiguration() == null) {
0680: throw new InvalidConfigurationException(
0681: "The sample chromosome's configuration may not be null.");
0682: }
0683: // Ensure that no other sample chromosome has been set in a
0684: // different configuration object within the same thread!
0685: // --------------------------------------------------------
0686: checkProperty(PROPERTY_SAMPLE_CHROM_INST,
0687: a_sampleChromosomeToSet, m_sampleChromosome,
0688: "Sample chromosome has already been set differently.");
0689: m_sampleChromosome = a_sampleChromosomeToSet;
0690: m_chromosomeSize = m_sampleChromosome.size();
0691: }
0692:
0693: /**
0694: * Retrieves the sample Chromosome that contains the desired Gene setup
0695: * for each respective gene position (locus).
0696: *
0697: * @return sample Chromosome instance
0698: *
0699: * @author Neil Rotstan
0700: * @since 1.0
0701: */
0702: public IChromosome getSampleChromosome() {
0703: return m_sampleChromosome;
0704: }
0705:
0706: /**
0707: * Retrieves the chromosome size being used by this genetic
0708: * algorithm. This value is set automatically when the sample chromosome
0709: * is provided.
0710: *
0711: * @return chromosome size used in this configuration
0712: *
0713: * @author Neil Rotstan
0714: * @since 1.0
0715: */
0716: public int getChromosomeSize() {
0717: return m_chromosomeSize;
0718: }
0719:
0720: /**
0721: * Sets the natural selector to be used for this genetic algorithm.
0722: * The natural selector is responsible for actually selecting
0723: * which Chromosome instances are allowed to move on to the next
0724: * round of evolution (usually guided by the fitness values
0725: * provided by the fitness function). This setting is required.
0726: *
0727: * @param a_selectorToSet the natural selector to be used
0728: *
0729: * @throws InvalidConfigurationException if the natural selector is null or
0730: * this Configuration object is locked
0731: *
0732: * @author Neil Rotstan
0733: * @since 1.0
0734: * @deprecated use addNaturalSelector(false) instead
0735: */
0736: public synchronized void setNaturalSelector(
0737: final NaturalSelector a_selectorToSet)
0738: throws InvalidConfigurationException {
0739: addNaturalSelector(a_selectorToSet, false);
0740: }
0741:
0742: /**
0743: * Retrieves the natural selector setup in this Configuration instance.
0744: *
0745: * @return the natural selector
0746: *
0747: * @author Neil Rotstan
0748: * @since 1.0
0749: * @deprecated use getNaturalSelectors(true) or getNaturalSelectors(false)
0750: * to obtain the relevant chain of NaturalSelector's and then call the
0751: * chain's get(index) method
0752: */
0753: public synchronized NaturalSelector getNaturalSelector() {
0754: if (getNaturalSelectors(false).size() < 1) {
0755: return null;
0756: }
0757: return getNaturalSelectors(false).get(0);
0758: }
0759:
0760: /**
0761: * @param a_processBeforeGeneticOperators true: retrieve selector that is
0762: * registered to be executed before genetic operators, false: get the one
0763: * that is registered to be executed after genetic operators
0764: * @param a_index index of the selector to get
0765: * @return NaturalSelector
0766: *
0767: * @author Klaus Meffert
0768: * @since 1.1
0769: */
0770: public synchronized NaturalSelector getNaturalSelector(
0771: final boolean a_processBeforeGeneticOperators,
0772: final int a_index) {
0773: if (a_processBeforeGeneticOperators) {
0774: return m_preSelectors.get(a_index);
0775: } else {
0776: return m_postSelectors.get(a_index);
0777: }
0778: }
0779:
0780: /**
0781: * Only use for read-only access! Especially don't call clear() for the
0782: * returned ChainOfSelectors object!
0783: *
0784: * @param a_processBeforeGeneticOperators true: retrieve selector that is
0785: * registered to be executed before genetic operators, false: get the one
0786: * that is registered to be executed after genetic operators
0787: * @return ChainOfSelectors
0788: *
0789: * @author Klaus Meffert
0790: * @since 1.1
0791: */
0792: public ChainOfSelectors getNaturalSelectors(
0793: final boolean a_processBeforeGeneticOperators) {
0794: if (a_processBeforeGeneticOperators) {
0795: return m_preSelectors;
0796: } else {
0797: return m_postSelectors;
0798: }
0799: }
0800:
0801: /**
0802: * @param a_processBeforeGeneticOperators true: retrieve selector that is
0803: * registered to be executed before genetic operators, false: get the one
0804: * that is registered to be executed after genetic operators
0805: * @return size of selector list (distinct by a_processBeforeGeneticOperators)
0806: *
0807: * @author Klaus Meffert
0808: * @since 1.1
0809: */
0810: public int getNaturalSelectorsSize(
0811: final boolean a_processBeforeGeneticOperators) {
0812: if (a_processBeforeGeneticOperators) {
0813: return m_preSelectors.size();
0814: } else {
0815: return m_postSelectors.size();
0816: }
0817: }
0818:
0819: /**
0820: * Removes all natural selectors (either pre or post ones).
0821: *
0822: * @param a_processBeforeGeneticOperators true: remove all selectors
0823: * processed before genetic operators, false: remove the ones processed
0824: * afterwards
0825: *
0826: * @author Klaus Meffert
0827: * @since 2.3
0828: */
0829: public void removeNaturalSelectors(
0830: final boolean a_processBeforeGeneticOperators) {
0831: if (a_processBeforeGeneticOperators) {
0832: getNaturalSelectors(true).clear();
0833: } else {
0834: getNaturalSelectors(false).clear();
0835: }
0836: }
0837:
0838: /**
0839: * Sets the random generator to be used for this genetic algorithm.
0840: * The random generator is responsible for generating random numbers,
0841: * which are used throughout the process of genetic evolution and
0842: * selection. This setting is required.
0843: *
0844: * @param a_generatorToSet random generator to be used
0845: *
0846: * @throws InvalidConfigurationException if the random generator is null or
0847: * this object is locked
0848: *
0849: * @author Neil Rotstan
0850: * @since 1.0
0851: */
0852: public synchronized void setRandomGenerator(
0853: final RandomGenerator a_generatorToSet)
0854: throws InvalidConfigurationException {
0855: verifyChangesAllowed();
0856: // Sanity check: Make sure that the given random generator isn't null.
0857: // -------------------------------------------------------------------
0858: if (a_generatorToSet == null) {
0859: throw new InvalidConfigurationException(
0860: "The RandomGenerator instance may not be null.");
0861: }
0862: m_randomGenerator = a_generatorToSet;
0863: }
0864:
0865: /**
0866: * Retrieves the random generator setup in this Configuration instance.
0867: *
0868: * @return the random generator
0869: *
0870: * @author Neil Rotstan
0871: * @since 1.0
0872: */
0873: public synchronized RandomGenerator getRandomGenerator() {
0874: return m_randomGenerator;
0875: }
0876:
0877: /**
0878: * Adds a genetic operator for use in this algorithm. Genetic operators
0879: * represent evolutionary steps that, when combined, make up the
0880: * evolutionary process. Examples of genetic operators are reproduction,
0881: * crossover, and mutation. During the evolution process, all of the
0882: * genetic operators added via this method are invoked in the order
0883: * they were added. At least one genetic operator must be provided.
0884: *
0885: * @param a_operatorToAdd the genetic operator to add.
0886: *
0887: * @throws InvalidConfigurationException if the genetic operator is null or
0888: * if this Configuration object is locked
0889: *
0890: * @author Neil Rotstan
0891: * @since 1.0
0892: */
0893: public synchronized void addGeneticOperator(
0894: final GeneticOperator a_operatorToAdd)
0895: throws InvalidConfigurationException {
0896: verifyChangesAllowed();
0897: // Sanity check: Make sure that the given genetic operator isn't null.
0898: // -------------------------------------------------------------------
0899: if (a_operatorToAdd == null) {
0900: throw new InvalidConfigurationException(
0901: "The GeneticOperator instance may not be null.");
0902: }
0903: m_geneticOperators.add(a_operatorToAdd);
0904: }
0905:
0906: /**
0907: * Retrieves the genetic operators setup in this Configuration instance.
0908: * Note that once this Configuration instance is locked, a new, immutable list
0909: * of operators is used and any lists previously retrieved with this method
0910: * will no longer reflect the actual list in use.
0911: *
0912: * @return the list of genetic operators
0913: *
0914: * @author Neil Rotstan
0915: * @since 1.0
0916: */
0917: public List getGeneticOperators() {
0918: return m_geneticOperators;
0919: }
0920:
0921: /**
0922: * Sets the population size to be used for this genetic algorithm.
0923: * The population size is a fixed value that represents the
0924: * number of Chromosomes contained within the Genotype (population).
0925: * This setting is required.
0926: *
0927: * @param a_sizeOfPopulation population size to be used
0928: *
0929: * @throws InvalidConfigurationException if the population size is not
0930: * positive or this object is locked
0931: *
0932: * @author Neil Rotstan
0933: * @since 1.0
0934: */
0935: public synchronized void setPopulationSize(
0936: final int a_sizeOfPopulation)
0937: throws InvalidConfigurationException {
0938: verifyChangesAllowed();
0939: // Sanity check: Make sure the population size is positive.
0940: // --------------------------------------------------------
0941: if (a_sizeOfPopulation < 1) {
0942: throw new InvalidConfigurationException(
0943: "The population size must be positive.");
0944: }
0945: m_config.m_populationSize = a_sizeOfPopulation;
0946: }
0947:
0948: /**
0949: * Retrieves the population size setup in this Configuration instance.
0950: *
0951: * @return population size
0952: */
0953: public synchronized int getPopulationSize() {
0954: return m_config.m_populationSize;
0955: }
0956:
0957: /**
0958: * Sets the event manager that is to be associated with this configuration.
0959: * The event manager is responsible for the management of event subscribers
0960: * and event notifications.
0961: *
0962: * @param a_eventManagerToSet the EventManager instance to use in this
0963: * configuration
0964: *
0965: * @throws InvalidConfigurationException if the event manager is null
0966: * or this Configuration object is locked
0967: *
0968: * @author Neil Rotstan
0969: * @since 1.0
0970: */
0971: public void setEventManager(final IEventManager a_eventManagerToSet)
0972: throws InvalidConfigurationException {
0973: verifyChangesAllowed();
0974: // Sanity check: Make sure that the given event manager isn't null.
0975: // ----------------------------------------------------------------
0976: if (a_eventManagerToSet == null) {
0977: throw new InvalidConfigurationException(
0978: "The event manager instance may not be null.");
0979: }
0980: // Ensure that no other event manager has been set in a different
0981: // configuration object within the same thread!
0982: // --------------------------------------------------------------
0983: checkProperty(PROPERTY_EVENT_MGR_INST, a_eventManagerToSet,
0984: m_eventManager,
0985: "Event manager has already been set differently.");
0986: m_eventManager = a_eventManagerToSet;
0987: }
0988:
0989: /**
0990: * Retrieves the event manager associated with this configuration. The event
0991: * manager is responsible for the management of event subscribers
0992: * and event notifications.
0993: *
0994: * @return the actively configured event manager instance
0995: *
0996: * @since 1.0
0997: */
0998: public IEventManager getEventManager() {
0999: return m_eventManager;
1000: }
1001:
1002: /**
1003: * Sets the ChromosomePool that is to be associated with this
1004: * configuration. The ChromosomePool is used to pool discarded Chromosome
1005: * instances so that they may be recycled later, thereby saving memory and
1006: * the time to construct them from scratch. The presence of a ChromosomePool
1007: * is optional. If none exists, then a new Chromosome will be constructed
1008: * each time one is needed.
1009: *
1010: * @param a_chromosomePoolToSet the ChromosomePool instance to use
1011: * @throws InvalidConfigurationException if this object is locked
1012: *
1013: * @author Neil Rotstan
1014: * @since 1.0
1015: */
1016: public void setChromosomePool(
1017: final IChromosomePool a_chromosomePoolToSet)
1018: throws InvalidConfigurationException {
1019: verifyChangesAllowed();
1020: m_chromosomePool = a_chromosomePoolToSet;
1021: }
1022:
1023: /**
1024: * Retrieves the ChromosomePool instance, if any, that is associated with
1025: * this configuration. The ChromosomePool is used to pool discarded
1026: * Chromosome instances so that they may be recycled later, thereby
1027: * saving memory and the time to construct them from scratch. The presence
1028: * of a ChromosomePool instance is optional. If none exists, then new
1029: * Chromosomes should be constructed each time one is needed.
1030: *
1031: * @return the ChromosomePool instance associated this configuration, or
1032: * null if none has been provided
1033: *
1034: * @author Neil Rotstan
1035: * @since 1.0
1036: */
1037: public IChromosomePool getChromosomePool() {
1038: return m_chromosomePool;
1039: }
1040:
1041: /**
1042: * Locks all of the settings in this configuration object. Once
1043: * this method is successfully invoked, none of the settings may
1044: * be changed. There is no way to unlock this object once it is locked.
1045: * <p>
1046: * Prior to returning successfully, this method will first invoke the
1047: * verifyStateIsValid() method to make sure that any required configuration
1048: * options have been properly set. If it detects a problem, it will
1049: * throw an InvalidConfigurationException and leave the object unlocked.
1050: * <p>
1051: * It's possible to test whether this object is locked through the
1052: * isLocked() method.
1053: * <p>
1054: * It is ok to lock an object more than once. In that case, this method
1055: * does nothing and simply returns.
1056: *
1057: * @throws InvalidConfigurationException if this Configuration object is
1058: * in an invalid state at the time of invocation
1059: *
1060: * @author Neil Rotstan
1061: * @since 1.0
1062: */
1063: public synchronized void lockSettings()
1064: throws InvalidConfigurationException {
1065: if (!m_settingsLocked) {
1066: verifyStateIsValid();
1067: // // Make genetic operators list immutable.
1068: // // --------------------------------------
1069: // m_geneticOperators = Collections.unmodifiableList(m_geneticOperators);
1070: m_settingsLocked = true;
1071: }
1072: }
1073:
1074: /**
1075: * Retrieves the lock status of this object.
1076: *
1077: * @return true if this object has been locked by a previous successful
1078: * call to the lockSettings() method, false otherwise
1079: *
1080: * @author Neil Rotstan
1081: * @since 1.0
1082: */
1083: public boolean isLocked() {
1084: return m_settingsLocked;
1085: }
1086:
1087: /**
1088: * Tests the state of this Configuration object to make sure it's valid.
1089: * This generally consists of verifying that required settings have, in
1090: * fact, been set. If this object is not in a valid state, then an
1091: * exception will be thrown detailing the reason the state is not valid.
1092: *
1093: * @throws InvalidConfigurationException if the state of this Configuration
1094: * is not valid. The error message in the exception will detail the reason
1095: * for invalidity
1096: *
1097: * @author Neil Rotstan
1098: * @since 1.0
1099: */
1100: public synchronized void verifyStateIsValid()
1101: throws InvalidConfigurationException {
1102: // First, make sure all of the required fields have been set to
1103: // appropriate values.
1104: // ------------------------------------------------------------
1105: if (m_objectiveFunction == null
1106: && m_bulkObjectiveFunction == null) {
1107: throw new InvalidConfigurationException(
1108: "A desired fitness function or bulk fitness function must "
1109: + "be specified in the active configuration.");
1110: }
1111: if (m_sampleChromosome == null) {
1112: throw new InvalidConfigurationException(
1113: "A sample instance of the desired Chromosome "
1114: + "setup must be specified in the active configuration.");
1115: }
1116: if (m_preSelectors.size() == 0 && m_postSelectors.size() == 0) {
1117: throw new InvalidConfigurationException(
1118: "At least one desired natural selector must be specified in the"
1119: + " active configuration.");
1120: }
1121: if (m_randomGenerator == null) {
1122: throw new InvalidConfigurationException(
1123: "A desired random number generator must be specified in the "
1124: + "active configuration.");
1125: }
1126: if (m_eventManager == null) {
1127: throw new InvalidConfigurationException(
1128: "A desired event manager must be specified in the active "
1129: + "configuration.");
1130: }
1131: if (m_geneticOperators.isEmpty()) {
1132: throw new InvalidConfigurationException(
1133: "At least one genetic operator must be specified in the "
1134: + "configuration.");
1135: }
1136: if (m_chromosomeSize <= 0) {
1137: throw new InvalidConfigurationException(
1138: "A chromosome size greater than zero must be specified in "
1139: + "the active configuration.");
1140: }
1141: if (m_config.m_populationSize <= 0) {
1142: throw new InvalidConfigurationException(
1143: "A population size greater than zero must be specified in "
1144: + "the active configuration.");
1145: }
1146: if (m_fitnessEvaluator == null) {
1147: throw new IllegalArgumentException(
1148: "The fitness evaluator may not be null.");
1149: }
1150: // Next, it's critical that each Gene implementation in the sample
1151: // Chromosome has a working equals() method, or else the genetic
1152: // engine will end up failing in mysterious and unpredictable ways.
1153: // We therefore verify right here that this method is working properly
1154: // in each of the Gene implementations used in the sample Chromosome.
1155: // -------------------------------------------------------------------
1156: Gene[] sampleGenes = m_sampleChromosome.getGenes();
1157: for (int i = 0; i < sampleGenes.length; i++) {
1158: Gene sampleCopy = sampleGenes[i].newGene();
1159: sampleCopy.setAllele(sampleGenes[i].getAllele());
1160: if (!(sampleCopy.equals(sampleGenes[i]))) {
1161: throw new InvalidConfigurationException(
1162: "The sample Gene at gene position (locus) "
1163: + i
1164: + " does not appear to have a working equals() or compareTo()"
1165: + " method.\n"
1166: + "It could also be that you forgot to implement method"
1167: + " newGene() in your Gene implementation.\n"
1168: + "When tested, the method returned false when comparing "
1169: + "the sample gene with a gene of the same type and "
1170: + "possessing the same value (allele).");
1171: }
1172: }
1173: }
1174:
1175: /**
1176: * Makes sure that this Configuration object isn't locked. If it is, then
1177: * an exception is thrown with an appropriate message indicating
1178: * that settings in this object may not be altered. This method
1179: * should be invoked by any mutator method in this object prior
1180: * to making any state alterations.
1181: *
1182: * @throws InvalidConfigurationException if this Configuration object is
1183: * locked
1184: *
1185: * @author Neil Rotstan
1186: * @since 1.0
1187: */
1188: protected void verifyChangesAllowed()
1189: throws InvalidConfigurationException {
1190: if (m_settingsLocked) {
1191: throw new InvalidConfigurationException(
1192: "This Configuration object is locked. Settings may not be "
1193: + "altered.");
1194: }
1195: }
1196:
1197: /**
1198: * Adds a NaturalSelector to the ordered chain of registered
1199: * NaturalSelector's. It's possible to execute the NaturalSelector before
1200: * or after (registered) genetic operations have been applied.
1201: * @param a_selector the selector to be added to the chain
1202: * @param a_processBeforeGeneticOperators true: execute NaturalSelector
1203: * before any genetic operator will be applied, false: .. after..
1204: * @throws InvalidConfigurationException
1205: *
1206: * @author Klaus Meffert
1207: * @since 1.1
1208: */
1209: public void addNaturalSelector(NaturalSelector a_selector,
1210: boolean a_processBeforeGeneticOperators)
1211: throws InvalidConfigurationException {
1212: verifyChangesAllowed();
1213: if (a_processBeforeGeneticOperators) {
1214: m_preSelectors.addNaturalSelector(a_selector);
1215: } else {
1216: m_postSelectors.addNaturalSelector(a_selector);
1217: }
1218: }
1219:
1220: /**
1221: * Minimum size guaranteed for population. This is significant during
1222: * evolution as natural selectors could select fewer chromosomes for the next
1223: * generation than the initial population size was.
1224: * @param a_minimumSizeGuaranteedPercent if zero or below then no ensurance
1225: * for size given, see Genotype.evolve()
1226: *
1227: * @author Klaus Meffert
1228: */
1229: public void setMinimumPopSizePercent(
1230: int a_minimumSizeGuaranteedPercent) {
1231: m_minPercentageSizePopulation = a_minimumSizeGuaranteedPercent;
1232: }
1233:
1234: public int getMinimumPopSizePercent() {
1235: return m_minPercentageSizePopulation;
1236: }
1237:
1238: /**
1239: * @return the assigned FitnessEvaluator
1240: *
1241: * @author Klaus Meffert
1242: * @since 2.0
1243: */
1244: public FitnessEvaluator getFitnessEvaluator() {
1245: return m_fitnessEvaluator;
1246: }
1247:
1248: /**
1249: * Set the fitness evaluator (deciding if a given fitness value is better
1250: * when it's higher or better when it's lower).
1251: * @param a_fitnessEvaluator the FitnessEvaluator to be used
1252: *
1253: * @author Klaus Meffert
1254: * @since 2.0
1255: */
1256: public void setFitnessEvaluator(FitnessEvaluator a_fitnessEvaluator) {
1257: if (a_fitnessEvaluator == null) {
1258: throw new IllegalStateException(
1259: "The fitness evaluator object must not be null!");
1260: }
1261: // Ensure that no other fitness evaluator has been set in a
1262: // different configuration object within the same thread!
1263: // --------------------------------------------------------
1264: checkProperty(PROPERTY_FITEVAL_INST, a_fitnessEvaluator,
1265: m_fitnessEvaluator,
1266: "Fitness evaluator has already been set differently.");
1267: m_fitnessEvaluator = a_fitnessEvaluator;
1268: }
1269:
1270: /**
1271: * @return true: fittest chromosome should always be transferred to next
1272: * generation
1273: *
1274: * @author Klaus Meffert
1275: * @since 2.1
1276: */
1277: public boolean isPreserveFittestIndividual() {
1278: return m_preserveFittestIndividual;
1279: }
1280:
1281: /**
1282: * Determines whether to save (keep) the fittest individual.
1283: * @param a_preserveFittest true: always transfer fittest chromosome to next
1284: * generation
1285: *
1286: * @author Klaus Meffert
1287: * @since 2.1
1288: */
1289: public void setPreservFittestIndividual(boolean a_preserveFittest) {
1290: m_preserveFittestIndividual = a_preserveFittest;
1291: }
1292:
1293: public void incrementGenerationNr() {
1294: m_generationNr++;
1295: }
1296:
1297: public int getGenerationNr() {
1298: return m_generationNr;
1299: }
1300:
1301: /**
1302: * Implementation of the Configurable interface.
1303: * @return ConfigurationHandler
1304: * @throws ConfigException
1305: *
1306: * @author Siddhartha Azad
1307: */
1308: public ConfigurationHandler getConfigurationHandler() {
1309: return m_conHandler;
1310: }
1311:
1312: /**
1313: * @return string representation of the configuration containing all
1314: * configurable elements
1315: *
1316: * @author Klaus Meffert
1317: * @since 2.3
1318: */
1319: public String toString() {
1320: String result = S_CONFIGURATION + ":";
1321: // Basic parameters.
1322: // -----------------
1323: result += "\n " + S_CONFIGURATION_NAME + ": " + getName();
1324: result += "\n " + S_POPULATION_SIZE + ": "
1325: + getPopulationSize();
1326: result += "\n " + S_MINPOPSIZE + ": "
1327: + getMinimumPopSizePercent();
1328: result += "\n " + S_CHROMOSOME_SIZE + ": "
1329: + getChromosomeSize();
1330: // Sample chromosome.
1331: // ------------------
1332: result += "\n " + S_SAMPLE_CHROM + ":\n";
1333: if (getSampleChromosome() == null) {
1334: result += "\n null";
1335: } else {
1336: result += "\n " + S_SIZE + ": "
1337: + getSampleChromosome().size();
1338: result += "\n " + S_TOSTRING + ": "
1339: + getSampleChromosome().toString();
1340: }
1341: // Random generator.
1342: // -----------------
1343: result += "\n " + S_RANDOM_GENERATOR + ": ";
1344: if (getRandomGenerator() != null) {
1345: result += getRandomGenerator().getClass().getName();
1346: } else {
1347: result += S_NONE;
1348: }
1349: result += "\n " + S_EVENT_MANAGER + ": ";
1350: // Event manager.
1351: // --------------
1352: if (getEventManager() == null) {
1353: result += S_NONE;
1354: } else {
1355: result += getEventManager().getClass().getName();
1356: }
1357: // Configuration handler.
1358: // ----------------------
1359: result += "\n " + S_CONFIGURATION_HANDLER + ": ";
1360: if (getConfigurationHandler() == null) {
1361: result += "null";
1362: } else {
1363: result += getConfigurationHandler().getName();
1364: }
1365: // Fitness function.
1366: // -----------------
1367: result += "\n " + S_FITNESS_FUNCTION + ": ";
1368: if (getFitnessFunction() == null) {
1369: result += "null";
1370: } else {
1371: result += getFitnessFunction().getClass().getName();
1372: }
1373: // Fitness evaluator.
1374: // ------------------
1375: result += "\n " + S_FITNESS_EVALUATOR + ": ";
1376: if (getFitnessEvaluator() == null) {
1377: result += "null";
1378: } else {
1379: result += getFitnessEvaluator().getClass().getName();
1380: }
1381: // Genetic operators.
1382: // ------------------
1383: result += "\n " + S_GENETIC_OPERATORS + ": ";
1384: if (getGeneticOperators() == null) {
1385: result += "null";
1386: } else {
1387: int gensize = getGeneticOperators().size();
1388: if (gensize < 1) {
1389: result += S_NONE;
1390: } else {
1391: for (int i = 0; i < gensize; i++) {
1392: if (i > 0) {
1393: result += "; ";
1394: }
1395: result += " "
1396: + getGeneticOperators().get(i).getClass()
1397: .getName();
1398: }
1399: }
1400: }
1401: // Natural selectors (pre).
1402: // ------------------------
1403: int natsize = getNaturalSelectors(true).size();
1404: result += "\n " + S_NATURAL_SELECTORS + "(" + S_PRE + "): ";
1405: if (natsize < 1) {
1406: result += S_NONE;
1407: } else {
1408: for (int i = 0; i < natsize; i++) {
1409: if (i > 0) {
1410: result += "; ";
1411: }
1412: result += " "
1413: + getNaturalSelectors(true).get(i).getClass()
1414: .getName();
1415: }
1416: }
1417: // Natural selectors (post).
1418: // -------------------------
1419: natsize = getNaturalSelectors(false).size();
1420: result += "\n " + S_NATURAL_SELECTORS + "(" + S_POST + "): ";
1421: if (natsize < 1) {
1422: result += "none";
1423: } else {
1424: for (int i = 0; i < natsize; i++) {
1425: if (i > 0) {
1426: result += "; ";
1427: }
1428: result += " "
1429: + getNaturalSelectors(false).get(i).getClass()
1430: .getName();
1431: }
1432: }
1433: // String popSelector;
1434: // if (m_popConstantSelector == null) {
1435: // popSelector = "null";
1436: // }
1437: // else {
1438: // popSelector = m_popConstantSelector.getClass().getName();
1439: // }
1440: // result += "\n " + S_POPCONSTANT_SELECTOR + ": "
1441: // + popSelector;
1442: return result;
1443: }
1444:
1445: /**
1446: * See setKeepPopulationSizeConstant for description.
1447: * @return true: population size will always be the same size
1448: * (as given with Configuration.setPopulationSize(int)
1449: *
1450: * @author Klaus Meffert
1451: * @since 2.4
1452: */
1453: public boolean isKeepPopulationSizeConstant() {
1454: return m_keepPopulationSizeConstant;
1455: }
1456:
1457: /**
1458: * Allows to keep the population size constant after one evolution, even if
1459: * there is no appropriate instance of NaturalSelector (such as
1460: * WeightedRouletteSelector) registered with the Configuration.<p>
1461: * Be aware that keeping the population size constant often means that a
1462: * higher population size is necessary (e.g. for the MinimizingMakeChange
1463: * example)!
1464: * @param a_keepPopSizeConstant true: population size will always be
1465: * the same size (as given with Configuration.setPopulationSize(int)
1466: *
1467: * @author Klaus Meffert
1468: * @since 2.4
1469: */
1470: public void setKeepPopulationSizeConstant(
1471: boolean a_keepPopSizeConstant) {
1472: m_keepPopulationSizeConstant = a_keepPopSizeConstant;
1473: }
1474:
1475: public void setSelectFromPrevGen(double a_percentage) {
1476: if (a_percentage < 0 || a_percentage > 1.00) {
1477: throw new IllegalArgumentException(
1478: "Argument must be between 0 and 1");
1479: }
1480: m_selectFromPrevGen = a_percentage;
1481: }
1482:
1483: public double getSelectFromPrevGen() {
1484: return m_selectFromPrevGen;
1485: }
1486:
1487: /**
1488: * @return the JGAP factory registered
1489: *
1490: * @author Klaus Meffert
1491: */
1492: public IJGAPFactory getJGAPFactory() {
1493: return m_factory;
1494: }
1495:
1496: class ConfigurationConfigurable implements Serializable {
1497: /**
1498: * The number of chromosomes that will be stored in the Genotype.
1499: */
1500: int m_populationSize;
1501: }
1502:
1503: /**
1504: * Builds a string considering the current thread and the given id.
1505: *
1506: * @param current the current Thread
1507: * @param a_id a hopefully unique id of the configuration
1508: *
1509: * @return string built up
1510: *
1511: * @author Klaus Meffert
1512: * @since 3.01
1513: */
1514: protected static String getThreadKey(Thread current, String a_id) {
1515: return current.toString() + "|" + a_id + "|";
1516: }
1517:
1518: /**
1519: * @param a_factory the IJGAPFactory to use
1520: *
1521: * @author Klaus Meffert
1522: * @since 3.01
1523: */
1524: public void setJGAPFactory(IJGAPFactory a_factory) {
1525: m_factory = a_factory;
1526: }
1527:
1528: /**
1529: * @param a_breeder the breeder to use
1530: *
1531: * @author Klaus Meffert
1532: * @since 3.2
1533: */
1534: public void setBreeder(IBreeder a_breeder) {
1535: assert (a_breeder != null);
1536: m_breeder = a_breeder;
1537: }
1538:
1539: /**
1540: * @return the breeder set or new standard breeder instance in case no breeder
1541: * was set before.
1542: *
1543: * @author Klaus Meffert
1544: * @since 3.2
1545: */
1546: public IBreeder getBreeder() {
1547: if (m_breeder == null) {
1548: m_breeder = new GABreeder();
1549: }
1550: return m_breeder;
1551: }
1552:
1553: // /**
1554: // * If population size should be kept constant then this selector determines
1555: // * which of the chromosomes to select into the next generation.
1556: // *
1557: // * @param a_popConstantSelector the selector to use
1558: // * @throws InvalidConfigurationException
1559: // *
1560: // * @author Klaus Meffert
1561: // * @since 3.2.2
1562: // */
1563: // public void setKeepPopConstantSelector(INaturalSelector a_popConstantSelector)
1564: // throws InvalidConfigurationException {
1565: // verifyChangesAllowed();
1566: // m_popConstantSelector = a_popConstantSelector;
1567: // }
1568:
1569: // /**
1570: // * @return the registered selector to keep population size constant. If none
1571: // * is set, the NewestChromosomesSelector is instantiated, assigned and
1572: // * returned
1573: // *
1574: // * @throws InvalidConfigurationException
1575: // *
1576: // * @author Klaus Meffert
1577: // * @since 3.2.2
1578: // */
1579: // public INaturalSelector getKeepPopConstantSelector()
1580: // throws InvalidConfigurationException{
1581: // if (m_popConstantSelector == null) {
1582: // m_popConstantSelector = new NewestChromosomesSelector(this);
1583: // }
1584: // return m_popConstantSelector;
1585: // }
1586:
1587: /**
1588: * @param a_alwaysCalculate true: Chromosome.getFitnessValue() will always
1589: * (re-)calculate the fitness value. This may be necessary in case of
1590: * environments where the state changes without the chromosome to notice.
1591: *
1592: * @author Klaus Meffert
1593: * @since 3.2.2
1594: */
1595: public void setAlwaysCaculateFitness(boolean a_alwaysCalculate) {
1596: m_alwaysCalculateFitness = a_alwaysCalculate;
1597: }
1598:
1599: /**
1600: * @return true: Chromosome.getFitnessValue() will always (re-)calculate the
1601: * fitness value. This may be necessary in case of environments where the
1602: * state changes without the chromosome to notice.
1603: *
1604: * @author Klaus Meffert
1605: * @since 3.2.2
1606: */
1607: public boolean isAlwaysCalculateFitness() {
1608: return m_alwaysCalculateFitness;
1609: }
1610:
1611: protected String makeThreadKey() {
1612: Thread current = Thread.currentThread();
1613: threadKey = getThreadKey(current, m_id);
1614: return threadKey;
1615: }
1616:
1617: /**
1618: * Sets a property in the bag.
1619: *
1620: * Be aware that setting in unserializable value here leads to problems with
1621: * distributed computing or other scenarios based on serialization!
1622: *
1623: * Be aware that cloning may also lead to conflicts
1624: * in case you use unsupported object types!
1625: *
1626: * @param a_propName name of the property to se the value for
1627: * @param a_value value of the property
1628: *
1629: * @author Klaus Meffert
1630: * @since 3.3.1
1631: */
1632: // public void setPropertyInBag(String a_propName, Object a_value) {
1633: // m_propertyBag.put(a_propName, a_value);
1634: // }
1635: /**
1636: *
1637: * @param a_propName name of the property to retrieve the value from
1638: * @return value of the property
1639: *
1640: * @author Klaus Meffert
1641: * @since 3.3.1
1642: */
1643: // public Object getPropertyFromBag(String a_propName) {
1644: // return m_propertyBag.get(a_propName);
1645: // }
1646: /**
1647: * Deserialize the object. Needed to provide a unique ID for each thread the
1648: * object is used in.
1649: *
1650: * @param a_inputStream the ObjectInputStream provided for deserialzation
1651: * @throws ClassNotFoundException
1652: * @throws IOException
1653: *
1654: * @author Klaus Meffert
1655: * @since 3.01
1656: */
1657: private void readObject(ObjectInputStream a_inputStream)
1658: throws ClassNotFoundException, IOException {
1659: // Always perform the default de-serialization first.
1660: // --------------------------------------------------
1661: a_inputStream.defaultReadObject();
1662: makeThreadKey();
1663: }
1664:
1665: /**
1666: * @return the id of the configuration set
1667: *
1668: * @author Klaus Meffert
1669: * @since 3.1
1670: */
1671: public String getId() {
1672: return m_id;
1673: }
1674:
1675: /**
1676: * Only to be called by sub classes, such as GPConfiguration.
1677: *
1678: * @param a_id the id to set
1679: *
1680: * @author Klaus Meffert
1681: * @since 3.2
1682: */
1683: protected void setId(String a_id) {
1684: m_id = a_id;
1685: }
1686:
1687: /**
1688: * @return deep clone of this instance
1689: *
1690: * @author Klaus Meffert
1691: * @since 3.2
1692: */
1693: public Object clone() {
1694: return newInstance(m_id, m_name);
1695: }
1696:
1697: /**
1698: * Creates a new Configuration instance by cloning. Allows to preset the
1699: * ID and the name.
1700: *
1701: * @param a_id new ID for clone
1702: * @param a_name new name for clone
1703: * @return deep clone of this instance
1704: *
1705: * @author Klaus Meffert
1706: * @since 3.2
1707: */
1708: public Configuration newInstance(String a_id, String a_name) {
1709: try {
1710: Configuration result = new Configuration(m_name);
1711: // Clone JGAPFactory first because it helps in cloning other objects.
1712: // ------------------------------------------------------------------
1713: if (m_factory instanceof ICloneable) {
1714: result.m_factory = (IJGAPFactory) ((ICloneable) m_factory)
1715: .clone();
1716: } else {
1717: // We must fallback to a standardized solution.
1718: // --------------------------------------------
1719: m_factory = new JGAPFactory(false);
1720: result.m_factory = (IJGAPFactory) ((JGAPFactory) m_factory)
1721: .clone();
1722: }
1723: if (m_breeder != null) {
1724: result.m_breeder = (IBreeder) doClone(m_breeder);
1725: }
1726: if (m_bulkObjectiveFunction != null) {
1727: result.m_bulkObjectiveFunction = m_bulkObjectiveFunction;
1728: }
1729: result.m_chromosomeSize = m_chromosomeSize;
1730: // result.m_chromosomePool = m_chromosomePool.clone();
1731: // result.m_conHandler = m_conHandler.clone();
1732: result.m_eventManager = (IEventManager) doClone(m_eventManager);
1733: result.m_fitnessEvaluator = (FitnessEvaluator) doClone(m_fitnessEvaluator);
1734: result.m_generationNr = 0;
1735: result.m_geneticOperators = (List) doClone(m_geneticOperators);
1736: result.m_keepPopulationSizeConstant = m_keepPopulationSizeConstant;
1737: result.m_minPercentageSizePopulation = m_minPercentageSizePopulation;
1738: result.m_selectFromPrevGen = m_selectFromPrevGen;
1739: result.m_objectiveFunction = (FitnessFunction) doClone(m_objectiveFunction);
1740: // result.m_popConstantSelector = (INaturalSelector)doClone(m_popConstantSelector);
1741: result.m_postSelectors = (ChainOfSelectors) doClone(m_postSelectors);
1742: result.m_preSelectors = (ChainOfSelectors) doClone(m_preSelectors);
1743: result.m_preserveFittestIndividual = m_preserveFittestIndividual;
1744: result.m_randomGenerator = (RandomGenerator) doClone(m_randomGenerator);
1745: result.m_sampleChromosome = (IChromosome) m_sampleChromosome
1746: .clone();
1747: result.m_alwaysCalculateFitness = m_alwaysCalculateFitness;
1748: result.m_settingsLocked = m_settingsLocked;
1749: // result.m_propertyBag = (Map)doClone(m_propertyBag);
1750: // Configurable data.
1751: // ------------------
1752: result.m_config = new ConfigurationConfigurable();
1753: result.m_config.m_populationSize = m_config.m_populationSize;
1754: // Identificative data.
1755: // --------------------
1756: result.m_name = a_name;
1757: result.m_id = a_id;
1758: result.makeThreadKey();// Must be called after m_id is set
1759: return result;
1760: } catch (Throwable t) {
1761: throw new CloneException(t);
1762: }
1763: }
1764:
1765: /**
1766: * Helper called from clone.
1767: *
1768: * @param a_objToClone the object to clone
1769: * @return cloned object or null, if cloning not possible
1770: * @throws Exception
1771: *
1772: * @author Klaus Meffert
1773: * @since 3.2
1774: */
1775: protected Object doClone(Object a_objToClone) throws Exception {
1776: if (a_objToClone != null) {
1777: ICloneHandler handler = getJGAPFactory()
1778: .getCloneHandlerFor(a_objToClone, null);
1779: if (handler != null) {
1780: return handler.perform(a_objToClone, null, null);
1781: }
1782: }
1783: return null;
1784: }
1785:
1786: /**
1787: * The equals-method.
1788: *
1789: * @param a_other the other object to compare
1790: * @return true if seen as equal
1791: *
1792: * @author Klaus Meffert
1793: * @since 3.2
1794: */
1795: public boolean equals(Object a_other) {
1796: return compareTo(a_other) == 0;
1797: }
1798:
1799: /**
1800: * The compareTo-method.
1801: *
1802: * @param a_other the other object to compare
1803: * @return -1, 0, 1
1804: *
1805: * @author Klaus Meffert
1806: * @since 3.2
1807: */
1808: public int compareTo(Object a_other) {
1809: if (a_other == null) {
1810: return 1;
1811: } else {
1812: Configuration other = (Configuration) a_other;
1813: try {
1814: return new CompareToBuilder()
1815: .append(m_config.m_populationSize,
1816: other.m_config.m_populationSize)
1817: .append(m_factory, other.m_factory)
1818: .append(m_breeder, other.m_breeder)
1819: .append(m_objectiveFunction,
1820: other.m_objectiveFunction)
1821: .append(m_fitnessEvaluator,
1822: other.m_fitnessEvaluator)
1823: .append(m_bulkObjectiveFunction,
1824: other.m_bulkObjectiveFunction)
1825: .append(m_sampleChromosome,
1826: other.m_sampleChromosome)
1827: .append(m_randomGenerator,
1828: other.m_randomGenerator)
1829: // .append(m_eventManager, other.m_eventManager)
1830: // .append(m_chromosomePool, other.m_chromosomePool)
1831: .append(m_geneticOperators.toArray(),
1832: other.m_geneticOperators.toArray())
1833: .append(m_chromosomeSize,
1834: other.m_chromosomeSize)
1835: .append(m_preSelectors, other.m_preSelectors)
1836: .append(m_postSelectors, other.m_postSelectors)
1837: // .append(m_popConstantSelector, other.m_popConstantSelector)
1838: .append(m_preserveFittestIndividual,
1839: other.m_preserveFittestIndividual)
1840: // .append(m_conHandler, other.m_conHandler)
1841: .append(threadKey, other.threadKey).append(
1842: m_keepPopulationSizeConstant,
1843: other.m_keepPopulationSizeConstant)
1844: .append(m_alwaysCalculateFitness,
1845: other.m_alwaysCalculateFitness).append(
1846: m_minPercentageSizePopulation,
1847: other.m_minPercentageSizePopulation)
1848: .append(m_selectFromPrevGen,
1849: other.m_selectFromPrevGen).append(
1850: m_generationNr, other.m_generationNr)
1851: .append(m_name, other.m_name)
1852: // .append(m_propertyBag, other.m_propertyBag)
1853: .append(m_settingsLocked,
1854: other.m_settingsLocked).toComparison();
1855: } catch (ClassCastException cex) {
1856: throw new RuntimeException(
1857: "Cannot compare all objects within"
1858: + " org.jgap.Configuration, because at"
1859: + " least one does not implement interface"
1860: + " java.lang.Comparable!");
1861: }
1862: }
1863: }
1864:
1865: }
|