KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jgap > Configuration


1 /*
2  * This file is part of JGAP.
3  *
4  * JGAP offers a dual license model containing the LGPL as well as the MPL.
5  *
6  * For licencing information please see the file license.txt included with JGAP
7  * or have a look at the top of class org.jgap.Chromosome which representatively
8  * includes the JGAP license policy applicable for any file delivered with JGAP.
9  */

10 package org.jgap;
11
12 import java.io.*;
13 import java.util.*;
14 import org.jgap.data.config.*;
15 import org.jgap.event.*;
16 import org.jgap.impl.*;
17 import org.jgap.util.*;
18 import org.apache.commons.lang.builder.*;
19
20 /**
21  * The Configuration class represents the current configuration of
22  * plugins and parameters necessary to execute the genetic algorithm (such
23  * as fitness function, natural selector, genetic operators, and so on).
24  * <p>
25  * Note that, while during setup, the settings, flags, and other
26  * values may be set multiple times. But once the lockSettings() method
27  * is invoked, they cannot be changed. The default behavior of the
28  * Genotype constructor is to invoke this method, meaning that
29  * once a Configuration object is passed to a Genotype, it cannot
30  * be subsequently modified. There is no mechanism for unlocking
31  * the settings once they are locked.
32  * <p>
33  * Not all configuration options are required. See the documentation
34  * for each of the respective mutator methods to determine whether
35  * it is required to provide a value for that setting, and what the
36  * setting will default to if not.
37  *
38  * @author Neil Rotstan
39  * @author Klaus Meffert
40  * @since 1.0
41  */

42 public class Configuration
43     implements Configurable, Serializable, ICloneable, Comparable JavaDoc {
44   /** String containing the CVS revision. Read out via reflection!*/
45   private final static String JavaDoc CVS_REVISION = "$Revision: 1.76 $";
46
47   /**
48    * Constant for class name of JGAP Factory to use. Use as:
49    * System.setProperty(PROPERTY_JGAPFACTORY_CLASS, "myJGAPFactory");
50    * If none such property set, class JGAPFactory will be used.
51    */

52   public static final String JavaDoc PROPERTY_JGAPFACTORY_CLASS = "JGAPFACTORYCLASS";
53
54   public static final String JavaDoc PROPERTY_FITFUNC_INST = "JGAPFITFUNCINST";
55
56   public static final String JavaDoc PROPERTY_BFITFNC_INST = "JGAPBFITFNCINST";
57
58   public static final String JavaDoc PROPERTY_FITEVAL_INST = "JGAPFITEVALINST";
59
60   public static final String JavaDoc PROPERTY_SAMPLE_CHROM_INST = "JGAPSAMPLECHRMINST";
61
62   public static final String JavaDoc PROPERTY_EVENT_MGR_INST = "JGAPEVNTMGRINST";
63
64   /**
65    * Constants for toString()
66    */

67   public static final String JavaDoc S_CONFIGURATION = "Configuration";
68
69   public static final String JavaDoc S_CONFIGURATION_NAME = "Configuration name";
70
71   public static final String JavaDoc S_POPULATION_SIZE = "Population size";
72
73   public static final String JavaDoc S_MINPOPSIZE = "Minimum pop. size [%]";
74
75   public static final String JavaDoc S_CHROMOSOME_SIZE = "Chromosome size";
76
77   public static final String JavaDoc S_SAMPLE_CHROM = "Sample Chromosome";
78
79   public static final String JavaDoc S_SIZE = "Size";
80
81   public static final String JavaDoc S_TOSTRING = "toString";
82
83   public static final String JavaDoc S_RANDOM_GENERATOR = "Random generator";
84
85   public static final String JavaDoc S_EVENT_MANAGER = "Event manager";
86
87   public static final String JavaDoc S_NONE = "none";
88
89   public static final String JavaDoc S_CONFIGURATION_HANDLER = "Configuration handler";
90
91   public static final String JavaDoc S_FITNESS_FUNCTION = "Fitness function";
92
93   public static final String JavaDoc S_FITNESS_EVALUATOR = "Fitness evaluator";
94
95   public static final String JavaDoc S_GENETIC_OPERATORS = "Genetic operators";
96
97   public static final String JavaDoc S_NATURAL_SELECTORS = "Natural Selectors";
98
99   public static final String JavaDoc S_PRE = "pre";
100
101   public static final String JavaDoc S_POST = "post";
102
103   private ConfigurationConfigurable m_config = new ConfigurationConfigurable();
104
105   /**
106    * References the current fitness function that will be used to evaluate
107    * chromosomes during the natural selection process. Note that only this
108    * or the bulk fitness function may be set - the two are mutually exclusive.
109    *
110    * @author Neil Rotstan
111    * @since 1.0
112    */

113   private FitnessFunction m_objectiveFunction;
114
115   /**
116    * The fitness evaluator. See interface class FitnessEvaluator for details.
117    *
118    * @since 2.0 (since 1.1 in class Genotype)
119    */

120   private FitnessEvaluator m_fitnessEvaluator;
121
122   /**
123    * Minimum size guaranteed for population. If zero or below then no ensurance.
124    *
125    * @author Klaus Meffert
126    */

127   private int m_minPercentageSizePopulation;
128
129   /**
130    * References the current bulk fitness function that will be used to
131    * evaluate chromosomes (in bulk) during the natural selection
132    * process. Note that only this or the normal fitness function
133    * may be set - the two are mutually exclusive.
134    *
135    * @author Neil Rotstan
136    * @since 1.0
137    */

138   private BulkFitnessFunction m_bulkObjectiveFunction;
139
140   /**
141    * References a Chromosome that serves as a sample of the Gene setup
142    * that is to be used. Each gene in the Chromosome should be represented
143    * with the desired Gene type.
144    *
145    * @author Neil Rotstan
146    * @since 1.0
147    */

148   private IChromosome m_sampleChromosome;
149
150   /**
151    * References the random number generator implementation that is to be
152    * used for the generation of any random numbers during the various
153    * genetic operations and processes.
154    *
155    * @author Neil Rotstan
156    * @since 1.0
157    */

158   private RandomGenerator m_randomGenerator;
159
160   /**
161    * References the event manager that is to be used for the notification
162    * of genetic events and the management of event subscribers.
163    *
164    * @author Neil Rotstan
165    * @since 1.0
166    */

167   private /*transient*/ IEventManager m_eventManager;
168
169   /**
170    * References the chromosome pool, if any, that is to be used to pool
171    * discarded Chromosome instances so that they may be recycled later,
172    * thereby saving memory and the time to construct them from scratch.
173    *
174    * @author Neil Rotstan
175    * @since 1.0
176    */

177   private transient IChromosomePool m_chromosomePool;
178
179   /**
180    * Stores all of the GeneticOperator implementations that are to be used
181    * to operate upon the chromosomes of a population prior to natural
182    * selection. Operators will be executed in the order that they are
183    * added to this list.
184    *
185    * @author Klaus Meffert
186    * @since 1.1
187    */

188   private List m_geneticOperators;
189
190   /**
191    * The number of genes that will be stored in each chromosome in the
192    * population.
193    */

194   private int m_chromosomeSize;
195
196   /**
197    * Indicates whether the settings of this Configuration instance have
198    * been locked. Prior to locking, the settings may be set and reset
199    * as desired. Once this flag is set to true, no settings may be
200    * altered.
201    */

202   private boolean m_settingsLocked;
203
204   /**
205    * Ordered chain of NaturalSelector's which will be executed before applying
206    * Genetic Operators.
207    *
208    * @author Klaus Meffert
209    * @since 1.1
210    */

211   private ChainOfSelectors m_preSelectors;
212
213   /**
214    * Ordered chain of NaturalSelector's which will be executed after applying
215    * Genetic Operators.
216    *
217    * @author Klaus Meffert
218    * @since 1.1
219    */

220   private ChainOfSelectors m_postSelectors;
221
222   private int m_sizeNaturalSelectorsPre;
223
224   private int m_sizeNaturalSelectorsPost;
225
226   /**
227    * Should the fittest chromosome in the population be preserved to the next
228    * generation when evolving (in Genotype.evolve()) ?
229    */

230   private boolean m_preserveFittestIndividual;
231
232   /**
233    * Indicates how many times the evolve()-method in class Genotype has been
234    * called. Represents the number of the current population.
235    *
236    * @author Klaus Meffert
237    * @since 2.2
238    */

239   private int m_generationNr;
240
241   /**
242    * The Configuration Handler for this Configurable.
243    *
244    * @author Siddhartha Azad
245    * @since 2.3
246    */

247   private transient RootConfigurationHandler m_conHandler;
248
249   /**
250    * Informative name for output.
251    *
252    * @author Klaus Meffert
253    * @since 2.3
254    */

255   private String JavaDoc m_name;
256
257   /**
258    * True: population size will be kept constant at specified size in
259    * configuration. False: population size will grow dependently on used
260    * NaturalSelector's and GeneticOperator's.
261    * Default is TRUE
262    *
263    * @author Klaus Meffert
264    * @since 2.4
265    */

266   private boolean m_keepPopulationSizeConstant;
267
268   /**
269    * Holds the central configurable factory for creating default objects.
270    *
271    * @author Klaus Meffert
272    * @since 2.6
273    */

274   private transient IJGAPFactory m_factory;
275
276   private transient String JavaDoc threadKey;
277
278   /**
279    * Unique ID for a configuration to distinguish it from other configurations
280    * instantiated within the same thread.
281    *
282    * @author Klaus Meffert
283    * @since 3.01
284    */

285   private String JavaDoc m_id;
286
287   public Configuration() {
288     this("", null);
289   }
290
291   /**
292    * Initialize with default values.
293    *
294    * @param a_id unique id for the configuration within the current thread
295    * @param a_name informative name of the configuration, may be null
296    *
297    * @author Neil Rotstan
298    * @author Klaus Meffert
299    * @since 1.0
300    */

301   public Configuration(String JavaDoc a_id, String JavaDoc a_name) {
302     m_id = a_id;
303     setName(a_name);
304     makeThreadKey();
305     m_preSelectors = new ChainOfSelectors();
306     m_postSelectors = new ChainOfSelectors();
307     m_sizeNaturalSelectorsPre = 0;
308     m_sizeNaturalSelectorsPost = 0;
309     // use synchronized list for distributed computing
310
m_geneticOperators = new Vector();
311     m_conHandler = new RootConfigurationHandler();
312     m_conHandler.setConfigurable(this);
313     m_keepPopulationSizeConstant = true;
314     // Create factory for being able to configure the used default objects,
315
// like random generators or fitness evaluators.
316
// --------------------------------------------------------------------
317
String JavaDoc clazz = System.getProperty(PROPERTY_JGAPFACTORY_CLASS);
318     if (clazz != null && clazz.length() > 0) {
319       try {
320         m_factory = (IJGAPFactory) Class.forName(clazz).newInstance();
321       } catch (Throwable JavaDoc ex) {
322         throw new RuntimeException JavaDoc("Class " + clazz
323                                    + " could not be instantiated"
324                                    + " as type IJGAPFactory");
325       }
326     }
327     else {
328       m_factory = new JGAPFactory(false);
329     }
330   }
331
332   /**
333    * Constructs a configuration with an informative name but without a unique
334    * ID. This practically prevents more than one configurations to be
335    * instantiated within the same thread.
336    *
337    * @param a_name informative name of the configuration, may be null
338    *
339    * @author Klaus Meffert
340    */

341   public Configuration(final String JavaDoc a_name) {
342     this();
343     setName(a_name);
344   }
345
346   /**
347    * Reads in the configuration from the given file.
348    *
349    * @param a_configFileName the config file from which to load the
350    * configuration
351    * @param a_ignore just there to create distinct signatures :-(
352    *
353    * @throws ConfigException
354    * @throws InvalidConfigurationException
355    *
356    * @author Siddhartha Azad
357    * @since 2.3
358    */

359   public Configuration(final String JavaDoc a_configFileName, boolean a_ignore)
360       throws ConfigException, InvalidConfigurationException {
361     this();
362     ConfigFileReader.instance().setFileName(a_configFileName);
363     // Set the configuration statically for constructing classes by the
364
// default constructor.
365
// ----------------------------------------------------------------
366
Genotype.setStaticConfiguration(this);
367     // Read in the config, thus creating instances of configurable classes
368
// by invoking their default constructor.
369
// -------------------------------------------------------------------
370
getConfigurationHandler().readConfig();
371   }
372
373   /**
374    * SHOULD NOT BE NECESSARY TO CALL UNDER NORMAL CIRCUMSTANCES. May be useful
375    * for unit tests.<p>
376    * Reset the configuration so that re-setting parameters such as fitness
377    * function is possible (without calling this method, an overwriting of a
378    * previously set fitness function results in a RuntimeException).
379    *
380    * @author Klaus Meffert
381    * @since 3.0
382    */

383   public static void reset() {
384     reset("");
385   }
386
387   public static void reset(final String JavaDoc a_id) {
388     String JavaDoc threadKey = getThreadKey(Thread.currentThread(), a_id);
389     System.setProperty(threadKey + Configuration.PROPERTY_FITFUNC_INST, "");
390     System.setProperty(threadKey + Configuration.PROPERTY_BFITFNC_INST, "");
391     System.setProperty(threadKey + Configuration.PROPERTY_FITEVAL_INST, "");
392     System.setProperty(threadKey + Configuration.PROPERTY_SAMPLE_CHROM_INST, "");
393     System.setProperty(threadKey + Configuration.PROPERTY_EVENT_MGR_INST, "");
394   }
395
396   /**
397    * See Configuration.reset().
398    * @param a_propName the property to reset
399    *
400    * @author Klaus Meffert
401    * @since 3.0
402    */

403   public static void resetProperty(final String JavaDoc a_propName) {
404     resetProperty(a_propName, "");
405   }
406
407   public static void resetProperty(final String JavaDoc a_propName, final String JavaDoc a_id) {
408     String JavaDoc threadKey = getThreadKey(Thread.currentThread(), a_id);
409     System.setProperty(threadKey + a_propName, "");
410   }
411
412   /**
413    * @param a_name informative name of the configuration
414    *
415    * @author Klaus Meffert
416    * @since 2.3
417    */

418   public void setName(final String JavaDoc a_name) {
419     m_name = a_name;
420   }
421
422   /**
423    * @return informative name of the configuration
424    *
425    * @author Klaus Meffert
426    * @since 2.3
427    */

428   public String JavaDoc getName() {
429     return m_name;
430   }
431
432   /**
433    * Sets the fitness function to be used for this genetic algorithm.
434    * The fitness function is responsible for evaluating a given
435    * Chromosome and returning a positive integer that represents its
436    * worth as a candidate solution. These values are used as a guide by the
437    * natural to determine which Chromosome instances will be allowed to move
438    * on to the next round of evolution, and which will instead be eliminated.
439    * <p>
440    * Note that it is illegal to set both this fitness function and a bulk
441    * fitness function. Although one or the other must be set, the two are
442    * mutually exclusive.
443    *
444    * @param a_functionToSet fitness function to be used
445    *
446    * @throws InvalidConfigurationException if the fitness function is null, a
447    * bulk fitness function has already been set, or if this Configuration
448    * object is locked.
449    *
450    * @author Neil Rotstan
451    * @since 1.1
452    */

453   public synchronized void setFitnessFunction(final FitnessFunction
454       a_functionToSet)
455       throws InvalidConfigurationException {
456     verifyChangesAllowed();
457     // Sanity check: Make sure that the given fitness function isn't null.
458
// -------------------------------------------------------------------
459
if (a_functionToSet == null) {
460       throw new InvalidConfigurationException(
461           "The FitnessFunction instance may not be null.");
462     }
463     // Make sure the bulk fitness function hasn't already been set.
464
// ------------------------------------------------------------
465
if (m_bulkObjectiveFunction != null) {
466       throw new InvalidConfigurationException(
467           "The bulk fitness function and normal fitness function " +
468           "may not both be set.");
469     }
470     // Ensure that no other fitness function has been set in a different
471
// configuration object within the same thread!
472
// -----------------------------------------------------------------
473
checkProperty(PROPERTY_FITFUNC_INST, a_functionToSet,
474                   "Fitness function has already been set differently.");
475     m_objectiveFunction = a_functionToSet;
476   }
477
478   /**
479    * Verifies that a property is not set. If not set, set it, otherwise throw
480    * a RuntimeException with a_errmsg as text.
481    * @param a_propname the property to check (the current thread will be
482    * considered as a part of the property's name, too)
483    * @param a_obj the object that should be set in charge of the property
484    * @param a_errmsg the error message to throw in case the property is already
485    * set for the current thread
486    *
487    * @author Klaus Meffert
488    * @since 3.0
489    */

490   protected void checkProperty(final String JavaDoc a_propname, final Object JavaDoc a_obj,
491                                final String JavaDoc a_errmsg) {
492     String JavaDoc instanceHash = System.getProperty(threadKey + a_propname, null);
493     String JavaDoc key = makeKey(a_obj);
494     if (instanceHash == null || instanceHash.length() < 1) {
495       System.setProperty(threadKey + a_propname, key);
496     }
497     else if (!instanceHash.equals(key)) {
498       throw new RuntimeException JavaDoc(a_errmsg + "\nIf you want to set or construct"
499                                  +
500                                  " a configuration multiple times, please call"
501                                  +
502                                  " static method Configuration.reset() before"
503                                  + " each setting!");
504     }
505   }
506
507   /**
508    * @param a_obj the object to make a key for, must not be null
509    * @return key produced for the object (hashCode() is used, so it should be
510    * implemented properly!)
511    *
512    * @author Klaus Meffert
513    * @since 3.0
514    */

515   protected String JavaDoc makeKey(final Object JavaDoc a_obj) {
516     String JavaDoc key = String.valueOf(a_obj.hashCode())
517         + a_obj.getClass().getName();
518     return key;
519   }
520
521   /**
522    * Retrieves the fitness function previously setup in this Configuration
523    * object.
524    *
525    * @return the fitness function
526    *
527    * @author Neil Rotstan
528    * @since 1.0
529    */

530   public synchronized FitnessFunction getFitnessFunction() {
531     return m_objectiveFunction;
532   }
533
534   /**
535    * Sets the bulk fitness function to be used for this genetic algorithm.
536    * The bulk fitness function may be used to evaluate and assign fitness
537    * values to the entire group of candidate Chromosomes in a single batch.
538    * This can be useful in cases where it's difficult to assign fitness
539    * values to a Chromosome in isolation from the other candidate
540    * Chromosomes.
541    * <p>
542    * Note that it is illegal to set both a bulk fitness function and a
543    * normal fitness function. Although one or the other is required, the
544    * two are mutually exclusive.
545    *
546    * @param a_functionToSet bulk fitness function to be used
547    *
548    * @throws InvalidConfigurationException if the bulk fitness function is
549    * null, the normal fitness function has already been set, or if this
550    * Configuration object is locked
551    *
552    * @author Neil Rotstan
553    * @author Klaus Meffert
554    * @since 1.0
555    */

556   public synchronized void setBulkFitnessFunction(
557       final BulkFitnessFunction a_functionToSet)
558       throws InvalidConfigurationException {
559     verifyChangesAllowed();
560     // Sanity check: Make sure that the given bulk fitness function
561
// isn't null.
562
// ------------------------------------------------------------
563
if (a_functionToSet == null) {
564       throw new InvalidConfigurationException(
565           "The BulkFitnessFunction instance may not be null.");
566     }
567     // Make sure a normal fitness function hasn't already been set.
568
// ------------------------------------------------------------
569
if (m_objectiveFunction != null) {
570       throw new InvalidConfigurationException(
571           "The bulk fitness function and normal fitness function " +
572           "may not both be set.");
573     }
574     // Ensure that no other bulk fitness function has been set in a
575
// different configuration object within the same thread!
576
// ------------------------------------------------------------
577
checkProperty(PROPERTY_BFITFNC_INST, a_functionToSet,
578                   "Bulk fitness function has already been set differently.");
579     m_bulkObjectiveFunction = a_functionToSet;
580   }
581
582   /**
583    * Retrieves the bulk fitness function previously setup in this
584    * Configuration object.
585    *
586    * @return the bulk fitness function
587    *
588    * @author Neil Rotstan
589    * @since 1.0
590    */

591   public synchronized BulkFitnessFunction getBulkFitnessFunction() {
592     return m_bulkObjectiveFunction;
593   }
594
595   /**
596    * Sets the sample Chromosome that is to be used as a guide for the
597    * construction of other Chromosomes. The Chromosome should be setup
598    * with each gene represented by the desired concrete Gene implementation
599    * for that gene position (locus). Anytime a new Chromosome is created,
600    * it will be constructed with the same Gene setup as that provided in
601    * this sample Chromosome.
602    *
603    * @param a_sampleChromosomeToSet Chromosome to be used as the sample
604    * @throws InvalidConfigurationException if the given Chromosome is null or
605    * this Configuration object is locked
606    *
607    * @author Neil Rotstan
608    * @since 1.0
609    */

610   public void setSampleChromosome(final IChromosome a_sampleChromosomeToSet)
611       throws InvalidConfigurationException {
612     verifyChangesAllowed();
613     // Sanity check: Make sure that the given chromosome isn't null.
614

615     // -----------------------------------------------------------
616
if (a_sampleChromosomeToSet == null) {
617       throw new InvalidConfigurationException(
618           "The sample chromosome instance may not be null.");
619     }
620     if (a_sampleChromosomeToSet.getConfiguration() == null) {
621       throw new InvalidConfigurationException(
622           "The sample chromosome's configuration may not be null.");
623     }
624     // Ensure that no other sample chromosome has been set in a
625
// different configuration object within the same thread!
626
// --------------------------------------------------------
627
checkProperty(PROPERTY_SAMPLE_CHROM_INST, a_sampleChromosomeToSet,
628                   "Sample chromosome has already been set differently.");
629     m_sampleChromosome = a_sampleChromosomeToSet;
630     m_chromosomeSize = m_sampleChromosome.size();
631   }
632
633   /**
634    * Retrieves the sample Chromosome that contains the desired Gene setup
635    * for each respective gene position (locus).
636    *
637    * @return sample Chromosome instance
638    *
639    * @author Neil Rotstan
640    * @since 1.0
641    */

642   public IChromosome getSampleChromosome() {
643     return m_sampleChromosome;
644   }
645
646   /**
647    * Retrieves the chromosome size being used by this genetic
648    * algorithm. This value is set automatically when the sample chromosome
649    * is provided.
650    *
651    * @return chromosome size used in this configuration
652    *
653    * @author Neil Rotstan
654    * @since 1.0
655    */

656   public int getChromosomeSize() {
657     return m_chromosomeSize;
658   }
659
660   /**
661    * Sets the natural selector to be used for this genetic algorithm.
662    * The natural selector is responsible for actually selecting
663    * which Chromosome instances are allowed to move on to the next
664    * round of evolution (usually guided by the fitness values
665    * provided by the fitness function). This setting is required.
666    *
667    * @param a_selectorToSet the natural selector to be used
668    *
669    * @throws InvalidConfigurationException if the natural selector is null or
670    * this Configuration object is locked
671    *
672    * @author Neil Rotstan
673    * @since 1.0
674    * @deprecated use addNaturalSelector(false) instead
675    */

676   public synchronized void setNaturalSelector(final NaturalSelector
677       a_selectorToSet)
678       throws InvalidConfigurationException {
679     addNaturalSelector(a_selectorToSet, false);
680   }
681
682   /**
683    * Retrieves the natural selector setup in this Configuration instance.
684    *
685    * @return the natural selector
686    *
687    * @author Neil Rotstan
688    * @since 1.0
689    * @deprecated use getNaturalSelectors(true) or getNaturalSelectors(false)
690    * to obtain the relevant chain of NaturalSelector's and then call the
691    * chain's get(index) method
692    */

693   public synchronized NaturalSelector getNaturalSelector() {
694     if (m_sizeNaturalSelectorsPost < 1) {
695       return null;
696     }
697     return getNaturalSelectors(false).get(0);
698   }
699
700   /**
701    *
702    * @param a_processBeforeGeneticOperators boolean
703    * @param a_index int
704    * @return NaturalSelector
705    *
706    * @author Klaus Meffert
707    * @since 1.1
708    */

709   public synchronized NaturalSelector getNaturalSelector(final boolean
710       a_processBeforeGeneticOperators, final int a_index) {
711     if (a_processBeforeGeneticOperators) {
712       if (m_sizeNaturalSelectorsPre <= a_index) {
713         throw new IllegalArgumentException JavaDoc(
714             "Index of NaturalSelector out of bounds");
715       }
716       else {
717         return m_preSelectors.get(a_index);
718       }
719     }
720     else {
721       if (m_sizeNaturalSelectorsPost <= a_index) {
722         throw new IllegalArgumentException JavaDoc(
723             "Index of NaturalSelector out of bounds");
724       }
725       else {
726         return m_postSelectors.get(a_index);
727       }
728     }
729   }
730
731   /**
732    * Only use for read-only access! Especially don't call clear() for the
733    * returned ChainOfSelectors object!
734    * @param a_processBeforeGeneticOperators boolean
735    * @return ChainOfSelectors
736    *
737    * @author Klaus Meffert
738    * @since 1.1
739    */

740   public ChainOfSelectors getNaturalSelectors(final boolean
741       a_processBeforeGeneticOperators) {
742     if (a_processBeforeGeneticOperators) {
743       return m_preSelectors;
744     }
745     else {
746       return m_postSelectors;
747     }
748   }
749
750   /**
751    *
752    * @param a_processBeforeGeneticOperators boolean
753    * @return int
754    *
755    * @author Klaus Meffert
756    * @since 1.1
757    */

758   public int getNaturalSelectorsSize(final boolean
759                                      a_processBeforeGeneticOperators) {
760     if (a_processBeforeGeneticOperators) {
761       return m_sizeNaturalSelectorsPre;
762     }
763     else {
764       return m_sizeNaturalSelectorsPost;
765     }
766   }
767
768   /**
769    * Removes all natural selectors (either pre or post ones).
770    *
771    * @param a_processBeforeGeneticOperators true: remove all selectors
772    * processed before genetic operators, false: remove the ones processed
773    * afterwards
774    *
775    * @author Klaus Meffert
776    * @since 2.3
777    */

778   public void removeNaturalSelectors(final boolean
779                                      a_processBeforeGeneticOperators) {
780     if (a_processBeforeGeneticOperators) {
781       getNaturalSelectors(true).clear();
782       m_sizeNaturalSelectorsPre = 0;
783     }
784     else {
785       getNaturalSelectors(false).clear();
786       m_sizeNaturalSelectorsPost = 0;
787     }
788   }
789
790   /**
791    * Sets the random generator to be used for this genetic algorithm.
792    * The random generator is responsible for generating random numbers,
793    * which are used throughout the process of genetic evolution and
794    * selection. This setting is required.
795    *
796    * @param a_generatorToSet random generator to be used
797    *
798    * @throws InvalidConfigurationException if the random generator is null or
799    * this object is locked
800    *
801    * @author Neil Rotstan
802    * @since 1.0
803    */

804   public synchronized void setRandomGenerator(final RandomGenerator
805       a_generatorToSet)
806       throws InvalidConfigurationException {
807     verifyChangesAllowed();
808     // Sanity check: Make sure that the given random generator isn't null.
809
// -------------------------------------------------------------------
810
if (a_generatorToSet == null) {
811       throw new InvalidConfigurationException(
812           "The RandomGenerator instance may not be null.");
813     }
814     m_randomGenerator = a_generatorToSet;
815   }
816
817   /**
818    * Retrieves the random generator setup in this Configuration instance.
819    *
820    * @return the random generator
821    *
822    * @author Neil Rotstan
823    * @since 1.0
824    */

825   public synchronized RandomGenerator getRandomGenerator() {
826     return m_randomGenerator;
827   }
828
829   /**
830    * Adds a genetic operator for use in this algorithm. Genetic operators
831    * represent evolutionary steps that, when combined, make up the
832    * evolutionary process. Examples of genetic operators are reproduction,
833    * crossover, and mutation. During the evolution process, all of the
834    * genetic operators added via this method are invoked in the order
835    * they were added. At least one genetic operator must be provided.
836    *
837    * @param a_operatorToAdd the genetic operator to add.
838    *
839    * @throws InvalidConfigurationException if the genetic operator is null or
840    * if this Configuration object is locked
841    *
842    * @author Neil Rotstan
843    * @since 1.0
844    */

845   public synchronized void addGeneticOperator(final GeneticOperator
846       a_operatorToAdd)
847       throws InvalidConfigurationException {
848     verifyChangesAllowed();
849     // Sanity check: Make sure that the given genetic operator isn't null.
850
// -------------------------------------------------------------------
851
if (a_operatorToAdd == null) {
852       throw new InvalidConfigurationException(
853           "The GeneticOperator instance may not be null.");
854     }
855     m_geneticOperators.add(a_operatorToAdd);
856   }
857
858   /**
859    * Retrieves the genetic operators setup in this Configuration instance.
860    * Note that once this Configuration instance is locked, a new,
861    * immutable list of operators is used and any lists previously
862    * retrieved with this method will no longer reflect the actual
863    * list in use.
864    *
865    * @return the list of genetic operators
866    *
867    * @author Neil Rotstan
868    * @since 1.0
869    */

870   public List getGeneticOperators() {
871     return m_geneticOperators;
872   }
873
874   /**
875    * Sets the population size to be used for this genetic algorithm.
876    * The population size is a fixed value that represents the
877    * number of Chromosomes contained within the Genotype (population).
878    * This setting is required.
879    *
880    * @param a_sizeOfPopulation population size to be used
881    *
882    * @throws InvalidConfigurationException if the population size is not
883    * positive or this object is locked
884    *
885    * @author Neil Rotstan
886    * @since 1.0
887    */

888   public synchronized void setPopulationSize(final int a_sizeOfPopulation)
889       throws InvalidConfigurationException {
890     verifyChangesAllowed();
891     // Sanity check: Make sure the population size is positive.
892
// --------------------------------------------------------
893
if (a_sizeOfPopulation < 1) {
894       throw new InvalidConfigurationException(
895           "The population size must be positive.");
896     }
897     m_config.m_populationSize = a_sizeOfPopulation;
898   }
899
900   /**
901    * Retrieves the population size setup in this Configuration instance.
902    *
903    * @return population size
904    */

905   public synchronized int getPopulationSize() {
906     return m_config.m_populationSize;
907   }
908
909   /**
910    * Sets the event manager that is to be associated with this configuration.
911    * The event manager is responsible for the management of event subscribers
912    * and event notifications.
913    *
914    * @param a_eventManagerToSet the EventManager instance to use in this
915    * configuration
916    *
917    * @throws InvalidConfigurationException if the event manager is null
918    * or this Configuration object is locked
919    *
920    * @author Neil Rotstan
921    * @since 1.0
922    */

923   public void setEventManager(final IEventManager a_eventManagerToSet)
924       throws InvalidConfigurationException {
925     verifyChangesAllowed();
926     // Sanity check: Make sure that the given event manager isn't null.
927
// ----------------------------------------------------------------
928
if (a_eventManagerToSet == null) {
929       throw new InvalidConfigurationException(
930           "The event manager instance may not be null.");
931     }
932     // Ensure that no other event manager has been set in a different
933
// configuration object within the same thread!
934
// --------------------------------------------------------------
935
checkProperty(PROPERTY_EVENT_MGR_INST, a_eventManagerToSet,
936                   "Event manager has already been set differently.");
937     m_eventManager = a_eventManagerToSet;
938   }
939
940   /**
941    * Retrieves the event manager associated with this configuration. The event
942    * manager is responsible for the management of event subscribers
943    * and event notifications.
944    *
945    * @return the actively configured event manager instance
946    *
947    * @since 1.0
948    */

949   public IEventManager getEventManager() {
950     return m_eventManager;
951   }
952
953   /**
954    * Sets the ChromosomePool that is to be associated with this
955    * configuration. The ChromosomePool is used to pool discarded Chromosome
956    * instances so that they may be recycled later, thereby saving memory and
957    * the time to construct them from scratch. The presence of a ChromosomePool
958    * is optional. If none exists, then a new Chromosome will be constructed
959    * each time one is needed.
960    *
961    * @param a_chromosomePoolToSet the ChromosomePool instance to use
962    * @throws InvalidConfigurationException if this object is locked
963    *
964    * @author Neil Rotstan
965    * @since 1.0
966    */

967   public void setChromosomePool(final IChromosomePool a_chromosomePoolToSet)
968       throws InvalidConfigurationException {
969     verifyChangesAllowed();
970     m_chromosomePool = a_chromosomePoolToSet;
971   }
972
973   /**
974    * Retrieves the ChromosomePool instance, if any, that is associated with
975    * this configuration. The ChromosomePool is used to pool discarded
976    * Chromosome instances so that they may be recycled later, thereby
977    * saving memory and the time to construct them from scratch. The presence
978    * of a ChromosomePool instance is optional. If none exists, then new
979    * Chromosomes should be constructed each time one is needed.
980    *
981    * @return the ChromosomePool instance associated this configuration, or
982    * null if none has been provided
983    *
984    * @author Neil Rotstan
985    * @since 1.0
986    */

987   public IChromosomePool getChromosomePool() {
988     return m_chromosomePool;
989   }
990
991   /**
992    * Locks all of the settings in this configuration object. Once
993    * this method is successfully invoked, none of the settings may
994    * be changed. There is no way to unlock this object once it is locked.
995    * <p>
996    * Prior to returning successfully, this method will first invoke the
997    * verifyStateIsValid() method to make sure that any required configuration
998    * options have been properly set. If it detects a problem, it will
999    * throw an InvalidConfigurationException and leave the object unlocked.
1000   * <p>
1001   * It's possible to test whether this object is locked through the
1002   * isLocked() method.
1003   * <p>
1004   * It is ok to lock an object more than once. In that case, this method
1005   * does nothing and simply returns.
1006   *
1007   * @throws InvalidConfigurationException if this Configuration object is
1008   * in an invalid state at the time of invocation
1009   *
1010   * @author Neil Rotstan
1011   * @since 1.0
1012   */

1013  public synchronized void lockSettings()
1014      throws InvalidConfigurationException {
1015    if (!m_settingsLocked) {
1016      verifyStateIsValid();
1017      // Make genetic operators list immutable.
1018
// --------------------------------------
1019
m_geneticOperators = Collections.unmodifiableList(m_geneticOperators);
1020      m_settingsLocked = true;
1021    }
1022  }
1023
1024  /**
1025   * Retrieves the lock status of this object.
1026   *
1027   * @return true if this object has been locked by a previous successful
1028   * call to the lockSettings() method, false otherwise
1029   *
1030   * @author Neil Rotstan
1031   * @since 1.0
1032   */

1033  public boolean isLocked() {
1034    return m_settingsLocked;
1035  }
1036
1037  /**
1038   * Tests the state of this Configuration object to make sure it's valid.
1039   * This generally consists of verifying that required settings have, in
1040   * fact, been set. If this object is not in a valid state, then an
1041   * exception will be thrown detailing the reason the state is not valid.
1042   *
1043   * @throws InvalidConfigurationException if the state of this Configuration
1044   * is not valid. The error message in the exception will detail the reason
1045   * for invalidity
1046   *
1047   * @author Neil Rotstan
1048   * @since 1.0
1049   */

1050  public synchronized void verifyStateIsValid()
1051      throws InvalidConfigurationException {
1052    // First, make sure all of the required fields have been set to
1053
// appropriate values.
1054
// ------------------------------------------------------------
1055
if (m_objectiveFunction == null && m_bulkObjectiveFunction == null) {
1056      throw new InvalidConfigurationException(
1057          "A desired fitness function or bulk fitness function must " +
1058          "be specified in the active configuration.");
1059    }
1060    if (m_sampleChromosome == null) {
1061      throw new InvalidConfigurationException(
1062          "A sample instance of the desired Chromosome " +
1063          "setup must be specified in the active configuration.");
1064    }
1065    if (m_preSelectors.size() == 0 && m_postSelectors.size() == 0) {
1066      throw new InvalidConfigurationException(
1067          "At least one desired natural selector must be specified in the"
1068          + " active configuration.");
1069    }
1070    if (m_randomGenerator == null) {
1071      throw new InvalidConfigurationException(
1072          "A desired random number generator must be specified in the " +
1073          "active configuration.");
1074    }
1075    if (m_eventManager == null) {
1076      throw new InvalidConfigurationException(
1077          "A desired event manager must be specified in the active " +
1078          "configuration.");
1079    }
1080    if (m_geneticOperators.isEmpty()) {
1081      throw new InvalidConfigurationException(
1082          "At least one genetic operator must be specified in the " +
1083          "configuration.");
1084    }
1085    if (m_chromosomeSize <= 0) {
1086      throw new InvalidConfigurationException(
1087          "A chromosome size greater than zero must be specified in " +
1088          "the active configuration.");
1089    }
1090    if (m_config.m_populationSize <= 0) {
1091      throw new InvalidConfigurationException(
1092          "A genotype size greater than zero must be specified in " +
1093          "the active configuration.");
1094    }
1095    if (m_fitnessEvaluator == null) {
1096      throw new IllegalArgumentException JavaDoc(
1097          "The fitness evaluator may not be null.");
1098    }
1099    // Next, it's critical that each Gene implementation in the sample
1100
// Chromosome has a working equals() method, or else the genetic
1101
// engine will end up failing in mysterious and unpredictable ways.
1102
// We therefore verify right here that this method is working properly
1103
// in each of the Gene implementations used in the sample Chromosome.
1104
// -------------------------------------------------------------------
1105
Gene[] sampleGenes = m_sampleChromosome.getGenes();
1106    for (int i = 0; i < sampleGenes.length; i++) {
1107      Gene sampleCopy = sampleGenes[i].newGene();
1108      sampleCopy.setAllele(sampleGenes[i].getAllele());
1109      if (! (sampleCopy.equals(sampleGenes[i]))) {
1110        throw new InvalidConfigurationException(
1111            "The sample Gene at gene position (locus) "
1112            + i
1113            + " does not appear to have a working equals() or compareTo()"
1114            + " method.\n"
1115            + "It could also be that you forgot to implement method"
1116            + " newGene() in your Gene implementation.\n"
1117            + "When tested, the method returned false when comparing "
1118            + "the sample gene with a gene of the same type and "
1119            + "possessing the same value (allele).");
1120      }
1121    }
1122  }
1123
1124  /**
1125   * Makes sure that this Configuration object isn't locked. If it is, then
1126   * an exception is thrown with an appropriate message indicating
1127   * that settings in this object may not be altered. This method
1128   * should be invoked by any mutator method in this object prior
1129   * to making any state alterations.
1130   *
1131   * @throws InvalidConfigurationException if this Configuration object is
1132   * locked
1133   *
1134   * @author Neil Rotstan
1135   * @since 1.0
1136   */

1137  protected void verifyChangesAllowed()
1138      throws InvalidConfigurationException {
1139    if (m_settingsLocked) {
1140      throw new InvalidConfigurationException(
1141          "This Configuration object is locked. Settings may not be " +
1142          "altered.");
1143    }
1144  }
1145
1146  /**
1147   * Adds a NaturalSelector to the ordered chain of registered
1148   * NaturalSelector's. It's possible to execute the NaturalSelector before
1149   * or after (registered) genetic operations have been applied.
1150   * @param a_selector the selector to be added to the chain
1151   * @param a_processBeforeGeneticOperators true: execute NaturalSelector
1152   * before any genetic operator will be applied, false: .. after..
1153   * @throws InvalidConfigurationException
1154   *
1155   * @author Klaus Meffert
1156   * @since 1.1
1157   */

1158  public void addNaturalSelector(NaturalSelector a_selector,
1159                                 boolean a_processBeforeGeneticOperators)
1160      throws InvalidConfigurationException {
1161    verifyChangesAllowed();
1162    if (a_processBeforeGeneticOperators) {
1163      m_preSelectors.addNaturalSelector(a_selector);
1164      m_sizeNaturalSelectorsPre = m_preSelectors.size();
1165    }
1166    else {
1167      m_postSelectors.addNaturalSelector(a_selector);
1168      m_sizeNaturalSelectorsPost = m_postSelectors.size();
1169    }
1170  }
1171
1172  /**
1173   * Minimum size guaranteed for population. This is significant during
1174   * evolution as natural selectors could select fewer chromosomes for the next
1175   * generation than the initial population size was.
1176   * @param a_minimumSizeGuaranteedPercent if zero or below then no ensurance
1177   * for size given, see Genotype.evolve()
1178   *
1179   * @author Klaus Meffert
1180   */

1181  public void setMinimumPopSizePercent(int a_minimumSizeGuaranteedPercent) {
1182    m_minPercentageSizePopulation = a_minimumSizeGuaranteedPercent;
1183  }
1184
1185  public int getMinimumPopSizePercent() {
1186    return m_minPercentageSizePopulation;
1187  }
1188
1189  /**
1190   * @return the assigned FitnessEvaluator
1191   *
1192   * @author Klaus Meffert
1193   * @since 2.0
1194   */

1195  public FitnessEvaluator getFitnessEvaluator() {
1196    return m_fitnessEvaluator;
1197  }
1198
1199  /**
1200   * Set the fitness evaluator (deciding if a given fitness value is better
1201   * when it's higher or better when it's lower).
1202   * @param a_fitnessEvaluator the FitnessEvaluator to be used
1203   *
1204   * @author Klaus Meffert
1205   * @since 2.0
1206   */

1207  public void setFitnessEvaluator(FitnessEvaluator a_fitnessEvaluator) {
1208    if (a_fitnessEvaluator == null) {
1209      throw new IllegalStateException JavaDoc(
1210          "The fitness evaluator object must not be null!");
1211    }
1212    // Ensure that no other fitness evaluator has been set in a
1213
// different configuration object within the same thread!
1214
// --------------------------------------------------------
1215
checkProperty(PROPERTY_FITEVAL_INST, a_fitnessEvaluator,
1216                  "Fitness evaluator has already been set differently.");
1217    m_fitnessEvaluator = a_fitnessEvaluator;
1218  }
1219
1220  /**
1221   * @return true: fittest chromosome should always be transferred to next
1222   * generation
1223   *
1224   * @author Klaus Meffert
1225   * @since 2.1
1226   */

1227  public boolean isPreserveFittestIndividual() {
1228    return m_preserveFittestIndividual;
1229  }
1230
1231  /**
1232   * Determines whether to save (keep) the fittest individual.
1233   * @param a_preserveFittest true: always transfer fittest chromosome to next
1234   * generation
1235   *
1236   * @author Klaus Meffert
1237   * @since 2.1
1238   */

1239  public void setPreservFittestIndividual(boolean a_preserveFittest) {
1240    m_preserveFittestIndividual = a_preserveFittest;
1241  }
1242
1243  public void incrementGenerationNr() {
1244    m_generationNr++;
1245  }
1246
1247  public int getGenerationNr() {
1248    return m_generationNr;
1249  }
1250
1251  /**
1252   * Implementation of the Configurable interface.
1253   * @return ConfigurationHandler
1254   * @throws ConfigException
1255   *
1256   * @author Siddhartha Azad
1257   */

1258  public ConfigurationHandler getConfigurationHandler() {
1259    return m_conHandler;
1260  }
1261
1262  /**
1263   * @return string representation of the configuration containing all
1264   * configurable elements
1265   *
1266   * @author Klaus Meffert
1267   * @since 2.3
1268   */

1269  public String JavaDoc toString() {
1270    String JavaDoc result = S_CONFIGURATION + ":";
1271    // Basic parameters.
1272
// -----------------
1273
result += "\n " + S_CONFIGURATION_NAME + ": " + getName();
1274    result += "\n " + S_POPULATION_SIZE + ": " + getPopulationSize();
1275    result += "\n " + S_MINPOPSIZE + ": " + getMinimumPopSizePercent();
1276    result += "\n " + S_CHROMOSOME_SIZE + ": " + getChromosomeSize();
1277    // Sample chromosome.
1278
// ------------------
1279
result += "\n " + S_SAMPLE_CHROM + ":\n";
1280    if (getSampleChromosome() == null) {
1281      result += "\n null";
1282    }
1283    else {
1284      result += "\n " + S_SIZE + ": " + getSampleChromosome().size();
1285      result += "\n " + S_TOSTRING + ": " + getSampleChromosome().toString();
1286    }
1287    // Random generator.
1288
// -----------------
1289
result += "\n " + S_RANDOM_GENERATOR + ": ";
1290    if (getRandomGenerator() != null) {
1291      result += getRandomGenerator().getClass().getName();
1292    }
1293    else {
1294      result += S_NONE;
1295    }
1296    result += "\n " + S_EVENT_MANAGER + ": ";
1297    // Event manager.
1298
// --------------
1299
if (getEventManager() == null) {
1300      result += S_NONE;
1301    }
1302    else {
1303      result += getEventManager().getClass().getName();
1304    }
1305    // Configuration handler.
1306
// ----------------------
1307
result += "\n " + S_CONFIGURATION_HANDLER + ": ";
1308    if (getConfigurationHandler() == null) {
1309      result += "null";
1310    }
1311    else {
1312      result += getConfigurationHandler().getName();
1313    }
1314    // Fitness function.
1315
// -----------------
1316
result += "\n " + S_FITNESS_FUNCTION + ": ";
1317    if (getFitnessFunction() == null) {
1318      result += "null";
1319    }
1320    else {
1321      result += getFitnessFunction().getClass().getName();
1322    }
1323    // Fitness evaluator.
1324
// ------------------
1325
result += "\n " + S_FITNESS_EVALUATOR + ": ";
1326    if (getFitnessEvaluator() == null) {
1327      result += "null";
1328    }
1329    else {
1330      result += getFitnessEvaluator().getClass().getName();
1331    }
1332    // Genetic operators.
1333
// ------------------
1334
result += "\n " + S_GENETIC_OPERATORS + ": ";
1335    if (getGeneticOperators() == null) {
1336      result += "null";
1337    }
1338    else {
1339      int gensize = getGeneticOperators().size();
1340      if (gensize < 1) {
1341        result += S_NONE;
1342      }
1343      else {
1344        for (int i = 0; i < gensize; i++) {
1345          if (i > 0) {
1346            result += "; ";
1347          }
1348          result += " " + getGeneticOperators().get(i).getClass().getName();
1349        }
1350      }
1351    }
1352    // Natural selectors (pre).
1353
// ------------------------
1354
int natsize = getNaturalSelectors(true).size();
1355    result += "\n " + S_NATURAL_SELECTORS + "(" + S_PRE + "): ";
1356    if (natsize < 1) {
1357      result += S_NONE;
1358    }
1359    else {
1360      for (int i = 0; i < natsize; i++) {
1361        if (i > 0) {
1362          result += "; ";
1363        }
1364        result += " " + getNaturalSelectors(true).get(i).getClass().getName();
1365      }
1366    }
1367    // Natural selectors (post).
1368
// -------------------------
1369
natsize = getNaturalSelectors(false).size();
1370    result += "\n " + S_NATURAL_SELECTORS + "(" + S_POST + "): ";
1371    if (natsize < 1) {
1372      result += "none";
1373    }
1374    else {
1375      for (int i = 0; i < natsize; i++) {
1376        if (i > 0) {
1377          result += "; ";
1378        }
1379        result += " " + getNaturalSelectors(false).get(i).getClass().getName();
1380      }
1381    }
1382    return result;
1383  }
1384
1385  /**
1386   * See setKeepPopulationSizeConstant for description.
1387   * @return true: population size will always be the same size
1388   * (as given with Configuration.setPopulationSize(int)
1389   *
1390   * @author Klaus Meffert
1391   * @since 2.4
1392   */

1393  public boolean isKeepPopulationSizeConstant() {
1394    return m_keepPopulationSizeConstant;
1395  }
1396
1397  /**
1398   * Allows to keep the population size constant after one evolution, even if
1399   * there is no appropriate instance of NaturalSelector (such as
1400   * WeightedRouletteSelector) registered with the Configuration.<p>
1401   * Be aware that keeping the population size constant often means that a
1402   * higher population size is necessary (e.g. for the MinimizingMakeChange
1403   * example)!
1404   * @param a_keepPopSizeConstant true: population size will always be
1405   * the same size (as given with Configuration.setPopulationSize(int)
1406   *
1407   * @author Klaus Meffert
1408   * @since 2.4
1409   */

1410  public void setKeepPopulationSizeConstant(boolean a_keepPopSizeConstant) {
1411    m_keepPopulationSizeConstant = a_keepPopSizeConstant;
1412  }
1413
1414  public IJGAPFactory getJGAPFactory() {
1415    return m_factory;
1416  }
1417
1418  class ConfigurationConfigurable
1419      implements Serializable {
1420    /**
1421     * The number of chromosomes that will be stored in the Genotype.
1422     */

1423    int m_populationSize;
1424  }
1425  /**
1426   * Builds a string considering the current thread and the given id.
1427   *
1428   * @param current the current Thread
1429   * @param a_id a hopefully unique id of the configuration
1430   *
1431   * @return string built up
1432   *
1433   * @author Klaus Meffert
1434   * @since 3.01
1435   */

1436  protected static String JavaDoc getThreadKey(Thread JavaDoc current, String JavaDoc a_id) {
1437    return current.toString() + "|" + a_id + "|";
1438  }
1439
1440  /**
1441   * @param a_factory the IJGAPFactory to use
1442   *
1443   * @author Klaus Meffert
1444   * @since 3.01
1445   */

1446  public void setJGAPFactory(IJGAPFactory a_factory) {
1447    m_factory = a_factory;
1448  }
1449
1450  private void makeThreadKey() {
1451    Thread JavaDoc current = Thread.currentThread();
1452    threadKey = getThreadKey(current, m_id);
1453  }
1454
1455  /**
1456   * Deserialize the object. Needed to provide a unique ID for each thread the
1457   * object is used in.
1458   *
1459   * @param a_inputStream the ObjectInputStream provided for deserialzation
1460   * @throws ClassNotFoundException
1461   * @throws IOException
1462   *
1463   * @author Klaus Meffert
1464   * @since 3.01
1465   */

1466  private void readObject(ObjectInputStream a_inputStream)
1467      throws ClassNotFoundException JavaDoc, IOException {
1468    // Always perform the default de-serialization first.
1469
// --------------------------------------------------
1470
a_inputStream.defaultReadObject();
1471    makeThreadKey();
1472  }
1473
1474  /**
1475   * @return the id of the configuration set
1476   *
1477   * @author Klaus Meffert
1478   * @since 3.1
1479   */

1480  public String JavaDoc getId() {
1481    return m_id;
1482  }
1483
1484  /**
1485   * @return deep clone of this instance
1486   *
1487   * @author Klaus Meffert
1488   * @since 3.2
1489   */

1490  public Object JavaDoc clone() {
1491    return newInstance(m_id, m_name);
1492  }
1493
1494  /**
1495   * Creates a new Configuration instance by cloning. Allows to preset the
1496   * ID and the name.
1497   *
1498   * @param a_id new ID for clone
1499   * @param a_name new name for clone
1500   * @return deep clone of this instance
1501   *
1502   * @author Klaus Meffert
1503   * @since 3.2
1504   */

1505  public Configuration newInstance(String JavaDoc a_id, String JavaDoc a_name) {
1506    try {
1507      Configuration result = new Configuration(m_name);
1508      // Clone JGAPFactory first because it helps in cloning other objects.
1509
// ------------------------------------------------------------------
1510
if (m_factory instanceof ICloneable) {
1511        result.m_factory = (IJGAPFactory)((ICloneable)m_factory).clone();
1512      }
1513      else {
1514        // We must fallback to a standardized solution.
1515
// --------------------------------------------
1516
m_factory = new JGAPFactory(false);
1517        result.m_factory = (IJGAPFactory)((JGAPFactory)m_factory).clone();
1518      }
1519      if (m_bulkObjectiveFunction != null) {
1520        result.m_bulkObjectiveFunction = m_bulkObjectiveFunction;
1521      }
1522      result.m_chromosomeSize = m_chromosomeSize;
1523// result.m_chromosomePool = m_chromosomePool.clone();
1524
// result.m_conHandler = m_conHandler.clone();
1525
result.m_eventManager = (IEventManager)doClone(m_eventManager);
1526      result.m_fitnessEvaluator = (FitnessEvaluator)doClone(m_fitnessEvaluator);
1527      result.m_generationNr = 0;
1528      result.m_geneticOperators = (List)doClone(m_geneticOperators);
1529      result.m_keepPopulationSizeConstant = m_keepPopulationSizeConstant;
1530      result.m_minPercentageSizePopulation = m_minPercentageSizePopulation;
1531      result.m_objectiveFunction = (FitnessFunction)doClone(m_objectiveFunction);
1532      result.m_postSelectors = (ChainOfSelectors)doClone(m_postSelectors);
1533      result.m_preSelectors = (ChainOfSelectors)doClone(m_preSelectors);
1534      result.m_preserveFittestIndividual = m_preserveFittestIndividual;
1535      result.m_randomGenerator = (RandomGenerator)doClone(m_randomGenerator);
1536      result.m_sampleChromosome = (IChromosome)m_sampleChromosome.clone();
1537      result.m_settingsLocked = m_settingsLocked;
1538      result.m_sizeNaturalSelectorsPost = m_sizeNaturalSelectorsPost;
1539      result.m_sizeNaturalSelectorsPre = m_sizeNaturalSelectorsPre;
1540      // Configurable data.
1541
// ------------------
1542
result.m_config = new ConfigurationConfigurable();
1543      result.m_config.m_populationSize = m_config.m_populationSize;
1544      // Identificative data.
1545
// --------------------
1546
result.m_name = a_name;
1547      result.m_id = a_id;
1548      result.makeThreadKey();// Must be called after m_id is set
1549
return result;
1550    } catch (Throwable JavaDoc t) {
1551      throw new CloneException(t);
1552    }
1553  }
1554
1555  /**
1556   * Helper called from clone.
1557   *
1558   * @param a_objToClone the object to clone
1559   * @return cloned object or null, if cloning not possible
1560   * @throws Exception
1561   *
1562   * @author Klaus Meffert
1563   * @since 3.2
1564   */

1565  protected Object JavaDoc doClone(Object JavaDoc a_objToClone) throws Exception JavaDoc {
1566    if (a_objToClone != null) {
1567      ICloneHandler handler = getJGAPFactory().getCloneHandlerFor(
1568          a_objToClone, null);
1569      if (handler != null) {
1570        return handler.perform(a_objToClone, null, null);
1571      }
1572    }
1573    return null;
1574  }
1575
1576  /**
1577   * The equals-method.
1578   *
1579   * @param a_other the other object to compare
1580   * @return true if seen as equal
1581   *
1582   * @author Klaus Meffert
1583   * @since 3.2
1584   */

1585  public boolean equals(Object JavaDoc a_other) {
1586    return compareTo(a_other) == 0;
1587  }
1588
1589  /**
1590   * The compareTo-method.
1591   *
1592   * @param a_other the other object to compare
1593   * @return -1, 0, 1
1594   *
1595   * @author Klaus Meffert
1596   * @since 3.2
1597   */

1598  public int compareTo(Object JavaDoc a_other) {
1599    if (a_other == null) {
1600      return 1;
1601    }
1602    else {
1603      Configuration other = (Configuration) a_other;
1604      try {
1605        return new CompareToBuilder()
1606            .append(m_config.m_populationSize, other.m_config.m_populationSize)
1607            .append(m_factory, other.m_factory)
1608            .append(m_objectiveFunction, other.m_objectiveFunction)
1609            .append(m_fitnessEvaluator, other.m_fitnessEvaluator)
1610            .append(m_bulkObjectiveFunction, other.m_bulkObjectiveFunction)
1611            .append(m_sampleChromosome, other.m_sampleChromosome)
1612            .append(m_randomGenerator, other.m_randomGenerator)
1613// .append(m_eventManager, other.m_eventManager)
1614
// .append(m_chromosomePool, other.m_chromosomePool)
1615
.append(m_geneticOperators.toArray(), other.m_geneticOperators.toArray())
1616            .append(m_chromosomeSize, other.m_chromosomeSize)
1617            .append(m_preSelectors, other.m_preSelectors)
1618            .append(m_postSelectors, other.m_postSelectors)
1619            .append(m_sizeNaturalSelectorsPre, other.m_sizeNaturalSelectorsPre)
1620            .append(m_sizeNaturalSelectorsPost,
1621                    other.m_sizeNaturalSelectorsPost)
1622            .append(m_preserveFittestIndividual,
1623                    other.m_preserveFittestIndividual)
1624// .append(m_conHandler, other.m_conHandler)
1625
.append(threadKey, other.threadKey)
1626            .append(m_keepPopulationSizeConstant,
1627                    other.m_keepPopulationSizeConstant)
1628            .append(m_minPercentageSizePopulation,
1629                    other.m_minPercentageSizePopulation)
1630            .append(m_generationNr, other.m_generationNr)
1631            .append(m_name, other.m_name)
1632            .append(m_settingsLocked, other.m_settingsLocked)
1633            .toComparison();
1634      } catch (ClassCastException JavaDoc cex) {
1635        throw new RuntimeException JavaDoc("Cannot compare all objects within"
1636                                   + " org.jgap.Configuration, because at"
1637                                   + " least one does not implement interface"
1638                                   + " java.lang.Comparable!");
1639      }
1640    }
1641  }
1642
1643}
1644
Popular Tags